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

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

Sleep is more natural as part of the fibril API.
(the implementation will move later)

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