source: mainline/uspace/drv/nic/ar9271/ar9271.c@ 5f4c41b2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5f4c41b2 was 582a0b8, checked in by Jakub Jermar <jakub@…>, 8 years ago

Remove unistd.h

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