1 /*
2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright 2019 Joyent, Inc.
8 */
9
10 /*
11 * Copyright (c) 2006 Sam Leffler, Errno Consulting
12 * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer,
20 * without modification.
21 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
22 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
23 * redistribution must be conditioned upon including a substantially
24 * similar Disclaimer requirement for further binary redistribution.
25 *
26 * NO WARRANTY
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
30 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
31 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
32 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
35 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
37 * THE POSSIBILITY OF SUCH DAMAGES.
38 */
39
40 /*
41 * This driver is distantly derived from a driver of the same name
42 * by Damien Bergamini. The original copyright is included below:
43 *
44 * Copyright (c) 2006
45 * Damien Bergamini <damien.bergamini@free.fr>
46 *
47 * Permission to use, copy, modify, and distribute this software for any
48 * purpose with or without fee is hereby granted, provided that the above
49 * copyright notice and this permission notice appear in all copies.
50 *
51 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
52 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
53 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
54 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
55 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
56 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
57 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
58 */
59
60
61 #include <sys/types.h>
62 #include <sys/cmn_err.h>
63 #include <sys/strsubr.h>
64 #include <sys/strsun.h>
65 #include <sys/modctl.h>
66 #include <sys/devops.h>
67 #include <sys/byteorder.h>
68 #include <sys/mac_provider.h>
69 #include <sys/mac_wifi.h>
70 #include <sys/net80211.h>
71
72 #define USBDRV_MAJOR_VER 2
73 #define USBDRV_MINOR_VER 0
74 #include <sys/usb/usba.h>
75 #include <sys/usb/usba/usba_types.h>
76
77 #include "uath_reg.h"
78 #include "uath_var.h"
79
80 static void *uath_soft_state_p = NULL;
81
82 /*
83 * Bit flags in the ral_dbg_flags
84 */
85 #define UATH_DBG_MSG 0x000001
86 #define UATH_DBG_ERR 0x000002
87 #define UATH_DBG_USB 0x000004
88 #define UATH_DBG_TX 0x000008
89 #define UATH_DBG_RX 0x000010
90 #define UATH_DBG_FW 0x000020
91 #define UATH_DBG_TX_CMD 0x000040
92 #define UATH_DBG_RX_CMD 0x000080
93 #define UATH_DBG_ALL 0x000fff
94
95 uint32_t uath_dbg_flags = 0;
96
97 #ifdef DEBUG
98 #define UATH_DEBUG \
99 uath_debug
100 #else
101 #define UATH_DEBUG(...) (void)(0)
102 #endif
103
104 /*
105 * Various supported device vendors/products.
106 * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11b/g
107 */
108 #define UATH_FLAG_PRE_FIRMWARE (1 << 0)
109 #define UATH_FLAG_ABG (1 << 1)
110 #define UATH_FLAG_ERR (1 << 2)
111 #define UATH_DEV(v, p, f) \
112 { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) }, \
113 { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p##_NF }, \
114 (f) | UATH_FLAG_PRE_FIRMWARE }
115 #define UATH_DEV_UG(v, p) UATH_DEV(v, p, 0)
116 #define UATH_DEV_UX(v, p) UATH_DEV(v, p, UATH_FLAG_ABG)
117
118 struct uath_devno {
119 uint16_t vendor_id;
120 uint16_t product_id;
121 };
122
123 static const struct uath_type {
124 struct uath_devno dev;
125 uint8_t flags;
126 } uath_devs[] = {
127 UATH_DEV_UG(ACCTON, SMCWUSBTG2),
128 UATH_DEV_UG(ATHEROS, AR5523),
129 UATH_DEV_UG(ATHEROS2, AR5523_1),
130 UATH_DEV_UG(ATHEROS2, AR5523_2),
131 UATH_DEV_UX(ATHEROS2, AR5523_3),
132 UATH_DEV_UG(CONCEPTRONIC, AR5523_1),
133 UATH_DEV_UX(CONCEPTRONIC, AR5523_2),
134 UATH_DEV_UX(DLINK, DWLAG122),
135 UATH_DEV_UX(DLINK, DWLAG132),
136 UATH_DEV_UG(DLINK, DWLG132),
137 UATH_DEV_UG(GIGASET, AR5523),
138 UATH_DEV_UG(GIGASET, SMCWUSBTG),
139 UATH_DEV_UG(GLOBALSUN, AR5523_1),
140 UATH_DEV_UX(GLOBALSUN, AR5523_2),
141 UATH_DEV_UG(IODATA, USBWNG54US),
142 UATH_DEV_UG(MELCO, WLIU2KAMG54),
143 UATH_DEV_UX(NETGEAR, WG111U),
144 UATH_DEV_UG(NETGEAR3, WG111T),
145 UATH_DEV_UG(NETGEAR3, WPN111),
146 UATH_DEV_UG(PHILIPS, SNU6500),
147 UATH_DEV_UX(UMEDIA, AR5523_2),
148 UATH_DEV_UG(UMEDIA, TEW444UBEU),
149 UATH_DEV_UG(WISTRONNEWEB, AR5523_1),
150 UATH_DEV_UX(WISTRONNEWEB, AR5523_2),
151 UATH_DEV_UG(ZCOM, AR5523)
152 };
153
154 static char uath_fwmod[] = "uathfw";
155 static char uath_binmod[] = "uathbin";
156
157 /*
158 * Supported rates for 802.11b/g modes (in 500Kbps unit).
159 */
160 static const struct ieee80211_rateset uath_rateset_11b =
161 { 4, { 2, 4, 11, 22 } };
162
163 static const struct ieee80211_rateset uath_rateset_11g =
164 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
165
166 /*
167 * device operations
168 */
169 static int uath_attach(dev_info_t *, ddi_attach_cmd_t);
170 static int uath_detach(dev_info_t *, ddi_detach_cmd_t);
171
172 /*
173 * Module Loading Data & Entry Points
174 */
175 DDI_DEFINE_STREAM_OPS(uath_dev_ops, nulldev, nulldev, uath_attach,
176 uath_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
177
178 static struct modldrv uath_modldrv = {
179 &mod_driverops, /* Type of module. This one is a driver */
180 "Atheros AR5523 USB Driver v1.1", /* short description */
181 &uath_dev_ops /* driver specific ops */
182 };
183
184 static struct modlinkage modlinkage = {
185 MODREV_1,
186 (void *)&uath_modldrv,
187 NULL
188 };
189
190 static int uath_m_stat(void *, uint_t, uint64_t *);
191 static int uath_m_start(void *);
192 static void uath_m_stop(void *);
193 static int uath_m_promisc(void *, boolean_t);
194 static int uath_m_multicst(void *, boolean_t, const uint8_t *);
195 static int uath_m_unicst(void *, const uint8_t *);
196 static mblk_t *uath_m_tx(void *, mblk_t *);
197 static void uath_m_ioctl(void *, queue_t *, mblk_t *);
198 static int uath_m_setprop(void *, const char *, mac_prop_id_t,
199 uint_t, const void *);
200 static int uath_m_getprop(void *, const char *, mac_prop_id_t,
201 uint_t, void *);
202 static void uath_m_propinfo(void *, const char *, mac_prop_id_t,
203 mac_prop_info_handle_t);
204
205 static mac_callbacks_t uath_m_callbacks = {
206 MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
207 uath_m_stat,
208 uath_m_start,
209 uath_m_stop,
210 uath_m_promisc,
211 uath_m_multicst,
212 uath_m_unicst,
213 uath_m_tx,
214 NULL,
215 uath_m_ioctl,
216 NULL,
217 NULL,
218 NULL,
219 uath_m_setprop,
220 uath_m_getprop,
221 uath_m_propinfo
222 };
223
224 static usb_alt_if_data_t *
225 uath_lookup_alt_if(usb_client_dev_data_t *,
226 uint_t, uint_t, uint_t);
227 static usb_ep_data_t *
228 uath_lookup_ep_data(dev_info_t *,
229 usb_client_dev_data_t *, uint_t, uint_t, uint8_t, uint8_t);
230 static const char *
231 uath_codename(int code);
232
233 static uint_t uath_lookup(uint16_t, uint16_t);
234 static void uath_list_all_eps(usb_alt_if_data_t *);
235 static int uath_open_pipes(struct uath_softc *);
236 static void uath_close_pipes(struct uath_softc *);
237 static int uath_fw_send(struct uath_softc *,
238 usb_pipe_handle_t, const void *, size_t);
239 static int uath_fw_ack(struct uath_softc *, int);
240 static int uath_loadsym(ddi_modhandle_t, char *, char **, size_t *);
241 static int uath_loadfirmware(struct uath_softc *);
242 static int uath_alloc_cmd_list(struct uath_softc *,
243 struct uath_cmd *, int, int);
244 static int uath_init_cmd_list(struct uath_softc *);
245 static void uath_free_cmd_list(struct uath_cmd *, int);
246 static int uath_host_available(struct uath_softc *);
247 static void uath_get_capability(struct uath_softc *, uint32_t, uint32_t *);
248 static int uath_get_devcap(struct uath_softc *);
249 static int uath_get_devstatus(struct uath_softc *, uint8_t *);
250 static int uath_get_status(struct uath_softc *, uint32_t, void *, int);
251
252 static void uath_cmd_lock_init(struct uath_cmd_lock *);
253 static void uath_cmd_lock_destroy(struct uath_cmd_lock *);
254 static int uath_cmd_lock_wait(struct uath_cmd_lock *, clock_t);
255 static void uath_cmd_lock_signal(struct uath_cmd_lock *);
256
257 static int uath_cmd_read(struct uath_softc *, uint32_t, const void *,
258 int, void *, int, int);
259 static int uath_cmd_write(struct uath_softc *, uint32_t, const void *,
260 int, int);
261 static int uath_cmdsend(struct uath_softc *, uint32_t,
262 const void *, int, void *, int, int);
263 static int uath_rx_cmd_xfer(struct uath_softc *);
264 static int uath_tx_cmd_xfer(struct uath_softc *,
265 usb_pipe_handle_t, const void *, uint_t);
266 static void uath_cmd_txeof(usb_pipe_handle_t, struct usb_bulk_req *);
267 static void uath_cmd_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
268 static void uath_cmdeof(struct uath_softc *, struct uath_cmd *);
269
270 static void uath_init_data_queue(struct uath_softc *);
271 static int uath_rx_data_xfer(struct uath_softc *sc);
272 static int uath_tx_data_xfer(struct uath_softc *, mblk_t *);
273 static void uath_data_txeof(usb_pipe_handle_t, usb_bulk_req_t *);
274 static void uath_data_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
275
276 static int uath_create_connection(struct uath_softc *, uint32_t);
277 static int uath_set_rates(struct uath_softc *,
278 const struct ieee80211_rateset *);
279 static int uath_write_associd(struct uath_softc *);
280 static int uath_set_ledsteady(struct uath_softc *, int, int);
281 static int uath_set_ledblink(struct uath_softc *, int, int, int, int);
282 static void uath_update_rxstat(struct uath_softc *, uint32_t);
283 static int uath_send(ieee80211com_t *, mblk_t *, uint8_t);
284 static int uath_reconnect(dev_info_t *);
285 static int uath_disconnect(dev_info_t *);
286 static int uath_newstate(struct ieee80211com *, enum ieee80211_state, int);
287
288 static int uath_dataflush(struct uath_softc *);
289 static int uath_cmdflush(struct uath_softc *);
290 static int uath_flush(struct uath_softc *);
291 static int uath_set_ledstate(struct uath_softc *, int);
292 static int uath_set_chan(struct uath_softc *, struct ieee80211_channel *);
293 static int uath_reset_tx_queues(struct uath_softc *);
294 static int uath_wme_init(struct uath_softc *);
295 static int uath_config_multi(struct uath_softc *,
296 uint32_t, const void *, int);
297 static void uath_config(struct uath_softc *, uint32_t, uint32_t);
298 static int uath_switch_channel(struct uath_softc *,
299 struct ieee80211_channel *);
300 static int uath_set_rxfilter(struct uath_softc *, uint32_t, uint32_t);
301 static int uath_init_locked(void *);
302 static void uath_stop_locked(void *);
303 static int uath_init(struct uath_softc *);
304 static void uath_stop(struct uath_softc *);
305 static void uath_resume(struct uath_softc *);
306
307 static void
308 uath_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
309 {
310 va_list args;
311
312 if (dbg_flags & uath_dbg_flags) {
313 va_start(args, fmt);
314 vcmn_err(CE_CONT, fmt, args);
315 va_end(args);
316 }
317 }
318
319 static uint_t
320 uath_lookup(uint16_t vendor_id, uint16_t product_id)
321 {
322 int i, size;
323
324 size = sizeof (uath_devs) / sizeof (struct uath_type);
325
326 for (i = 0; i < size; i++) {
327 if ((vendor_id == uath_devs[i].dev.vendor_id) &&
328 (product_id == uath_devs[i].dev.product_id))
329 return (uath_devs[i].flags);
330 }
331 return (UATH_FLAG_ERR);
332 }
333
334 /*
335 * Return a specific alt_if from the device descriptor tree.
336 */
337 static usb_alt_if_data_t *
338 uath_lookup_alt_if(usb_client_dev_data_t *dev_data, uint_t config,
339 uint_t interface, uint_t alt)
340 {
341 usb_cfg_data_t *cfg_data;
342 usb_if_data_t *if_data;
343 usb_alt_if_data_t *if_alt_data;
344
345 /*
346 * Assume everything is in the tree for now,
347 * (USB_PARSE_LVL_ALL)
348 * so we can directly index the array.
349 */
350
351 /* Descend to configuration, configs are 1-based */
352 if (config < 1 || config > dev_data->dev_n_cfg)
353 return (NULL);
354 cfg_data = &dev_data->dev_cfg[config - 1];
355
356 /* Descend to interface */
357 if (interface > cfg_data->cfg_n_if - 1)
358 return (NULL);
359 if_data = &cfg_data->cfg_if[interface];
360
361 /* Descend to alt */
362 if (alt > if_data->if_n_alt - 1)
363 return (NULL);
364 if_alt_data = &if_data->if_alt[alt];
365
366 return (if_alt_data);
367 }
368
369 /*
370 * Print all endpoints of an alt_if.
371 */
372 static void
373 uath_list_all_eps(usb_alt_if_data_t *ifalt)
374 {
375 usb_ep_data_t *ep_data;
376 usb_ep_descr_t *ep_descr;
377 int i;
378
379 for (i = 0; i < ifalt->altif_n_ep; i++) {
380 ep_data = &ifalt->altif_ep[i];
381 ep_descr = &ep_data->ep_descr;
382 UATH_DEBUG(UATH_DBG_USB,
383 "uath: uath_list_all_endpoint: "
384 "ep addresa[%x] is %x",
385 i, ep_descr->bEndpointAddress);
386 }
387 }
388
389 static usb_ep_data_t *
390 uath_lookup_ep_data(dev_info_t *dip,
391 usb_client_dev_data_t *dev_datap,
392 uint_t interface,
393 uint_t alternate,
394 uint8_t address,
395 uint8_t type)
396 {
397 usb_alt_if_data_t *altif_data;
398 int i;
399
400 if ((dip == NULL) || (dev_datap == NULL))
401 return (NULL);
402
403 altif_data = &dev_datap->dev_curr_cfg->
404 cfg_if[interface].if_alt[alternate];
405
406 for (i = 0; i < altif_data->altif_n_ep; i++) {
407 usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
408 uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
409 uint8_t ept_address = ept->bEndpointAddress;
410
411 if (ept->bLength == 0)
412 continue;
413 if ((ept_type == type) &&
414 ((type == USB_EP_ATTR_CONTROL) || (address == ept_address)))
415 return (&altif_data->altif_ep[i]);
416 }
417 return (NULL);
418 }
419
420 /*
421 * Open communication pipes.
422 * The following pipes are used by the AR5523:
423 * ep0: 0x81 IN Rx cmd
424 * ep1: 0x01 OUT Tx cmd
425 * ep2: 0x82 IN Rx data
426 * ep3: 0x02 OUT Tx data
427 */
428 static int
429 uath_open_pipes(struct uath_softc *sc)
430 {
431 usb_ep_data_t *ep_node;
432 usb_ep_descr_t *ep_descr;
433 usb_pipe_policy_t policy;
434 int err;
435
436 #ifdef DEBUG
437 usb_alt_if_data_t *altif_data;
438
439 altif_data = uath_lookup_alt_if(sc->sc_udev, UATH_CONFIG_NO,
440 UATH_IFACE_INDEX, UATH_ALT_IF_INDEX);
441 if (altif_data == NULL) {
442 UATH_DEBUG(UATH_DBG_ERR, "alt_if not found");
443 return (USB_FAILURE);
444 }
445
446 uath_list_all_eps(altif_data);
447 #endif
448
449 /*
450 * XXX pipes numbers are hardcoded because we don't have any way
451 * to distinguish the data pipes from the firmware command pipes
452 * (both are bulk pipes) using the endpoints descriptors.
453 */
454 ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
455 0, 0, 0x81, USB_EP_ATTR_BULK);
456 ep_descr = &ep_node->ep_descr;
457 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_open_pipes(): "
458 "find pipe %x\n", ep_descr->bEndpointAddress);
459
460 bzero(&policy, sizeof (usb_pipe_policy_t));
461 policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
462
463 err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
464 &policy, USB_FLAGS_SLEEP, &sc->rx_cmd_pipe);
465 if (err != USB_SUCCESS) {
466 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
467 "failed to open rx data pipe, err = %x\n",
468 err);
469 goto fail;
470 }
471
472
473 ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
474 0, 0, 0x01, USB_EP_ATTR_BULK);
475 ep_descr = &ep_node->ep_descr;
476 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
477 "find pipe %x\n",
478 ep_descr->bEndpointAddress);
479
480 bzero(&policy, sizeof (usb_pipe_policy_t));
481 policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
482
483 err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
484 &policy, USB_FLAGS_SLEEP, &sc->tx_cmd_pipe);
485 if (err != USB_SUCCESS) {
486 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
487 "failed to open tx command pipe, err = %x\n",
488 err);
489 goto fail;
490 }
491
492 ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
493 0, 0, 0x82, USB_EP_ATTR_BULK);
494 ep_descr = &ep_node->ep_descr;
495 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
496 "find pipe %x\n",
497 ep_descr->bEndpointAddress);
498
499 bzero(&policy, sizeof (usb_pipe_policy_t));
500 policy.pp_max_async_reqs = UATH_RX_DATA_LIST_COUNT;
501
502 err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
503 &policy, USB_FLAGS_SLEEP, &sc->rx_data_pipe);
504 if (err != USB_SUCCESS) {
505 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
506 "failed to open tx pipe, err = %x\n",
507 err);
508 goto fail;
509 }
510
511 ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
512 0, 0, 0x02, USB_EP_ATTR_BULK);
513 ep_descr = &ep_node->ep_descr;
514 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
515 "find pipe %x\n",
516 ep_descr->bEndpointAddress);
517
518 bzero(&policy, sizeof (usb_pipe_policy_t));
519 policy.pp_max_async_reqs = UATH_TX_DATA_LIST_COUNT;
520
521 err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
522 &policy, USB_FLAGS_SLEEP, &sc->tx_data_pipe);
523 if (err != USB_SUCCESS) {
524 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
525 "failed to open rx command pipe, err = %x\n",
526 err);
527 goto fail;
528 }
529
530 return (UATH_SUCCESS);
531 fail:
532 uath_close_pipes(sc);
533 return (err);
534 }
535
536 static void
537 uath_close_pipes(struct uath_softc *sc)
538 {
539 usb_flags_t flags = USB_FLAGS_SLEEP;
540
541 if (sc->rx_cmd_pipe != NULL) {
542 usb_pipe_reset(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
543 usb_pipe_close(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
544 sc->rx_cmd_pipe = NULL;
545 }
546
547 if (sc->tx_cmd_pipe != NULL) {
548 usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
549 usb_pipe_close(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
550 sc->tx_cmd_pipe = NULL;
551 }
552
553 if (sc->rx_data_pipe != NULL) {
554 usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
555 usb_pipe_close(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
556 sc->rx_data_pipe = NULL;
557 }
558
559 if (sc->tx_data_pipe != NULL) {
560 usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
561 usb_pipe_close(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
562 sc->tx_data_pipe = NULL;
563 }
564
565 }
566
567 static const char *
568 uath_codename(int code)
569 {
570 #define N(a) (sizeof (a)/sizeof (a[0]))
571 static const char *names[] = {
572 "0x00",
573 "HOST_AVAILABLE",
574 "BIND",
575 "TARGET_RESET",
576 "TARGET_GET_CAPABILITY",
577 "TARGET_SET_CONFIG",
578 "TARGET_GET_STATUS",
579 "TARGET_GET_STATS",
580 "TARGET_START",
581 "TARGET_STOP",
582 "TARGET_ENABLE",
583 "TARGET_DISABLE",
584 "CREATE_CONNECTION",
585 "UPDATE_CONNECT_ATTR",
586 "DELETE_CONNECT",
587 "SEND",
588 "FLUSH",
589 "STATS_UPDATE",
590 "BMISS",
591 "DEVICE_AVAIL",
592 "SEND_COMPLETE",
593 "DATA_AVAIL",
594 "SET_PWR_MODE",
595 "BMISS_ACK",
596 "SET_LED_STEADY",
597 "SET_LED_BLINK",
598 "SETUP_BEACON_DESC",
599 "BEACON_INIT",
600 "RESET_KEY_CACHE",
601 "RESET_KEY_CACHE_ENTRY",
602 "SET_KEY_CACHE_ENTRY",
603 "SET_DECOMP_MASK",
604 "SET_REGULATORY_DOMAIN",
605 "SET_LED_STATE",
606 "WRITE_ASSOCID",
607 "SET_STA_BEACON_TIMERS",
608 "GET_TSF",
609 "RESET_TSF",
610 "SET_ADHOC_MODE",
611 "SET_BASIC_RATE",
612 "MIB_CONTROL",
613 "GET_CHANNEL_DATA",
614 "GET_CUR_RSSI",
615 "SET_ANTENNA_SWITCH",
616 "0x2c", "0x2d", "0x2e",
617 "USE_SHORT_SLOT_TIME",
618 "SET_POWER_MODE",
619 "SETUP_PSPOLL_DESC",
620 "SET_RX_MULTICAST_FILTER",
621 "RX_FILTER",
622 "PER_CALIBRATION",
623 "RESET",
624 "DISABLE",
625 "PHY_DISABLE",
626 "SET_TX_POWER_LIMIT",
627 "SET_TX_QUEUE_PARAMS",
628 "SETUP_TX_QUEUE",
629 "RELEASE_TX_QUEUE",
630 };
631 static char buf[8];
632
633 if (code < N(names))
634 return (names[code]);
635 if (code == WDCMSG_SET_DEFAULT_KEY)
636 return ("SET_DEFAULT_KEY");
637
638 (void) snprintf(buf, sizeof (buf), "0x%02x", code);
639 return (buf);
640 #undef N
641 }
642
643 static int
644 uath_fw_send(struct uath_softc *sc, usb_pipe_handle_t pipe,
645 const void *data, size_t len)
646 {
647 usb_bulk_req_t *send_req;
648 mblk_t *mblk;
649 int res;
650
651 send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
652
653 send_req->bulk_len = (int)len;
654 send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
655 send_req->bulk_timeout = UATH_CMD_TIMEOUT;
656
657 mblk = send_req->bulk_data;
658 bcopy(data, mblk->b_wptr, len);
659 mblk->b_wptr += len;
660
661 res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_SLEEP);
662 if (res != USB_SUCCESS) {
663 UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_send(): "
664 "Error %x writing data to bulk/out pipe", res);
665 return (UATH_FAILURE);
666 }
667
668 usb_free_bulk_req(send_req);
669 return (UATH_SUCCESS);
670 }
671
672 static int
673 uath_fw_ack(struct uath_softc *sc, int len)
674 {
675 struct uath_fwblock *rxblock;
676 usb_bulk_req_t *req;
677 mblk_t *mp;
678 int err;
679
680 req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
681 if (req == NULL) {
682 UATH_DEBUG(UATH_DBG_FW,
683 "uath: uath_fw_ack(): "
684 "uath_rx_transfer(): failed to allocate req");
685 return (UATH_FAILURE);
686 }
687
688 req->bulk_len = len;
689 req->bulk_client_private = (usb_opaque_t)sc;
690 req->bulk_timeout = 0;
691 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK
692 | USB_ATTRS_AUTOCLEARING;
693
694 err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_SLEEP);
695 if (err != USB_SUCCESS) {
696 UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack(): "
697 "failed to do rx xfer, %d", err);
698 usb_free_bulk_req(req);
699 return (UATH_FAILURE);
700 }
701
702 mp = req->bulk_data;
703 req->bulk_data = NULL;
704
705 rxblock = (struct uath_fwblock *)mp->b_rptr;
706 UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack() "
707 "rxblock flags=0x%x total=%d\n",
708 BE_32(rxblock->flags), BE_32(rxblock->rxtotal));
709
710 freemsg(mp);
711 usb_free_bulk_req(req);
712
713 return (UATH_SUCCESS);
714 }
715
716 /*
717 * find uath firmware module's "_start" "_end" symbols
718 * and get its size.
719 */
720 static int
721 uath_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
722 {
723 char start_sym[64];
724 char end_sym[64];
725 char *p, *end;
726 int rv;
727 size_t n;
728
729 (void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
730 (void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
731
732 p = (char *)ddi_modsym(modp, start_sym, &rv);
733 if (p == NULL || rv != 0) {
734 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
735 "mod %s: symbol %s not found\n", uath_fwmod, start_sym);
736 return (UATH_FAILURE);
737 }
738
739 end = (char *)ddi_modsym(modp, end_sym, &rv);
740 if (end == NULL || rv != 0) {
741 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
742 "mod %s: symbol %s not found\n", uath_fwmod, end_sym);
743 return (UATH_FAILURE);
744 }
745
746 n = _PTRDIFF(end, p);
747 *start = p;
748 *len = n;
749
750 return (UATH_SUCCESS);
751 }
752
753 /*
754 * Load the MIPS R4000 microcode into the device. Once the image is loaded,
755 * the device will detach itself from the bus and reattach later with a new
756 * product Id (a la ezusb). XXX this could also be implemented in userland
757 * through /dev/ugen.
758 */
759 static int
760 uath_loadfirmware(struct uath_softc *sc)
761 {
762 struct uath_fwblock txblock;
763 ddi_modhandle_t modp;
764 char *fw_index, *fw_image = NULL;
765 size_t fw_size, len;
766 int err = DDI_SUCCESS, rv = 0;
767
768 modp = ddi_modopen(uath_fwmod, KRTLD_MODE_FIRST, &rv);
769 if (modp == NULL) {
770 cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
771 "module %s not found\n", uath_fwmod);
772 goto label;
773 }
774
775 err = uath_loadsym(modp, uath_binmod, &fw_index, &fw_size);
776 if (err != UATH_SUCCESS) {
777 cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
778 "could not get firmware\n");
779 goto label;
780 }
781
782 fw_image = (char *)kmem_alloc(fw_size, KM_SLEEP);
783 if (fw_image == NULL) {
784 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_loadfirmware(): "
785 "failed to alloc firmware memory\n");
786 err = UATH_FAILURE;
787 goto label;
788 }
789
790 (void) memcpy(fw_image, fw_index, fw_size);
791 fw_index = fw_image;
792 len = fw_size;
793 UATH_DEBUG(UATH_DBG_MSG, "loading firmware size = %lu\n", fw_size);
794
795 /* bzero(txblock, sizeof (struct uath_fwblock)); */
796 txblock.flags = BE_32(UATH_WRITE_BLOCK);
797 txblock.total = BE_32(fw_size);
798
799 while (len > 0) {
800 size_t mlen = min(len, UATH_MAX_FWBLOCK_SIZE);
801
802 txblock.remain = BE_32(len - mlen);
803 txblock.len = BE_32(mlen);
804
805 UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
806 "sending firmware block: %d bytes sending\n", mlen);
807 UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
808 "sending firmware block: %d bytes remaining\n",
809 len - mlen);
810
811 /* send firmware block meta-data */
812 err = uath_fw_send(sc, sc->tx_cmd_pipe, &txblock,
813 sizeof (struct uath_fwblock));
814 if (err != UATH_SUCCESS) {
815 UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
816 "send block meta-data error");
817 goto label;
818 }
819
820 /* send firmware block data */
821 err = uath_fw_send(sc, sc->tx_data_pipe, fw_index, mlen);
822 if (err != UATH_SUCCESS) {
823 UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
824 "send block data err");
825 goto label;
826 }
827
828 /* wait for ack from firmware */
829 err = uath_fw_ack(sc, sizeof (struct uath_fwblock));
830 if (err != UATH_SUCCESS) {
831 UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
832 "rx block ack err");
833 goto label;
834 }
835
836 fw_index += mlen;
837 len -= mlen;
838 }
839
840 label:
841 if (fw_image != NULL)
842 kmem_free(fw_image, fw_size);
843 fw_image = fw_index = NULL;
844 if (modp != NULL)
845 (void) ddi_modclose(modp);
846 return (err);
847 }
848
849 static int
850 uath_alloc_cmd_list(struct uath_softc *sc, struct uath_cmd cmds[],
851 int ncmd, int maxsz)
852 {
853 int i, err;
854
855 for (i = 0; i < ncmd; i++) {
856 struct uath_cmd *cmd = &cmds[i];
857
858 cmd->sc = sc; /* backpointer for callbacks */
859 cmd->msgid = i;
860 cmd->buf = kmem_zalloc(maxsz, KM_NOSLEEP);
861 if (cmd->buf == NULL) {
862 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_alloc_cmd_list(): "
863 "could not allocate xfer buffer\n");
864 err = DDI_ENOMEM;
865 goto fail;
866 }
867 }
868 return (UATH_SUCCESS);
869
870 fail:
871 uath_free_cmd_list(cmds, ncmd);
872 return (err);
873 }
874
875 static int
876 uath_init_cmd_list(struct uath_softc *sc)
877 {
878 int i;
879
880 sc->sc_cmdid = sc->rx_cmd_queued = sc->tx_cmd_queued = 0;
881 for (i = 0; i < UATH_CMD_LIST_COUNT; i++) {
882 if (uath_rx_cmd_xfer(sc) != UATH_SUCCESS) {
883 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_cmd_list(): "
884 "failed to init cmd list %x\n", i);
885 return (UATH_FAILURE);
886 }
887 }
888 return (UATH_SUCCESS);
889 }
890
891 static void
892 uath_free_cmd_list(struct uath_cmd cmds[], int ncmd)
893 {
894 int i;
895
896 for (i = 0; i < ncmd; i++)
897 if (cmds[i].buf != NULL) {
898 kmem_free(cmds[i].buf, UATH_MAX_CMDSZ);
899 cmds[i].buf = NULL;
900 }
901 }
902
903 static int
904 uath_host_available(struct uath_softc *sc)
905 {
906 struct uath_cmd_host_available setup;
907
908 /* inform target the host is available */
909 setup.sw_ver_major = BE_32(ATH_SW_VER_MAJOR);
910 setup.sw_ver_minor = BE_32(ATH_SW_VER_MINOR);
911 setup.sw_ver_patch = BE_32(ATH_SW_VER_PATCH);
912 setup.sw_ver_build = BE_32(ATH_SW_VER_BUILD);
913 return (uath_cmd_read(sc, WDCMSG_HOST_AVAILABLE,
914 &setup, sizeof (setup), NULL, 0, 0));
915 }
916
917 static void
918 uath_get_capability(struct uath_softc *sc, uint32_t cap, uint32_t *val)
919 {
920 int err;
921
922 cap = BE_32(cap);
923 err = uath_cmd_read(sc, WDCMSG_TARGET_GET_CAPABILITY, &cap,
924 sizeof (cap), val, sizeof (uint32_t), UATH_CMD_FLAG_MAGIC);
925 if (err == UATH_SUCCESS)
926 *val = BE_32(*val);
927 else
928 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_capability(): "
929 "could not read capability %u\n", BE_32(cap));
930 }
931
932 static int
933 uath_get_devcap(struct uath_softc *sc)
934 {
935 struct uath_devcap *cap = &sc->sc_devcap;
936
937 /* collect device capabilities */
938 uath_get_capability(sc, CAP_TARGET_VERSION,
939 &cap->targetVersion);
940 uath_get_capability(sc, CAP_TARGET_REVISION,
941 &cap->targetRevision);
942 uath_get_capability(sc, CAP_MAC_VERSION,
943 &cap->macVersion);
944 uath_get_capability(sc, CAP_MAC_REVISION,
945 &cap->macRevision);
946 uath_get_capability(sc, CAP_PHY_REVISION,
947 &cap->phyRevision);
948 uath_get_capability(sc, CAP_ANALOG_5GHz_REVISION,
949 &cap->analog5GhzRevision);
950 uath_get_capability(sc, CAP_ANALOG_2GHz_REVISION,
951 &cap->analog2GhzRevision);
952 uath_get_capability(sc, CAP_REG_DOMAIN,
953 &cap->regDomain);
954 uath_get_capability(sc, CAP_REG_CAP_BITS,
955 &cap->regCapBits);
956
957 /* NB: not supported in rev 1.5 */
958 /* uath_get_capability(sc, CAP_COUNTRY_CODE, cap->countryCode); */
959
960 uath_get_capability(sc, CAP_WIRELESS_MODES,
961 &cap->wirelessModes);
962 uath_get_capability(sc, CAP_CHAN_SPREAD_SUPPORT,
963 &cap->chanSpreadSupport);
964 uath_get_capability(sc, CAP_COMPRESS_SUPPORT,
965 &cap->compressSupport);
966 uath_get_capability(sc, CAP_BURST_SUPPORT,
967 &cap->burstSupport);
968 uath_get_capability(sc, CAP_FAST_FRAMES_SUPPORT,
969 &cap->fastFramesSupport);
970 uath_get_capability(sc, CAP_CHAP_TUNING_SUPPORT,
971 &cap->chapTuningSupport);
972 uath_get_capability(sc, CAP_TURBOG_SUPPORT,
973 &cap->turboGSupport);
974 uath_get_capability(sc, CAP_TURBO_PRIME_SUPPORT,
975 &cap->turboPrimeSupport);
976 uath_get_capability(sc, CAP_DEVICE_TYPE,
977 &cap->deviceType);
978 uath_get_capability(sc, CAP_WME_SUPPORT,
979 &cap->wmeSupport);
980 uath_get_capability(sc, CAP_TOTAL_QUEUES,
981 &cap->numTxQueues);
982 uath_get_capability(sc, CAP_CONNECTION_ID_MAX,
983 &cap->connectionIdMax);
984
985 uath_get_capability(sc, CAP_LOW_5GHZ_CHAN,
986 &cap->low5GhzChan);
987 uath_get_capability(sc, CAP_HIGH_5GHZ_CHAN,
988 &cap->high5GhzChan);
989 uath_get_capability(sc, CAP_LOW_2GHZ_CHAN,
990 &cap->low2GhzChan);
991 uath_get_capability(sc, CAP_HIGH_2GHZ_CHAN,
992 &cap->high2GhzChan);
993 uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_5G,
994 &cap->twiceAntennaGain5G);
995 uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_2G,
996 &cap->twiceAntennaGain2G);
997
998 uath_get_capability(sc, CAP_CIPHER_AES_CCM,
999 &cap->supportCipherAES_CCM);
1000 uath_get_capability(sc, CAP_CIPHER_TKIP,
1001 &cap->supportCipherTKIP);
1002 uath_get_capability(sc, CAP_MIC_TKIP,
1003 &cap->supportMicTKIP);
1004
1005 cap->supportCipherWEP = 1; /* NB: always available */
1006 return (UATH_SUCCESS);
1007 }
1008
1009 static int
1010 uath_get_status(struct uath_softc *sc, uint32_t which, void *odata, int olen)
1011 {
1012 int err;
1013
1014 which = BE_32(which);
1015 err = uath_cmd_read(sc, WDCMSG_TARGET_GET_STATUS,
1016 &which, sizeof (which), odata, olen, UATH_CMD_FLAG_MAGIC);
1017 if (err != UATH_SUCCESS)
1018 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_status(): "
1019 "could not read EEPROM offset 0x%02x\n", BE_32(which));
1020 return (err);
1021 }
1022
1023 static int
1024 uath_get_devstatus(struct uath_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN])
1025 {
1026 int err;
1027
1028 /* retrieve MAC address */
1029 err = uath_get_status(sc, ST_MAC_ADDR, macaddr, IEEE80211_ADDR_LEN);
1030 if (err != UATH_SUCCESS) {
1031 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
1032 "could not read MAC address\n");
1033 return (err);
1034 }
1035
1036 err = uath_get_status(sc, ST_SERIAL_NUMBER,
1037 &sc->sc_serial[0], sizeof (sc->sc_serial));
1038 if (err != UATH_SUCCESS) {
1039 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
1040 "could not read device serial number\n");
1041 return (err);
1042 }
1043
1044 return (UATH_SUCCESS);
1045 }
1046
1047 /*
1048 * uath_cmd_lock: a special signal structure that is used for notification
1049 * that a callback function has been called.
1050 */
1051
1052 /* Initializes the uath_cmd_lock structure. */
1053 static void
1054 uath_cmd_lock_init(struct uath_cmd_lock *lock)
1055 {
1056 ASSERT(lock != NULL);
1057 mutex_init(&lock->mutex, NULL, MUTEX_DRIVER, NULL);
1058 cv_init(&lock->cv, NULL, CV_DRIVER, NULL);
1059 lock->done = B_FALSE;
1060 }
1061
1062 /* Deinitalizes the uath_cb_lock structure. */
1063 void
1064 uath_cmd_lock_destroy(struct uath_cmd_lock *lock)
1065 {
1066 ASSERT(lock != NULL);
1067 mutex_destroy(&lock->mutex);
1068 cv_destroy(&lock->cv);
1069 }
1070
1071 /*
1072 * Wait on lock until someone calls the "signal" function or the timeout
1073 * expires. Note: timeout is in microseconds.
1074 */
1075 static int
1076 uath_cmd_lock_wait(struct uath_cmd_lock *lock, clock_t timeout)
1077 {
1078 int res, cv_res;
1079 clock_t etime;
1080
1081 ASSERT(lock != NULL);
1082 mutex_enter(&lock->mutex);
1083
1084 if (timeout < 0) {
1085 /* no timeout - wait as long as needed */
1086 while (lock->done == B_FALSE)
1087 cv_wait(&lock->cv, &lock->mutex);
1088 } else {
1089 /* wait with timeout (given in usec) */
1090 etime = ddi_get_lbolt() + drv_usectohz(timeout);
1091 while (lock->done == B_FALSE) {
1092 cv_res = cv_timedwait_sig(&lock->cv,
1093 &lock->mutex, etime);
1094 if (cv_res <= 0) break;
1095 }
1096 }
1097
1098 res = (lock->done == B_TRUE) ? UATH_SUCCESS : UATH_FAILURE;
1099 mutex_exit(&lock->mutex);
1100
1101 return (res);
1102 }
1103
1104 /* Signal that the job (eg. callback) is done and unblock anyone who waits. */
1105 static void
1106 uath_cmd_lock_signal(struct uath_cmd_lock *lock)
1107 {
1108 ASSERT(lock != NULL);
1109
1110 mutex_enter(&lock->mutex);
1111 lock->done = B_TRUE;
1112 cv_broadcast(&lock->cv);
1113 mutex_exit(&lock->mutex);
1114 }
1115
1116 static int
1117 uath_cmd_read(struct uath_softc *sc, uint32_t code, const void *idata,
1118 int ilen, void *odata, int olen, int flags)
1119 {
1120 flags |= UATH_CMD_FLAG_READ;
1121 return (uath_cmdsend(sc, code, idata, ilen, odata, olen, flags));
1122 }
1123
1124 static int
1125 uath_cmd_write(struct uath_softc *sc, uint32_t code, const void *data,
1126 int len, int flags)
1127 {
1128 flags &= ~UATH_CMD_FLAG_READ;
1129 return (uath_cmdsend(sc, code, data, len, NULL, 0, flags));
1130 }
1131
1132 /*
1133 * Low-level function to send read or write commands to the firmware.
1134 */
1135 static int
1136 uath_cmdsend(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
1137 void *odata, int olen, int flags)
1138 {
1139 struct uath_cmd_hdr *hdr;
1140 struct uath_cmd *cmd;
1141 int err;
1142
1143 /* grab a xfer */
1144 cmd = &sc->sc_cmd[sc->sc_cmdid];
1145
1146 cmd->flags = flags;
1147 /* always bulk-out a multiple of 4 bytes */
1148 cmd->buflen = (sizeof (struct uath_cmd_hdr) + ilen + 3) & ~3;
1149
1150 hdr = (struct uath_cmd_hdr *)cmd->buf;
1151 bzero(hdr, sizeof (struct uath_cmd_hdr));
1152 hdr->len = BE_32(cmd->buflen);
1153 hdr->code = BE_32(code);
1154 hdr->msgid = cmd->msgid; /* don't care about endianness */
1155 hdr->magic = BE_32((cmd->flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0);
1156 bcopy(idata, (uint8_t *)(hdr + 1), ilen);
1157
1158 UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1159 "queue %x send %s [flags 0x%x] olen %d\n",
1160 cmd->msgid, uath_codename(code), cmd->flags, olen);
1161
1162 cmd->odata = odata;
1163 if (odata == NULL)
1164 UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1165 "warning - odata is NULL\n");
1166 else if (olen < UATH_MAX_CMDSZ - sizeof (*hdr) + sizeof (uint32_t))
1167 UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1168 "warning - olen %x is short\n, olen");
1169 cmd->olen = olen;
1170
1171 err = uath_tx_cmd_xfer(sc, sc->tx_cmd_pipe, cmd->buf, cmd->buflen);
1172 if (err != UATH_SUCCESS) {
1173 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1174 "Error writing command\n");
1175 return (UATH_FAILURE);
1176 }
1177
1178 sc->sc_cmdid = (sc->sc_cmdid + 1) % UATH_CMD_LIST_COUNT;
1179
1180 if (cmd->flags & UATH_CMD_FLAG_READ) {
1181 /* wait at most two seconds for command reply */
1182 uath_cmd_lock_init(&sc->rlock);
1183 err = uath_cmd_lock_wait(&sc->rlock, 2000000);
1184 cmd->odata = NULL; /* in case reply comes too late */
1185 if (err != UATH_SUCCESS) {
1186 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1187 "timeout waiting for reply, "
1188 "to cmd 0x%x (%u), queue %x\n",
1189 code, code, cmd->msgid);
1190 err = UATH_FAILURE;
1191 } else if (cmd->olen != olen) {
1192 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1193 "unexpected reply data count "
1194 "to cmd 0x%x (%x), got %u, expected %u\n",
1195 code, cmd->msgid, cmd->olen, olen);
1196 err = UATH_FAILURE;
1197 }
1198 uath_cmd_lock_destroy(&sc->rlock);
1199 return (err);
1200 }
1201
1202 return (UATH_SUCCESS);
1203 }
1204
1205 /* ARGSUSED */
1206 static void
1207 uath_cmd_txeof(usb_pipe_handle_t pipe, struct usb_bulk_req *req)
1208 {
1209 struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1210
1211 UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmd_txeof(): "
1212 "cr:%s(%d), flags:0x%x, tx queued %d\n",
1213 usb_str_cr(req->bulk_completion_reason),
1214 req->bulk_completion_reason,
1215 req->bulk_cb_flags,
1216 sc->tx_cmd_queued);
1217
1218 if (req->bulk_completion_reason != USB_CR_OK)
1219 sc->sc_tx_err++;
1220
1221 mutex_enter(&sc->sc_txlock_cmd);
1222 sc->tx_cmd_queued--;
1223 mutex_exit(&sc->sc_txlock_cmd);
1224 usb_free_bulk_req(req);
1225 }
1226
1227 static int
1228 uath_tx_cmd_xfer(struct uath_softc *sc,
1229 usb_pipe_handle_t pipe, const void *data, uint_t len)
1230 {
1231 usb_bulk_req_t *send_req;
1232 mblk_t *mblk;
1233 int res;
1234
1235 send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
1236
1237 send_req->bulk_client_private = (usb_opaque_t)sc;
1238 send_req->bulk_len = (int)len;
1239 send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1240 send_req->bulk_timeout = UATH_CMD_TIMEOUT;
1241 send_req->bulk_cb = uath_cmd_txeof;
1242 send_req->bulk_exc_cb = uath_cmd_txeof;
1243 send_req->bulk_completion_reason = 0;
1244 send_req->bulk_cb_flags = 0;
1245
1246 mblk = send_req->bulk_data;
1247 bcopy(data, mblk->b_rptr, len);
1248 mblk->b_wptr += len;
1249
1250 res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_NOSLEEP);
1251 if (res != UATH_SUCCESS) {
1252 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_tx_cmd_xfer(): "
1253 "Error %x writing cmd to bulk/out pipe", res);
1254 return (UATH_FAILURE);
1255 }
1256
1257 mutex_enter(&sc->sc_txlock_cmd);
1258 sc->tx_cmd_queued++;
1259 mutex_exit(&sc->sc_txlock_cmd);
1260 return (UATH_SUCCESS);
1261 }
1262
1263 static void
1264 uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd)
1265 {
1266 struct uath_cmd_hdr *hdr;
1267 int dlen;
1268
1269 hdr = (struct uath_cmd_hdr *)cmd->buf;
1270
1271 hdr->code = BE_32(hdr->code);
1272 hdr->len = BE_32(hdr->len);
1273 hdr->magic = BE_32(hdr->magic); /* target status on return */
1274
1275 /* NB: msgid is passed thru w/o byte swapping */
1276 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1277 "%s: [ix %x] len=%x status %x\n",
1278 uath_codename(hdr->code),
1279 hdr->msgid,
1280 hdr->len,
1281 hdr->magic);
1282
1283 switch (hdr->code & 0xff) {
1284 /* reply to a read command */
1285 default:
1286 dlen = hdr->len - sizeof (*hdr);
1287 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1288 "code %x data len %u\n",
1289 hdr->code & 0xff, dlen);
1290
1291 /*
1292 * The first response from the target after the
1293 * HOST_AVAILABLE has an invalid msgid so we must
1294 * treat it specially.
1295 */
1296 if ((hdr->msgid < UATH_CMD_LIST_COUNT) && (hdr->code != 0x13)) {
1297 uint32_t *rp = (uint32_t *)(hdr + 1);
1298 uint_t olen;
1299
1300 if (!(sizeof (*hdr) <= hdr->len &&
1301 hdr->len < UATH_MAX_CMDSZ)) {
1302 UATH_DEBUG(UATH_DBG_RX_CMD,
1303 "uath: uath_cmdeof(): "
1304 "invalid WDC msg length %u; "
1305 "msg ignored\n",
1306 hdr->len);
1307 return;
1308 }
1309
1310 /*
1311 * Calculate return/receive payload size; the
1312 * first word, if present, always gives the
1313 * number of bytes--unless it's 0 in which
1314 * case a single 32-bit word should be present.
1315 */
1316 if (dlen >= sizeof (uint32_t)) {
1317 olen = BE_32(rp[0]);
1318 dlen -= sizeof (uint32_t);
1319 if (olen == 0) {
1320 /* convention is 0 =>'s one word */
1321 olen = sizeof (uint32_t);
1322 /* XXX KASSERT(olen == dlen ) */
1323 }
1324 } else
1325 olen = 0;
1326
1327 if (cmd->odata != NULL) {
1328 /* NB: cmd->olen validated in uath_cmd */
1329 if (olen > cmd->olen) {
1330 /* XXX complain? */
1331 UATH_DEBUG(UATH_DBG_RX_CMD,
1332 "uath: uath_cmdeof(): "
1333 "cmd 0x%x olen %u cmd olen %u\n",
1334 hdr->code, olen, cmd->olen);
1335 olen = cmd->olen;
1336 }
1337 if (olen > dlen) {
1338 /* XXX complain, shouldn't happen */
1339 UATH_DEBUG(UATH_DBG_RX_CMD,
1340 "uath: uath_cmdeof(): "
1341 "cmd 0x%x olen %u dlen %u\n",
1342 hdr->code, olen, dlen);
1343 olen = dlen;
1344 }
1345 /* XXX have submitter do this */
1346 /* copy answer into caller's supplied buffer */
1347 bcopy(&rp[1], cmd->odata, olen);
1348 cmd->olen = olen;
1349 }
1350 }
1351
1352 /* Just signal that something happened */
1353 uath_cmd_lock_signal(&sc->rlock);
1354 break;
1355
1356 case WDCMSG_TARGET_START:
1357 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1358 "receive TARGET STAERT\n");
1359
1360 if (hdr->msgid >= UATH_CMD_LIST_COUNT) {
1361 /* XXX */
1362 return;
1363 }
1364 dlen = hdr->len - sizeof (*hdr);
1365 if (dlen != sizeof (uint32_t)) {
1366 /* XXX something wrong */
1367 return;
1368 }
1369 /* XXX have submitter do this */
1370 /* copy answer into caller's supplied buffer */
1371 bcopy(hdr + 1, cmd->odata, sizeof (uint32_t));
1372 cmd->olen = sizeof (uint32_t);
1373
1374 /* wake up caller */
1375 uath_cmd_lock_signal(&sc->rlock);
1376 break;
1377
1378 case WDCMSG_SEND_COMPLETE:
1379 /* this notification is sent when UATH_TX_NOTIFY is set */
1380 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1381 "receive Tx notification\n");
1382 break;
1383
1384 case WDCMSG_TARGET_GET_STATS:
1385 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1386 "received device statistics\n");
1387 break;
1388 }
1389 }
1390
1391 /* ARGSUSED */
1392 static void
1393 uath_cmd_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1394 {
1395 struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1396 struct uath_cmd_hdr *hdr;
1397 struct uath_cmd *cmd;
1398 mblk_t *m, *mp;
1399 int len;
1400
1401 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
1402 "cr:%s(%d), flags:0x%x, rx queued %d\n",
1403 usb_str_cr(req->bulk_completion_reason),
1404 req->bulk_completion_reason,
1405 req->bulk_cb_flags,
1406 sc->rx_cmd_queued);
1407
1408 m = req->bulk_data;
1409 req->bulk_data = NULL;
1410
1411 if (req->bulk_completion_reason != USB_CR_OK) {
1412 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
1413 "USB CR is not OK\n");
1414 goto fail;
1415 }
1416
1417 if (m->b_cont != NULL) {
1418 /* Fragmented message, concatenate */
1419 mp = msgpullup(m, -1);
1420 freemsg(m);
1421 m = mp;
1422 mp = NULL;
1423 }
1424
1425 len = msgdsize(m);
1426 if (len < sizeof (struct uath_cmd_hdr)) {
1427 UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_rx_cmdeof(): "
1428 "short xfer error\n");
1429 goto fail;
1430 }
1431
1432 hdr = (struct uath_cmd_hdr *)m->b_rptr;
1433 if (BE_32(hdr->code) == 0x13)
1434 cmd = &sc->sc_cmd[0];
1435 else
1436 cmd = &sc->sc_cmd[hdr->msgid];
1437
1438 bcopy(m->b_rptr, cmd->buf, len);
1439 uath_cmdeof(sc, cmd);
1440 (void) uath_rx_cmd_xfer(sc);
1441 fail:
1442 mutex_enter(&sc->sc_rxlock_cmd);
1443 sc->rx_cmd_queued--;
1444 mutex_exit(&sc->sc_rxlock_cmd);
1445 if (m) freemsg(m);
1446 usb_free_bulk_req(req);
1447 }
1448
1449 static int
1450 uath_rx_cmd_xfer(struct uath_softc *sc)
1451 {
1452 usb_bulk_req_t *req;
1453 int err;
1454
1455 req = usb_alloc_bulk_req(sc->sc_dev, UATH_MAX_CMDSZ, USB_FLAGS_SLEEP);
1456 if (req == NULL) {
1457 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
1458 "failed to allocate req");
1459 return (UATH_FAILURE);
1460 }
1461
1462 req->bulk_len = UATH_MAX_CMDSZ;
1463 req->bulk_client_private = (usb_opaque_t)sc;
1464 req->bulk_cb = uath_cmd_rxeof;
1465 req->bulk_exc_cb = uath_cmd_rxeof;
1466 req->bulk_timeout = 0;
1467 req->bulk_completion_reason = 0;
1468 req->bulk_cb_flags = 0;
1469 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK
1470 | USB_ATTRS_AUTOCLEARING;
1471
1472 err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_NOSLEEP);
1473 if (err != USB_SUCCESS) {
1474 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
1475 "failed to do rx xfer, %d", err);
1476 usb_free_bulk_req(req);
1477 return (UATH_FAILURE);
1478 }
1479
1480 mutex_enter(&sc->sc_rxlock_cmd);
1481 sc->rx_cmd_queued++;
1482 mutex_exit(&sc->sc_rxlock_cmd);
1483 return (UATH_SUCCESS);
1484 }
1485
1486 static void
1487 uath_init_data_queue(struct uath_softc *sc)
1488 {
1489 sc->tx_data_queued = sc->rx_data_queued = 0;
1490 }
1491
1492 /* ARGSUSED */
1493 static void
1494 uath_data_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1495 {
1496 struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1497 struct ieee80211com *ic = &sc->sc_ic;
1498
1499 UATH_DEBUG(UATH_DBG_TX, "uath: uath_data_txeof(): "
1500 "uath_txeof(): cr:%s(%d), flags:0x%x, tx_data_queued %d\n",
1501 usb_str_cr(req->bulk_completion_reason),
1502 req->bulk_completion_reason,
1503 req->bulk_cb_flags,
1504 sc->tx_data_queued);
1505
1506 if (req->bulk_completion_reason != USB_CR_OK)
1507 sc->sc_tx_err++;
1508
1509 mutex_enter(&sc->sc_txlock_data);
1510 sc->tx_data_queued--;
1511
1512 if (sc->sc_need_sched) {
1513 sc->sc_need_sched = 0;
1514 mac_tx_update(ic->ic_mach);
1515 }
1516
1517 mutex_exit(&sc->sc_txlock_data);
1518 usb_free_bulk_req(req);
1519 }
1520
1521 static int
1522 uath_tx_data_xfer(struct uath_softc *sc, mblk_t *mp)
1523 {
1524 usb_bulk_req_t *req;
1525 int err;
1526
1527 req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
1528 if (req == NULL) {
1529 UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
1530 "uath_tx_data_xfer(): failed to allocate req");
1531 freemsg(mp);
1532 return (UATH_FAILURE);
1533 }
1534
1535 req->bulk_len = msgdsize(mp);
1536 req->bulk_data = mp;
1537 req->bulk_client_private = (usb_opaque_t)sc;
1538 req->bulk_timeout = UATH_DATA_TIMEOUT;
1539 req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1540 req->bulk_cb = uath_data_txeof;
1541 req->bulk_exc_cb = uath_data_txeof;
1542 req->bulk_completion_reason = 0;
1543 req->bulk_cb_flags = 0;
1544
1545 if ((err = usb_pipe_bulk_xfer(sc->tx_data_pipe, req, 0)) !=
1546 USB_SUCCESS) {
1547
1548 UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
1549 "failed to do tx xfer, %d", err);
1550 usb_free_bulk_req(req);
1551 return (UATH_FAILURE);
1552 }
1553
1554 sc->tx_data_queued++;
1555 return (UATH_SUCCESS);
1556 }
1557
1558 /* ARGSUSED */
1559 static void
1560 uath_data_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1561 {
1562 struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1563 struct ieee80211com *ic = &sc->sc_ic;
1564 struct uath_chunk *chunk;
1565 struct uath_rx_desc *desc;
1566 struct ieee80211_frame *wh;
1567 struct ieee80211_node *ni;
1568
1569 mblk_t *m, *mp;
1570 uint8_t *rxbuf;
1571 int actlen, pktlen;
1572
1573 mutex_enter(&sc->sc_rxlock_data);
1574
1575 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1576 "cr:%s(%d), flags:0x%x, rx_data_queued %d\n",
1577 usb_str_cr(req->bulk_completion_reason),
1578 req->bulk_completion_reason,
1579 req->bulk_cb_flags,
1580 sc->rx_data_queued);
1581
1582 mp = req->bulk_data;
1583 req->bulk_data = NULL;
1584
1585 if (req->bulk_completion_reason != USB_CR_OK) {
1586 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1587 "USB CR is not OK\n");
1588 sc->sc_rx_err++;
1589 goto fail;
1590 }
1591
1592 rxbuf = (uint8_t *)mp->b_rptr;
1593 actlen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
1594 if (actlen < UATH_MIN_RXBUFSZ) {
1595 UATH_DEBUG(UATH_DBG_RX, "uath_data_rxeof(): "
1596 "wrong recv size %d\n", actlen);
1597 sc->sc_rx_err++;
1598 goto fail;
1599 }
1600
1601 chunk = (struct uath_chunk *)rxbuf;
1602 if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) {
1603 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1604 "strange response\n");
1605 UATH_RESET_INTRX(sc);
1606 sc->sc_rx_err++;
1607 goto fail;
1608 }
1609
1610 if (chunk->seqnum != sc->sc_intrx_nextnum) {
1611 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1612 "invalid seqnum %d, expected %d\n",
1613 chunk->seqnum, sc->sc_intrx_nextnum);
1614 UATH_STAT_INC(sc, st_badchunkseqnum);
1615 UATH_RESET_INTRX(sc);
1616 sc->sc_rx_err++;
1617 goto fail;
1618 }
1619
1620 /* check multi-chunk frames */
1621 if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) ||
1622 (chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) ||
1623 chunk->flags & UATH_CFLAGS_RXMSG) {
1624 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1625 "receive multi-chunk frames "
1626 "chunk seqnum %x, flags %x, length %u\n",
1627 chunk->seqnum, chunk->flags, BE_16(chunk->length));
1628 UATH_STAT_INC(sc, st_multichunk);
1629 }
1630
1631
1632 /* if the frame is not final continue the transfer */
1633 if (!(chunk->flags & UATH_CFLAGS_FINAL))
1634 sc->sc_intrx_nextnum++;
1635
1636 /*
1637 * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is
1638 * located at the end, 32-bit aligned
1639 */
1640 desc = (chunk->flags & UATH_CFLAGS_RXMSG) ?
1641 (struct uath_rx_desc *)(chunk + 1) :
1642 (struct uath_rx_desc *)(((uint8_t *)chunk) +
1643 sizeof (struct uath_chunk) + BE_16(chunk->length) -
1644 sizeof (struct uath_rx_desc));
1645
1646 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1647 "frame len %u code %u status %u rate %u antenna %u "
1648 "rssi %d channel %u phyerror %u connix %u "
1649 "decrypterror %u keycachemiss %u\n",
1650 BE_32(desc->framelen), BE_32(desc->code), BE_32(desc->status),
1651 BE_32(desc->rate), BE_32(desc->antenna), BE_32(desc->rssi),
1652 BE_32(desc->channel), BE_32(desc->phyerror), BE_32(desc->connix),
1653 BE_32(desc->decrypterror), BE_32(desc->keycachemiss));
1654
1655 if (BE_32(desc->len) > IEEE80211_MAX_LEN) {
1656 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1657 "bad descriptor (len=%d)\n", BE_32(desc->len));
1658 UATH_STAT_INC(sc, st_toobigrxpkt);
1659 goto fail;
1660 }
1661
1662 uath_update_rxstat(sc, BE_32(desc->status));
1663
1664 pktlen = BE_32(desc->framelen) - UATH_RX_DUMMYSIZE;
1665
1666 if ((m = allocb(pktlen, BPRI_MED)) == NULL) {
1667 UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1668 "allocate mblk failed.\n");
1669 sc->sc_rx_nobuf++;
1670 goto fail;
1671 }
1672 bcopy((rxbuf + sizeof (struct uath_chunk)), m->b_rptr, pktlen);
1673
1674 m->b_wptr = m->b_rptr + pktlen;
1675 wh = (struct ieee80211_frame *)m->b_rptr;
1676 ni = ieee80211_find_rxnode(ic, wh);
1677
1678 /* send the frame to the 802.11 layer */
1679 (void) ieee80211_input(ic, m, ni, (int)BE_32(desc->rssi), 0);
1680
1681 /* node is no longer needed */
1682 ieee80211_free_node(ni);
1683 fail:
1684 sc->rx_data_queued--;
1685 if (mp) freemsg(mp);
1686 usb_free_bulk_req(req);
1687 mutex_exit(&sc->sc_rxlock_data);
1688 if (UATH_IS_RUNNING(sc) && !UATH_IS_SUSPEND(sc)) {
1689 (void) uath_rx_data_xfer(sc);
1690 }
1691 }
1692
1693 static int
1694 uath_rx_data_xfer(struct uath_softc *sc)
1695 {
1696 usb_bulk_req_t *req;
1697 int err;
1698
1699 req = usb_alloc_bulk_req(sc->sc_dev,
1700 IEEE80211_MAX_LEN, USB_FLAGS_SLEEP);
1701 if (req == NULL) {
1702 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
1703 "failed to allocate req");
1704 return (UATH_SUCCESS);
1705 }
1706
1707 req->bulk_len = IEEE80211_MAX_LEN;
1708 req->bulk_cb = uath_data_rxeof;
1709 req->bulk_exc_cb = uath_data_rxeof;
1710 req->bulk_client_private = (usb_opaque_t)sc;
1711 req->bulk_timeout = 0;
1712 req->bulk_completion_reason = 0;
1713 req->bulk_cb_flags = 0;
1714 req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK
1715 | USB_ATTRS_AUTOCLEARING;
1716
1717 err = usb_pipe_bulk_xfer(sc->rx_data_pipe, req, 0);
1718 if (err != UATH_SUCCESS) {
1719 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
1720 "failed to do rx xfer, %d", err);
1721 usb_free_bulk_req(req);
1722 return (UATH_FAILURE);
1723 }
1724
1725 mutex_enter(&sc->sc_rxlock_data);
1726 sc->rx_data_queued++;
1727 mutex_exit(&sc->sc_rxlock_data);
1728 return (UATH_SUCCESS);
1729 }
1730
1731 static void
1732 uath_update_rxstat(struct uath_softc *sc, uint32_t status)
1733 {
1734
1735 switch (status) {
1736 case UATH_STATUS_STOP_IN_PROGRESS:
1737 UATH_STAT_INC(sc, st_stopinprogress);
1738 break;
1739 case UATH_STATUS_CRC_ERR:
1740 UATH_STAT_INC(sc, st_crcerr);
1741 break;
1742 case UATH_STATUS_PHY_ERR:
1743 UATH_STAT_INC(sc, st_phyerr);
1744 break;
1745 case UATH_STATUS_DECRYPT_CRC_ERR:
1746 UATH_STAT_INC(sc, st_decrypt_crcerr);
1747 break;
1748 case UATH_STATUS_DECRYPT_MIC_ERR:
1749 UATH_STAT_INC(sc, st_decrypt_micerr);
1750 break;
1751 case UATH_STATUS_DECOMP_ERR:
1752 UATH_STAT_INC(sc, st_decomperr);
1753 break;
1754 case UATH_STATUS_KEY_ERR:
1755 UATH_STAT_INC(sc, st_keyerr);
1756 break;
1757 case UATH_STATUS_ERR:
1758 UATH_STAT_INC(sc, st_err);
1759 break;
1760 default:
1761 break;
1762 }
1763 }
1764
1765 static void
1766 uath_next_scan(void *arg)
1767 {
1768 struct uath_softc *sc = arg;
1769 struct ieee80211com *ic = &sc->sc_ic;
1770
1771 if (ic->ic_state == IEEE80211_S_SCAN)
1772 ieee80211_next_scan(ic);
1773
1774 sc->sc_scan_id = 0;
1775 }
1776
1777 static int
1778 uath_create_connection(struct uath_softc *sc, uint32_t connid)
1779 {
1780 const struct ieee80211_rateset *rs;
1781 struct ieee80211com *ic = &sc->sc_ic;
1782 struct ieee80211_node *ni = ic->ic_bss;
1783 struct uath_cmd_create_connection create;
1784 int err;
1785
1786 bzero(&create, sizeof (create));
1787 create.connid = BE_32(connid);
1788 create.bssid = BE_32(0);
1789 /* XXX packed or not? */
1790 create.size = BE_32(sizeof (struct uath_cmd_rateset));
1791
1792 rs = &ni->in_rates;
1793 create.connattr.rateset.length = rs->ir_nrates;
1794 bcopy(rs->ir_rates, &create.connattr.rateset.set[0],
1795 rs->ir_nrates);
1796
1797 /* XXX turbo */
1798 if (UATH_IS_CHAN_A(ni->in_chan))
1799 create.connattr.wlanmode = BE_32(WLAN_MODE_11a);
1800 else if (UATH_IS_CHAN_ANYG(ni->in_chan))
1801 create.connattr.wlanmode = BE_32(WLAN_MODE_11g);
1802 else
1803 create.connattr.wlanmode = BE_32(WLAN_MODE_11b);
1804
1805 err = uath_cmd_write(sc, WDCMSG_CREATE_CONNECTION, &create,
1806 sizeof (create), 0);
1807 return (err);
1808 }
1809
1810 static int
1811 uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs)
1812 {
1813 struct uath_cmd_rates rates;
1814 int err;
1815
1816 bzero(&rates, sizeof (rates));
1817 rates.connid = BE_32(UATH_ID_BSS); /* XXX */
1818 rates.size = BE_32(sizeof (struct uath_cmd_rateset));
1819 /* XXX bounds check rs->rs_nrates */
1820 rates.rateset.length = rs->ir_nrates;
1821 bcopy(rs->ir_rates, &rates.rateset.set[0], rs->ir_nrates);
1822
1823 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rates(): "
1824 "setting supported rates nrates=%d\n", rs->ir_nrates);
1825 err = uath_cmd_write(sc, WDCMSG_SET_BASIC_RATE,
1826 &rates, sizeof (rates), 0);
1827 return (err);
1828 }
1829
1830 static int
1831 uath_write_associd(struct uath_softc *sc)
1832 {
1833 struct ieee80211com *ic = &sc->sc_ic;
1834 struct ieee80211_node *ni = ic->ic_bss;
1835 struct uath_cmd_set_associd associd;
1836 int err;
1837
1838 bzero(&associd, sizeof (associd));
1839 associd.defaultrateix = BE_32(1); /* XXX */
1840 associd.associd = BE_32(ni->in_associd);
1841 associd.timoffset = BE_32(0x3b); /* XXX */
1842 IEEE80211_ADDR_COPY(associd.bssid, ni->in_bssid);
1843 err = uath_cmd_write(sc, WDCMSG_WRITE_ASSOCID, &associd,
1844 sizeof (associd), 0);
1845 return (err);
1846 }
1847
1848 static int
1849 uath_set_ledsteady(struct uath_softc *sc, int lednum, int ledmode)
1850 {
1851 struct uath_cmd_ledsteady led;
1852 int err;
1853
1854 led.lednum = BE_32(lednum);
1855 led.ledmode = BE_32(ledmode);
1856
1857 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledsteady(): "
1858 "set %s led %s (steady)\n",
1859 (lednum == UATH_LED_LINK) ? "link" : "activity",
1860 ledmode ? "on" : "off");
1861 err = uath_cmd_write(sc, WDCMSG_SET_LED_STEADY, &led, sizeof (led), 0);
1862 return (err);
1863 }
1864
1865 static int
1866 uath_set_ledblink(struct uath_softc *sc, int lednum, int ledmode,
1867 int blinkrate, int slowmode)
1868 {
1869 struct uath_cmd_ledblink led;
1870 int err;
1871
1872 led.lednum = BE_32(lednum);
1873 led.ledmode = BE_32(ledmode);
1874 led.blinkrate = BE_32(blinkrate);
1875 led.slowmode = BE_32(slowmode);
1876
1877 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledblink(): "
1878 "set %s led %s (blink)\n",
1879 (lednum == UATH_LED_LINK) ? "link" : "activity",
1880 ledmode ? "on" : "off");
1881
1882 err = uath_cmd_write(sc, WDCMSG_SET_LED_BLINK,
1883 &led, sizeof (led), 0);
1884 return (err);
1885 }
1886
1887
1888 static int
1889 uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1890 {
1891 struct uath_softc *sc = (struct uath_softc *)ic;
1892 struct ieee80211_node *ni = ic->ic_bss;
1893 enum ieee80211_state ostate;
1894 int err;
1895
1896 ostate = ic->ic_state;
1897 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_newstate(): "
1898 "%d -> %d\n", ostate, nstate);
1899
1900 if (sc->sc_scan_id != 0) {
1901 (void) untimeout(sc->sc_scan_id);
1902 sc->sc_scan_id = 0;
1903 }
1904
1905 UATH_LOCK(sc);
1906
1907 if (UATH_IS_DISCONNECT(sc) && (nstate != IEEE80211_S_INIT)) {
1908 UATH_UNLOCK(sc);
1909 return (DDI_SUCCESS);
1910 }
1911
1912 if (UATH_IS_SUSPEND(sc) && (nstate != IEEE80211_S_INIT)) {
1913 UATH_UNLOCK(sc);
1914 return (DDI_SUCCESS);
1915 }
1916
1917 switch (nstate) {
1918 case IEEE80211_S_INIT:
1919 if (ostate == IEEE80211_S_RUN) {
1920 /* turn link and activity LEDs off */
1921 (void) uath_set_ledstate(sc, 0);
1922 }
1923 break;
1924 case IEEE80211_S_SCAN:
1925 if (uath_switch_channel(sc, ic->ic_curchan) != UATH_SUCCESS) {
1926 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1927 "could not switch channel\n");
1928 break;
1929 }
1930 sc->sc_scan_id = timeout(uath_next_scan, (void *)sc,
1931 drv_usectohz(250000));
1932 break;
1933 case IEEE80211_S_AUTH:
1934 /* XXX good place? set RTS threshold */
1935 uath_config(sc, CFG_USER_RTS_THRESHOLD, ic->ic_rtsthreshold);
1936
1937 if (uath_switch_channel(sc, ni->in_chan) != 0) {
1938 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1939 "could not switch channel\n");
1940 break;
1941 }
1942 if (uath_create_connection(sc, UATH_ID_BSS) != 0) {
1943 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1944 "could not create connection\n");
1945 break;
1946 }
1947 break;
1948 case IEEE80211_S_ASSOC:
1949 if (uath_set_rates(sc, &ni->in_rates) != 0) {
1950 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1951 "could not set negotiated rate set\n");
1952 break;
1953 }
1954 break;
1955 case IEEE80211_S_RUN:
1956 /* XXX monitor mode doesn't be supported */
1957 if (ic->ic_opmode == IEEE80211_M_MONITOR) {
1958 (void) uath_set_ledstate(sc, 1);
1959 break;
1960 }
1961
1962 /*
1963 * Tx rate is controlled by firmware, report the maximum
1964 * negotiated rate in ifconfig output.
1965 */
1966 ni->in_txrate = ni->in_rates.ir_nrates - 1;
1967
1968 if (uath_write_associd(sc) != 0) {
1969 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1970 "could not write association id\n");
1971 break;
1972 }
1973 /* turn link LED on */
1974 (void) uath_set_ledsteady(sc, UATH_LED_LINK, UATH_LED_ON);
1975 /* make activity LED blink */
1976 (void) uath_set_ledblink(sc, UATH_LED_ACTIVITY,
1977 UATH_LED_ON, 1, 2);
1978 /* set state to associated */
1979 (void) uath_set_ledstate(sc, 1);
1980 break;
1981 }
1982
1983 UATH_UNLOCK(sc);
1984
1985 err = sc->sc_newstate(ic, nstate, arg);
1986 return (err);
1987 }
1988
1989 static int
1990 uath_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
1991 {
1992 struct uath_softc *sc = (struct uath_softc *)ic;
1993 struct uath_chunk *chunk;
1994 struct uath_tx_desc *desc;
1995 struct ieee80211_frame *wh;
1996 struct ieee80211_node *ni = NULL;
1997 struct ieee80211_key *k;
1998
1999 mblk_t *m, *m0;
2000 int err, off, mblen;
2001 int pktlen, framelen, msglen;
2002
2003 err = UATH_SUCCESS;
2004
2005 mutex_enter(&sc->sc_txlock_data);
2006
2007 if (UATH_IS_SUSPEND(sc)) {
2008 err = 0;
2009 goto fail;
2010 }
2011
2012 if (sc->tx_data_queued > UATH_TX_DATA_LIST_COUNT) {
2013 UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2014 "no TX buffer available!\n");
2015 if ((type & IEEE80211_FC0_TYPE_MASK) ==
2016 IEEE80211_FC0_TYPE_DATA) {
2017 sc->sc_need_sched = 1;
2018 }
2019 sc->sc_tx_nobuf++;
2020 err = ENOMEM;
2021 goto fail;
2022 }
2023
2024 m = allocb(UATH_MAX_TXBUFSZ, BPRI_MED);
2025 if (m == NULL) {
2026 UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2027 "can't alloc mblk.\n");
2028 err = DDI_FAILURE;
2029 goto fail;
2030 }
2031
2032 /* skip TX descriptor */
2033 m->b_rptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2034 m->b_wptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2035
2036 for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2037 mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
2038 (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
2039 off += mblen;
2040 }
2041 m->b_wptr += off;
2042
2043 wh = (struct ieee80211_frame *)m->b_rptr;
2044
2045 ni = ieee80211_find_txnode(ic, wh->i_addr1);
2046 if (ni == NULL) {
2047 err = DDI_FAILURE;
2048 freemsg(m);
2049 goto fail;
2050 }
2051
2052 if ((type & IEEE80211_FC0_TYPE_MASK) ==
2053 IEEE80211_FC0_TYPE_DATA) {
2054 (void) ieee80211_encap(ic, m, ni);
2055 }
2056
2057 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2058 k = ieee80211_crypto_encap(ic, m);
2059 if (k == NULL) {
2060 freemsg(m);
2061 err = DDI_FAILURE;
2062 goto fail;
2063 }
2064 /* packet header may have moved, reset our local pointer */
2065 wh = (struct ieee80211_frame *)m->b_rptr;
2066 }
2067
2068 pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr;
2069 framelen = pktlen + IEEE80211_CRC_LEN;
2070 msglen = framelen + sizeof (struct uath_tx_desc);
2071
2072 m->b_rptr -= sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2073
2074 chunk = (struct uath_chunk *)m->b_rptr;
2075 desc = (struct uath_tx_desc *)(chunk + 1);
2076
2077 /* one chunk only for now */
2078 chunk->seqnum = 0;
2079 chunk->flags = UATH_CFLAGS_FINAL;
2080 chunk->length = BE_16(msglen);
2081
2082 /* fill Tx descriptor */
2083 desc->msglen = BE_32(msglen);
2084 /* NB: to get UATH_TX_NOTIFY reply, `msgid' must be larger than 0 */
2085 desc->msgid = sc->sc_msgid; /* don't care about endianness */
2086 desc->type = BE_32(WDCMSG_SEND);
2087 switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
2088 case IEEE80211_FC0_TYPE_CTL:
2089 case IEEE80211_FC0_TYPE_MGT:
2090 /* NB: force all management frames to highest queue */
2091 if (ni->in_flags & UATH_NODE_QOS) {
2092 /* NB: force all management frames to highest queue */
2093 desc->txqid = BE_32(WME_AC_VO | UATH_TXQID_MINRATE);
2094 } else
2095 desc->txqid = BE_32(WME_AC_BE | UATH_TXQID_MINRATE);
2096 break;
2097 case IEEE80211_FC0_TYPE_DATA:
2098 /* XXX multicast frames should honor mcastrate */
2099 desc->txqid = BE_32(WME_AC_BE);
2100 break;
2101 default:
2102 UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2103 "bogus frame type 0x%x (%s)\n",
2104 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
2105 err = EIO;
2106 goto fail;
2107 }
2108
2109 if (ic->ic_state == IEEE80211_S_AUTH ||
2110 ic->ic_state == IEEE80211_S_ASSOC ||
2111 ic->ic_state == IEEE80211_S_RUN)
2112 desc->connid = BE_32(UATH_ID_BSS);
2113 else
2114 desc->connid = BE_32(UATH_ID_INVALID);
2115 desc->flags = BE_32(0 /* no UATH_TX_NOTIFY */);
2116 desc->buflen = BE_32(pktlen);
2117
2118 (void) uath_tx_data_xfer(sc, m);
2119
2120 sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
2121
2122 ic->ic_stats.is_tx_frags++;
2123 ic->ic_stats.is_tx_bytes += pktlen;
2124
2125 fail:
2126 if (ni != NULL)
2127 ieee80211_free_node(ni);
2128 if ((mp) &&
2129 ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
2130 err == 0)) {
2131 freemsg(mp);
2132 }
2133 mutex_exit(&sc->sc_txlock_data);
2134 return (err);
2135 }
2136
2137 static int
2138 uath_reconnect(dev_info_t *devinfo)
2139 {
2140 struct uath_softc *sc;
2141 struct ieee80211com *ic;
2142 int err;
2143 uint16_t vendor_id, product_id;
2144
2145 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
2146 "uath online\n");
2147
2148 sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
2149 ASSERT(sc != NULL);
2150 ic = (struct ieee80211com *)&sc->sc_ic;
2151
2152 if (!UATH_IS_RECONNECT(sc)) {
2153 err = uath_open_pipes(sc);
2154 if (err != UATH_SUCCESS) {
2155 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2156 "could not open pipes\n");
2157 return (DDI_FAILURE);
2158 }
2159
2160 err = uath_loadfirmware(sc);
2161 if (err != DDI_SUCCESS) {
2162 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2163 "could not download firmware\n");
2164 return (DDI_FAILURE);
2165 }
2166
2167 uath_close_pipes(sc);
2168 usb_client_detach(sc->sc_dev, sc->sc_udev);
2169
2170 /* reset device */
2171 err = usb_reset_device(sc->sc_dev, USB_RESET_LVL_DEFAULT);
2172 if (err != USB_SUCCESS) {
2173 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2174 "could not reset device %x\n", err);
2175 }
2176
2177 err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
2178 if (err != USB_SUCCESS) {
2179 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2180 "usb_client_attach failed\n");
2181 }
2182
2183 err = usb_get_dev_data(devinfo, &sc->sc_udev,
2184 USB_PARSE_LVL_ALL, 0);
2185 if (err != USB_SUCCESS) {
2186 sc->sc_udev = NULL;
2187 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2188 "usb_get_dev_data failed\n");
2189 }
2190
2191 vendor_id = sc->sc_udev->dev_descr->idVendor;
2192 product_id = sc->sc_udev->dev_descr->idProduct;
2193 sc->dev_flags = uath_lookup(vendor_id, product_id);
2194 if (sc->dev_flags == UATH_FLAG_ERR) {
2195 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2196 "HW does not match\n");
2197 }
2198
2199 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
2200 "vendorId = %x,deviceID = %x, flags = %x\n",
2201 vendor_id, product_id, sc->dev_flags);
2202
2203 UATH_LOCK(sc);
2204 sc->sc_flags |= UATH_FLAG_RECONNECT;
2205 UATH_UNLOCK(sc);
2206
2207 } else {
2208 err = uath_open_pipes(sc);
2209 if (err != UATH_SUCCESS) {
2210 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2211 "could not open pipes\n");
2212 return (DDI_FAILURE);
2213 }
2214
2215 /*
2216 * Allocate xfers for firmware commands.
2217 */
2218 err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
2219 UATH_MAX_CMDSZ);
2220 if (err != UATH_SUCCESS) {
2221 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2222 "could not allocate Tx command list\n");
2223 return (DDI_FAILURE);
2224 }
2225
2226 err = uath_init_cmd_list(sc);
2227 if (err != UATH_SUCCESS) {
2228 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2229 "could not init RX command list\n");
2230 return (DDI_FAILURE);
2231 }
2232
2233 /*
2234 * We're now ready to send+receive firmware commands.
2235 */
2236 err = uath_host_available(sc);
2237 if (err != UATH_SUCCESS) {
2238 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2239 "could not initialize adapter\n");
2240 return (DDI_FAILURE);
2241 }
2242
2243 err = uath_get_devcap(sc);
2244 if (err != UATH_SUCCESS) {
2245 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2246 "could not get device capabilities\n");
2247 return (DDI_FAILURE);
2248 }
2249
2250 err = uath_get_devstatus(sc, ic->ic_macaddr);
2251 if (err != UATH_SUCCESS) {
2252 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2253 "could not get dev status\n");
2254 return (DDI_FAILURE);
2255 }
2256
2257 err = usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
2258 USB_CHK_BASIC, NULL);
2259 if (err != USB_SUCCESS) {
2260 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2261 "different device connected %x\n", err);
2262 return (DDI_FAILURE);
2263 }
2264
2265 err = uath_init(sc);
2266 if (err != UATH_SUCCESS) {
2267 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2268 "device re-connect failed\n");
2269 return (DDI_FAILURE);
2270 }
2271
2272 UATH_LOCK(sc);
2273 sc->sc_flags &= ~UATH_FLAG_RECONNECT;
2274 sc->sc_flags &= ~UATH_FLAG_DISCONNECT;
2275 sc->sc_flags |= UATH_FLAG_RUNNING;
2276 UATH_UNLOCK(sc);
2277 }
2278
2279 return (DDI_SUCCESS);
2280 }
2281
2282 static int
2283 uath_disconnect(dev_info_t *devinfo)
2284 {
2285 struct uath_softc *sc;
2286 struct ieee80211com *ic;
2287
2288 /*
2289 * We can't call uath_stop() here, since the hardware is removed,
2290 * we can't access the register anymore.
2291 */
2292 sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
2293 ASSERT(sc != NULL);
2294
2295 if (sc->sc_flags & UATH_FLAG_RECONNECT) {
2296 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
2297 "stage 0 in re-connect\n");
2298 uath_close_pipes(sc);
2299 return (DDI_SUCCESS);
2300 }
2301
2302 UATH_LOCK(sc);
2303 sc->sc_flags |= UATH_FLAG_DISCONNECT;
2304 UATH_UNLOCK(sc);
2305
2306 ic = (struct ieee80211com *)&sc->sc_ic;
2307 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2308
2309 UATH_LOCK(sc);
2310 sc->sc_flags &= ~UATH_FLAG_RUNNING; /* STOP */
2311 UATH_UNLOCK(sc);
2312
2313 /* abort and free xfers */
2314 uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
2315
2316 /* close Tx/Rx pipes */
2317 uath_close_pipes(sc);
2318
2319 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
2320 "offline success\n");
2321
2322 return (DDI_SUCCESS);
2323 }
2324
2325 static int
2326 uath_dataflush(struct uath_softc *sc)
2327 {
2328 struct uath_chunk *chunk;
2329 struct uath_tx_desc *desc;
2330 uint8_t *buf;
2331 int err;
2332
2333 buf = kmem_alloc(UATH_MAX_TXBUFSZ, KM_NOSLEEP);
2334 if (buf == NULL) {
2335 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
2336 "no bufs\n");
2337 return (ENOBUFS);
2338 }
2339
2340 chunk = (struct uath_chunk *)buf;
2341 desc = (struct uath_tx_desc *)(chunk + 1);
2342
2343 /* one chunk only */
2344 chunk->seqnum = 0;
2345 chunk->flags = UATH_CFLAGS_FINAL;
2346 chunk->length = BE_16(sizeof (struct uath_tx_desc));
2347
2348 bzero(desc, sizeof (struct uath_tx_desc));
2349 desc->msglen = BE_32(sizeof (struct uath_tx_desc));
2350 desc->msgid = sc->sc_msgid; /* don't care about endianness */
2351 desc->type = BE_32(WDCMSG_FLUSH);
2352 desc->txqid = BE_32(0);
2353 desc->connid = BE_32(0);
2354 desc->flags = BE_32(0);
2355
2356 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_dataflush(): "
2357 "send flush ix %d\n", desc->msgid);
2358
2359 err = uath_fw_send(sc, sc->tx_data_pipe, buf,
2360 sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc));
2361 if (err != UATH_SUCCESS) {
2362 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
2363 "data flush error");
2364 return (UATH_FAILURE);
2365 }
2366
2367 kmem_free(buf, UATH_MAX_TXBUFSZ);
2368 sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
2369
2370 return (UATH_SUCCESS);
2371 }
2372
2373 static int
2374 uath_cmdflush(struct uath_softc *sc)
2375 {
2376 return (uath_cmd_write(sc, WDCMSG_FLUSH, NULL, 0, 0));
2377 }
2378
2379 static int
2380 uath_flush(struct uath_softc *sc)
2381 {
2382 int err;
2383
2384 err = uath_dataflush(sc);
2385 if (err != UATH_SUCCESS)
2386 goto failed;
2387
2388 err = uath_cmdflush(sc);
2389 if (err != UATH_SUCCESS)
2390 goto failed;
2391
2392 return (UATH_SUCCESS);
2393 failed:
2394 return (err);
2395 }
2396
2397 static int
2398 uath_set_ledstate(struct uath_softc *sc, int connected)
2399 {
2400 int err;
2401
2402 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledstate(): "
2403 "set led state %sconnected\n", connected ? "" : "!");
2404
2405 connected = BE_32(connected);
2406 err = uath_cmd_write(sc, WDCMSG_SET_LED_STATE,
2407 &connected, sizeof (connected), 0);
2408 return (err);
2409 }
2410
2411 static int
2412 uath_config_multi(struct uath_softc *sc, uint32_t reg, const void *data,
2413 int len)
2414 {
2415 struct uath_write_mac write;
2416 int err;
2417
2418 write.reg = BE_32(reg);
2419 write.len = BE_32(len);
2420 bcopy(data, write.data, len);
2421
2422 /* properly handle the case where len is zero (reset) */
2423 err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
2424 (len == 0) ? sizeof (uint32_t) : 2 * sizeof (uint32_t) + len, 0);
2425 if (err != UATH_SUCCESS) {
2426 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config_multi(): "
2427 "could not write %d bytes to register 0x%02x\n", len, reg);
2428 }
2429 return (err);
2430 }
2431
2432 static void
2433 uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val)
2434 {
2435 struct uath_write_mac write;
2436 int err;
2437
2438 write.reg = BE_32(reg);
2439 write.len = BE_32(0); /* 0 = single write */
2440 *(uint32_t *)write.data = BE_32(val);
2441
2442 err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
2443 3 * sizeof (uint32_t), 0);
2444 if (err != UATH_SUCCESS) {
2445 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config(): "
2446 "could not write register 0x%02x\n",
2447 reg);
2448 }
2449 }
2450
2451 static int
2452 uath_switch_channel(struct uath_softc *sc, struct ieee80211_channel *c)
2453 {
2454 int err;
2455
2456 /* set radio frequency */
2457 err = uath_set_chan(sc, c);
2458 if (err) {
2459 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2460 "could not set channel\n");
2461 goto failed;
2462 }
2463
2464 /* reset Tx rings */
2465 err = uath_reset_tx_queues(sc);
2466 if (err) {
2467 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2468 "could not reset Tx queues\n");
2469 goto failed;
2470 }
2471
2472 /* set Tx rings WME properties */
2473 err = uath_wme_init(sc);
2474 if (err) {
2475 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2476 "could not init Tx queues\n");
2477 goto failed;
2478 }
2479
2480 err = uath_set_ledstate(sc, 0);
2481 if (err) {
2482 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2483 "could not set led state\n");
2484 goto failed;
2485 }
2486
2487 err = uath_flush(sc);
2488 if (err) {
2489 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2490 "could not flush pipes\n");
2491 goto failed;
2492 }
2493
2494 failed:
2495 return (err);
2496 }
2497
2498 static int
2499 uath_set_rxfilter(struct uath_softc *sc, uint32_t bits, uint32_t op)
2500 {
2501 struct uath_cmd_rx_filter rxfilter;
2502
2503 rxfilter.bits = BE_32(bits);
2504 rxfilter.op = BE_32(op);
2505
2506 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rxfilter(): "
2507 "setting Rx filter=0x%x flags=0x%x\n", bits, op);
2508
2509 return ((uath_cmd_write(sc, WDCMSG_RX_FILTER, &rxfilter,
2510 sizeof (rxfilter), 0)));
2511 }
2512
2513 static int
2514 uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c)
2515 {
2516 struct ieee80211com *ic = &sc->sc_ic;
2517 struct uath_cmd_reset reset;
2518
2519 bzero(&reset, sizeof (reset));
2520 if (IEEE80211_IS_CHAN_2GHZ(c))
2521 reset.flags |= BE_32(UATH_CHAN_2GHZ);
2522 if (IEEE80211_IS_CHAN_5GHZ(c))
2523 reset.flags |= BE_32(UATH_CHAN_5GHZ);
2524 /* NB: 11g =>'s 11b so don't specify both OFDM and CCK */
2525 if (UATH_IS_CHAN_OFDM(c))
2526 reset.flags |= BE_32(UATH_CHAN_OFDM);
2527 else if (UATH_IS_CHAN_CCK(c))
2528 reset.flags |= BE_32(UATH_CHAN_CCK);
2529 /* turbo can be used in either 2GHz or 5GHz */
2530 if (c->ich_flags & IEEE80211_CHAN_TURBO)
2531 reset.flags |= BE_32(UATH_CHAN_TURBO);
2532
2533 reset.freq = BE_32(c->ich_freq);
2534 reset.maxrdpower = BE_32(50); /* XXX */
2535 reset.channelchange = BE_32(1);
2536 reset.keeprccontent = BE_32(0);
2537
2538 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_chan(): "
2539 "set channel %d, flags 0x%x freq %u\n",
2540 ieee80211_chan2ieee(ic, c),
2541 BE_32(reset.flags), BE_32(reset.freq));
2542
2543 return (uath_cmd_write(sc, WDCMSG_RESET, &reset, sizeof (reset), 0));
2544 }
2545
2546 static int
2547 uath_reset_tx_queues(struct uath_softc *sc)
2548 {
2549 int ac, err;
2550
2551 for (ac = 0; ac < 4; ac++) {
2552 const uint32_t qid = BE_32(ac);
2553 err = uath_cmd_write(sc, WDCMSG_RELEASE_TX_QUEUE, &qid,
2554 sizeof (qid), 0);
2555 if (err != UATH_SUCCESS)
2556 break;
2557 }
2558 return (err);
2559 }
2560
2561 static int
2562 uath_wme_init(struct uath_softc *sc)
2563 {
2564 /* XXX get from net80211 */
2565 static const struct uath_wme_settings uath_wme_11g[4] = {
2566 { 7, 4, 10, 0, 0 }, /* Background */
2567 { 3, 4, 10, 0, 0 }, /* Best-Effort */
2568 { 3, 3, 4, 26, 0 }, /* Video */
2569 { 2, 2, 3, 47, 0 } /* Voice */
2570 };
2571
2572 struct uath_cmd_txq_setup qinfo;
2573 int ac, err;
2574
2575 for (ac = 0; ac < 4; ac++) {
2576 qinfo.qid = BE_32(ac);
2577 qinfo.len = BE_32(sizeof (qinfo.attr));
2578 qinfo.attr.priority = BE_32(ac); /* XXX */
2579 qinfo.attr.aifs = BE_32(uath_wme_11g[ac].aifsn);
2580 qinfo.attr.logcwmin = BE_32(uath_wme_11g[ac].logcwmin);
2581 qinfo.attr.logcwmax = BE_32(uath_wme_11g[ac].logcwmax);
2582 qinfo.attr.mode = BE_32(uath_wme_11g[ac].acm);
2583 qinfo.attr.qflags = BE_32(1);
2584 qinfo.attr.bursttime =
2585 BE_32(UATH_TXOP_TO_US(uath_wme_11g[ac].txop));
2586
2587 err = uath_cmd_write(sc, WDCMSG_SETUP_TX_QUEUE, &qinfo,
2588 sizeof (qinfo), 0);
2589 if (err != UATH_SUCCESS)
2590 break;
2591 }
2592 return (err);
2593 }
2594
2595 static void
2596 uath_stop_locked(void *arg)
2597 {
2598 struct uath_softc *sc = (struct uath_softc *)arg;
2599
2600 /* flush data & control requests into the target */
2601 (void) uath_flush(sc);
2602
2603 /* set a LED status to the disconnected. */
2604 (void) uath_set_ledstate(sc, 0);
2605
2606 /* stop the target */
2607 (void) uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0);
2608
2609 /* abort any pending transfers */
2610 usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
2611 usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
2612 usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, USB_FLAGS_SLEEP, NULL, 0);
2613 }
2614
2615 static int
2616 uath_init_locked(void *arg)
2617 {
2618 struct uath_softc *sc = arg;
2619 struct ieee80211com *ic = &sc->sc_ic;
2620 uint32_t val;
2621 int i, err;
2622
2623 if (UATH_IS_RUNNING(sc))
2624 uath_stop_locked(sc);
2625
2626 uath_init_data_queue(sc);
2627
2628 /* reset variables */
2629 sc->sc_intrx_nextnum = sc->sc_msgid = 0;
2630
2631 val = BE_32(0);
2632 (void) uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof (val), 0);
2633
2634 /* set MAC address */
2635 (void) uath_config_multi(sc, CFG_MAC_ADDR,
2636 ic->ic_macaddr, IEEE80211_ADDR_LEN);
2637
2638 /* XXX honor net80211 state */
2639 uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001);
2640 uath_config(sc, CFG_DIVERSITY_CTL, 0x00000001);
2641 uath_config(sc, CFG_ABOLT, 0x0000003f);
2642 uath_config(sc, CFG_WME_ENABLED, 0x00000001);
2643
2644 uath_config(sc, CFG_SERVICE_TYPE, 1);
2645 uath_config(sc, CFG_TP_SCALE, 0x00000000);
2646 uath_config(sc, CFG_TPC_HALF_DBM5, 0x0000003c);
2647 uath_config(sc, CFG_TPC_HALF_DBM2, 0x0000003c);
2648 uath_config(sc, CFG_OVERRD_TX_POWER, 0x00000000);
2649 uath_config(sc, CFG_GMODE_PROTECTION, 0x00000000);
2650 uath_config(sc, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003);
2651 uath_config(sc, CFG_PROTECTION_TYPE, 0x00000000);
2652 uath_config(sc, CFG_MODE_CTS, 0x00000002);
2653
2654 err = uath_cmd_read(sc, WDCMSG_TARGET_START, NULL, 0,
2655 &val, sizeof (val), UATH_CMD_FLAG_MAGIC);
2656 if (err) {
2657 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2658 "could not start target\n");
2659 goto fail;
2660 }
2661
2662 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_init_locked(): "
2663 "%s returns handle: 0x%x\n",
2664 uath_codename(WDCMSG_TARGET_START), BE_32(val));
2665
2666 /* set default channel */
2667 err = uath_switch_channel(sc, ic->ic_curchan);
2668 if (err) {
2669 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2670 "could not switch channel, error %d\n", err);
2671 goto fail;
2672 }
2673
2674 val = BE_32(TARGET_DEVICE_AWAKE);
2675 (void) uath_cmd_write(sc, WDCMSG_SET_PWR_MODE, &val, sizeof (val), 0);
2676 /* XXX? check */
2677 (void) uath_cmd_write(sc, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0);
2678
2679 for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) {
2680 err = uath_rx_data_xfer(sc);
2681 if (err != UATH_SUCCESS) {
2682 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2683 "could not alloc rx xfer %x\n", i);
2684 goto fail;
2685 }
2686 }
2687
2688 /* enable Rx */
2689 (void) uath_set_rxfilter(sc, 0x0, UATH_FILTER_OP_INIT);
2690 (void) uath_set_rxfilter(sc,
2691 UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST |
2692 UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON,
2693 UATH_FILTER_OP_SET);
2694
2695 return (UATH_SUCCESS);
2696
2697 fail:
2698 uath_stop_locked(sc);
2699 return (err);
2700 }
2701
2702 static int
2703 uath_init(struct uath_softc *sc)
2704 {
2705 int err;
2706
2707 UATH_LOCK(sc);
2708 err = uath_init_locked(sc);
2709 if (err != UATH_SUCCESS) {
2710 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init(): "
2711 "failed to initialize uath hardware\n");
2712 UATH_UNLOCK(sc);
2713 return (DDI_FAILURE);
2714 }
2715 UATH_UNLOCK(sc);
2716 return (DDI_SUCCESS);
2717 }
2718
2719 static void
2720 uath_stop(struct uath_softc *sc)
2721 {
2722 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_stop(): "
2723 "uath stop now\n");
2724
2725 UATH_LOCK(sc);
2726 uath_stop_locked(sc);
2727 UATH_UNLOCK(sc);
2728 }
2729
2730 static void
2731 uath_resume(struct uath_softc *sc)
2732 {
2733 int err;
2734
2735 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2736 "uath resume now\n");
2737
2738 /* check device changes after suspend */
2739 if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
2740 USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
2741 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume: "
2742 "no or different device connected\n");
2743 return;
2744 }
2745
2746 /*
2747 * initialize hardware
2748 */
2749 err = uath_init_cmd_list(sc);
2750 if (err != UATH_SUCCESS) {
2751 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2752 "could not init RX command list\n");
2753 return;
2754 }
2755
2756 err = uath_init(sc);
2757 if (err != UATH_SUCCESS) {
2758 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2759 "hardware init failed\n");
2760 uath_stop(sc);
2761 return;
2762 }
2763
2764 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2765 UATH_LOCK(sc);
2766 sc->sc_flags &= ~UATH_FLAG_SUSPEND;
2767 sc->sc_flags |= UATH_FLAG_RUNNING;
2768 UATH_UNLOCK(sc);
2769 }
2770
2771 static int
2772 uath_m_start(void *arg)
2773 {
2774 struct uath_softc *sc = (struct uath_softc *)arg;
2775 struct ieee80211com *ic = &sc->sc_ic;
2776 int err;
2777
2778 /*
2779 * initialize hardware
2780 */
2781 err = uath_init(sc);
2782 if (err != UATH_SUCCESS) {
2783 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_m_start(): "
2784 "device configuration failed\n");
2785 uath_stop(sc);
2786 return (err);
2787 }
2788
2789 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2790
2791 UATH_LOCK(sc);
2792 sc->sc_flags |= UATH_FLAG_RUNNING;
2793 UATH_UNLOCK(sc);
2794 return (DDI_SUCCESS);
2795 }
2796
2797 static void
2798 uath_m_stop(void *arg)
2799 {
2800 struct uath_softc *sc = (struct uath_softc *)arg;
2801 struct ieee80211com *ic = &sc->sc_ic;
2802
2803 ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2804
2805 if (!UATH_IS_DISCONNECT(sc))
2806 uath_stop(sc);
2807
2808 UATH_LOCK(sc);
2809 sc->sc_flags &= ~UATH_FLAG_RUNNING;
2810 UATH_UNLOCK(sc);
2811 }
2812
2813 static void
2814 uath_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
2815 {
2816 struct uath_softc *sc = (struct uath_softc *)arg;
2817 struct ieee80211com *ic = &sc->sc_ic;
2818 int err;
2819
2820 err = ieee80211_ioctl(ic, wq, mp);
2821 UATH_LOCK(sc);
2822 if (err == ENETRESET) {
2823 if (ic->ic_des_esslen) {
2824 if (UATH_IS_RUNNING(sc)) {
2825 UATH_UNLOCK(sc);
2826 (void) uath_init(sc);
2827 (void) ieee80211_new_state(ic,
2828 IEEE80211_S_SCAN, -1);
2829 UATH_LOCK(sc);
2830 }
2831 }
2832 }
2833 UATH_UNLOCK(sc);
2834 }
2835
2836 /*ARGSUSED*/
2837 static int
2838 uath_m_unicst(void *arg, const uint8_t *macaddr)
2839 {
2840 return (0);
2841 }
2842
2843 /*ARGSUSED*/
2844 static int
2845 uath_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
2846 {
2847 return (0);
2848 }
2849
2850 /*ARGSUSED*/
2851 static int
2852 uath_m_promisc(void *arg, boolean_t on)
2853 {
2854 return (0);
2855 }
2856
2857 /*
2858 * callback functions for /get/set properties
2859 */
2860 static int
2861 uath_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2862 uint_t wldp_length, const void *wldp_buf)
2863 {
2864 struct uath_softc *sc = (struct uath_softc *)arg;
2865 struct ieee80211com *ic = &sc->sc_ic;
2866 int err;
2867
2868 err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
2869 wldp_length, wldp_buf);
2870 UATH_LOCK(sc);
2871 if (err == ENETRESET) {
2872 if (ic->ic_des_esslen && UATH_IS_RUNNING(sc)) {
2873 UATH_UNLOCK(sc);
2874 (void) uath_init(sc);
2875 (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2876 UATH_LOCK(sc);
2877 }
2878 err = 0;
2879 }
2880 UATH_UNLOCK(sc);
2881 return (err);
2882 }
2883
2884 static int
2885 uath_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2886 uint_t wldp_length, void *wldp_buf)
2887 {
2888 struct uath_softc *sc = (struct uath_softc *)arg;
2889 int err;
2890
2891 err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
2892 wldp_length, wldp_buf);
2893 return (err);
2894 }
2895
2896 static void
2897 uath_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2898 mac_prop_info_handle_t prh)
2899 {
2900 struct uath_softc *sc = (struct uath_softc *)arg;
2901
2902 ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
2903 }
2904
2905 static int
2906 uath_m_stat(void *arg, uint_t stat, uint64_t *val)
2907 {
2908 struct uath_softc *sc = (struct uath_softc *)arg;
2909 struct ieee80211com *ic = &sc->sc_ic;
2910 struct ieee80211_node *ni = NULL;
2911 struct ieee80211_rateset *rs = NULL;
2912
2913 UATH_LOCK(sc);
2914 switch (stat) {
2915 case MAC_STAT_IFSPEED:
2916 ni = ic->ic_bss;
2917 rs = &ni->in_rates;
2918 *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
2919 (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
2920 : ic->ic_fixed_rate) * 5000000ull;
2921 break;
2922 case MAC_STAT_NOXMTBUF:
2923 *val = sc->sc_tx_nobuf;
2924 break;
2925 case MAC_STAT_NORCVBUF:
2926 *val = sc->sc_rx_nobuf;
2927 break;
2928 case MAC_STAT_IERRORS:
2929 *val = sc->sc_rx_err;
2930 break;
2931 case MAC_STAT_RBYTES:
2932 *val = ic->ic_stats.is_rx_bytes;
2933 break;
2934 case MAC_STAT_IPACKETS:
2935 *val = ic->ic_stats.is_rx_frags;
2936 break;
2937 case MAC_STAT_OBYTES:
2938 *val = ic->ic_stats.is_tx_bytes;
2939 break;
2940 case MAC_STAT_OPACKETS:
2941 *val = ic->ic_stats.is_tx_frags;
2942 break;
2943 case MAC_STAT_OERRORS:
2944 case WIFI_STAT_TX_FAILED:
2945 *val = sc->sc_tx_err;
2946 break;
2947 case WIFI_STAT_TX_RETRANS:
2948 *val = sc->sc_tx_retries;
2949 break;
2950 case WIFI_STAT_FCS_ERRORS:
2951 case WIFI_STAT_WEP_ERRORS:
2952 case WIFI_STAT_TX_FRAGS:
2953 case WIFI_STAT_MCAST_TX:
2954 case WIFI_STAT_RTS_SUCCESS:
2955 case WIFI_STAT_RTS_FAILURE:
2956 case WIFI_STAT_ACK_FAILURE:
2957 case WIFI_STAT_RX_FRAGS:
2958 case WIFI_STAT_MCAST_RX:
2959 case WIFI_STAT_RX_DUPS:
2960 UATH_UNLOCK(sc);
2961 return (ieee80211_stat(ic, stat, val));
2962 default:
2963 UATH_UNLOCK(sc);
2964 return (ENOTSUP);
2965 }
2966 UATH_UNLOCK(sc);
2967
2968 return (0);
2969 }
2970
2971 static mblk_t *
2972 uath_m_tx(void *arg, mblk_t *mp)
2973 {
2974 struct uath_softc *sc = (struct uath_softc *)arg;
2975 struct ieee80211com *ic = &sc->sc_ic;
2976 mblk_t *next;
2977
2978 /*
2979 * No data frames go out unless we're associated; this
2980 * should not happen as the 802.11 layer does not enable
2981 * the xmit queue until we enter the RUN state.
2982 */
2983 if ((ic->ic_state != IEEE80211_S_RUN) ||
2984 UATH_IS_SUSPEND(sc)) {
2985 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_m_tx(): "
2986 "discard, state %u\n", ic->ic_state);
2987 freemsgchain(mp);
2988 return (NULL);
2989 }
2990
2991 while (mp != NULL) {
2992 next = mp->b_next;
2993 mp->b_next = NULL;
2994 if (uath_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
2995 mp->b_next = next;
2996 break;
2997 }
2998 mp = next;
2999 }
3000 return (mp);
3001 }
3002
3003 static int
3004 uath_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3005 {
3006 struct uath_softc *sc;
3007 struct ieee80211com *ic;
3008
3009 int i, err, instance;
3010 char strbuf[32];
3011 uint16_t vendor_id, product_id;
3012
3013 wifi_data_t wd = { 0 };
3014 mac_register_t *macp;
3015
3016 switch (cmd) {
3017 case DDI_ATTACH:
3018 break;
3019 case DDI_RESUME:
3020 sc = ddi_get_soft_state(uath_soft_state_p,
3021 ddi_get_instance(devinfo));
3022 ASSERT(sc != NULL);
3023 uath_resume(sc);
3024 return (DDI_SUCCESS);
3025 default:
3026 return (DDI_FAILURE);
3027 }
3028
3029 instance = ddi_get_instance(devinfo);
3030 err = ddi_soft_state_zalloc(uath_soft_state_p, instance);
3031 if (err != DDI_SUCCESS) {
3032 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3033 "ddi_soft_state_zalloc failed\n");
3034 return (DDI_FAILURE);
3035 }
3036
3037 sc = ddi_get_soft_state(uath_soft_state_p, instance);
3038 ic = (ieee80211com_t *)&sc->sc_ic;
3039 sc->sc_dev = devinfo;
3040
3041 err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
3042 if (err != USB_SUCCESS) {
3043 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3044 "usb_client_attach failed\n");
3045 goto fail1;
3046 }
3047
3048 err = usb_get_dev_data(devinfo, &sc->sc_udev, USB_PARSE_LVL_ALL, 0);
3049 if (err != USB_SUCCESS) {
3050 sc->sc_udev = NULL;
3051 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3052 "usb_get_dev_data failed\n");
3053 goto fail2;
3054 }
3055
3056 vendor_id = sc->sc_udev->dev_descr->idVendor;
3057 product_id = sc->sc_udev->dev_descr->idProduct;
3058 sc->dev_flags = uath_lookup(vendor_id, product_id);
3059 if (sc->dev_flags == UATH_FLAG_ERR) {
3060 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3061 "HW does not match\n");
3062 goto fail2;
3063 }
3064
3065 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3066 "vendorId = %x,deviceID = %x, flags = %x\n",
3067 vendor_id, product_id, sc->dev_flags);
3068
3069 /*
3070 * We must open the pipes early because they're used to upload the
3071 * firmware (pre-firmware devices) or to send firmware commands.
3072 */
3073 err = uath_open_pipes(sc);
3074 if (err != UATH_SUCCESS) {
3075 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3076 "could not open pipes\n");
3077 goto fail3;
3078 }
3079
3080 if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
3081 err = uath_loadfirmware(sc);
3082 if (err != DDI_SUCCESS) {
3083 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3084 "could not read firmware %s, err %d\n",
3085 "uath-ar5523", err);
3086 goto fail3;
3087 }
3088
3089 uath_close_pipes(sc);
3090 usb_client_detach(sc->sc_dev, sc->sc_udev);
3091
3092 err = usb_reset_device(devinfo, USB_RESET_LVL_REATTACH);
3093 if (err != USB_SUCCESS) {
3094 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3095 "could not re-attach, err %d\n", err);
3096 goto fail1;
3097 }
3098 return (DDI_SUCCESS);
3099 }
3100
3101 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3102 "firmware download and re-attach successfully\n");
3103
3104 /*
3105 * Only post-firmware devices here.
3106 */
3107 mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
3108 mutex_init(&sc->sc_rxlock_cmd, NULL, MUTEX_DRIVER, NULL);
3109 mutex_init(&sc->sc_txlock_cmd, NULL, MUTEX_DRIVER, NULL);
3110 mutex_init(&sc->sc_rxlock_data, NULL, MUTEX_DRIVER, NULL);
3111 mutex_init(&sc->sc_txlock_data, NULL, MUTEX_DRIVER, NULL);
3112
3113 /*
3114 * Allocate xfers for firmware commands.
3115 */
3116 err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
3117 UATH_MAX_CMDSZ);
3118 if (err != UATH_SUCCESS) {
3119 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3120 "could not allocate Tx command list\n");
3121 goto fail4;
3122 }
3123
3124 err = uath_init_cmd_list(sc);
3125 if (err != UATH_SUCCESS) {
3126 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3127 "could not init RX command list\n");
3128 goto fail5;
3129 }
3130
3131 /*
3132 * We're now ready to send+receive firmware commands.
3133 */
3134 err = uath_host_available(sc);
3135 if (err != UATH_SUCCESS) {
3136 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3137 "could not initialize adapter\n");
3138 goto fail5;
3139 }
3140
3141 err = uath_get_devcap(sc);
3142 if (err != UATH_SUCCESS) {
3143 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3144 "could not get device capabilities\n");
3145 goto fail5;
3146 }
3147
3148 err = uath_get_devstatus(sc, ic->ic_macaddr);
3149 if (err != UATH_SUCCESS) {
3150 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3151 "could not get dev status\n");
3152 goto fail5;
3153 }
3154
3155 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3156 "MAC address is: %x:%x:%x:%x:%x:%x\n",
3157 ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
3158 ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]);
3159
3160 ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
3161 ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
3162 ic->ic_state = IEEE80211_S_INIT;
3163
3164 ic->ic_maxrssi = 40;
3165
3166 ic->ic_xmit = uath_send;
3167
3168 /* set device capabilities */
3169 ic->ic_caps =
3170 IEEE80211_C_TXPMGT | /* tx power management */
3171 IEEE80211_C_SHPREAMBLE | /* short preamble supported */
3172 IEEE80211_C_SHSLOT; /* short slot time supported */
3173
3174 ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
3175
3176 /* set supported .11b and .11g rates */
3177 ic->ic_sup_rates[IEEE80211_MODE_11B] = uath_rateset_11b;
3178 ic->ic_sup_rates[IEEE80211_MODE_11G] = uath_rateset_11g;
3179
3180 /* set supported .11b and .11g channels (1 through 11) */
3181 for (i = 1; i <= 11; i++) {
3182 ic->ic_sup_channels[i].ich_freq =
3183 ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
3184 ic->ic_sup_channels[i].ich_flags =
3185 IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
3186 IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
3187 }
3188
3189 ieee80211_attach(ic);
3190
3191 /* register WPA door */
3192 ieee80211_register_door(ic, ddi_driver_name(devinfo),
3193 ddi_get_instance(devinfo));
3194
3195 /* override state transition machine */
3196 sc->sc_newstate = ic->ic_newstate;
3197 ic->ic_newstate = uath_newstate;
3198 ieee80211_media_init(ic);
3199 ic->ic_def_txkey = 0;
3200
3201 sc->sc_flags = 0;
3202
3203 /*
3204 * Provide initial settings for the WiFi plugin; whenever this
3205 * information changes, we need to call mac_plugindata_update()
3206 */
3207 wd.wd_opmode = ic->ic_opmode;
3208 wd.wd_secalloc = WIFI_SEC_NONE;
3209 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
3210
3211 if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
3212 UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
3213 "MAC version mismatch\n");
3214 goto fail5;
3215 }
3216
3217 macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI;
3218 macp->m_driver = sc;
3219 macp->m_dip = devinfo;
3220 macp->m_src_addr = ic->ic_macaddr;
3221 macp->m_callbacks = &uath_m_callbacks;
3222 macp->m_min_sdu = 0;
3223 macp->m_max_sdu = IEEE80211_MTU;
3224 macp->m_pdata = &wd;
3225 macp->m_pdata_size = sizeof (wd);
3226
3227 err = mac_register(macp, &ic->ic_mach);
3228 mac_free(macp);
3229 if (err != 0) {
3230 UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
3231 "mac_register() error %x\n", err);
3232 goto fail5;
3233 };
3234
3235 err = usb_register_hotplug_cbs(devinfo,
3236 uath_disconnect, uath_reconnect);
3237 if (err != USB_SUCCESS) {
3238 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3239 "failed to register events\n");
3240 goto fail6;
3241 }
3242
3243 /*
3244 * Create minor node of type DDI_NT_NET_WIFI
3245 */
3246 (void) snprintf(strbuf, sizeof (strbuf), "%s%d",
3247 "uath", instance);
3248 err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
3249 instance + 1, DDI_NT_NET_WIFI, 0);
3250 if (err != DDI_SUCCESS)
3251 UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3252 "ddi_create_minor_node() failed\n");
3253
3254 /*
3255 * Notify link is down now
3256 */
3257 mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
3258
3259 UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3260 "attach success\n");
3261 return (DDI_SUCCESS);
3262
3263 fail6:
3264 (void) mac_unregister(ic->ic_mach);
3265 fail5:
3266 uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
3267 fail4:
3268 mutex_destroy(&sc->sc_genlock);
3269 mutex_destroy(&sc->sc_rxlock_cmd);
3270 mutex_destroy(&sc->sc_rxlock_data);
3271 mutex_destroy(&sc->sc_txlock_cmd);
3272 mutex_destroy(&sc->sc_txlock_data);
3273 fail3:
3274 uath_close_pipes(sc);
3275 fail2:
3276 usb_client_detach(sc->sc_dev, sc->sc_udev);
3277 fail1:
3278 ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
3279 return (DDI_FAILURE);
3280 }
3281
3282 static int
3283 uath_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
3284 {
3285 struct uath_softc *sc;
3286
3287 sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
3288 ASSERT(sc != NULL);
3289
3290 switch (cmd) {
3291 case DDI_DETACH:
3292 break;
3293 case DDI_SUSPEND:
3294 if (UATH_IS_RUNNING(sc)) {
3295 ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3296 uath_stop(sc);
3297 }
3298 UATH_LOCK(sc);
3299 sc->sc_flags &= ~UATH_FLAG_RUNNING;
3300 sc->sc_flags |= UATH_FLAG_SUSPEND;
3301 UATH_UNLOCK(sc);
3302 return (DDI_SUCCESS);
3303 default:
3304 return (DDI_FAILURE);
3305 }
3306
3307 if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
3308 ddi_soft_state_free(uath_soft_state_p,
3309 ddi_get_instance(devinfo));
3310 return (DDI_SUCCESS);
3311 }
3312
3313 if (!UATH_IS_DISCONNECT(sc) && UATH_IS_RUNNING(sc))
3314 uath_stop(sc);
3315
3316 uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
3317
3318 if (mac_disable(sc->sc_ic.ic_mach) != 0)
3319 return (DDI_FAILURE);
3320
3321 /*
3322 * Unregister from the MAC layer subsystem
3323 */
3324 if (mac_unregister(sc->sc_ic.ic_mach) != 0)
3325 return (DDI_FAILURE);
3326
3327 /*
3328 * detach ieee80211 layer
3329 */
3330 ieee80211_detach(&sc->sc_ic);
3331
3332 /* close Tx/Rx pipes */
3333 uath_close_pipes(sc);
3334 usb_unregister_hotplug_cbs(devinfo);
3335
3336 mutex_destroy(&sc->sc_genlock);
3337 mutex_destroy(&sc->sc_rxlock_cmd);
3338 mutex_destroy(&sc->sc_rxlock_data);
3339 mutex_destroy(&sc->sc_txlock_cmd);
3340 mutex_destroy(&sc->sc_txlock_data);
3341
3342 /* pipes will be close in uath_stop() */
3343 usb_client_detach(devinfo, sc->sc_udev);
3344 sc->sc_udev = NULL;
3345
3346 ddi_remove_minor_node(devinfo, NULL);
3347 ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
3348
3349 return (DDI_SUCCESS);
3350 }
3351
3352 int
3353 _info(struct modinfo *modinfop)
3354 {
3355 return (mod_info(&modlinkage, modinfop));
3356 }
3357
3358 int
3359 _init(void)
3360 {
3361 int status;
3362
3363 status = ddi_soft_state_init(&uath_soft_state_p,
3364 sizeof (struct uath_softc), 1);
3365 if (status != 0)
3366 return (status);
3367
3368 mac_init_ops(&uath_dev_ops, "uath");
3369 status = mod_install(&modlinkage);
3370 if (status != 0) {
3371 mac_fini_ops(&uath_dev_ops);
3372 ddi_soft_state_fini(&uath_soft_state_p);
3373 }
3374 return (status);
3375 }
3376
3377 int
3378 _fini(void)
3379 {
3380 int status;
3381
3382 status = mod_remove(&modlinkage);
3383 if (status == 0) {
3384 mac_fini_ops(&uath_dev_ops);
3385 ddi_soft_state_fini(&uath_soft_state_p);
3386 }
3387 return (status);
3388 }