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