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