source: mainline/uspace/drv/nic/ar9271/ar9271.c@ 76d0981d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 76d0981d was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 24.8 KB
Line 
1/*
2 * Copyright (c) 2014 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file ar9271.c
30 *
31 * Driver for AR9271 USB WiFi dongle.
32 *
33 */
34
35#include <async.h>
36#include <ieee80211.h>
37#include <usb/classes/classes.h>
38#include <usb/dev/request.h>
39#include <usb/dev/poll.h>
40#include <usb/debug.h>
41#include <stdio.h>
42#include <ddf/interrupt.h>
43#include <errno.h>
44#include <str_error.h>
45#include <nic.h>
46#include <macros.h>
47#include "ath_usb.h"
48#include "wmi.h"
49#include "hw.h"
50#include "ar9271.h"
51
52#define NAME "ar9271"
53#define FIRMWARE_FILENAME "/drv/ar9271/ar9271.fw"
54
55const usb_endpoint_description_t usb_ar9271_out_bulk_endpoint_description = {
56 .transfer_type = USB_TRANSFER_BULK,
57 .direction = USB_DIRECTION_OUT,
58 .interface_class = USB_CLASS_VENDOR_SPECIFIC,
59 .interface_subclass = 0x0,
60 .interface_protocol = 0x0,
61 .flags = 0
62};
63
64const usb_endpoint_description_t usb_ar9271_in_bulk_endpoint_description = {
65 .transfer_type = USB_TRANSFER_BULK,
66 .direction = USB_DIRECTION_IN,
67 .interface_class = USB_CLASS_VENDOR_SPECIFIC,
68 .interface_subclass = 0x0,
69 .interface_protocol = 0x0,
70 .flags = 0
71};
72
73const usb_endpoint_description_t usb_ar9271_in_int_endpoint_description = {
74 .transfer_type = USB_TRANSFER_INTERRUPT,
75 .direction = USB_DIRECTION_IN,
76 .interface_class = USB_CLASS_VENDOR_SPECIFIC,
77 .interface_subclass = 0x0,
78 .interface_protocol = 0x0,
79 .flags = 0
80};
81
82const usb_endpoint_description_t usb_ar9271_out_int_endpoint_description = {
83 .transfer_type = USB_TRANSFER_INTERRUPT,
84 .direction = USB_DIRECTION_OUT,
85 .interface_class = USB_CLASS_VENDOR_SPECIFIC,
86 .interface_subclass = 0x0,
87 .interface_protocol = 0x0,
88 .flags = 0
89};
90
91/* Array of endpoints expected on the device, NULL terminated. */
92const usb_endpoint_description_t *endpoints[] = {
93 &usb_ar9271_out_bulk_endpoint_description,
94 &usb_ar9271_in_bulk_endpoint_description,
95 &usb_ar9271_in_int_endpoint_description,
96 &usb_ar9271_out_int_endpoint_description,
97 NULL
98};
99
100/* Callback when new device is to be controlled by this driver. */
101static errno_t ar9271_add_device(ddf_dev_t *);
102
103/* IEEE 802.11 callbacks */
104static errno_t ar9271_ieee80211_start(ieee80211_dev_t *);
105static errno_t ar9271_ieee80211_tx_handler(ieee80211_dev_t *, void *, size_t);
106static errno_t ar9271_ieee80211_set_freq(ieee80211_dev_t *, uint16_t);
107static errno_t ar9271_ieee80211_bssid_change(ieee80211_dev_t *, bool);
108static errno_t ar9271_ieee80211_key_config(ieee80211_dev_t *, ieee80211_key_config_t *,
109 bool);
110
111static driver_ops_t ar9271_driver_ops = {
112 .dev_add = ar9271_add_device
113};
114
115static driver_t ar9271_driver = {
116 .name = NAME,
117 .driver_ops = &ar9271_driver_ops
118};
119
120static ieee80211_ops_t ar9271_ieee80211_ops = {
121 .start = ar9271_ieee80211_start,
122 .tx_handler = ar9271_ieee80211_tx_handler,
123 .set_freq = ar9271_ieee80211_set_freq,
124 .bssid_change = ar9271_ieee80211_bssid_change,
125 .key_config = ar9271_ieee80211_key_config
126};
127
128static ieee80211_iface_t ar9271_ieee80211_iface;
129
130static errno_t ar9271_get_device_info(ddf_fun_t *, nic_device_info_t *);
131static errno_t ar9271_get_cable_state(ddf_fun_t *, nic_cable_state_t *);
132static errno_t ar9271_get_operation_mode(ddf_fun_t *, int *, nic_channel_mode_t *,
133 nic_role_t *);
134
135static nic_iface_t ar9271_ieee80211_nic_iface = {
136 .get_device_info = &ar9271_get_device_info,
137 .get_cable_state = &ar9271_get_cable_state,
138 .get_operation_mode = &ar9271_get_operation_mode
139};
140
141static ddf_dev_ops_t ar9271_ieee80211_dev_ops;
142
143/** Get device information.
144 *
145 */
146static errno_t ar9271_get_device_info(ddf_fun_t *dev, nic_device_info_t *info)
147{
148 assert(dev);
149 assert(info);
150
151 memset(info, 0, sizeof(nic_device_info_t));
152
153 info->vendor_id = 0x0cf3;
154 info->device_id = 0x9271;
155 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH,
156 "Atheros Communications, Inc.");
157 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH,
158 "AR9271");
159
160 return EOK;
161}
162
163/** Get cable state.
164 *
165 */
166static errno_t ar9271_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
167{
168 *state = NIC_CS_PLUGGED;
169
170 return EOK;
171}
172
173/** Get operation mode of the device.
174 *
175 */
176static errno_t ar9271_get_operation_mode(ddf_fun_t *fun, int *speed,
177 nic_channel_mode_t *duplex, nic_role_t *role)
178{
179 *duplex = NIC_CM_FULL_DUPLEX;
180 *speed = 10;
181 *role = NIC_ROLE_UNKNOWN;
182
183 return EOK;
184}
185
186/** Set multicast frames acceptance mode.
187 *
188 */
189static errno_t ar9271_on_multicast_mode_change(nic_t *nic,
190 nic_multicast_mode_t mode, const nic_address_t *addr, size_t addr_cnt)
191{
192 switch (mode) {
193 case NIC_MULTICAST_BLOCKED:
194 /* TODO */
195 break;
196 case NIC_MULTICAST_LIST:
197 /* TODO */
198 break;
199 case NIC_MULTICAST_PROMISC:
200 /* TODO */
201 break;
202 default:
203 return ENOTSUP;
204 }
205
206 return EOK;
207}
208
209/** Set unicast frames acceptance mode.
210 *
211 */
212static errno_t ar9271_on_unicast_mode_change(nic_t *nic, nic_unicast_mode_t mode,
213 const nic_address_t *addr, size_t addr_cnt)
214{
215 switch (mode) {
216 case NIC_UNICAST_BLOCKED:
217 /* TODO */
218 break;
219 case NIC_UNICAST_DEFAULT:
220 /* TODO */
221 break;
222 case NIC_UNICAST_LIST:
223 /* TODO */
224 break;
225 case NIC_UNICAST_PROMISC:
226 /* TODO */
227 break;
228 default:
229 return ENOTSUP;
230 }
231
232 return EOK;
233}
234
235/** Set broadcast frames acceptance mode.
236 *
237 */
238static errno_t ar9271_on_broadcast_mode_change(nic_t *nic,
239 nic_broadcast_mode_t mode)
240{
241 switch (mode) {
242 case NIC_BROADCAST_BLOCKED:
243 /* TODO */
244 break;
245 case NIC_BROADCAST_ACCEPTED:
246 /* TODO */
247 break;
248 default:
249 return ENOTSUP;
250 }
251
252 return EOK;
253}
254
255static bool ar9271_rx_status_error(uint8_t status)
256{
257 return (status & AR9271_RX_ERROR_PHY) || (status & AR9271_RX_ERROR_CRC);
258}
259
260static errno_t ar9271_data_polling(void *arg)
261{
262 assert(arg);
263
264 ar9271_t *ar9271 = (ar9271_t *) arg;
265
266 size_t buffer_size = ar9271->ath_device->data_response_length;
267 void *buffer = malloc(buffer_size);
268
269 while (true) {
270 size_t transferred_size;
271 if (htc_read_data_message(ar9271->htc_device,
272 buffer, buffer_size, &transferred_size) == EOK) {
273 size_t strip_length =
274 sizeof(ath_usb_data_header_t) +
275 sizeof(htc_frame_header_t) +
276 sizeof(htc_rx_status_t);
277
278 if (transferred_size < strip_length)
279 continue;
280
281 ath_usb_data_header_t *data_header =
282 (ath_usb_data_header_t *) buffer;
283
284 /* Invalid packet. */
285 if (data_header->tag != uint16_t_le2host(RX_TAG))
286 continue;
287
288 htc_rx_status_t *rx_status =
289 (htc_rx_status_t *) ((void *) buffer +
290 sizeof(ath_usb_data_header_t) +
291 sizeof(htc_frame_header_t));
292
293 uint16_t data_length =
294 uint16_t_be2host(rx_status->data_length);
295
296 int16_t payload_length =
297 transferred_size - strip_length;
298
299 if (payload_length - data_length < 0)
300 continue;
301
302 if (ar9271_rx_status_error(rx_status->status))
303 continue;
304
305 void *strip_buffer = buffer + strip_length;
306
307 ieee80211_rx_handler(ar9271->ieee80211_dev,
308 strip_buffer,
309 payload_length);
310 }
311 }
312
313 free(buffer);
314
315 return EOK;
316}
317
318/** IEEE 802.11 handlers.
319 *
320 */
321static errno_t ar9271_ieee80211_set_freq(ieee80211_dev_t *ieee80211_dev,
322 uint16_t freq)
323{
324 assert(ieee80211_dev);
325
326 ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
327
328 wmi_send_command(ar9271->htc_device, WMI_DISABLE_INTR, NULL, 0, NULL);
329 wmi_send_command(ar9271->htc_device, WMI_DRAIN_TXQ_ALL, NULL, 0, NULL);
330 wmi_send_command(ar9271->htc_device, WMI_STOP_RECV, NULL, 0, NULL);
331
332 errno_t rc = hw_freq_switch(ar9271, freq);
333 if (rc != EOK) {
334 usb_log_error("Failed to HW switch frequency.\n");
335 return rc;
336 }
337
338 wmi_send_command(ar9271->htc_device, WMI_START_RECV, NULL, 0, NULL);
339
340 rc = hw_rx_init(ar9271);
341 if (rc != EOK) {
342 usb_log_error("Failed to initialize RX.\n");
343 return rc;
344 }
345
346 uint16_t htc_mode = host2uint16_t_be(1);
347 wmi_send_command(ar9271->htc_device, WMI_SET_MODE,
348 (uint8_t *) &htc_mode, sizeof(htc_mode), NULL);
349 wmi_send_command(ar9271->htc_device, WMI_ENABLE_INTR, NULL, 0, NULL);
350
351 return EOK;
352}
353
354static errno_t ar9271_ieee80211_bssid_change(ieee80211_dev_t *ieee80211_dev,
355 bool connected)
356{
357 assert(ieee80211_dev);
358
359 ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
360
361 if (connected) {
362 nic_address_t bssid;
363 ieee80211_query_bssid(ieee80211_dev, &bssid);
364
365 htc_sta_msg_t sta_msg;
366 memset(&sta_msg, 0, sizeof(htc_sta_msg_t));
367 sta_msg.is_vif_sta = 0;
368 sta_msg.max_ampdu =
369 host2uint16_t_be(1 << IEEE80211_MAX_AMPDU_FACTOR);
370 sta_msg.sta_index = 1;
371 sta_msg.vif_index = 0;
372 memcpy(&sta_msg.addr, bssid.address, ETH_ADDR);
373
374 wmi_send_command(ar9271->htc_device, WMI_NODE_CREATE,
375 (uint8_t *) &sta_msg, sizeof(sta_msg), NULL);
376
377 htc_rate_msg_t rate_msg;
378 memset(&rate_msg, 0, sizeof(htc_rate_msg_t));
379 rate_msg.sta_index = 1;
380 rate_msg.is_new = 1;
381 rate_msg.legacy_rates_count = ARRAY_SIZE(ieee80211bg_data_rates);
382 memcpy(&rate_msg.legacy_rates,
383 ieee80211bg_data_rates,
384 ARRAY_SIZE(ieee80211bg_data_rates));
385
386 wmi_send_command(ar9271->htc_device, WMI_RC_RATE_UPDATE,
387 (uint8_t *) &rate_msg, sizeof(rate_msg), NULL);
388
389 hw_set_rx_filter(ar9271, true);
390 } else {
391 uint8_t station_id = 1;
392 wmi_send_command(ar9271->htc_device, WMI_NODE_REMOVE,
393 &station_id, sizeof(station_id), NULL);
394
395 hw_set_rx_filter(ar9271, false);
396 }
397
398 hw_set_bssid(ar9271);
399
400 return EOK;
401}
402
403static errno_t ar9271_ieee80211_key_config(ieee80211_dev_t *ieee80211_dev,
404 ieee80211_key_config_t *key_conf, bool insert)
405{
406 assert(ieee80211_dev);
407
408 ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
409
410 if(insert) {
411 assert(key_conf);
412
413 uint32_t key[5];
414 uint32_t key_type;
415 uint32_t reg_ptr, mic_reg_ptr;
416 void *data_start;
417
418 nic_address_t bssid;
419 ieee80211_query_bssid(ieee80211_dev, &bssid);
420
421 switch (key_conf->suite) {
422 case IEEE80211_SECURITY_SUITE_WEP40:
423 key_type = AR9271_KEY_TABLE_TYPE_WEP40;
424 break;
425 case IEEE80211_SECURITY_SUITE_WEP104:
426 key_type = AR9271_KEY_TABLE_TYPE_WEP104;
427 break;
428 case IEEE80211_SECURITY_SUITE_TKIP:
429 key_type = AR9271_KEY_TABLE_TYPE_TKIP;
430 break;
431 case IEEE80211_SECURITY_SUITE_CCMP:
432 key_type = AR9271_KEY_TABLE_TYPE_CCMP;
433 break;
434 default:
435 key_type = -1;
436 }
437
438 uint8_t key_id =
439 (key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) ?
440 AR9271_STA_KEY_INDEX : key_conf->id;
441
442 reg_ptr = AR9271_KEY_TABLE(key_id);
443 mic_reg_ptr = AR9271_KEY_TABLE(key_id + 64);
444 data_start = (void *) key_conf->data;
445
446 key[0] = uint32_t_le2host(*((uint32_t *) data_start));
447 key[1] = uint16_t_le2host(*((uint16_t *) (data_start + 4)));
448 key[2] = uint32_t_le2host(*((uint32_t *) (data_start + 6)));
449 key[3] = uint16_t_le2host(*((uint16_t *) (data_start + 10)));
450 key[4] = uint32_t_le2host(*((uint32_t *) (data_start + 12)));
451
452 if ((key_conf->suite == IEEE80211_SECURITY_SUITE_WEP40) ||
453 (key_conf->suite == IEEE80211_SECURITY_SUITE_WEP104))
454 key[4] &= 0xFF;
455
456 wmi_reg_write(ar9271->htc_device, reg_ptr + 0, key[0]);
457 wmi_reg_write(ar9271->htc_device, reg_ptr + 4, key[1]);
458 wmi_reg_write(ar9271->htc_device, reg_ptr + 8, key[2]);
459 wmi_reg_write(ar9271->htc_device, reg_ptr + 12, key[3]);
460 wmi_reg_write(ar9271->htc_device, reg_ptr + 16, key[4]);
461 wmi_reg_write(ar9271->htc_device, reg_ptr + 20, key_type);
462
463 uint32_t macl;
464 uint32_t mach;
465 if (key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) {
466 data_start = (void *) bssid.address;
467 macl = uint32_t_le2host(*((uint32_t *) data_start));
468 mach = uint16_t_le2host(*((uint16_t *) (data_start + 4)));
469 } else {
470 macl = 0;
471 mach = 0;
472 }
473
474 macl >>= 1;
475 macl |= (mach & 1) << 31;
476 mach >>= 1;
477 mach |= 0x8000;
478
479 wmi_reg_write(ar9271->htc_device, reg_ptr + 24, macl);
480 wmi_reg_write(ar9271->htc_device, reg_ptr + 28, mach);
481
482 /* Setup MIC keys for TKIP. */
483 if (key_conf->suite == IEEE80211_SECURITY_SUITE_TKIP) {
484 uint32_t mic[5];
485 uint8_t *gen_mic = data_start + IEEE80211_TKIP_RX_MIC_OFFSET;
486 uint8_t *tx_mic;
487
488 if (key_conf->flags & IEEE80211_KEY_FLAG_TYPE_GROUP)
489 tx_mic = gen_mic;
490 else
491 tx_mic = data_start + IEEE80211_TKIP_TX_MIC_OFFSET;
492
493 mic[0] = uint32_t_le2host(*((uint32_t *) gen_mic));
494 mic[1] = uint16_t_le2host(*((uint16_t *) (tx_mic + 2))) & 0xFFFF;
495 mic[2] = uint32_t_le2host(*((uint32_t *) (gen_mic + 4)));
496 mic[3] = uint16_t_le2host(*((uint16_t *) tx_mic)) & 0xFFFF;
497 mic[4] = uint32_t_le2host(*((uint32_t *) (tx_mic + 4)));
498
499 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 0, mic[0]);
500 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 4, mic[1]);
501 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 8, mic[2]);
502 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 12, mic[3]);
503 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 16, mic[4]);
504 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 20,
505 AR9271_KEY_TABLE_TYPE_CLR);
506
507 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 24, 0);
508 wmi_reg_write(ar9271->htc_device, mic_reg_ptr + 28, 0);
509 }
510
511 if (key_conf->flags & IEEE80211_KEY_FLAG_TYPE_GROUP)
512 ieee80211_setup_key_confirm(ieee80211_dev, true);
513 } else {
514 /* TODO: Delete keys from device */
515 ieee80211_setup_key_confirm(ieee80211_dev, false);
516 }
517
518 return EOK;
519}
520
521static errno_t ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
522 void *buffer, size_t buffer_size)
523{
524 assert(ieee80211_dev);
525
526 size_t complete_size;
527 size_t offset;
528 void *complete_buffer;
529 int endpoint;
530
531 ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
532
533 uint16_t frame_ctrl = *((uint16_t *) buffer);
534 if (ieee80211_is_data_frame(frame_ctrl)) {
535 offset = sizeof(htc_tx_data_header_t) +
536 sizeof(htc_frame_header_t);
537 complete_size = buffer_size + offset;
538 complete_buffer = malloc(complete_size);
539 memset(complete_buffer, 0, complete_size);
540
541 /*
542 * Because we handle just station mode yet, node ID and VIF ID
543 * are fixed.
544 */
545 htc_tx_data_header_t *data_header =
546 (htc_tx_data_header_t *)
547 (complete_buffer + sizeof(htc_frame_header_t));
548 data_header->data_type = HTC_DATA_NORMAL;
549 data_header->node_idx = 1;
550 data_header->vif_idx = 0;
551 data_header->cookie = 0;
552
553 if (ieee80211_query_using_key(ieee80211_dev)) {
554 data_header->keyix = AR9271_STA_KEY_INDEX;
555
556 int sec_suite =
557 ieee80211_get_pairwise_security(ieee80211_dev);
558
559 switch (sec_suite) {
560 case IEEE80211_SECURITY_SUITE_WEP40:
561 case IEEE80211_SECURITY_SUITE_WEP104:
562 data_header->key_type = AR9271_KEY_TYPE_WEP;
563 break;
564 case IEEE80211_SECURITY_SUITE_TKIP:
565 data_header->key_type = AR9271_KEY_TYPE_TKIP;
566 break;
567 case IEEE80211_SECURITY_SUITE_CCMP:
568 data_header->key_type = AR9271_KEY_TYPE_AES;
569 break;
570 }
571 } else {
572 data_header->key_type = 0;
573 data_header->keyix = 0xFF;
574 }
575
576 endpoint = ar9271->htc_device->endpoints.data_be_endpoint;
577 } else {
578 offset = sizeof(htc_tx_management_header_t) +
579 sizeof(htc_frame_header_t);
580 complete_size = buffer_size + offset;
581 complete_buffer = malloc(complete_size);
582 memset(complete_buffer, 0, complete_size);
583
584 /*
585 * Because we handle just station mode yet, node ID and VIF ID
586 * are fixed.
587 */
588 htc_tx_management_header_t *mgmt_header =
589 (htc_tx_management_header_t *)
590 (complete_buffer + sizeof(htc_frame_header_t));
591 mgmt_header->node_idx = 0;
592 mgmt_header->vif_idx = 0;
593 mgmt_header->cookie = 0;
594 mgmt_header->keyix = 0xFF;
595
596 endpoint = ar9271->htc_device->endpoints.mgmt_endpoint;
597 }
598
599 /* Copy IEEE802.11 data to new allocated buffer with HTC headers. */
600 memcpy(complete_buffer + offset, buffer, buffer_size);
601
602 htc_send_data_message(ar9271->htc_device, complete_buffer,
603 complete_size, endpoint);
604
605 free(complete_buffer);
606
607 return EOK;
608}
609
610static errno_t ar9271_ieee80211_start(ieee80211_dev_t *ieee80211_dev)
611{
612 assert(ieee80211_dev);
613
614 ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
615
616 wmi_send_command(ar9271->htc_device, WMI_FLUSH_RECV, NULL, 0, NULL);
617
618 errno_t rc = hw_reset(ar9271);
619 if (rc != EOK) {
620 usb_log_error("Failed to do HW reset.\n");
621 return rc;
622 }
623
624 uint16_t htc_mode = host2uint16_t_be(1);
625 wmi_send_command(ar9271->htc_device, WMI_SET_MODE,
626 (uint8_t *) &htc_mode, sizeof(htc_mode), NULL);
627 wmi_send_command(ar9271->htc_device, WMI_ATH_INIT, NULL, 0, NULL);
628 wmi_send_command(ar9271->htc_device, WMI_START_RECV, NULL, 0, NULL);
629 wmi_send_command(ar9271->htc_device, WMI_ENABLE_INTR, NULL, 0, NULL);
630
631 rc = hw_rx_init(ar9271);
632 if (rc != EOK) {
633 usb_log_error("Failed to initialize RX.\n");
634 return rc;
635 }
636
637 /* Send capability message to target. */
638 htc_cap_msg_t cap_msg;
639 cap_msg.ampdu_limit = host2uint32_t_be(0xffff);
640 cap_msg.ampdu_subframes = 0xff;
641 cap_msg.enable_coex = 0;
642 cap_msg.tx_chainmask = 0x1;
643
644 wmi_send_command(ar9271->htc_device, WMI_TARGET_IC_UPDATE,
645 (uint8_t *) &cap_msg, sizeof(cap_msg), NULL);
646
647 rc = htc_init_new_vif(ar9271->htc_device);
648 if (rc != EOK) {
649 usb_log_error("Failed to initialize new VIF.\n");
650 return rc;
651 }
652
653 /* Add data polling fibril. */
654 fid_t fibril = fibril_create(ar9271_data_polling, ar9271);
655 if (fibril == 0)
656 return ENOMEM;
657
658 fibril_add_ready(fibril);
659
660 ar9271->starting_up = false;
661 ieee80211_set_ready(ieee80211_dev, true);
662
663 usb_log_info("Device fully initialized.\n");
664
665 return EOK;
666}
667
668static errno_t ar9271_init(ar9271_t *ar9271, usb_device_t *usb_device, const usb_endpoint_description_t **endpoints)
669{
670 ar9271->starting_up = true;
671 ar9271->usb_device = usb_device;
672
673 fibril_mutex_initialize(&ar9271->ar9271_lock);
674
675 ar9271->ath_device = calloc(1, sizeof(ath_t));
676 if (!ar9271->ath_device) {
677 usb_log_error("Failed to allocate memory for ath device "
678 "structure.\n");
679 return ENOMEM;
680 }
681
682 errno_t rc = ath_usb_init(ar9271->ath_device, usb_device, endpoints);
683 if (rc != EOK) {
684 free(ar9271->ath_device);
685 usb_log_error("Failed to initialize ath device.\n");
686 return rc;
687 }
688
689 /* IEEE 802.11 framework structure initialization. */
690 ar9271->ieee80211_dev = ieee80211_device_create();
691 if (!ar9271->ieee80211_dev) {
692 free(ar9271->ath_device);
693 usb_log_error("Failed to allocate memory for IEEE80211 device "
694 "structure.\n");
695 return ENOMEM;
696 }
697
698 rc = ieee80211_device_init(ar9271->ieee80211_dev, ar9271->ddf_dev);
699 if (rc != EOK) {
700 free(ar9271->ieee80211_dev);
701 free(ar9271->ath_device);
702 usb_log_error("Failed to initialize IEEE80211 device structure."
703 "\n");
704 return rc;
705 }
706
707 ieee80211_set_specific(ar9271->ieee80211_dev, ar9271);
708
709 /* HTC device structure initialization. */
710 ar9271->htc_device = calloc(1, sizeof(htc_device_t));
711 if (!ar9271->htc_device) {
712 free(ar9271->ieee80211_dev);
713 free(ar9271->ath_device);
714 usb_log_error("Failed to allocate memory for HTC device "
715 "structure.\n");
716 return ENOMEM;
717 }
718
719 rc = htc_device_init(ar9271->ath_device, ar9271->ieee80211_dev,
720 ar9271->htc_device);
721 if (rc != EOK) {
722 free(ar9271->htc_device);
723 free(ar9271->ieee80211_dev);
724 free(ar9271->ath_device);
725 usb_log_error("Failed to initialize HTC device structure.\n");
726 return rc;
727 }
728
729 return EOK;
730}
731
732/** Upload firmware to WiFi device.
733 *
734 * @param ar9271 AR9271 device structure
735 *
736 * @return EOK if succeed, error code otherwise
737 *
738 */
739static errno_t ar9271_upload_fw(ar9271_t *ar9271)
740{
741 usb_device_t *usb_device = ar9271->usb_device;
742
743 /* TODO: Set by maximum packet size in pipe. */
744 static const size_t MAX_TRANSFER_SIZE = 512;
745
746 /* Load FW from file. */
747 FILE *fw_file = fopen(FIRMWARE_FILENAME, "rb");
748 if (fw_file == NULL) {
749 usb_log_error("Failed opening file with firmware.\n");
750 return ENOENT;
751 }
752
753 fseek(fw_file, 0, SEEK_END);
754 uint64_t file_size = ftell(fw_file);
755 fseek(fw_file, 0, SEEK_SET);
756
757 void *fw_data = malloc(file_size);
758 if (fw_data == NULL) {
759 fclose(fw_file);
760 usb_log_error("Failed allocating memory for firmware.\n");
761 return ENOMEM;
762 }
763
764 fread(fw_data, file_size, 1, fw_file);
765 fclose(fw_file);
766
767 /* Upload FW to device. */
768 uint64_t remain_size = file_size;
769 uint32_t current_addr = AR9271_FW_ADDRESS;
770 uint8_t *current_data = fw_data;
771 uint8_t *buffer = malloc(MAX_TRANSFER_SIZE);
772
773 while (remain_size > 0) {
774 size_t chunk_size = min(remain_size, MAX_TRANSFER_SIZE);
775 memcpy(buffer, current_data, chunk_size);
776 usb_pipe_t *ctrl_pipe = usb_device_get_default_pipe(usb_device);
777 errno_t rc = usb_control_request_set(ctrl_pipe,
778 USB_REQUEST_TYPE_VENDOR,
779 USB_REQUEST_RECIPIENT_DEVICE,
780 AR9271_FW_DOWNLOAD,
781 uint16_host2usb(current_addr >> 8),
782 0, buffer, chunk_size);
783 if (rc != EOK) {
784 free(fw_data);
785 free(buffer);
786 usb_log_error("Error while uploading firmware. "
787 "Error: %s\n", str_error_name(rc));
788 return rc;
789 }
790
791 remain_size -= chunk_size;
792 current_addr += chunk_size;
793 current_data += chunk_size;
794 }
795
796 free(fw_data);
797 free(buffer);
798
799 /*
800 * Send command that firmware is successfully uploaded.
801 * This should initiate creating confirmation message in
802 * device side buffer which we will check in htc_check_ready function.
803 */
804 usb_pipe_t *ctrl_pipe = usb_device_get_default_pipe(usb_device);
805 errno_t rc = usb_control_request_set(ctrl_pipe,
806 USB_REQUEST_TYPE_VENDOR,
807 USB_REQUEST_RECIPIENT_DEVICE,
808 AR9271_FW_DOWNLOAD_COMP,
809 uint16_host2usb(AR9271_FW_OFFSET >> 8),
810 0, NULL, 0);
811
812 if (rc != EOK) {
813 usb_log_error("IO error when sending fw upload confirmation "
814 "message.\n");
815 return rc;
816 }
817
818 usb_log_info("Firmware uploaded successfully.\n");
819
820 /* Wait until firmware is ready - wait for 1 second to be sure. */
821 async_sleep(1);
822
823 return rc;
824}
825
826/** Create driver data structure.
827 *
828 * @param dev The device structure
829 *
830 * @return Intialized device data structure or NULL if error occured
831 */
832static ar9271_t *ar9271_create_dev_data(ddf_dev_t *dev)
833{
834 /* USB framework initialization. */
835 const char *err_msg = NULL;
836 errno_t rc = usb_device_create_ddf(dev, endpoints, &err_msg);
837 if (rc != EOK) {
838 usb_log_error("Failed to create USB device: %s, "
839 "ERR_NUM = %s\n", err_msg, str_error_name(rc));
840 return NULL;
841 }
842
843 /* AR9271 structure initialization. */
844 ar9271_t *ar9271 = calloc(1, sizeof(ar9271_t));
845 if (!ar9271) {
846 usb_log_error("Failed to allocate memory for device "
847 "structure.\n");
848 return NULL;
849 }
850
851 ar9271->ddf_dev = dev;
852
853 rc = ar9271_init(ar9271, usb_device_get(dev), endpoints);
854 if (rc != EOK) {
855 free(ar9271);
856 usb_log_error("Failed to initialize AR9271 structure: %s\n",
857 str_error_name(rc));
858 return NULL;
859 }
860
861 return ar9271;
862}
863
864/** Clean up the ar9271 device structure.
865 *
866 * @param dev The device structure.
867 */
868static void ar9271_delete_dev_data(ar9271_t *ar9271)
869{
870 assert(ar9271);
871
872 // TODO
873}
874
875/** Probe and initialize the newly added device.
876 *
877 * @param dev The device structure.
878 *
879 * @return EOK if succeed, error code otherwise
880 */
881static errno_t ar9271_add_device(ddf_dev_t *dev)
882{
883 assert(dev);
884
885 /* Allocate driver data for the device. */
886 ar9271_t *ar9271 = ar9271_create_dev_data(dev);
887 if (ar9271 == NULL) {
888 usb_log_error("Unable to allocate device softstate.\n");
889 return ENOMEM;
890 }
891
892 usb_log_info("HelenOS AR9271 device initialized.\n");
893
894 /* Upload AR9271 firmware. */
895 ar9271_upload_fw(ar9271);
896
897 /* Initialize AR9271 HTC services. */
898 errno_t rc = htc_init(ar9271->htc_device);
899 if (rc != EOK) {
900 ar9271_delete_dev_data(ar9271);
901 usb_log_error("HTC initialization failed.\n");
902 return rc;
903 }
904
905 /* Initialize AR9271 HW. */
906 rc = hw_init(ar9271);
907 if (rc != EOK) {
908 ar9271_delete_dev_data(ar9271);
909 usb_log_error("HW initialization failed.\n");
910 return rc;
911 }
912
913 /* Initialize AR9271 IEEE 802.11 framework. */
914 rc = ieee80211_init(ar9271->ieee80211_dev, &ar9271_ieee80211_ops,
915 &ar9271_ieee80211_iface, &ar9271_ieee80211_nic_iface,
916 &ar9271_ieee80211_dev_ops);
917 if (rc != EOK) {
918 ar9271_delete_dev_data(ar9271);
919 usb_log_error("Failed to initialize IEEE80211 framework.\n");
920 return rc;
921 }
922
923 nic_set_filtering_change_handlers(nic_get_from_ddf_dev(dev),
924 ar9271_on_unicast_mode_change, ar9271_on_multicast_mode_change,
925 ar9271_on_broadcast_mode_change, NULL, NULL);
926
927 usb_log_info("HelenOS AR9271 added device.\n");
928
929 return EOK;
930}
931
932int main(void)
933{
934 log_init(NAME);
935
936 if (nic_driver_init(NAME) != EOK)
937 return 1;
938
939 usb_log_info("HelenOS AR9271 driver started.\n");
940
941 return ddf_driver_main(&ar9271_driver);
942}
Note: See TracBrowser for help on using the repository browser.