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