Line data Source code
1 : /* $OpenBSD: if_athn_usb.c,v 1.51 2018/09/06 11:50:54 jsg Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
5 : * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
6 : *
7 : * Permission to use, copy, modify, and distribute this software for any
8 : * purpose with or without fee is hereby granted, provided that the above
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 :
20 : /*
21 : * USB front-end for Atheros AR9271 and AR7010 chipsets.
22 : */
23 :
24 : #include "bpfilter.h"
25 :
26 : #include <sys/param.h>
27 : #include <sys/sockio.h>
28 : #include <sys/mbuf.h>
29 : #include <sys/kernel.h>
30 : #include <sys/socket.h>
31 : #include <sys/systm.h>
32 : #include <sys/timeout.h>
33 : #include <sys/conf.h>
34 : #include <sys/device.h>
35 : #include <sys/endian.h>
36 :
37 : #include <machine/bus.h>
38 : #include <machine/intr.h>
39 :
40 : #if NBPFILTER > 0
41 : #include <net/bpf.h>
42 : #endif
43 : #include <net/if.h>
44 : #include <net/if_dl.h>
45 : #include <net/if_media.h>
46 :
47 : #include <netinet/in.h>
48 : #include <netinet/if_ether.h>
49 :
50 : #include <net80211/ieee80211_var.h>
51 : #include <net80211/ieee80211_amrr.h>
52 : #include <net80211/ieee80211_mira.h>
53 : #include <net80211/ieee80211_radiotap.h>
54 :
55 : #include <dev/ic/athnreg.h>
56 : #include <dev/ic/athnvar.h>
57 :
58 : #include <dev/usb/usb.h>
59 : #include <dev/usb/usbdi.h>
60 : #include <dev/usb/usbdi_util.h>
61 : #include <dev/usb/usbdevs.h>
62 :
63 : #include <dev/usb/if_athn_usb.h>
64 :
65 : static const struct athn_usb_type {
66 : struct usb_devno devno;
67 : u_int flags;
68 : } athn_usb_devs[] = {
69 : {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_AR9280 },
70 : ATHN_USB_FLAG_AR7010 },
71 : {{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_AR9287 },
72 : ATHN_USB_FLAG_AR7010 },
73 : {{ USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9271_1 }},
74 : {{ USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9271_2 }},
75 : {{ USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9271_3 }},
76 : {{ USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9280 },
77 : ATHN_USB_FLAG_AR7010 },
78 : {{ USB_VENDOR_ATHEROS2, USB_PRODUCT_ATHEROS2_AR9287 },
79 : ATHN_USB_FLAG_AR7010 },
80 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_1 }},
81 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_2 }},
82 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_3 }},
83 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_4 }},
84 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_5 }},
85 : {{ USB_VENDOR_AZUREWAVE, USB_PRODUCT_AZUREWAVE_AR9271_6 }},
86 : {{ USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_AR9271 }},
87 : {{ USB_VENDOR_LITEON, USB_PRODUCT_LITEON_AR9271 }},
88 : {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WNA1100 }},
89 : {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_WNDA3200 },
90 : ATHN_USB_FLAG_AR7010 },
91 : {{ USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_N5HBZ0000055 },
92 : ATHN_USB_FLAG_AR7010 },
93 : {{ USB_VENDOR_VIA, USB_PRODUCT_VIA_AR9271 }}
94 : };
95 : #define athn_usb_lookup(v, p) \
96 : ((const struct athn_usb_type *)usb_lookup(athn_usb_devs, v, p))
97 :
98 : int athn_usb_match(struct device *, void *, void *);
99 : void athn_usb_attach(struct device *, struct device *, void *);
100 : int athn_usb_detach(struct device *, int);
101 : void athn_usb_attachhook(struct device *);
102 : int athn_usb_open_pipes(struct athn_usb_softc *);
103 : void athn_usb_close_pipes(struct athn_usb_softc *);
104 : int athn_usb_alloc_rx_list(struct athn_usb_softc *);
105 : void athn_usb_free_rx_list(struct athn_usb_softc *);
106 : int athn_usb_alloc_tx_list(struct athn_usb_softc *);
107 : void athn_usb_free_tx_list(struct athn_usb_softc *);
108 : int athn_usb_alloc_tx_cmd(struct athn_usb_softc *);
109 : void athn_usb_free_tx_cmd(struct athn_usb_softc *);
110 : void athn_usb_task(void *);
111 : void athn_usb_do_async(struct athn_usb_softc *,
112 : void (*)(struct athn_usb_softc *, void *), void *, int);
113 : void athn_usb_wait_async(struct athn_usb_softc *);
114 : int athn_usb_load_firmware(struct athn_usb_softc *);
115 : int athn_usb_htc_msg(struct athn_usb_softc *, uint16_t, void *,
116 : int);
117 : int athn_usb_htc_setup(struct athn_usb_softc *);
118 : int athn_usb_htc_connect_svc(struct athn_usb_softc *, uint16_t,
119 : uint8_t, uint8_t, uint8_t *);
120 : int athn_usb_wmi_xcmd(struct athn_usb_softc *, uint16_t, void *,
121 : int, void *);
122 : int athn_usb_read_rom(struct athn_softc *);
123 : uint32_t athn_usb_read(struct athn_softc *, uint32_t);
124 : void athn_usb_write(struct athn_softc *, uint32_t, uint32_t);
125 : void athn_usb_write_barrier(struct athn_softc *);
126 : int athn_usb_media_change(struct ifnet *);
127 : void athn_usb_next_scan(void *);
128 : int athn_usb_newstate(struct ieee80211com *, enum ieee80211_state,
129 : int);
130 : void athn_usb_newstate_cb(struct athn_usb_softc *, void *);
131 : void athn_usb_newassoc(struct ieee80211com *,
132 : struct ieee80211_node *, int);
133 : void athn_usb_newassoc_cb(struct athn_usb_softc *, void *);
134 : struct ieee80211_node *athn_usb_node_alloc(struct ieee80211com *);
135 : void athn_usb_count_active_sta(void *, struct ieee80211_node *);
136 : void athn_usb_newauth_cb(struct athn_usb_softc *, void *);
137 : int athn_usb_newauth(struct ieee80211com *,
138 : struct ieee80211_node *, int, uint16_t);
139 : void athn_usb_node_free(struct ieee80211com *,
140 : struct ieee80211_node *);
141 : void athn_usb_node_free_cb(struct athn_usb_softc *, void *);
142 : int athn_usb_ampdu_tx_start(struct ieee80211com *,
143 : struct ieee80211_node *, uint8_t);
144 : void athn_usb_ampdu_tx_start_cb(struct athn_usb_softc *, void *);
145 : void athn_usb_ampdu_tx_stop(struct ieee80211com *,
146 : struct ieee80211_node *, uint8_t);
147 : void athn_usb_ampdu_tx_stop_cb(struct athn_usb_softc *, void *);
148 : void athn_usb_clean_nodes(void *, struct ieee80211_node *);
149 : int athn_usb_create_node(struct athn_usb_softc *,
150 : struct ieee80211_node *);
151 : int athn_usb_node_set_rates(struct athn_usb_softc *,
152 : struct ieee80211_node *);
153 : int athn_usb_remove_node(struct athn_usb_softc *,
154 : struct ieee80211_node *);
155 : void athn_usb_rx_enable(struct athn_softc *);
156 : int athn_set_chan(struct athn_softc *, struct ieee80211_channel *,
157 : struct ieee80211_channel *);
158 : int athn_usb_switch_chan(struct athn_softc *,
159 : struct ieee80211_channel *, struct ieee80211_channel *);
160 : void athn_usb_updateedca(struct ieee80211com *);
161 : void athn_usb_updateedca_cb(struct athn_usb_softc *, void *);
162 : void athn_usb_updateslot(struct ieee80211com *);
163 : void athn_usb_updateslot_cb(struct athn_usb_softc *, void *);
164 : int athn_usb_set_key(struct ieee80211com *,
165 : struct ieee80211_node *, struct ieee80211_key *);
166 : void athn_usb_set_key_cb(struct athn_usb_softc *, void *);
167 : void athn_usb_delete_key(struct ieee80211com *,
168 : struct ieee80211_node *, struct ieee80211_key *);
169 : void athn_usb_delete_key_cb(struct athn_usb_softc *, void *);
170 : void athn_usb_bcneof(struct usbd_xfer *, void *,
171 : usbd_status);
172 : void athn_usb_swba(struct athn_usb_softc *);
173 : void athn_usb_tx_status(void *, struct ieee80211_node *);
174 : void athn_usb_rx_wmi_ctrl(struct athn_usb_softc *, uint8_t *, int);
175 : void athn_usb_intr(struct usbd_xfer *, void *,
176 : usbd_status);
177 : void athn_usb_rx_radiotap(struct athn_softc *, struct mbuf *,
178 : struct ar_rx_status *);
179 : void athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *);
180 : void athn_usb_rxeof(struct usbd_xfer *, void *,
181 : usbd_status);
182 : void athn_usb_txeof(struct usbd_xfer *, void *,
183 : usbd_status);
184 : int athn_usb_tx(struct athn_softc *, struct mbuf *,
185 : struct ieee80211_node *);
186 : void athn_usb_start(struct ifnet *);
187 : void athn_usb_watchdog(struct ifnet *);
188 : int athn_usb_ioctl(struct ifnet *, u_long, caddr_t);
189 : int athn_usb_init(struct ifnet *);
190 : void athn_usb_stop(struct ifnet *);
191 : void ar9271_load_ani(struct athn_softc *);
192 :
193 : /* Shortcut. */
194 : #define athn_usb_wmi_cmd(sc, cmd_id) \
195 : athn_usb_wmi_xcmd(sc, cmd_id, NULL, 0, NULL)
196 :
197 : /* Extern functions. */
198 : void athn_led_init(struct athn_softc *);
199 : void athn_set_led(struct athn_softc *, int);
200 : void athn_btcoex_init(struct athn_softc *);
201 : void athn_set_rxfilter(struct athn_softc *, uint32_t);
202 : int athn_reset(struct athn_softc *, int);
203 : void athn_init_pll(struct athn_softc *,
204 : const struct ieee80211_channel *);
205 : int athn_set_power_awake(struct athn_softc *);
206 : void athn_set_power_sleep(struct athn_softc *);
207 : void athn_reset_key(struct athn_softc *, int);
208 : int athn_set_key(struct ieee80211com *, struct ieee80211_node *,
209 : struct ieee80211_key *);
210 : void athn_delete_key(struct ieee80211com *, struct ieee80211_node *,
211 : struct ieee80211_key *);
212 : void athn_rx_start(struct athn_softc *);
213 : void athn_set_sta_timers(struct athn_softc *);
214 : void athn_set_hostap_timers(struct athn_softc *);
215 : void athn_set_opmode(struct athn_softc *);
216 : void athn_set_bss(struct athn_softc *, struct ieee80211_node *);
217 : int athn_hw_reset(struct athn_softc *, struct ieee80211_channel *,
218 : struct ieee80211_channel *, int);
219 : void athn_updateedca(struct ieee80211com *);
220 : void athn_updateslot(struct ieee80211com *);
221 :
222 : const struct cfattach athn_usb_ca = {
223 : sizeof(struct athn_usb_softc),
224 : athn_usb_match,
225 : athn_usb_attach,
226 : athn_usb_detach
227 : };
228 :
229 : int
230 0 : athn_usb_match(struct device *parent, void *match, void *aux)
231 : {
232 0 : struct usb_attach_arg *uaa = aux;
233 :
234 0 : if (uaa->iface == NULL || uaa->configno != 1)
235 0 : return (UMATCH_NONE);
236 :
237 0 : return ((athn_usb_lookup(uaa->vendor, uaa->product) != NULL) ?
238 : UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
239 0 : }
240 :
241 : void
242 0 : athn_usb_attach(struct device *parent, struct device *self, void *aux)
243 : {
244 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)self;
245 0 : struct athn_softc *sc = &usc->sc_sc;
246 0 : struct usb_attach_arg *uaa = aux;
247 :
248 0 : usc->sc_udev = uaa->device;
249 0 : usc->sc_iface = uaa->iface;
250 :
251 0 : usc->flags = athn_usb_lookup(uaa->vendor, uaa->product)->flags;
252 0 : sc->flags |= ATHN_FLAG_USB;
253 : #ifdef notyet
254 : /* Check if it is a combo WiFi+Bluetooth (WB193) device. */
255 : if (strncmp(product, "wb193", 5) == 0)
256 : sc->flags |= ATHN_FLAG_BTCOEX3WIRE;
257 : #endif
258 :
259 0 : sc->ops.read = athn_usb_read;
260 0 : sc->ops.write = athn_usb_write;
261 0 : sc->ops.write_barrier = athn_usb_write_barrier;
262 :
263 0 : usb_init_task(&usc->sc_task, athn_usb_task, sc, USB_TASK_TYPE_GENERIC);
264 :
265 0 : if (athn_usb_open_pipes(usc) != 0)
266 0 : return;
267 :
268 : /* Allocate xfer for firmware commands. */
269 0 : if (athn_usb_alloc_tx_cmd(usc) != 0)
270 0 : return;
271 :
272 0 : config_mountroot(self, athn_usb_attachhook);
273 0 : }
274 :
275 : int
276 0 : athn_usb_detach(struct device *self, int flags)
277 : {
278 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)self;
279 0 : struct athn_softc *sc = &usc->sc_sc;
280 :
281 0 : if (usc->sc_athn_attached)
282 0 : athn_detach(sc);
283 :
284 : /* Wait for all async commands to complete. */
285 0 : athn_usb_wait_async(usc);
286 :
287 0 : usbd_ref_wait(usc->sc_udev);
288 :
289 : /* Abort and close Tx/Rx pipes. */
290 0 : athn_usb_close_pipes(usc);
291 :
292 : /* Free Tx/Rx buffers. */
293 0 : athn_usb_free_tx_cmd(usc);
294 0 : athn_usb_free_tx_list(usc);
295 0 : athn_usb_free_rx_list(usc);
296 :
297 0 : return (0);
298 : }
299 :
300 : void
301 0 : athn_usb_attachhook(struct device *self)
302 : {
303 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)self;
304 0 : struct athn_softc *sc = &usc->sc_sc;
305 0 : struct athn_ops *ops = &sc->ops;
306 0 : struct ieee80211com *ic = &sc->sc_ic;
307 0 : struct ifnet *ifp = &ic->ic_if;
308 : int s, i, error;
309 :
310 : /* Load firmware. */
311 0 : error = athn_usb_load_firmware(usc);
312 0 : if (error != 0) {
313 0 : printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
314 0 : return;
315 : }
316 :
317 : /* Setup the host transport communication interface. */
318 0 : error = athn_usb_htc_setup(usc);
319 0 : if (error != 0)
320 0 : return;
321 :
322 : /* We're now ready to attach the bus agnostic driver. */
323 0 : s = splnet();
324 0 : error = athn_attach(sc);
325 0 : if (error != 0) {
326 0 : splx(s);
327 0 : return;
328 : }
329 0 : usc->sc_athn_attached = 1;
330 : /* Override some operations for USB. */
331 0 : ifp->if_ioctl = athn_usb_ioctl;
332 0 : ifp->if_start = athn_usb_start;
333 0 : ifp->if_watchdog = athn_usb_watchdog;
334 0 : ic->ic_node_alloc = athn_usb_node_alloc;
335 0 : ic->ic_newauth = athn_usb_newauth;
336 0 : ic->ic_newassoc = athn_usb_newassoc;
337 : #ifndef IEEE80211_STA_ONLY
338 0 : usc->sc_node_free = ic->ic_node_free;
339 0 : ic->ic_node_free = athn_usb_node_free;
340 : #endif
341 0 : ic->ic_updateslot = athn_usb_updateslot;
342 0 : ic->ic_updateedca = athn_usb_updateedca;
343 : #ifdef notyet
344 : ic->ic_set_key = athn_usb_set_key;
345 : ic->ic_delete_key = athn_usb_delete_key;
346 : ic->ic_ampdu_tx_start = athn_usb_ampdu_tx_start;
347 : ic->ic_ampdu_tx_stop = athn_usb_ampdu_tx_stop;
348 : #endif
349 0 : ic->ic_newstate = athn_usb_newstate;
350 0 : ic->ic_media.ifm_change = athn_usb_media_change;
351 0 : timeout_set(&sc->scan_to, athn_usb_next_scan, usc);
352 :
353 0 : ops->rx_enable = athn_usb_rx_enable;
354 0 : splx(s);
355 :
356 : /* Reset HW key cache entries. */
357 0 : for (i = 0; i < sc->kc_entries; i++)
358 0 : athn_reset_key(sc, i);
359 :
360 0 : ops->enable_antenna_diversity(sc);
361 :
362 : #ifdef ATHN_BT_COEXISTENCE
363 : /* Configure bluetooth coexistence for combo chips. */
364 : if (sc->flags & ATHN_FLAG_BTCOEX)
365 : athn_btcoex_init(sc);
366 : #endif
367 : /* Configure LED. */
368 0 : athn_led_init(sc);
369 0 : }
370 :
371 : int
372 0 : athn_usb_open_pipes(struct athn_usb_softc *usc)
373 : {
374 : usb_endpoint_descriptor_t *ed;
375 : int isize, error;
376 :
377 0 : error = usbd_open_pipe(usc->sc_iface, AR_PIPE_TX_DATA, 0,
378 0 : &usc->tx_data_pipe);
379 0 : if (error != 0) {
380 0 : printf("%s: could not open Tx bulk pipe\n",
381 0 : usc->usb_dev.dv_xname);
382 0 : goto fail;
383 : }
384 :
385 0 : error = usbd_open_pipe(usc->sc_iface, AR_PIPE_RX_DATA, 0,
386 0 : &usc->rx_data_pipe);
387 0 : if (error != 0) {
388 0 : printf("%s: could not open Rx bulk pipe\n",
389 0 : usc->usb_dev.dv_xname);
390 0 : goto fail;
391 : }
392 :
393 0 : ed = usbd_get_endpoint_descriptor(usc->sc_iface, AR_PIPE_RX_INTR);
394 0 : if (ed == NULL) {
395 0 : printf("%s: could not retrieve Rx intr pipe descriptor\n",
396 0 : usc->usb_dev.dv_xname);
397 0 : goto fail;
398 : }
399 0 : isize = UGETW(ed->wMaxPacketSize);
400 0 : if (isize == 0) {
401 0 : printf("%s: invalid Rx intr pipe descriptor\n",
402 0 : usc->usb_dev.dv_xname);
403 0 : goto fail;
404 : }
405 0 : usc->ibuf = malloc(isize, M_USBDEV, M_NOWAIT);
406 0 : if (usc->ibuf == NULL) {
407 0 : printf("%s: could not allocate Rx intr buffer\n",
408 0 : usc->usb_dev.dv_xname);
409 0 : goto fail;
410 : }
411 0 : usc->ibuflen = isize;
412 0 : error = usbd_open_pipe_intr(usc->sc_iface, AR_PIPE_RX_INTR,
413 0 : USBD_SHORT_XFER_OK, &usc->rx_intr_pipe, usc, usc->ibuf, isize,
414 : athn_usb_intr, USBD_DEFAULT_INTERVAL);
415 0 : if (error != 0) {
416 0 : printf("%s: could not open Rx intr pipe\n",
417 0 : usc->usb_dev.dv_xname);
418 0 : goto fail;
419 : }
420 :
421 0 : error = usbd_open_pipe(usc->sc_iface, AR_PIPE_TX_INTR, 0,
422 0 : &usc->tx_intr_pipe);
423 0 : if (error != 0) {
424 0 : printf("%s: could not open Tx intr pipe\n",
425 0 : usc->usb_dev.dv_xname);
426 0 : goto fail;
427 : }
428 : fail:
429 0 : if (error != 0)
430 0 : athn_usb_close_pipes(usc);
431 0 : return (error);
432 : }
433 :
434 : void
435 0 : athn_usb_close_pipes(struct athn_usb_softc *usc)
436 : {
437 0 : if (usc->tx_data_pipe != NULL) {
438 0 : usbd_close_pipe(usc->tx_data_pipe);
439 0 : usc->tx_data_pipe = NULL;
440 0 : }
441 0 : if (usc->rx_data_pipe != NULL) {
442 0 : usbd_close_pipe(usc->rx_data_pipe);
443 0 : usc->rx_data_pipe = NULL;
444 0 : }
445 0 : if (usc->tx_intr_pipe != NULL) {
446 0 : usbd_close_pipe(usc->tx_intr_pipe);
447 0 : usc->tx_intr_pipe = NULL;
448 0 : }
449 0 : if (usc->rx_intr_pipe != NULL) {
450 0 : usbd_close_pipe(usc->rx_intr_pipe);
451 0 : usc->rx_intr_pipe = NULL;
452 0 : }
453 0 : if (usc->ibuf != NULL) {
454 0 : free(usc->ibuf, M_USBDEV, usc->ibuflen);
455 0 : usc->ibuf = NULL;
456 0 : }
457 0 : }
458 :
459 : int
460 0 : athn_usb_alloc_rx_list(struct athn_usb_softc *usc)
461 : {
462 : struct athn_usb_rx_data *data;
463 : int i, error = 0;
464 :
465 0 : for (i = 0; i < ATHN_USB_RX_LIST_COUNT; i++) {
466 0 : data = &usc->rx_data[i];
467 :
468 0 : data->sc = usc; /* Backpointer for callbacks. */
469 :
470 0 : data->xfer = usbd_alloc_xfer(usc->sc_udev);
471 0 : if (data->xfer == NULL) {
472 0 : printf("%s: could not allocate xfer\n",
473 0 : usc->usb_dev.dv_xname);
474 : error = ENOMEM;
475 0 : break;
476 : }
477 0 : data->buf = usbd_alloc_buffer(data->xfer, ATHN_USB_RXBUFSZ);
478 0 : if (data->buf == NULL) {
479 0 : printf("%s: could not allocate xfer buffer\n",
480 0 : usc->usb_dev.dv_xname);
481 : error = ENOMEM;
482 0 : break;
483 : }
484 : }
485 0 : if (error != 0)
486 0 : athn_usb_free_rx_list(usc);
487 0 : return (error);
488 : }
489 :
490 : void
491 0 : athn_usb_free_rx_list(struct athn_usb_softc *usc)
492 : {
493 : int i;
494 :
495 : /* NB: Caller must abort pipe first. */
496 0 : for (i = 0; i < ATHN_USB_RX_LIST_COUNT; i++) {
497 0 : if (usc->rx_data[i].xfer != NULL)
498 0 : usbd_free_xfer(usc->rx_data[i].xfer);
499 0 : usc->rx_data[i].xfer = NULL;
500 : }
501 0 : }
502 :
503 : int
504 0 : athn_usb_alloc_tx_list(struct athn_usb_softc *usc)
505 : {
506 : struct athn_usb_tx_data *data;
507 : int i, error = 0;
508 :
509 0 : TAILQ_INIT(&usc->tx_free_list);
510 0 : for (i = 0; i < ATHN_USB_TX_LIST_COUNT; i++) {
511 0 : data = &usc->tx_data[i];
512 :
513 0 : data->sc = usc; /* Backpointer for callbacks. */
514 :
515 0 : data->xfer = usbd_alloc_xfer(usc->sc_udev);
516 0 : if (data->xfer == NULL) {
517 0 : printf("%s: could not allocate xfer\n",
518 0 : usc->usb_dev.dv_xname);
519 : error = ENOMEM;
520 0 : break;
521 : }
522 0 : data->buf = usbd_alloc_buffer(data->xfer, ATHN_USB_TXBUFSZ);
523 0 : if (data->buf == NULL) {
524 0 : printf("%s: could not allocate xfer buffer\n",
525 0 : usc->usb_dev.dv_xname);
526 : error = ENOMEM;
527 0 : break;
528 : }
529 : /* Append this Tx buffer to our free list. */
530 0 : TAILQ_INSERT_TAIL(&usc->tx_free_list, data, next);
531 : }
532 0 : if (error != 0)
533 0 : athn_usb_free_tx_list(usc);
534 0 : return (error);
535 : }
536 :
537 : void
538 0 : athn_usb_free_tx_list(struct athn_usb_softc *usc)
539 : {
540 : int i;
541 :
542 : /* NB: Caller must abort pipe first. */
543 0 : for (i = 0; i < ATHN_USB_TX_LIST_COUNT; i++) {
544 0 : if (usc->tx_data[i].xfer != NULL)
545 0 : usbd_free_xfer(usc->tx_data[i].xfer);
546 0 : usc->tx_data[i].xfer = NULL;
547 : }
548 0 : }
549 :
550 : int
551 0 : athn_usb_alloc_tx_cmd(struct athn_usb_softc *usc)
552 : {
553 0 : struct athn_usb_tx_data *data = &usc->tx_cmd;
554 :
555 0 : data->sc = usc; /* Backpointer for callbacks. */
556 :
557 0 : data->xfer = usbd_alloc_xfer(usc->sc_udev);
558 0 : if (data->xfer == NULL) {
559 0 : printf("%s: could not allocate xfer\n",
560 0 : usc->usb_dev.dv_xname);
561 0 : return (ENOMEM);
562 : }
563 0 : data->buf = usbd_alloc_buffer(data->xfer, ATHN_USB_TXCMDSZ);
564 0 : if (data->buf == NULL) {
565 0 : printf("%s: could not allocate xfer buffer\n",
566 0 : usc->usb_dev.dv_xname);
567 0 : return (ENOMEM);
568 : }
569 0 : return (0);
570 0 : }
571 :
572 : void
573 0 : athn_usb_free_tx_cmd(struct athn_usb_softc *usc)
574 : {
575 0 : if (usc->tx_cmd.xfer != NULL)
576 0 : usbd_free_xfer(usc->tx_cmd.xfer);
577 0 : usc->tx_cmd.xfer = NULL;
578 0 : }
579 :
580 : void
581 0 : athn_usb_task(void *arg)
582 : {
583 0 : struct athn_usb_softc *usc = arg;
584 0 : struct athn_usb_host_cmd_ring *ring = &usc->cmdq;
585 : struct athn_usb_host_cmd *cmd;
586 : int s;
587 :
588 : /* Process host commands. */
589 0 : s = splusb();
590 0 : while (ring->next != ring->cur) {
591 0 : cmd = &ring->cmd[ring->next];
592 0 : splx(s);
593 : /* Invoke callback. */
594 0 : cmd->cb(usc, cmd->data);
595 0 : s = splusb();
596 0 : ring->queued--;
597 0 : ring->next = (ring->next + 1) % ATHN_USB_HOST_CMD_RING_COUNT;
598 : }
599 0 : splx(s);
600 0 : }
601 :
602 : void
603 0 : athn_usb_do_async(struct athn_usb_softc *usc,
604 : void (*cb)(struct athn_usb_softc *, void *), void *arg, int len)
605 : {
606 0 : struct athn_usb_host_cmd_ring *ring = &usc->cmdq;
607 : struct athn_usb_host_cmd *cmd;
608 : int s;
609 :
610 0 : if (ring->queued == ATHN_USB_HOST_CMD_RING_COUNT) {
611 0 : printf("%s: host cmd queue overrun\n", usc->usb_dev.dv_xname);
612 0 : return; /* XXX */
613 : }
614 :
615 0 : s = splusb();
616 0 : cmd = &ring->cmd[ring->cur];
617 0 : cmd->cb = cb;
618 0 : KASSERT(len <= sizeof(cmd->data));
619 0 : memcpy(cmd->data, arg, len);
620 0 : ring->cur = (ring->cur + 1) % ATHN_USB_HOST_CMD_RING_COUNT;
621 :
622 : /* If there is no pending command already, schedule a task. */
623 0 : if (++ring->queued == 1)
624 0 : usb_add_task(usc->sc_udev, &usc->sc_task);
625 0 : splx(s);
626 0 : }
627 :
628 : void
629 0 : athn_usb_wait_async(struct athn_usb_softc *usc)
630 : {
631 : /* Wait for all queued asynchronous commands to complete. */
632 0 : usb_wait_task(usc->sc_udev, &usc->sc_task);
633 0 : }
634 :
635 : int
636 0 : athn_usb_load_firmware(struct athn_usb_softc *usc)
637 : {
638 : usb_device_descriptor_t *dd;
639 0 : usb_device_request_t req;
640 : const char *name;
641 0 : u_char *fw, *ptr;
642 0 : size_t fwsize, size;
643 : uint32_t addr;
644 : int s, mlen, error;
645 :
646 : /* Determine which firmware image to load. */
647 0 : if (usc->flags & ATHN_USB_FLAG_AR7010) {
648 0 : dd = usbd_get_device_descriptor(usc->sc_udev);
649 : name = "athn-open-ar7010";
650 0 : } else
651 : name = "athn-open-ar9271";
652 : /* Read firmware image from the filesystem. */
653 0 : if ((error = loadfirmware(name, &fw, &fwsize)) != 0) {
654 0 : printf("%s: failed loadfirmware of file %s (error %d)\n",
655 0 : usc->usb_dev.dv_xname, name, error);
656 0 : return (error);
657 : }
658 : /* Load firmware image. */
659 0 : ptr = fw;
660 : addr = AR9271_FIRMWARE >> 8;
661 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
662 0 : req.bRequest = AR_FW_DOWNLOAD;
663 0 : USETW(req.wIndex, 0);
664 0 : size = fwsize;
665 0 : while (size > 0) {
666 0 : mlen = MIN(size, 4096);
667 :
668 0 : USETW(req.wValue, addr);
669 0 : USETW(req.wLength, mlen);
670 0 : error = usbd_do_request(usc->sc_udev, &req, ptr);
671 0 : if (error != 0) {
672 0 : free(fw, M_DEVBUF, fwsize);
673 0 : return (error);
674 : }
675 0 : addr += mlen >> 8;
676 0 : ptr += mlen;
677 0 : size -= mlen;
678 : }
679 0 : free(fw, M_DEVBUF, fwsize);
680 :
681 : /* Start firmware. */
682 0 : if (usc->flags & ATHN_USB_FLAG_AR7010)
683 0 : addr = AR7010_FIRMWARE_TEXT >> 8;
684 : else
685 : addr = AR9271_FIRMWARE_TEXT >> 8;
686 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
687 0 : req.bRequest = AR_FW_DOWNLOAD_COMP;
688 0 : USETW(req.wIndex, 0);
689 0 : USETW(req.wValue, addr);
690 0 : USETW(req.wLength, 0);
691 0 : s = splusb();
692 0 : usc->wait_msg_id = AR_HTC_MSG_READY;
693 0 : error = usbd_do_request(usc->sc_udev, &req, NULL);
694 : /* Wait at most 1 second for firmware to boot. */
695 0 : if (error == 0 && usc->wait_msg_id != 0)
696 0 : error = tsleep(&usc->wait_msg_id, 0, "athnfw", hz);
697 0 : usc->wait_msg_id = 0;
698 0 : splx(s);
699 0 : return (error);
700 0 : }
701 :
702 : int
703 0 : athn_usb_htc_msg(struct athn_usb_softc *usc, uint16_t msg_id, void *buf,
704 : int len)
705 : {
706 0 : struct athn_usb_tx_data *data = &usc->tx_cmd;
707 : struct ar_htc_frame_hdr *htc;
708 : struct ar_htc_msg_hdr *msg;
709 :
710 0 : htc = (struct ar_htc_frame_hdr *)data->buf;
711 0 : memset(htc, 0, sizeof(*htc));
712 0 : htc->endpoint_id = 0;
713 0 : htc->payload_len = htobe16(sizeof(*msg) + len);
714 :
715 0 : msg = (struct ar_htc_msg_hdr *)&htc[1];
716 0 : msg->msg_id = htobe16(msg_id);
717 :
718 0 : memcpy(&msg[1], buf, len);
719 :
720 0 : usbd_setup_xfer(data->xfer, usc->tx_intr_pipe, NULL, data->buf,
721 0 : sizeof(*htc) + sizeof(*msg) + len,
722 : USBD_SHORT_XFER_OK | USBD_NO_COPY | USBD_SYNCHRONOUS,
723 : ATHN_USB_CMD_TIMEOUT, NULL);
724 0 : return (usbd_transfer(data->xfer));
725 : }
726 :
727 : int
728 0 : athn_usb_htc_setup(struct athn_usb_softc *usc)
729 : {
730 0 : struct ar_htc_msg_config_pipe cfg;
731 : int s, error;
732 :
733 : /*
734 : * Connect WMI services to USB pipes.
735 : */
736 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_CONTROL,
737 0 : AR_PIPE_TX_INTR, AR_PIPE_RX_INTR, &usc->ep_ctrl);
738 0 : if (error != 0)
739 0 : return (error);
740 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_BEACON,
741 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_bcn);
742 0 : if (error != 0)
743 0 : return (error);
744 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_CAB,
745 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_cab);
746 0 : if (error != 0)
747 0 : return (error);
748 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_UAPSD,
749 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_uapsd);
750 0 : if (error != 0)
751 0 : return (error);
752 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_MGMT,
753 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_mgmt);
754 0 : if (error != 0)
755 0 : return (error);
756 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_DATA_BE,
757 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_data[EDCA_AC_BE]);
758 0 : if (error != 0)
759 0 : return (error);
760 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_DATA_BK,
761 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_data[EDCA_AC_BK]);
762 0 : if (error != 0)
763 0 : return (error);
764 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_DATA_VI,
765 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_data[EDCA_AC_VI]);
766 0 : if (error != 0)
767 0 : return (error);
768 0 : error = athn_usb_htc_connect_svc(usc, AR_SVC_WMI_DATA_VO,
769 0 : AR_PIPE_TX_DATA, AR_PIPE_RX_DATA, &usc->ep_data[EDCA_AC_VO]);
770 0 : if (error != 0)
771 0 : return (error);
772 :
773 : /* Set credits for WLAN Tx pipe. */
774 0 : memset(&cfg, 0, sizeof(cfg));
775 0 : cfg.pipe_id = UE_GET_ADDR(AR_PIPE_TX_DATA);
776 0 : cfg.credits = (usc->flags & ATHN_USB_FLAG_AR7010) ? 45 : 33;
777 0 : s = splusb();
778 0 : usc->wait_msg_id = AR_HTC_MSG_CONF_PIPE_RSP;
779 0 : error = athn_usb_htc_msg(usc, AR_HTC_MSG_CONF_PIPE, &cfg, sizeof(cfg));
780 0 : if (error == 0 && usc->wait_msg_id != 0)
781 0 : error = tsleep(&usc->wait_msg_id, 0, "athnhtc", hz);
782 0 : usc->wait_msg_id = 0;
783 0 : splx(s);
784 0 : if (error != 0) {
785 0 : printf("%s: could not configure pipe\n",
786 0 : usc->usb_dev.dv_xname);
787 0 : return (error);
788 : }
789 :
790 0 : error = athn_usb_htc_msg(usc, AR_HTC_MSG_SETUP_COMPLETE, NULL, 0);
791 0 : if (error != 0) {
792 0 : printf("%s: could not complete setup\n",
793 0 : usc->usb_dev.dv_xname);
794 0 : return (error);
795 : }
796 0 : return (0);
797 0 : }
798 :
799 : int
800 0 : athn_usb_htc_connect_svc(struct athn_usb_softc *usc, uint16_t svc_id,
801 : uint8_t ul_pipe, uint8_t dl_pipe, uint8_t *endpoint_id)
802 : {
803 0 : struct ar_htc_msg_conn_svc msg;
804 0 : struct ar_htc_msg_conn_svc_rsp rsp;
805 : int s, error;
806 :
807 0 : memset(&msg, 0, sizeof(msg));
808 0 : msg.svc_id = htobe16(svc_id);
809 0 : msg.dl_pipeid = UE_GET_ADDR(dl_pipe);
810 0 : msg.ul_pipeid = UE_GET_ADDR(ul_pipe);
811 0 : s = splusb();
812 0 : usc->msg_conn_svc_rsp = &rsp;
813 0 : usc->wait_msg_id = AR_HTC_MSG_CONN_SVC_RSP;
814 0 : error = athn_usb_htc_msg(usc, AR_HTC_MSG_CONN_SVC, &msg, sizeof(msg));
815 : /* Wait at most 1 second for response. */
816 0 : if (error == 0 && usc->wait_msg_id != 0)
817 0 : error = tsleep(&usc->wait_msg_id, 0, "athnhtc", hz);
818 0 : usc->wait_msg_id = 0;
819 0 : splx(s);
820 0 : if (error != 0) {
821 0 : printf("%s: error waiting for service %d connection\n",
822 0 : usc->usb_dev.dv_xname, svc_id);
823 0 : return (error);
824 : }
825 0 : if (rsp.status != AR_HTC_SVC_SUCCESS) {
826 0 : printf("%s: service %d connection failed, error %d\n",
827 0 : usc->usb_dev.dv_xname, svc_id, rsp.status);
828 0 : return (EIO);
829 : }
830 : DPRINTF(("service %d successfully connected to endpoint %d\n",
831 : svc_id, rsp.endpoint_id));
832 :
833 : /* Return endpoint id. */
834 0 : *endpoint_id = rsp.endpoint_id;
835 0 : return (0);
836 0 : }
837 :
838 : int
839 0 : athn_usb_wmi_xcmd(struct athn_usb_softc *usc, uint16_t cmd_id, void *ibuf,
840 : int ilen, void *obuf)
841 : {
842 0 : struct athn_usb_tx_data *data = &usc->tx_cmd;
843 : struct ar_htc_frame_hdr *htc;
844 : struct ar_wmi_cmd_hdr *wmi;
845 : int s, error;
846 :
847 0 : if (usbd_is_dying(usc->sc_udev))
848 0 : return ENXIO;
849 :
850 0 : s = splusb();
851 0 : while (usc->wait_cmd_id) {
852 : /*
853 : * The previous USB transfer is not done yet. We can't use
854 : * data->xfer until it is done or we'll cause major confusion
855 : * in the USB stack.
856 : */
857 0 : tsleep(&usc->wait_cmd_id, 0, "athnwmx", ATHN_USB_CMD_TIMEOUT);
858 0 : if (usbd_is_dying(usc->sc_udev)) {
859 0 : splx(s);
860 0 : return ENXIO;
861 : }
862 : }
863 0 : splx(s);
864 :
865 0 : htc = (struct ar_htc_frame_hdr *)data->buf;
866 0 : memset(htc, 0, sizeof(*htc));
867 0 : htc->endpoint_id = usc->ep_ctrl;
868 0 : htc->payload_len = htobe16(sizeof(*wmi) + ilen);
869 :
870 0 : wmi = (struct ar_wmi_cmd_hdr *)&htc[1];
871 0 : wmi->cmd_id = htobe16(cmd_id);
872 0 : usc->wmi_seq_no++;
873 0 : wmi->seq_no = htobe16(usc->wmi_seq_no);
874 :
875 0 : memcpy(&wmi[1], ibuf, ilen);
876 :
877 0 : usbd_setup_xfer(data->xfer, usc->tx_intr_pipe, NULL, data->buf,
878 0 : sizeof(*htc) + sizeof(*wmi) + ilen,
879 : USBD_SHORT_XFER_OK | USBD_NO_COPY, ATHN_USB_CMD_TIMEOUT,
880 : NULL);
881 0 : s = splusb();
882 0 : error = usbd_transfer(data->xfer);
883 0 : if (__predict_false(error != USBD_IN_PROGRESS && error != 0)) {
884 0 : splx(s);
885 0 : return (error);
886 : }
887 0 : usc->obuf = obuf;
888 0 : usc->wait_cmd_id = cmd_id;
889 : /*
890 : * Wait for WMI command complete interrupt. In case it does not fire
891 : * wait until the USB transfer times out to avoid racing the transfer.
892 : */
893 0 : error = tsleep(&usc->wait_cmd_id, 0, "athnwmi", ATHN_USB_CMD_TIMEOUT);
894 0 : if (error) {
895 0 : if (error == EWOULDBLOCK) {
896 0 : printf("%s: firmware command 0x%x timed out\n",
897 0 : usc->usb_dev.dv_xname, cmd_id);
898 : error = ETIMEDOUT;
899 0 : }
900 : }
901 :
902 : /*
903 : * Both the WMI command and transfer are done or have timed out.
904 : * Allow other threads to enter this function and use data->xfer.
905 : */
906 0 : usc->wait_cmd_id = 0;
907 0 : wakeup(&usc->wait_cmd_id);
908 :
909 0 : splx(s);
910 0 : return (error);
911 0 : }
912 :
913 : int
914 0 : athn_usb_read_rom(struct athn_softc *sc)
915 : {
916 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
917 0 : uint32_t addrs[8], vals[8], addr;
918 : uint16_t *eep;
919 : int i, j, error;
920 :
921 : /* Read EEPROM by blocks of 16 bytes. */
922 0 : eep = sc->eep;
923 0 : addr = AR_EEPROM_OFFSET(sc->eep_base);
924 0 : for (i = 0; i < sc->eep_size / 16; i++) {
925 0 : for (j = 0; j < 8; j++, addr += 4)
926 0 : addrs[j] = htobe32(addr);
927 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_REG_READ,
928 0 : addrs, sizeof(addrs), vals);
929 0 : if (error != 0)
930 : break;
931 0 : for (j = 0; j < 8; j++)
932 0 : *eep++ = betoh32(vals[j]);
933 : }
934 0 : return (error);
935 0 : }
936 :
937 : uint32_t
938 0 : athn_usb_read(struct athn_softc *sc, uint32_t addr)
939 : {
940 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
941 0 : uint32_t val;
942 : int error;
943 :
944 : /* Flush pending writes for strict consistency. */
945 0 : athn_usb_write_barrier(sc);
946 :
947 0 : addr = htobe32(addr);
948 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_REG_READ,
949 0 : &addr, sizeof(addr), &val);
950 0 : if (error != 0)
951 0 : return (0xdeadbeef);
952 0 : return (betoh32(val));
953 0 : }
954 :
955 : void
956 0 : athn_usb_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
957 : {
958 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
959 :
960 0 : usc->wbuf[usc->wcount].addr = htobe32(addr);
961 0 : usc->wbuf[usc->wcount].val = htobe32(val);
962 0 : if (++usc->wcount == AR_MAX_WRITE_COUNT)
963 0 : athn_usb_write_barrier(sc);
964 0 : }
965 :
966 : void
967 0 : athn_usb_write_barrier(struct athn_softc *sc)
968 : {
969 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
970 :
971 0 : if (usc->wcount == 0)
972 0 : return; /* Nothing to write. */
973 :
974 0 : (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_REG_WRITE,
975 0 : usc->wbuf, usc->wcount * sizeof(usc->wbuf[0]), NULL);
976 0 : usc->wcount = 0; /* Always flush buffer. */
977 0 : }
978 :
979 : int
980 0 : athn_usb_media_change(struct ifnet *ifp)
981 : {
982 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)ifp->if_softc;
983 : int error;
984 :
985 0 : if (usbd_is_dying(usc->sc_udev))
986 0 : return ENXIO;
987 :
988 0 : error = ieee80211_media_change(ifp);
989 0 : if (error != ENETRESET)
990 0 : return (error);
991 :
992 0 : if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
993 : (IFF_UP | IFF_RUNNING)) {
994 0 : athn_usb_stop(ifp);
995 0 : error = athn_usb_init(ifp);
996 0 : }
997 0 : return (error);
998 0 : }
999 :
1000 : void
1001 0 : athn_usb_next_scan(void *arg)
1002 : {
1003 0 : struct athn_usb_softc *usc = arg;
1004 0 : struct athn_softc *sc = &usc->sc_sc;
1005 0 : struct ieee80211com *ic = &sc->sc_ic;
1006 : int s;
1007 :
1008 0 : if (usbd_is_dying(usc->sc_udev))
1009 0 : return;
1010 :
1011 0 : usbd_ref_incr(usc->sc_udev);
1012 :
1013 0 : s = splnet();
1014 0 : if (ic->ic_state == IEEE80211_S_SCAN)
1015 0 : ieee80211_next_scan(&ic->ic_if);
1016 0 : splx(s);
1017 :
1018 0 : usbd_ref_decr(usc->sc_udev);
1019 0 : }
1020 :
1021 : int
1022 0 : athn_usb_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
1023 : int arg)
1024 : {
1025 0 : struct athn_usb_softc *usc = ic->ic_softc;
1026 0 : struct athn_usb_cmd_newstate cmd;
1027 :
1028 : /* Do it in a process context. */
1029 0 : cmd.state = nstate;
1030 0 : cmd.arg = arg;
1031 0 : athn_usb_do_async(usc, athn_usb_newstate_cb, &cmd, sizeof(cmd));
1032 0 : return (0);
1033 0 : }
1034 :
1035 : void
1036 0 : athn_usb_newstate_cb(struct athn_usb_softc *usc, void *arg)
1037 : {
1038 0 : struct athn_usb_cmd_newstate *cmd = arg;
1039 0 : struct athn_softc *sc = &usc->sc_sc;
1040 0 : struct ieee80211com *ic = &sc->sc_ic;
1041 : enum ieee80211_state ostate;
1042 0 : uint32_t reg, imask;
1043 : int s, error;
1044 :
1045 0 : timeout_del(&sc->calib_to);
1046 :
1047 0 : s = splnet();
1048 0 : ostate = ic->ic_state;
1049 :
1050 0 : if (ostate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA) {
1051 0 : athn_usb_remove_node(usc, ic->ic_bss);
1052 0 : reg = AR_READ(sc, AR_RX_FILTER);
1053 0 : reg = (reg & ~AR_RX_FILTER_MYBEACON) |
1054 : AR_RX_FILTER_BEACON;
1055 0 : AR_WRITE(sc, AR_RX_FILTER, reg);
1056 0 : AR_WRITE_BARRIER(sc);
1057 0 : }
1058 0 : switch (cmd->state) {
1059 : case IEEE80211_S_INIT:
1060 0 : athn_set_led(sc, 0);
1061 0 : break;
1062 : case IEEE80211_S_SCAN:
1063 : /* Make the LED blink while scanning. */
1064 0 : athn_set_led(sc, !sc->led_state);
1065 0 : error = athn_usb_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
1066 0 : if (error)
1067 0 : printf("%s: could not switch to channel %d\n",
1068 0 : usc->usb_dev.dv_xname,
1069 0 : ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
1070 0 : if (!usbd_is_dying(usc->sc_udev))
1071 0 : timeout_add_msec(&sc->scan_to, 200);
1072 : break;
1073 : case IEEE80211_S_AUTH:
1074 0 : athn_set_led(sc, 0);
1075 0 : error = athn_usb_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
1076 0 : if (error)
1077 0 : printf("%s: could not switch to channel %d\n",
1078 0 : usc->usb_dev.dv_xname,
1079 0 : ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan));
1080 : break;
1081 : case IEEE80211_S_ASSOC:
1082 : break;
1083 : case IEEE80211_S_RUN:
1084 0 : athn_set_led(sc, 1);
1085 :
1086 0 : if (ic->ic_opmode == IEEE80211_M_MONITOR)
1087 : break;
1088 :
1089 0 : if (ic->ic_opmode == IEEE80211_M_STA) {
1090 : /* Create node entry for our BSS */
1091 0 : error = athn_usb_create_node(usc, ic->ic_bss);
1092 0 : if (error)
1093 0 : printf("%s: could not update firmware station "
1094 0 : "table\n", usc->usb_dev.dv_xname);
1095 : }
1096 0 : athn_set_bss(sc, ic->ic_bss);
1097 0 : athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR);
1098 : #ifndef IEEE80211_STA_ONLY
1099 0 : if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
1100 0 : athn_usb_switch_chan(sc, ic->ic_bss->ni_chan, NULL);
1101 0 : athn_set_hostap_timers(sc);
1102 : /* Enable software beacon alert interrupts. */
1103 0 : imask = htobe32(AR_IMR_SWBA);
1104 0 : } else
1105 : #endif
1106 : {
1107 0 : athn_set_sta_timers(sc);
1108 : /* Enable beacon miss interrupts. */
1109 0 : imask = htobe32(AR_IMR_BMISS);
1110 :
1111 : /* Stop receiving beacons from other BSS. */
1112 0 : reg = AR_READ(sc, AR_RX_FILTER);
1113 0 : reg = (reg & ~AR_RX_FILTER_BEACON) |
1114 : AR_RX_FILTER_MYBEACON;
1115 0 : AR_WRITE(sc, AR_RX_FILTER, reg);
1116 0 : AR_WRITE_BARRIER(sc);
1117 : }
1118 0 : athn_usb_wmi_xcmd(usc, AR_WMI_CMD_ENABLE_INTR,
1119 : &imask, sizeof(imask), NULL);
1120 0 : break;
1121 : }
1122 0 : (void)sc->sc_newstate(ic, cmd->state, cmd->arg);
1123 0 : splx(s);
1124 0 : }
1125 :
1126 : void
1127 0 : athn_usb_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni,
1128 : int isnew)
1129 : {
1130 : #ifndef IEEE80211_STA_ONLY
1131 0 : struct athn_usb_softc *usc = ic->ic_softc;
1132 :
1133 0 : if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
1134 0 : ic->ic_state != IEEE80211_S_RUN)
1135 0 : return;
1136 :
1137 : /* Update the node's supported rates in a process context. */
1138 0 : ieee80211_ref_node(ni);
1139 0 : athn_usb_do_async(usc, athn_usb_newassoc_cb, &ni, sizeof(ni));
1140 : #endif
1141 0 : }
1142 :
1143 : #ifndef IEEE80211_STA_ONLY
1144 : void
1145 0 : athn_usb_newassoc_cb(struct athn_usb_softc *usc, void *arg)
1146 : {
1147 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1148 0 : struct ieee80211_node *ni = *(void **)arg;
1149 0 : struct athn_node *an = (struct athn_node *)ni;
1150 : int s;
1151 :
1152 0 : if (ic->ic_state != IEEE80211_S_RUN)
1153 0 : return;
1154 :
1155 0 : s = splnet();
1156 : /* NB: Node may have left before we got scheduled. */
1157 0 : if (an->sta_index != 0)
1158 0 : (void)athn_usb_node_set_rates(usc, ni);
1159 0 : ieee80211_release_node(ic, ni);
1160 0 : splx(s);
1161 0 : }
1162 : #endif
1163 :
1164 : struct ieee80211_node *
1165 0 : athn_usb_node_alloc(struct ieee80211com *ic)
1166 : {
1167 : struct athn_node *an;
1168 :
1169 0 : an = malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO);
1170 0 : return (struct ieee80211_node *)an;
1171 : }
1172 :
1173 :
1174 : #ifndef IEEE80211_STA_ONLY
1175 : void
1176 0 : athn_usb_count_active_sta(void *arg, struct ieee80211_node *ni)
1177 : {
1178 0 : int *nsta = arg;
1179 0 : struct athn_node *an = (struct athn_node *)ni;
1180 :
1181 0 : if (an->sta_index == 0)
1182 0 : return;
1183 :
1184 0 : if ((ni->ni_state == IEEE80211_STA_AUTH ||
1185 0 : ni->ni_state == IEEE80211_STA_ASSOC) &&
1186 0 : ni->ni_inact < IEEE80211_INACT_MAX)
1187 0 : (*nsta)++;
1188 0 : }
1189 :
1190 : struct athn_usb_newauth_cb_arg {
1191 : struct ieee80211_node *ni;
1192 : uint16_t seq;
1193 : };
1194 :
1195 : void
1196 0 : athn_usb_newauth_cb(struct athn_usb_softc *usc, void *arg)
1197 : {
1198 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1199 0 : struct athn_usb_newauth_cb_arg *a = arg;
1200 0 : struct ieee80211_node *ni = a->ni;
1201 0 : uint16_t seq = a->seq;
1202 0 : struct athn_node *an = (struct athn_node *)ni;
1203 : int s, error = 0;
1204 :
1205 0 : free(arg, M_DEVBUF, sizeof(*arg));
1206 :
1207 0 : if (ic->ic_state != IEEE80211_S_RUN)
1208 0 : return;
1209 :
1210 0 : s = splnet();
1211 0 : if (an->sta_index == 0) {
1212 0 : error = athn_usb_create_node(usc, ni);
1213 0 : if (error)
1214 0 : printf("%s: could not add station %s to firmware "
1215 0 : "table\n", usc->usb_dev.dv_xname,
1216 0 : ether_sprintf(ni->ni_macaddr));
1217 : }
1218 0 : if (error == 0)
1219 0 : ieee80211_auth_open_confirm(ic, ni, seq);
1220 0 : ieee80211_unref_node(&ni);
1221 0 : splx(s);
1222 0 : }
1223 : #endif
1224 :
1225 : int
1226 0 : athn_usb_newauth(struct ieee80211com *ic, struct ieee80211_node *ni,
1227 : int isnew, uint16_t seq)
1228 : {
1229 : #ifndef IEEE80211_STA_ONLY
1230 0 : struct athn_usb_softc *usc = ic->ic_softc;
1231 : struct ifnet *ifp = &ic->ic_if;
1232 0 : struct athn_node *an = (struct athn_node *)ni;
1233 0 : int nsta;
1234 : struct athn_usb_newauth_cb_arg *arg;
1235 :
1236 0 : if (ic->ic_opmode != IEEE80211_M_HOSTAP)
1237 0 : return 0;
1238 :
1239 0 : if (!isnew && an->sta_index != 0) /* already in firmware table */
1240 0 : return 0;
1241 :
1242 : /* Check if we have room in the firmware table. */
1243 0 : nsta = 1; /* Account for default node. */
1244 0 : ieee80211_iterate_nodes(ic, athn_usb_count_active_sta, &nsta);
1245 0 : if (nsta >= AR_USB_MAX_STA) {
1246 0 : if (ifp->if_flags & IFF_DEBUG)
1247 0 : printf("%s: cannot authenticate station %s: firmware "
1248 0 : "table is full\n", usc->usb_dev.dv_xname,
1249 0 : ether_sprintf(ni->ni_macaddr));
1250 0 : return ENOSPC;
1251 : }
1252 :
1253 : /*
1254 : * In a process context, try to add this node to the
1255 : * firmware table and confirm the AUTH request.
1256 : */
1257 0 : arg = malloc(sizeof(*arg), M_DEVBUF, M_NOWAIT);
1258 0 : if (arg == NULL)
1259 0 : return ENOMEM;
1260 0 : arg->ni = ieee80211_ref_node(ni);
1261 0 : arg->seq = seq;
1262 0 : athn_usb_do_async(usc, athn_usb_newauth_cb, arg, sizeof(*arg));
1263 0 : return EBUSY;
1264 : #else
1265 : return 0;
1266 : #endif /* IEEE80211_STA_ONLY */
1267 0 : }
1268 :
1269 : #ifndef IEEE80211_STA_ONLY
1270 : void
1271 0 : athn_usb_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
1272 : {
1273 0 : struct athn_usb_softc *usc = ic->ic_softc;
1274 0 : struct athn_node *an = (struct athn_node *)ni;
1275 :
1276 : /*
1277 : * Remove the node from the firmware table in a process context.
1278 : * Pass an index rather than the pointer which we will free.
1279 : */
1280 0 : if (an->sta_index != 0)
1281 0 : athn_usb_do_async(usc, athn_usb_node_free_cb,
1282 : &an->sta_index, sizeof(an->sta_index));
1283 0 : usc->sc_node_free(ic, ni);
1284 0 : }
1285 :
1286 : void
1287 0 : athn_usb_node_free_cb(struct athn_usb_softc *usc, void *arg)
1288 : {
1289 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1290 0 : struct ifnet *ifp = &ic->ic_if;
1291 0 : uint8_t sta_index = *(uint8_t *)arg;
1292 : int error;
1293 :
1294 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE,
1295 : &sta_index, sizeof(sta_index), NULL);
1296 0 : if (error) {
1297 0 : printf("%s: could not remove station %u from firmware table\n",
1298 0 : usc->usb_dev.dv_xname, sta_index);
1299 0 : return;
1300 : }
1301 0 : usc->free_node_slots |= (1 << sta_index);
1302 0 : if (ifp->if_flags & IFF_DEBUG)
1303 0 : printf("%s: station %u removed from firmware table\n",
1304 0 : usc->usb_dev.dv_xname, sta_index);
1305 0 : }
1306 : #endif /* IEEE80211_STA_ONLY */
1307 :
1308 : int
1309 0 : athn_usb_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
1310 : uint8_t tid)
1311 : {
1312 0 : struct athn_usb_softc *usc = ic->ic_softc;
1313 0 : struct athn_node *an = (struct athn_node *)ni;
1314 0 : struct athn_usb_aggr_cmd cmd;
1315 :
1316 : /* Do it in a process context. */
1317 0 : cmd.sta_index = an->sta_index;
1318 0 : cmd.tid = tid;
1319 0 : athn_usb_do_async(usc, athn_usb_ampdu_tx_start_cb, &cmd, sizeof(cmd));
1320 0 : return (0);
1321 0 : }
1322 :
1323 : void
1324 0 : athn_usb_ampdu_tx_start_cb(struct athn_usb_softc *usc, void *arg)
1325 : {
1326 0 : struct athn_usb_aggr_cmd *cmd = arg;
1327 0 : struct ar_htc_target_aggr aggr;
1328 :
1329 0 : memset(&aggr, 0, sizeof(aggr));
1330 0 : aggr.sta_index = cmd->sta_index;
1331 0 : aggr.tidno = cmd->tid;
1332 0 : aggr.aggr_enable = 1;
1333 0 : (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_TX_AGGR_ENABLE,
1334 : &aggr, sizeof(aggr), NULL);
1335 0 : }
1336 :
1337 : void
1338 0 : athn_usb_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
1339 : uint8_t tid)
1340 : {
1341 0 : struct athn_usb_softc *usc = ic->ic_softc;
1342 0 : struct athn_node *an = (struct athn_node *)ni;
1343 0 : struct athn_usb_aggr_cmd cmd;
1344 :
1345 : /* Do it in a process context. */
1346 0 : cmd.sta_index = an->sta_index;
1347 0 : cmd.tid = tid;
1348 0 : athn_usb_do_async(usc, athn_usb_ampdu_tx_stop_cb, &cmd, sizeof(cmd));
1349 0 : }
1350 :
1351 : void
1352 0 : athn_usb_ampdu_tx_stop_cb(struct athn_usb_softc *usc, void *arg)
1353 : {
1354 0 : struct athn_usb_aggr_cmd *cmd = arg;
1355 0 : struct ar_htc_target_aggr aggr;
1356 :
1357 0 : memset(&aggr, 0, sizeof(aggr));
1358 0 : aggr.sta_index = cmd->sta_index;
1359 0 : aggr.tidno = cmd->tid;
1360 0 : aggr.aggr_enable = 0;
1361 0 : (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_TX_AGGR_ENABLE,
1362 : &aggr, sizeof(aggr), NULL);
1363 0 : }
1364 :
1365 : #ifndef IEEE80211_STA_ONLY
1366 : /* Try to find a node we can evict to make room in the firmware table. */
1367 : void
1368 0 : athn_usb_clean_nodes(void *arg, struct ieee80211_node *ni)
1369 : {
1370 0 : struct athn_usb_softc *usc = arg;
1371 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1372 0 : struct athn_node *an = (struct athn_node *)ni;
1373 :
1374 : /*
1375 : * Don't remove the default node (used for management frames).
1376 : * Nodes which are not in the firmware table also have index zero.
1377 : */
1378 0 : if (an->sta_index == 0)
1379 0 : return;
1380 :
1381 : /* Remove non-associated nodes. */
1382 0 : if (ni->ni_state != IEEE80211_STA_AUTH &&
1383 0 : ni->ni_state != IEEE80211_STA_ASSOC) {
1384 0 : athn_usb_remove_node(usc, ni);
1385 0 : return;
1386 : }
1387 :
1388 : /*
1389 : * Kick off inactive associated nodes. This won't help
1390 : * immediately but will help if the new STA retries later.
1391 : */
1392 0 : if (ni->ni_inact >= IEEE80211_INACT_MAX) {
1393 0 : IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
1394 : IEEE80211_REASON_AUTH_EXPIRE);
1395 0 : ieee80211_node_leave(ic, ni);
1396 0 : }
1397 0 : }
1398 : #endif
1399 :
1400 : int
1401 0 : athn_usb_create_node(struct athn_usb_softc *usc, struct ieee80211_node *ni)
1402 : {
1403 0 : struct athn_node *an = (struct athn_node *)ni;
1404 0 : struct ar_htc_target_sta sta;
1405 : int error, sta_index;
1406 : #ifndef IEEE80211_STA_ONLY
1407 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1408 0 : struct ifnet *ifp = &ic->ic_if;
1409 :
1410 : /* Firmware cannot handle more than 8 STAs. Try to make room first. */
1411 0 : if (ic->ic_opmode == IEEE80211_M_HOSTAP)
1412 0 : ieee80211_iterate_nodes(ic, athn_usb_clean_nodes, usc);
1413 : #endif
1414 0 : if (usc->free_node_slots == 0x00)
1415 0 : return ENOBUFS;
1416 :
1417 0 : sta_index = ffs(usc->free_node_slots) - 1;
1418 0 : if (sta_index < 0 || sta_index >= AR_USB_MAX_STA)
1419 0 : return ENOSPC;
1420 :
1421 : /* Create node entry on target. */
1422 0 : memset(&sta, 0, sizeof(sta));
1423 0 : IEEE80211_ADDR_COPY(sta.macaddr, ni->ni_macaddr);
1424 0 : IEEE80211_ADDR_COPY(sta.bssid, ni->ni_bssid);
1425 0 : sta.sta_index = sta_index;
1426 0 : sta.maxampdu = 0xffff;
1427 0 : if (ni->ni_flags & IEEE80211_NODE_HT)
1428 0 : sta.flags |= htobe16(AR_HTC_STA_HT);
1429 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_CREATE,
1430 : &sta, sizeof(sta), NULL);
1431 0 : if (error != 0)
1432 0 : return (error);
1433 0 : an->sta_index = sta_index;
1434 0 : usc->free_node_slots &= ~(1 << an->sta_index);
1435 :
1436 : #ifndef IEEE80211_STA_ONLY
1437 0 : if (ifp->if_flags & IFF_DEBUG)
1438 0 : printf("%s: station %u (%s) added to firmware table\n",
1439 0 : usc->usb_dev.dv_xname, sta_index,
1440 0 : ether_sprintf(ni->ni_macaddr));
1441 : #endif
1442 0 : return athn_usb_node_set_rates(usc, ni);
1443 0 : }
1444 :
1445 : int
1446 0 : athn_usb_node_set_rates(struct athn_usb_softc *usc, struct ieee80211_node *ni)
1447 : {
1448 0 : struct athn_node *an = (struct athn_node *)ni;
1449 0 : struct ar_htc_target_rate rate;
1450 : int i, j;
1451 :
1452 : /* Setup supported rates. */
1453 0 : memset(&rate, 0, sizeof(rate));
1454 0 : rate.sta_index = an->sta_index;
1455 0 : rate.isnew = 1;
1456 0 : rate.lg_rates.rs_nrates = ni->ni_rates.rs_nrates;
1457 0 : memcpy(rate.lg_rates.rs_rates, ni->ni_rates.rs_rates,
1458 : ni->ni_rates.rs_nrates);
1459 0 : if (ni->ni_flags & IEEE80211_NODE_HT) {
1460 0 : rate.capflags |= htobe32(AR_RC_HT_FLAG);
1461 : /* Setup HT rates. */
1462 0 : for (i = 0, j = 0; i < IEEE80211_HT_NUM_MCS; i++) {
1463 0 : if (!isset(ni->ni_rxmcs, i))
1464 : continue;
1465 0 : if (j >= AR_HTC_RATE_MAX)
1466 : break;
1467 0 : rate.ht_rates.rs_rates[j++] = i;
1468 0 : }
1469 0 : rate.ht_rates.rs_nrates = j;
1470 :
1471 0 : if (ni->ni_rxmcs[1]) /* dual-stream MIMO rates */
1472 0 : rate.capflags |= htobe32(AR_RC_DS_FLAG);
1473 : #ifdef notyet
1474 : if (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40)
1475 : rate.capflags |= htobe32(AR_RC_40_FLAG);
1476 : if (ni->ni_htcaps & IEEE80211_HTCAP_SGI40)
1477 : rate.capflags |= htobe32(AR_RC_SGI_FLAG);
1478 : if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20)
1479 : rate.capflags |= htobe32(AR_RC_SGI_FLAG);
1480 : #endif
1481 : }
1482 :
1483 0 : return athn_usb_wmi_xcmd(usc, AR_WMI_CMD_RC_RATE_UPDATE,
1484 : &rate, sizeof(rate), NULL);
1485 0 : }
1486 :
1487 : int
1488 0 : athn_usb_remove_node(struct athn_usb_softc *usc, struct ieee80211_node *ni)
1489 : {
1490 0 : struct athn_node *an = (struct athn_node *)ni;
1491 : int error;
1492 : #ifndef IEEE80211_STA_ONLY
1493 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1494 0 : struct ifnet *ifp = &ic->ic_if;
1495 : #endif
1496 :
1497 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE,
1498 0 : &an->sta_index, sizeof(an->sta_index), NULL);
1499 0 : if (error) {
1500 0 : printf("%s: could not remove station %u (%s) from "
1501 0 : "firmware table\n", usc->usb_dev.dv_xname, an->sta_index,
1502 0 : ether_sprintf(ni->ni_macaddr));
1503 0 : return error;
1504 : }
1505 :
1506 : #ifndef IEEE80211_STA_ONLY
1507 0 : if (ifp->if_flags & IFF_DEBUG)
1508 0 : printf("%s: station %u (%s) removed from firmware table\n",
1509 0 : usc->usb_dev.dv_xname, an->sta_index,
1510 0 : ether_sprintf(ni->ni_macaddr));
1511 : #endif
1512 :
1513 0 : usc->free_node_slots |= (1 << an->sta_index);
1514 0 : an->sta_index = 0;
1515 0 : return 0;
1516 0 : }
1517 :
1518 : void
1519 0 : athn_usb_rx_enable(struct athn_softc *sc)
1520 : {
1521 0 : AR_WRITE(sc, AR_CR, AR_CR_RXE);
1522 0 : AR_WRITE_BARRIER(sc);
1523 0 : }
1524 :
1525 : int
1526 0 : athn_usb_switch_chan(struct athn_softc *sc, struct ieee80211_channel *c,
1527 : struct ieee80211_channel *extc)
1528 : {
1529 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
1530 0 : uint16_t mode;
1531 : int error;
1532 :
1533 : /* Disable interrupts. */
1534 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR);
1535 0 : if (error != 0)
1536 : goto reset;
1537 : /* Stop all Tx queues. */
1538 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_DRAIN_TXQ_ALL);
1539 0 : if (error != 0)
1540 : goto reset;
1541 : /* Stop Rx. */
1542 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_STOP_RECV);
1543 0 : if (error != 0)
1544 : goto reset;
1545 :
1546 : /* If band or bandwidth changes, we need to do a full reset. */
1547 0 : if (c->ic_flags != sc->curchan->ic_flags ||
1548 0 : ((extc != NULL) ^ (sc->curchanext != NULL))) {
1549 : DPRINTFN(2, ("channel band switch\n"));
1550 : goto reset;
1551 : }
1552 :
1553 0 : error = athn_set_chan(sc, c, extc);
1554 0 : if (AR_SREV_9271(sc) && error == 0)
1555 0 : ar9271_load_ani(sc);
1556 0 : if (error != 0) {
1557 : reset: /* Error found, try a full reset. */
1558 : DPRINTFN(3, ("needs a full reset\n"));
1559 0 : error = athn_hw_reset(sc, c, extc, 0);
1560 0 : if (error != 0) /* Hopeless case. */
1561 0 : return (error);
1562 :
1563 0 : error = athn_set_chan(sc, c, extc);
1564 0 : if (AR_SREV_9271(sc) && error == 0)
1565 0 : ar9271_load_ani(sc);
1566 0 : if (error != 0)
1567 0 : return (error);
1568 : }
1569 :
1570 0 : sc->ops.set_txpower(sc, c, extc);
1571 :
1572 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_START_RECV);
1573 0 : if (error != 0)
1574 0 : return (error);
1575 0 : athn_rx_start(sc);
1576 :
1577 0 : mode = htobe16(IEEE80211_IS_CHAN_2GHZ(c) ?
1578 : AR_HTC_MODE_11NG : AR_HTC_MODE_11NA);
1579 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_SET_MODE,
1580 : &mode, sizeof(mode), NULL);
1581 0 : if (error != 0)
1582 0 : return (error);
1583 :
1584 : /* Re-enable interrupts. */
1585 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_ENABLE_INTR);
1586 0 : return (error);
1587 0 : }
1588 :
1589 : void
1590 0 : athn_usb_updateedca(struct ieee80211com *ic)
1591 : {
1592 0 : struct athn_usb_softc *usc = ic->ic_softc;
1593 :
1594 : /* Do it in a process context. */
1595 0 : athn_usb_do_async(usc, athn_usb_updateedca_cb, NULL, 0);
1596 0 : }
1597 :
1598 : void
1599 0 : athn_usb_updateedca_cb(struct athn_usb_softc *usc, void *arg)
1600 : {
1601 : int s;
1602 :
1603 0 : s = splnet();
1604 0 : athn_updateedca(&usc->sc_sc.sc_ic);
1605 0 : splx(s);
1606 0 : }
1607 :
1608 : void
1609 0 : athn_usb_updateslot(struct ieee80211com *ic)
1610 : {
1611 0 : struct athn_usb_softc *usc = ic->ic_softc;
1612 :
1613 : return; /* XXX */
1614 : /* Do it in a process context. */
1615 : athn_usb_do_async(usc, athn_usb_updateslot_cb, NULL, 0);
1616 0 : }
1617 :
1618 : void
1619 0 : athn_usb_updateslot_cb(struct athn_usb_softc *usc, void *arg)
1620 : {
1621 : int s;
1622 :
1623 0 : s = splnet();
1624 0 : athn_updateslot(&usc->sc_sc.sc_ic);
1625 0 : splx(s);
1626 0 : }
1627 :
1628 : int
1629 0 : athn_usb_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
1630 : struct ieee80211_key *k)
1631 : {
1632 0 : struct athn_usb_softc *usc = ic->ic_softc;
1633 0 : struct athn_usb_cmd_key cmd;
1634 :
1635 : /* Defer setting of WEP keys until interface is brought up. */
1636 0 : if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
1637 : (IFF_UP | IFF_RUNNING))
1638 0 : return (0);
1639 :
1640 : /* Do it in a process context. */
1641 0 : cmd.ni = (ni != NULL) ? ieee80211_ref_node(ni) : NULL;
1642 0 : cmd.key = k;
1643 0 : athn_usb_do_async(usc, athn_usb_set_key_cb, &cmd, sizeof(cmd));
1644 0 : return (0);
1645 0 : }
1646 :
1647 : void
1648 0 : athn_usb_set_key_cb(struct athn_usb_softc *usc, void *arg)
1649 : {
1650 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1651 0 : struct athn_usb_cmd_key *cmd = arg;
1652 : int s;
1653 :
1654 0 : s = splnet();
1655 0 : athn_set_key(ic, cmd->ni, cmd->key);
1656 0 : if (cmd->ni != NULL)
1657 0 : ieee80211_release_node(ic, cmd->ni);
1658 0 : splx(s);
1659 0 : }
1660 :
1661 : void
1662 0 : athn_usb_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
1663 : struct ieee80211_key *k)
1664 : {
1665 0 : struct athn_usb_softc *usc = ic->ic_softc;
1666 0 : struct athn_usb_cmd_key cmd;
1667 :
1668 0 : if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
1669 0 : ic->ic_state != IEEE80211_S_RUN)
1670 0 : return; /* Nothing to do. */
1671 :
1672 : /* Do it in a process context. */
1673 0 : cmd.ni = (ni != NULL) ? ieee80211_ref_node(ni) : NULL;
1674 0 : cmd.key = k;
1675 0 : athn_usb_do_async(usc, athn_usb_delete_key_cb, &cmd, sizeof(cmd));
1676 0 : }
1677 :
1678 : void
1679 0 : athn_usb_delete_key_cb(struct athn_usb_softc *usc, void *arg)
1680 : {
1681 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1682 0 : struct athn_usb_cmd_key *cmd = arg;
1683 : int s;
1684 :
1685 0 : s = splnet();
1686 0 : athn_delete_key(ic, cmd->ni, cmd->key);
1687 0 : if (cmd->ni != NULL)
1688 0 : ieee80211_release_node(ic, cmd->ni);
1689 0 : splx(s);
1690 0 : }
1691 :
1692 : #ifndef IEEE80211_STA_ONLY
1693 : void
1694 0 : athn_usb_bcneof(struct usbd_xfer *xfer, void *priv,
1695 : usbd_status status)
1696 : {
1697 0 : struct athn_usb_tx_data *data = priv;
1698 0 : struct athn_usb_softc *usc = data->sc;
1699 :
1700 0 : if (__predict_false(status == USBD_STALLED))
1701 0 : usbd_clear_endpoint_stall_async(usc->tx_data_pipe);
1702 0 : usc->tx_bcn = data;
1703 0 : }
1704 :
1705 : /*
1706 : * Process Software Beacon Alert interrupts.
1707 : */
1708 : void
1709 0 : athn_usb_swba(struct athn_usb_softc *usc)
1710 : {
1711 0 : struct athn_softc *sc = &usc->sc_sc;
1712 0 : struct ieee80211com *ic = &sc->sc_ic;
1713 : struct athn_usb_tx_data *data;
1714 : struct ieee80211_frame *wh;
1715 : struct ar_stream_hdr *hdr;
1716 : struct ar_htc_frame_hdr *htc;
1717 : struct ar_tx_bcn *bcn;
1718 : struct mbuf *m;
1719 : int error;
1720 :
1721 0 : if (ic->ic_dtim_count == 0)
1722 0 : ic->ic_dtim_count = ic->ic_dtim_period - 1;
1723 : else
1724 0 : ic->ic_dtim_count--;
1725 :
1726 : /* Make sure previous beacon has been sent. */
1727 0 : if (usc->tx_bcn == NULL)
1728 0 : return;
1729 : data = usc->tx_bcn;
1730 :
1731 : /* Get new beacon. */
1732 0 : m = ieee80211_beacon_alloc(ic, ic->ic_bss);
1733 0 : if (__predict_false(m == NULL))
1734 0 : return;
1735 : /* Assign sequence number. */
1736 0 : wh = mtod(m, struct ieee80211_frame *);
1737 0 : *(uint16_t *)&wh->i_seq[0] =
1738 0 : htole16(ic->ic_bss->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
1739 0 : ic->ic_bss->ni_txseq++;
1740 :
1741 0 : hdr = (struct ar_stream_hdr *)data->buf;
1742 0 : hdr->tag = htole16(AR_USB_TX_STREAM_TAG);
1743 0 : hdr->len = htole16(sizeof(*htc) + sizeof(*bcn) + m->m_pkthdr.len);
1744 :
1745 0 : htc = (struct ar_htc_frame_hdr *)&hdr[1];
1746 0 : memset(htc, 0, sizeof(*htc));
1747 0 : htc->endpoint_id = usc->ep_bcn;
1748 0 : htc->payload_len = htobe16(sizeof(*bcn) + m->m_pkthdr.len);
1749 :
1750 0 : bcn = (struct ar_tx_bcn *)&htc[1];
1751 0 : memset(bcn, 0, sizeof(*bcn));
1752 0 : bcn->vif_idx = 0;
1753 :
1754 0 : m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&bcn[1]);
1755 :
1756 0 : usbd_setup_xfer(data->xfer, usc->tx_data_pipe, data, data->buf,
1757 0 : sizeof(*hdr) + sizeof(*htc) + sizeof(*bcn) + m->m_pkthdr.len,
1758 : USBD_SHORT_XFER_OK | USBD_NO_COPY, ATHN_USB_TX_TIMEOUT,
1759 : athn_usb_bcneof);
1760 :
1761 0 : m_freem(m);
1762 0 : usc->tx_bcn = NULL;
1763 0 : error = usbd_transfer(data->xfer);
1764 0 : if (__predict_false(error != USBD_IN_PROGRESS && error != 0))
1765 0 : usc->tx_bcn = data;
1766 0 : }
1767 : #endif
1768 :
1769 : /* Update current transmit rate for a node based on firmware Tx status. */
1770 : void
1771 0 : athn_usb_tx_status(void *arg, struct ieee80211_node *ni)
1772 : {
1773 0 : struct ar_wmi_evt_txstatus *ts = arg;
1774 0 : struct athn_node *an = (struct athn_node *)ni;
1775 0 : uint8_t rate_index = (ts->rate & AR_HTC_TXSTAT_RATE);
1776 :
1777 0 : if (an->sta_index != ts->cookie) /* Tx report for a different node */
1778 0 : return;
1779 :
1780 0 : if (ts->flags & AR_HTC_TXSTAT_MCS) {
1781 0 : if (isset(ni->ni_rxmcs, rate_index))
1782 0 : ni->ni_txmcs = rate_index;
1783 0 : } else if (rate_index < ni->ni_rates.rs_nrates)
1784 0 : ni->ni_txrate = rate_index;
1785 0 : }
1786 :
1787 : void
1788 0 : athn_usb_rx_wmi_ctrl(struct athn_usb_softc *usc, uint8_t *buf, int len)
1789 : {
1790 : struct ar_wmi_cmd_hdr *wmi;
1791 : uint16_t cmd_id;
1792 :
1793 0 : if (__predict_false(len < sizeof(*wmi)))
1794 0 : return;
1795 0 : wmi = (struct ar_wmi_cmd_hdr *)buf;
1796 0 : cmd_id = betoh16(wmi->cmd_id);
1797 :
1798 0 : if (!(cmd_id & AR_WMI_EVT_FLAG)) {
1799 0 : if (usc->wait_cmd_id != cmd_id)
1800 0 : return; /* Unexpected reply. */
1801 0 : if (usc->obuf != NULL) {
1802 : /* Copy answer into caller supplied buffer. */
1803 0 : memcpy(usc->obuf, &wmi[1], len - sizeof(*wmi));
1804 0 : }
1805 : /* Notify caller of completion. */
1806 0 : wakeup(&usc->wait_cmd_id);
1807 0 : return;
1808 : }
1809 0 : switch (cmd_id & 0xfff) {
1810 : #ifndef IEEE80211_STA_ONLY
1811 : case AR_WMI_EVT_SWBA:
1812 0 : athn_usb_swba(usc);
1813 0 : break;
1814 : #endif
1815 : case AR_WMI_EVT_TXSTATUS: {
1816 : struct ar_wmi_evt_txstatus_list *tsl;
1817 : int i;
1818 :
1819 0 : tsl = (struct ar_wmi_evt_txstatus_list *)&wmi[1];
1820 0 : for (i = 0; i < tsl->count && i < nitems(tsl->ts); i++) {
1821 0 : struct ieee80211com *ic = &usc->sc_sc.sc_ic;
1822 0 : struct athn_node *an = (struct athn_node *)ic->ic_bss;
1823 0 : struct ar_wmi_evt_txstatus *ts = &tsl->ts[i];
1824 : uint8_t qid;
1825 :
1826 : /* Skip the node we use to send management frames. */
1827 0 : if (ts->cookie == 0)
1828 0 : continue;
1829 :
1830 : /* Skip Tx reports for non-data frame endpoints. */
1831 0 : qid = (ts->rate & AR_HTC_TXSTAT_EPID) >>
1832 : AR_HTC_TXSTAT_EPID_SHIFT;
1833 0 : if (qid != usc->ep_data[EDCA_AC_BE] &&
1834 0 : qid != usc->ep_data[EDCA_AC_BK] &&
1835 0 : qid != usc->ep_data[EDCA_AC_VI] &&
1836 0 : qid != usc->ep_data[EDCA_AC_VO])
1837 0 : continue;
1838 :
1839 0 : if (ts->cookie == an->sta_index)
1840 0 : athn_usb_tx_status(ts, ic->ic_bss);
1841 : else
1842 0 : ieee80211_iterate_nodes(ic, athn_usb_tx_status,
1843 0 : ts);
1844 0 : }
1845 : break;
1846 : }
1847 : case AR_WMI_EVT_FATAL:
1848 0 : printf("%s: fatal firmware error\n", usc->usb_dev.dv_xname);
1849 0 : break;
1850 : default:
1851 : DPRINTF(("WMI event %d ignored\n", cmd_id));
1852 : break;
1853 : }
1854 0 : }
1855 :
1856 : void
1857 0 : athn_usb_intr(struct usbd_xfer *xfer, void *priv,
1858 : usbd_status status)
1859 : {
1860 0 : struct athn_usb_softc *usc = priv;
1861 : struct ar_htc_frame_hdr *htc;
1862 : struct ar_htc_msg_hdr *msg;
1863 0 : uint8_t *buf = usc->ibuf;
1864 : uint16_t msg_id;
1865 0 : int len;
1866 :
1867 0 : if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
1868 : DPRINTF(("intr status=%d\n", status));
1869 0 : if (status == USBD_STALLED)
1870 0 : usbd_clear_endpoint_stall_async(usc->rx_intr_pipe);
1871 0 : else if (status == USBD_IOERROR) {
1872 : /*
1873 : * The device has gone away. If async commands are
1874 : * pending or running ensure the device dies ASAP
1875 : * and any blocked processes are woken up.
1876 : */
1877 0 : if (usc->cmdq.queued > 0)
1878 0 : usbd_deactivate(usc->sc_udev);
1879 : }
1880 0 : return;
1881 : }
1882 0 : usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
1883 :
1884 : /* Skip watchdog pattern if present. */
1885 0 : if (len >= 4 && *(uint32_t *)buf == htobe32(0x00c60000)) {
1886 0 : buf += 4;
1887 0 : len -= 4;
1888 0 : }
1889 0 : if (__predict_false(len < sizeof(*htc)))
1890 0 : return;
1891 0 : htc = (struct ar_htc_frame_hdr *)buf;
1892 : /* Skip HTC header. */
1893 0 : buf += sizeof(*htc);
1894 0 : len -= sizeof(*htc);
1895 :
1896 0 : if (htc->endpoint_id != 0) {
1897 0 : if (__predict_false(htc->endpoint_id != usc->ep_ctrl))
1898 0 : return;
1899 : /* Remove trailer if present. */
1900 0 : if (htc->flags & AR_HTC_FLAG_TRAILER) {
1901 0 : if (__predict_false(len < htc->control[0]))
1902 0 : return;
1903 0 : len -= htc->control[0];
1904 0 : }
1905 0 : athn_usb_rx_wmi_ctrl(usc, buf, len);
1906 0 : return;
1907 : }
1908 : /* Endpoint 0 carries HTC messages. */
1909 0 : if (__predict_false(len < sizeof(*msg)))
1910 0 : return;
1911 0 : msg = (struct ar_htc_msg_hdr *)buf;
1912 0 : msg_id = betoh16(msg->msg_id);
1913 : DPRINTF(("Rx HTC message %d\n", msg_id));
1914 0 : switch (msg_id) {
1915 : case AR_HTC_MSG_READY:
1916 0 : if (usc->wait_msg_id != msg_id)
1917 : break;
1918 0 : usc->wait_msg_id = 0;
1919 0 : wakeup(&usc->wait_msg_id);
1920 0 : break;
1921 : case AR_HTC_MSG_CONN_SVC_RSP:
1922 0 : if (usc->wait_msg_id != msg_id)
1923 : break;
1924 0 : if (usc->msg_conn_svc_rsp != NULL) {
1925 0 : memcpy(usc->msg_conn_svc_rsp, &msg[1],
1926 : sizeof(struct ar_htc_msg_conn_svc_rsp));
1927 0 : }
1928 0 : usc->wait_msg_id = 0;
1929 0 : wakeup(&usc->wait_msg_id);
1930 0 : break;
1931 : case AR_HTC_MSG_CONF_PIPE_RSP:
1932 0 : if (usc->wait_msg_id != msg_id)
1933 : break;
1934 0 : usc->wait_msg_id = 0;
1935 0 : wakeup(&usc->wait_msg_id);
1936 0 : break;
1937 : default:
1938 : DPRINTF(("HTC message %d ignored\n", msg_id));
1939 : break;
1940 : }
1941 0 : }
1942 :
1943 : #if NBPFILTER > 0
1944 : void
1945 0 : athn_usb_rx_radiotap(struct athn_softc *sc, struct mbuf *m,
1946 : struct ar_rx_status *rs)
1947 : {
1948 : #define IEEE80211_RADIOTAP_F_SHORTGI 0x80 /* XXX from FBSD */
1949 :
1950 0 : struct athn_rx_radiotap_header *tap = &sc->sc_rxtap;
1951 0 : struct ieee80211com *ic = &sc->sc_ic;
1952 0 : struct mbuf mb;
1953 : uint8_t rate;
1954 :
1955 0 : tap->wr_flags = IEEE80211_RADIOTAP_F_FCS;
1956 0 : tap->wr_tsft = htole64(betoh64(rs->rs_tstamp));
1957 0 : tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
1958 0 : tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
1959 0 : tap->wr_dbm_antsignal = rs->rs_rssi;
1960 : /* XXX noise. */
1961 0 : tap->wr_antenna = rs->rs_antenna;
1962 0 : tap->wr_rate = 0; /* In case it can't be found below. */
1963 0 : rate = rs->rs_rate;
1964 0 : if (rate & 0x80) { /* HT. */
1965 : /* Bit 7 set means HT MCS instead of rate. */
1966 0 : tap->wr_rate = rate;
1967 0 : if (!(rs->rs_flags & AR_RXS_FLAG_GI))
1968 0 : tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;
1969 :
1970 0 : } else if (rate & 0x10) { /* CCK. */
1971 0 : if (rate & 0x04)
1972 0 : tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
1973 0 : switch (rate & ~0x14) {
1974 0 : case 0xb: tap->wr_rate = 2; break;
1975 0 : case 0xa: tap->wr_rate = 4; break;
1976 0 : case 0x9: tap->wr_rate = 11; break;
1977 0 : case 0x8: tap->wr_rate = 22; break;
1978 : }
1979 : } else { /* OFDM. */
1980 0 : switch (rate) {
1981 0 : case 0xb: tap->wr_rate = 12; break;
1982 0 : case 0xf: tap->wr_rate = 18; break;
1983 0 : case 0xa: tap->wr_rate = 24; break;
1984 0 : case 0xe: tap->wr_rate = 36; break;
1985 0 : case 0x9: tap->wr_rate = 48; break;
1986 0 : case 0xd: tap->wr_rate = 72; break;
1987 0 : case 0x8: tap->wr_rate = 96; break;
1988 0 : case 0xc: tap->wr_rate = 108; break;
1989 : }
1990 : }
1991 0 : mb.m_data = (caddr_t)tap;
1992 0 : mb.m_len = sc->sc_rxtap_len;
1993 0 : mb.m_next = m;
1994 0 : mb.m_nextpkt = NULL;
1995 0 : mb.m_type = 0;
1996 0 : mb.m_flags = 0;
1997 0 : bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
1998 0 : }
1999 : #endif
2000 :
2001 : void
2002 0 : athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m)
2003 : {
2004 0 : struct athn_softc *sc = &usc->sc_sc;
2005 0 : struct ieee80211com *ic = &sc->sc_ic;
2006 0 : struct ifnet *ifp = &ic->ic_if;
2007 : struct ieee80211_frame *wh;
2008 : struct ieee80211_node *ni;
2009 0 : struct ieee80211_rxinfo rxi;
2010 : struct ar_htc_frame_hdr *htc;
2011 : struct ar_rx_status *rs;
2012 : uint16_t datalen;
2013 : int s;
2014 :
2015 0 : if (__predict_false(m->m_len < sizeof(*htc)))
2016 : goto skip;
2017 0 : htc = mtod(m, struct ar_htc_frame_hdr *);
2018 0 : if (__predict_false(htc->endpoint_id == 0)) {
2019 : DPRINTF(("bad endpoint %d\n", htc->endpoint_id));
2020 : goto skip;
2021 : }
2022 0 : if (htc->flags & AR_HTC_FLAG_TRAILER) {
2023 0 : if (m->m_len < htc->control[0])
2024 : goto skip;
2025 0 : m_adj(m, -(int)htc->control[0]);
2026 0 : }
2027 0 : m_adj(m, sizeof(*htc)); /* Strip HTC header. */
2028 :
2029 0 : if (__predict_false(m->m_len < sizeof(*rs)))
2030 : goto skip;
2031 0 : rs = mtod(m, struct ar_rx_status *);
2032 :
2033 : /* Make sure that payload fits. */
2034 0 : datalen = betoh16(rs->rs_datalen);
2035 0 : if (__predict_false(m->m_len < sizeof(*rs) + datalen))
2036 : goto skip;
2037 :
2038 0 : if (__predict_false(datalen < sizeof(*wh) + IEEE80211_CRC_LEN))
2039 : goto skip;
2040 :
2041 0 : m_adj(m, sizeof(*rs)); /* Strip Rx status. */
2042 :
2043 0 : s = splnet();
2044 :
2045 : /* Grab a reference to the source node. */
2046 0 : wh = mtod(m, struct ieee80211_frame *);
2047 0 : ni = ieee80211_find_rxnode(ic, wh);
2048 :
2049 : /* Remove any HW padding after the 802.11 header. */
2050 0 : if (!(wh->i_fc[0] & IEEE80211_FC0_TYPE_CTL)) {
2051 0 : u_int hdrlen = ieee80211_get_hdrlen(wh);
2052 0 : if (hdrlen & 3) {
2053 0 : memmove((caddr_t)wh + 2, wh, hdrlen);
2054 0 : m_adj(m, 2);
2055 0 : }
2056 0 : }
2057 : #if NBPFILTER > 0
2058 0 : if (__predict_false(sc->sc_drvbpf != NULL))
2059 0 : athn_usb_rx_radiotap(sc, m, rs);
2060 : #endif
2061 : /* Trim 802.11 FCS after radiotap. */
2062 0 : m_adj(m, -IEEE80211_CRC_LEN);
2063 :
2064 : /* Send the frame to the 802.11 layer. */
2065 0 : rxi.rxi_flags = 0;
2066 0 : rxi.rxi_rssi = rs->rs_rssi + AR_USB_DEFAULT_NF;
2067 0 : rxi.rxi_tstamp = betoh64(rs->rs_tstamp);
2068 0 : ieee80211_input(ifp, m, ni, &rxi);
2069 :
2070 : /* Node is no longer needed. */
2071 0 : ieee80211_release_node(ic, ni);
2072 0 : splx(s);
2073 0 : return;
2074 : skip:
2075 0 : m_freem(m);
2076 0 : }
2077 :
2078 : void
2079 0 : athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
2080 : usbd_status status)
2081 : {
2082 0 : struct athn_usb_rx_data *data = priv;
2083 0 : struct athn_usb_softc *usc = data->sc;
2084 0 : struct athn_softc *sc = &usc->sc_sc;
2085 0 : struct ifnet *ifp = &sc->sc_ic.ic_if;
2086 0 : struct athn_usb_rx_stream *stream = &usc->rx_stream;
2087 0 : uint8_t *buf = data->buf;
2088 : struct ar_stream_hdr *hdr;
2089 : struct mbuf *m;
2090 : uint16_t pktlen;
2091 0 : int off, len;
2092 :
2093 0 : if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
2094 : DPRINTF(("RX status=%d\n", status));
2095 0 : if (status == USBD_STALLED)
2096 0 : usbd_clear_endpoint_stall_async(usc->rx_data_pipe);
2097 0 : if (status != USBD_CANCELLED)
2098 : goto resubmit;
2099 0 : return;
2100 : }
2101 0 : usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
2102 :
2103 0 : if (stream->left > 0) {
2104 0 : if (len >= stream->left) {
2105 : /* We have all our pktlen bytes now. */
2106 0 : if (__predict_true(stream->m != NULL)) {
2107 0 : memcpy(mtod(stream->m, uint8_t *) +
2108 : stream->moff, buf, stream->left);
2109 0 : athn_usb_rx_frame(usc, stream->m);
2110 0 : stream->m = NULL;
2111 0 : }
2112 : /* Next header is 32-bit aligned. */
2113 0 : off = (stream->left + 3) & ~3;
2114 0 : buf += off;
2115 0 : len -= off;
2116 0 : stream->left = 0;
2117 : } else {
2118 : /* Still need more bytes, save what we have. */
2119 0 : if (__predict_true(stream->m != NULL)) {
2120 0 : memcpy(mtod(stream->m, uint8_t *) +
2121 : stream->moff, buf, len);
2122 0 : stream->moff += len;
2123 0 : }
2124 0 : stream->left -= len;
2125 0 : goto resubmit;
2126 : }
2127 0 : }
2128 0 : KASSERT(stream->left == 0);
2129 0 : while (len >= sizeof(*hdr)) {
2130 0 : hdr = (struct ar_stream_hdr *)buf;
2131 0 : if (hdr->tag != htole16(AR_USB_RX_STREAM_TAG)) {
2132 : DPRINTF(("invalid tag 0x%x\n", hdr->tag));
2133 : break;
2134 : }
2135 0 : pktlen = letoh16(hdr->len);
2136 0 : buf += sizeof(*hdr);
2137 0 : len -= sizeof(*hdr);
2138 :
2139 0 : if (__predict_true(pktlen <= MCLBYTES)) {
2140 : /* Allocate an mbuf to store the next pktlen bytes. */
2141 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
2142 0 : if (__predict_true(m != NULL)) {
2143 0 : m->m_pkthdr.len = m->m_len = pktlen;
2144 0 : if (pktlen > MHLEN) {
2145 0 : MCLGET(m, M_DONTWAIT);
2146 0 : if (!(m->m_flags & M_EXT)) {
2147 0 : m_free(m);
2148 : m = NULL;
2149 0 : }
2150 : }
2151 : }
2152 : } else /* Drop frames larger than MCLBYTES. */
2153 : m = NULL;
2154 :
2155 0 : if (m == NULL)
2156 0 : ifp->if_ierrors++;
2157 :
2158 : /*
2159 : * NB: m can be NULL, in which case the next pktlen bytes
2160 : * will be discarded from the Rx stream.
2161 : */
2162 0 : if (pktlen > len) {
2163 : /* Need more bytes, save what we have. */
2164 0 : stream->m = m; /* NB: m can be NULL. */
2165 0 : if (__predict_true(stream->m != NULL)) {
2166 0 : memcpy(mtod(stream->m, uint8_t *), buf, len);
2167 0 : stream->moff = len;
2168 0 : }
2169 0 : stream->left = pktlen - len;
2170 0 : goto resubmit;
2171 : }
2172 0 : if (__predict_true(m != NULL)) {
2173 : /* We have all the pktlen bytes in this xfer. */
2174 0 : memcpy(mtod(m, uint8_t *), buf, pktlen);
2175 0 : athn_usb_rx_frame(usc, m);
2176 0 : }
2177 :
2178 : /* Next header is 32-bit aligned. */
2179 0 : off = (pktlen + 3) & ~3;
2180 0 : buf += off;
2181 0 : len -= off;
2182 : }
2183 :
2184 : resubmit:
2185 : /* Setup a new transfer. */
2186 0 : usbd_setup_xfer(xfer, usc->rx_data_pipe, data, data->buf,
2187 : ATHN_USB_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
2188 : USBD_NO_TIMEOUT, athn_usb_rxeof);
2189 0 : (void)usbd_transfer(xfer);
2190 0 : }
2191 :
2192 : void
2193 0 : athn_usb_txeof(struct usbd_xfer *xfer, void *priv,
2194 : usbd_status status)
2195 : {
2196 0 : struct athn_usb_tx_data *data = priv;
2197 0 : struct athn_usb_softc *usc = data->sc;
2198 0 : struct athn_softc *sc = &usc->sc_sc;
2199 0 : struct ifnet *ifp = &sc->sc_ic.ic_if;
2200 : int s;
2201 :
2202 0 : s = splnet();
2203 : /* Put this Tx buffer back to our free list. */
2204 0 : TAILQ_INSERT_TAIL(&usc->tx_free_list, data, next);
2205 :
2206 0 : if (__predict_false(status != USBD_NORMAL_COMPLETION)) {
2207 : DPRINTF(("TX status=%d\n", status));
2208 0 : if (status == USBD_STALLED)
2209 0 : usbd_clear_endpoint_stall_async(usc->tx_data_pipe);
2210 0 : ifp->if_oerrors++;
2211 0 : splx(s);
2212 : /* XXX Why return? */
2213 0 : return;
2214 : }
2215 0 : sc->sc_tx_timer = 0;
2216 :
2217 : /* We just released a Tx buffer, notify Tx. */
2218 0 : if (ifq_is_oactive(&ifp->if_snd)) {
2219 0 : ifq_clr_oactive(&ifp->if_snd);
2220 0 : ifp->if_start(ifp);
2221 0 : }
2222 0 : splx(s);
2223 0 : }
2224 :
2225 : int
2226 0 : athn_usb_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
2227 : {
2228 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
2229 0 : struct athn_node *an = (struct athn_node *)ni;
2230 0 : struct ieee80211com *ic = &sc->sc_ic;
2231 : struct ieee80211_frame *wh;
2232 : struct ieee80211_key *k = NULL;
2233 : struct athn_usb_tx_data *data;
2234 : struct ar_stream_hdr *hdr;
2235 : struct ar_htc_frame_hdr *htc;
2236 : struct ar_tx_frame *txf;
2237 : struct ar_tx_mgmt *txm;
2238 : uint8_t *frm;
2239 : uint16_t qos;
2240 : uint8_t qid, tid = 0;
2241 : int hasqos, xferlen, error;
2242 :
2243 0 : wh = mtod(m, struct ieee80211_frame *);
2244 0 : if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
2245 0 : k = ieee80211_get_txkey(ic, wh, ni);
2246 0 : if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
2247 0 : return (ENOBUFS);
2248 0 : wh = mtod(m, struct ieee80211_frame *);
2249 0 : }
2250 0 : if ((hasqos = ieee80211_has_qos(wh))) {
2251 0 : qos = ieee80211_get_qos(wh);
2252 0 : tid = qos & IEEE80211_QOS_TID;
2253 0 : qid = ieee80211_up_to_ac(ic, tid);
2254 0 : } else
2255 : qid = EDCA_AC_BE;
2256 :
2257 : /* Grab a Tx buffer from our free list. */
2258 0 : data = TAILQ_FIRST(&usc->tx_free_list);
2259 0 : TAILQ_REMOVE(&usc->tx_free_list, data, next);
2260 :
2261 : #if NBPFILTER > 0
2262 : /* XXX Change radiotap Tx header for USB (no txrate). */
2263 0 : if (__predict_false(sc->sc_drvbpf != NULL)) {
2264 0 : struct athn_tx_radiotap_header *tap = &sc->sc_txtap;
2265 0 : struct mbuf mb;
2266 :
2267 0 : tap->wt_flags = 0;
2268 0 : tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
2269 0 : tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
2270 0 : mb.m_data = (caddr_t)tap;
2271 0 : mb.m_len = sc->sc_txtap_len;
2272 0 : mb.m_next = m;
2273 0 : mb.m_nextpkt = NULL;
2274 0 : mb.m_type = 0;
2275 0 : mb.m_flags = 0;
2276 0 : bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
2277 0 : }
2278 : #endif
2279 :
2280 : /* NB: We don't take advantage of USB Tx stream mode for now. */
2281 0 : hdr = (struct ar_stream_hdr *)data->buf;
2282 0 : hdr->tag = htole16(AR_USB_TX_STREAM_TAG);
2283 :
2284 0 : htc = (struct ar_htc_frame_hdr *)&hdr[1];
2285 0 : memset(htc, 0, sizeof(*htc));
2286 0 : if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
2287 : IEEE80211_FC0_TYPE_DATA) {
2288 0 : htc->endpoint_id = usc->ep_data[qid];
2289 :
2290 0 : txf = (struct ar_tx_frame *)&htc[1];
2291 0 : memset(txf, 0, sizeof(*txf));
2292 0 : txf->data_type = AR_HTC_NORMAL;
2293 0 : txf->node_idx = an->sta_index;
2294 0 : txf->vif_idx = 0;
2295 0 : txf->tid = tid;
2296 0 : if (m->m_pkthdr.len + IEEE80211_CRC_LEN > ic->ic_rtsthreshold)
2297 0 : txf->flags |= htobe32(AR_HTC_TX_RTSCTS);
2298 0 : else if (ic->ic_flags & IEEE80211_F_USEPROT) {
2299 0 : if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
2300 0 : txf->flags |= htobe32(AR_HTC_TX_CTSONLY);
2301 0 : else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
2302 0 : txf->flags |= htobe32(AR_HTC_TX_RTSCTS);
2303 : }
2304 0 : txf->key_idx = 0xff;
2305 0 : txf->cookie = an->sta_index;
2306 0 : frm = (uint8_t *)&txf[1];
2307 0 : } else {
2308 0 : htc->endpoint_id = usc->ep_mgmt;
2309 :
2310 0 : txm = (struct ar_tx_mgmt *)&htc[1];
2311 0 : memset(txm, 0, sizeof(*txm));
2312 0 : txm->node_idx = an->sta_index;
2313 0 : txm->vif_idx = 0;
2314 0 : txm->key_idx = 0xff;
2315 0 : txm->cookie = an->sta_index;
2316 0 : frm = (uint8_t *)&txm[1];
2317 : }
2318 : /* Copy payload. */
2319 0 : m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)frm);
2320 0 : frm += m->m_pkthdr.len;
2321 0 : m_freem(m);
2322 :
2323 : /* Finalize headers. */
2324 0 : htc->payload_len = htobe16(frm - (uint8_t *)&htc[1]);
2325 0 : hdr->len = htole16(frm - (uint8_t *)&hdr[1]);
2326 0 : xferlen = frm - data->buf;
2327 :
2328 0 : usbd_setup_xfer(data->xfer, usc->tx_data_pipe, data, data->buf,
2329 : xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, ATHN_USB_TX_TIMEOUT,
2330 : athn_usb_txeof);
2331 0 : error = usbd_transfer(data->xfer);
2332 0 : if (__predict_false(error != USBD_IN_PROGRESS && error != 0)) {
2333 : /* Put this Tx buffer back to our free list. */
2334 0 : TAILQ_INSERT_TAIL(&usc->tx_free_list, data, next);
2335 0 : return (error);
2336 : }
2337 0 : ieee80211_release_node(ic, ni);
2338 0 : return (0);
2339 0 : }
2340 :
2341 : void
2342 0 : athn_usb_start(struct ifnet *ifp)
2343 : {
2344 0 : struct athn_softc *sc = ifp->if_softc;
2345 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
2346 0 : struct ieee80211com *ic = &sc->sc_ic;
2347 0 : struct ieee80211_node *ni;
2348 : struct mbuf *m;
2349 :
2350 0 : if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
2351 0 : return;
2352 :
2353 0 : for (;;) {
2354 0 : if (TAILQ_EMPTY(&usc->tx_free_list)) {
2355 0 : ifq_set_oactive(&ifp->if_snd);
2356 0 : break;
2357 : }
2358 : /* Send pending management frames first. */
2359 0 : m = mq_dequeue(&ic->ic_mgtq);
2360 0 : if (m != NULL) {
2361 0 : ni = m->m_pkthdr.ph_cookie;
2362 0 : goto sendit;
2363 : }
2364 0 : if (ic->ic_state != IEEE80211_S_RUN)
2365 : break;
2366 :
2367 : /* Encapsulate and send data frames. */
2368 0 : IFQ_DEQUEUE(&ifp->if_snd, m);
2369 0 : if (m == NULL)
2370 : break;
2371 : #if NBPFILTER > 0
2372 0 : if (ifp->if_bpf != NULL)
2373 0 : bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
2374 : #endif
2375 0 : if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
2376 0 : continue;
2377 : sendit:
2378 : #if NBPFILTER > 0
2379 0 : if (ic->ic_rawbpf != NULL)
2380 0 : bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
2381 : #endif
2382 0 : if (athn_usb_tx(sc, m, ni) != 0) {
2383 0 : ieee80211_release_node(ic, ni);
2384 0 : ifp->if_oerrors++;
2385 0 : continue;
2386 : }
2387 :
2388 0 : sc->sc_tx_timer = 5;
2389 0 : ifp->if_timer = 1;
2390 : }
2391 0 : }
2392 :
2393 : void
2394 0 : athn_usb_watchdog(struct ifnet *ifp)
2395 : {
2396 0 : struct athn_softc *sc = ifp->if_softc;
2397 :
2398 0 : ifp->if_timer = 0;
2399 :
2400 0 : if (sc->sc_tx_timer > 0) {
2401 0 : if (--sc->sc_tx_timer == 0) {
2402 0 : printf("%s: device timeout\n", sc->sc_dev.dv_xname);
2403 : /* athn_usb_init(ifp); XXX needs a process context! */
2404 0 : ifp->if_oerrors++;
2405 0 : return;
2406 : }
2407 0 : ifp->if_timer = 1;
2408 0 : }
2409 0 : ieee80211_watchdog(ifp);
2410 0 : }
2411 :
2412 : int
2413 0 : athn_usb_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
2414 : {
2415 0 : struct athn_softc *sc = ifp->if_softc;
2416 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
2417 0 : struct ieee80211com *ic = &sc->sc_ic;
2418 : int s, error = 0;
2419 :
2420 0 : if (usbd_is_dying(usc->sc_udev))
2421 0 : return ENXIO;
2422 :
2423 0 : usbd_ref_incr(usc->sc_udev);
2424 :
2425 0 : s = splnet();
2426 :
2427 0 : switch (cmd) {
2428 : case SIOCSIFADDR:
2429 0 : ifp->if_flags |= IFF_UP;
2430 : /* FALLTHROUGH */
2431 : case SIOCSIFFLAGS:
2432 0 : if (ifp->if_flags & IFF_UP) {
2433 0 : if (!(ifp->if_flags & IFF_RUNNING))
2434 0 : error = athn_usb_init(ifp);
2435 : } else {
2436 0 : if (ifp->if_flags & IFF_RUNNING)
2437 0 : athn_usb_stop(ifp);
2438 : }
2439 : break;
2440 : case SIOCS80211CHANNEL:
2441 0 : error = ieee80211_ioctl(ifp, cmd, data);
2442 0 : if (error == ENETRESET &&
2443 0 : ic->ic_opmode == IEEE80211_M_MONITOR) {
2444 0 : if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
2445 : (IFF_UP | IFF_RUNNING)) {
2446 0 : athn_usb_switch_chan(sc, ic->ic_ibss_chan,
2447 : NULL);
2448 0 : }
2449 : error = 0;
2450 0 : }
2451 : break;
2452 : default:
2453 0 : error = ieee80211_ioctl(ifp, cmd, data);
2454 0 : }
2455 :
2456 0 : if (error == ENETRESET) {
2457 : error = 0;
2458 0 : if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
2459 : (IFF_UP | IFF_RUNNING)) {
2460 0 : athn_usb_stop(ifp);
2461 0 : error = athn_usb_init(ifp);
2462 0 : }
2463 : }
2464 0 : splx(s);
2465 :
2466 0 : usbd_ref_decr(usc->sc_udev);
2467 :
2468 0 : return (error);
2469 0 : }
2470 :
2471 : int
2472 0 : athn_usb_init(struct ifnet *ifp)
2473 : {
2474 0 : struct athn_softc *sc = ifp->if_softc;
2475 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
2476 0 : struct athn_ops *ops = &sc->ops;
2477 0 : struct ieee80211com *ic = &sc->sc_ic;
2478 : struct ieee80211_channel *c, *extc;
2479 : struct athn_usb_rx_data *data;
2480 0 : struct ar_htc_target_vif hvif;
2481 0 : struct ar_htc_target_sta sta;
2482 0 : struct ar_htc_cap_target hic;
2483 0 : uint16_t mode;
2484 : int i, error;
2485 :
2486 : /* Init host async commands ring. */
2487 0 : usc->cmdq.cur = usc->cmdq.next = usc->cmdq.queued = 0;
2488 :
2489 : /* Allocate Tx/Rx buffers. */
2490 0 : error = athn_usb_alloc_rx_list(usc);
2491 0 : if (error != 0)
2492 : goto fail;
2493 0 : error = athn_usb_alloc_tx_list(usc);
2494 0 : if (error != 0)
2495 : goto fail;
2496 : /* Steal one buffer for beacons. */
2497 0 : usc->tx_bcn = TAILQ_FIRST(&usc->tx_free_list);
2498 0 : TAILQ_REMOVE(&usc->tx_free_list, usc->tx_bcn, next);
2499 :
2500 0 : c = ic->ic_bss->ni_chan = ic->ic_ibss_chan;
2501 : extc = NULL;
2502 :
2503 : /* In case a new MAC address has been configured. */
2504 0 : IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
2505 :
2506 0 : error = athn_set_power_awake(sc);
2507 0 : if (error != 0)
2508 : goto fail;
2509 :
2510 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_FLUSH_RECV);
2511 0 : if (error != 0)
2512 : goto fail;
2513 :
2514 0 : error = athn_hw_reset(sc, c, extc, 1);
2515 0 : if (error != 0)
2516 : goto fail;
2517 :
2518 0 : ops->set_txpower(sc, c, extc);
2519 :
2520 0 : mode = htobe16(IEEE80211_IS_CHAN_2GHZ(c) ?
2521 : AR_HTC_MODE_11NG : AR_HTC_MODE_11NA);
2522 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_SET_MODE,
2523 : &mode, sizeof(mode), NULL);
2524 0 : if (error != 0)
2525 : goto fail;
2526 :
2527 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_ATH_INIT);
2528 0 : if (error != 0)
2529 : goto fail;
2530 :
2531 0 : error = athn_usb_wmi_cmd(usc, AR_WMI_CMD_START_RECV);
2532 0 : if (error != 0)
2533 : goto fail;
2534 :
2535 0 : athn_rx_start(sc);
2536 :
2537 : /* Create main interface on target. */
2538 0 : memset(&hvif, 0, sizeof(hvif));
2539 0 : hvif.index = 0;
2540 0 : IEEE80211_ADDR_COPY(hvif.myaddr, ic->ic_myaddr);
2541 0 : switch (ic->ic_opmode) {
2542 : case IEEE80211_M_STA:
2543 0 : hvif.opmode = htobe32(AR_HTC_M_STA);
2544 0 : break;
2545 : case IEEE80211_M_MONITOR:
2546 0 : hvif.opmode = htobe32(AR_HTC_M_MONITOR);
2547 0 : break;
2548 : #ifndef IEEE80211_STA_ONLY
2549 : case IEEE80211_M_IBSS:
2550 0 : hvif.opmode = htobe32(AR_HTC_M_IBSS);
2551 0 : break;
2552 : case IEEE80211_M_AHDEMO:
2553 0 : hvif.opmode = htobe32(AR_HTC_M_AHDEMO);
2554 0 : break;
2555 : case IEEE80211_M_HOSTAP:
2556 0 : hvif.opmode = htobe32(AR_HTC_M_HOSTAP);
2557 0 : break;
2558 : #endif
2559 : }
2560 0 : hvif.rtsthreshold = htobe16(ic->ic_rtsthreshold);
2561 : DPRINTF(("creating VAP\n"));
2562 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_VAP_CREATE,
2563 : &hvif, sizeof(hvif), NULL);
2564 0 : if (error != 0)
2565 : goto fail;
2566 :
2567 : /* Create a fake node to send management frames before assoc. */
2568 0 : memset(&sta, 0, sizeof(sta));
2569 0 : IEEE80211_ADDR_COPY(sta.macaddr, ic->ic_myaddr);
2570 0 : sta.sta_index = 0;
2571 0 : sta.is_vif_sta = 1;
2572 0 : sta.vif_index = hvif.index;
2573 0 : sta.maxampdu = 0xffff;
2574 : DPRINTF(("creating default node\n"));
2575 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_CREATE,
2576 : &sta, sizeof(sta), NULL);
2577 0 : if (error != 0)
2578 : goto fail;
2579 0 : usc->free_node_slots = ~(1 << sta.sta_index);
2580 :
2581 : /* Update target capabilities. */
2582 0 : memset(&hic, 0, sizeof(hic));
2583 0 : hic.ampdu_limit = htobe32(0x0000ffff);
2584 0 : hic.ampdu_subframes = 20;
2585 0 : hic.txchainmask = sc->txchainmask;
2586 : DPRINTF(("updating target configuration\n"));
2587 0 : error = athn_usb_wmi_xcmd(usc, AR_WMI_CMD_TARGET_IC_UPDATE,
2588 : &hic, sizeof(hic), NULL);
2589 0 : if (error != 0)
2590 : goto fail;
2591 :
2592 : /* Queue Rx xfers. */
2593 0 : for (i = 0; i < ATHN_USB_RX_LIST_COUNT; i++) {
2594 0 : data = &usc->rx_data[i];
2595 :
2596 0 : usbd_setup_xfer(data->xfer, usc->rx_data_pipe, data, data->buf,
2597 : ATHN_USB_RXBUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
2598 : USBD_NO_TIMEOUT, athn_usb_rxeof);
2599 0 : error = usbd_transfer(data->xfer);
2600 0 : if (error != 0 && error != USBD_IN_PROGRESS)
2601 : goto fail;
2602 : }
2603 : /* We're ready to go. */
2604 0 : ifp->if_flags |= IFF_RUNNING;
2605 0 : ifq_clr_oactive(&ifp->if_snd);
2606 :
2607 : #ifdef notyet
2608 : if (ic->ic_flags & IEEE80211_F_WEPON) {
2609 : /* Install WEP keys. */
2610 : for (i = 0; i < IEEE80211_WEP_NKID; i++)
2611 : athn_usb_set_key(ic, NULL, &ic->ic_nw_keys[i]);
2612 : }
2613 : #endif
2614 0 : if (ic->ic_opmode == IEEE80211_M_MONITOR)
2615 0 : ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2616 : else
2617 0 : ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2618 0 : athn_usb_wait_async(usc);
2619 0 : return (0);
2620 : fail:
2621 0 : athn_usb_stop(ifp);
2622 0 : return (error);
2623 0 : }
2624 :
2625 : void
2626 0 : athn_usb_stop(struct ifnet *ifp)
2627 : {
2628 0 : struct athn_softc *sc = ifp->if_softc;
2629 0 : struct athn_usb_softc *usc = (struct athn_usb_softc *)sc;
2630 0 : struct ieee80211com *ic = &sc->sc_ic;
2631 0 : struct ar_htc_target_vif hvif;
2632 0 : uint8_t sta_index;
2633 : int s;
2634 :
2635 0 : sc->sc_tx_timer = 0;
2636 0 : ifp->if_timer = 0;
2637 0 : ifp->if_flags &= ~IFF_RUNNING;
2638 0 : ifq_clr_oactive(&ifp->if_snd);
2639 :
2640 0 : s = splusb();
2641 0 : ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2642 :
2643 : /* Wait for all async commands to complete. */
2644 0 : athn_usb_wait_async(usc);
2645 :
2646 0 : timeout_del(&sc->scan_to);
2647 0 : timeout_del(&sc->calib_to);
2648 :
2649 : /* Remove all non-default nodes. */
2650 0 : for (sta_index = 1; sta_index < AR_USB_MAX_STA; sta_index++) {
2651 0 : if (usc->free_node_slots & (1 << sta_index))
2652 : continue;
2653 0 : (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE,
2654 : &sta_index, sizeof(sta_index), NULL);
2655 0 : }
2656 :
2657 : /* Remove main interface. This also invalidates our default node. */
2658 0 : memset(&hvif, 0, sizeof(hvif));
2659 0 : hvif.index = 0;
2660 0 : IEEE80211_ADDR_COPY(hvif.myaddr, ic->ic_myaddr);
2661 0 : (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_VAP_REMOVE,
2662 : &hvif, sizeof(hvif), NULL);
2663 :
2664 0 : usc->free_node_slots = 0xff;
2665 :
2666 0 : (void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR);
2667 0 : (void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DRAIN_TXQ_ALL);
2668 0 : (void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_STOP_RECV);
2669 :
2670 0 : athn_reset(sc, 0);
2671 0 : athn_init_pll(sc, NULL);
2672 0 : athn_set_power_awake(sc);
2673 0 : athn_reset(sc, 1);
2674 0 : athn_init_pll(sc, NULL);
2675 0 : athn_set_power_sleep(sc);
2676 :
2677 : /* Abort Tx/Rx. */
2678 0 : usbd_abort_pipe(usc->tx_data_pipe);
2679 0 : usbd_abort_pipe(usc->rx_data_pipe);
2680 :
2681 : /* Free Tx/Rx buffers. */
2682 0 : athn_usb_free_tx_list(usc);
2683 0 : athn_usb_free_rx_list(usc);
2684 0 : splx(s);
2685 :
2686 : /* Flush Rx stream. */
2687 0 : m_freem(usc->rx_stream.m);
2688 0 : usc->rx_stream.m = NULL;
2689 0 : usc->rx_stream.left = 0;
2690 0 : }
|