source: mainline/uspace/drv/nic/ar9271/ar9271.c@ a157846

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a157846 was 8a64320e, checked in by Martin Decky <martin@…>, 10 years ago

pre-merge coding style cleanup and code review

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