2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2006 Sam Leffler, Errno Consulting
8 * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
37 * This driver is distantly derived from a driver of the same name
38 * by Damien Bergamini. The original copyright is included below:
41 * Damien Bergamini <damien.bergamini@free.fr>
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.
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.
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>
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>
76 static void *uath_soft_state_p
= NULL
;
79 * Bit flags in the ral_dbg_flags
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
91 uint32_t uath_dbg_flags
= 0;
101 * Various supported device vendors/products.
102 * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11b/g
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)
119 static const struct uath_type
{
120 struct uath_devno dev
;
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
)
150 static char uath_fwmod
[] = "uathfw";
151 static char uath_binmod
[] = "uathbin";
154 * Supported rates for 802.11b/g modes (in 500Kbps unit).
156 static const struct ieee80211_rateset uath_rateset_11b
=
157 { 4, { 2, 4, 11, 22 } };
159 static const struct ieee80211_rateset uath_rateset_11g
=
160 { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
165 static int uath_attach(dev_info_t
*, ddi_attach_cmd_t
);
166 static int uath_detach(dev_info_t
*, ddi_detach_cmd_t
);
169 * Module Loading Data & Entry Points
171 DDI_DEFINE_STREAM_OPS(uath_dev_ops
, nulldev
, nulldev
, uath_attach
,
172 uath_detach
, nodev
, NULL
, D_MP
, NULL
, ddi_quiesce_not_needed
);
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 */
180 static struct modlinkage modlinkage
= {
182 (void *)&uath_modldrv
,
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
,
198 static void uath_m_propinfo(void *, const char *, mac_prop_id_t
,
199 mac_prop_info_handle_t
);
201 static mac_callbacks_t uath_m_callbacks
= {
202 MC_IOCTL
| MC_SETPROP
| MC_GETPROP
| MC_PROPINFO
,
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);
227 uath_codename(int code
);
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);
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
*);
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 *,
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
*);
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
*);
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);
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
*);
304 uath_debug(uint32_t dbg_flags
, const int8_t *fmt
, ...)
308 if (dbg_flags
& uath_dbg_flags
) {
310 vcmn_err(CE_CONT
, fmt
, args
);
316 uath_lookup(uint16_t vendor_id
, uint16_t product_id
)
320 size
= sizeof (uath_devs
) / sizeof (struct uath_type
);
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
);
327 return (UATH_FLAG_ERR
);
331 * Return a specific alt_if from the device descriptor tree.
333 static usb_alt_if_data_t
*
334 uath_lookup_alt_if(usb_client_dev_data_t
*dev_data
, uint_t config
,
335 uint_t interface
, uint_t alt
)
337 usb_cfg_data_t
*cfg_data
;
338 usb_if_data_t
*if_data
;
339 usb_alt_if_data_t
*if_alt_data
;
342 * Assume everything is in the tree for now,
343 * (USB_PARSE_LVL_ALL)
344 * so we can directly index the array.
347 /* Descend to configuration, configs are 1-based */
348 if (config
< 1 || config
> dev_data
->dev_n_cfg
)
350 cfg_data
= &dev_data
->dev_cfg
[config
- 1];
352 /* Descend to interface */
353 if (interface
> cfg_data
->cfg_n_if
- 1)
355 if_data
= &cfg_data
->cfg_if
[interface
];
358 if (alt
> if_data
->if_n_alt
- 1)
360 if_alt_data
= &if_data
->if_alt
[alt
];
362 return (if_alt_data
);
366 * Print all endpoints of an alt_if.
369 uath_list_all_eps(usb_alt_if_data_t
*ifalt
)
371 usb_ep_data_t
*ep_data
;
372 usb_ep_descr_t
*ep_descr
;
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
);
385 static usb_ep_data_t
*
386 uath_lookup_ep_data(dev_info_t
*dip
,
387 usb_client_dev_data_t
*dev_datap
,
393 usb_alt_if_data_t
*altif_data
;
396 if ((dip
== NULL
) || (dev_datap
== NULL
))
399 altif_data
= &dev_datap
->dev_curr_cfg
->
400 cfg_if
[interface
].if_alt
[alternate
];
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
;
407 if (ept
->bLength
== 0)
409 if ((ept_type
== type
) &&
410 ((type
== USB_EP_ATTR_CONTROL
) || (address
== ept_address
)))
411 return (&altif_data
->altif_ep
[i
]);
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
425 uath_open_pipes(struct uath_softc
*sc
)
427 usb_ep_data_t
*ep_node
;
428 usb_ep_descr_t
*ep_descr
;
429 usb_pipe_policy_t policy
;
433 usb_alt_if_data_t
*altif_data
;
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
);
442 uath_list_all_eps(altif_data
);
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.
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
);
456 bzero(&policy
, sizeof (usb_pipe_policy_t
));
457 policy
.pp_max_async_reqs
= UATH_CMD_LIST_COUNT
;
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",
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(): "
474 ep_descr
->bEndpointAddress
);
476 bzero(&policy
, sizeof (usb_pipe_policy_t
));
477 policy
.pp_max_async_reqs
= UATH_CMD_LIST_COUNT
;
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",
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(): "
493 ep_descr
->bEndpointAddress
);
495 bzero(&policy
, sizeof (usb_pipe_policy_t
));
496 policy
.pp_max_async_reqs
= UATH_RX_DATA_LIST_COUNT
;
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",
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(): "
512 ep_descr
->bEndpointAddress
);
514 bzero(&policy
, sizeof (usb_pipe_policy_t
));
515 policy
.pp_max_async_reqs
= UATH_TX_DATA_LIST_COUNT
;
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",
526 return (UATH_SUCCESS
);
528 uath_close_pipes(sc
);
533 uath_close_pipes(struct uath_softc
*sc
)
535 usb_flags_t flags
= USB_FLAGS_SLEEP
;
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
;
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
;
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
;
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
;
564 uath_codename(int code
)
566 #define N(a) (sizeof (a)/sizeof (a[0]))
567 static const char *names
[] = {
572 "TARGET_GET_CAPABILITY",
581 "UPDATE_CONNECT_ATTR",
597 "RESET_KEY_CACHE_ENTRY",
598 "SET_KEY_CACHE_ENTRY",
600 "SET_REGULATORY_DOMAIN",
603 "SET_STA_BEACON_TIMERS",
611 "SET_ANTENNA_SWITCH",
612 "0x2c", "0x2d", "0x2e",
613 "USE_SHORT_SLOT_TIME",
616 "SET_RX_MULTICAST_FILTER",
622 "SET_TX_POWER_LIMIT",
623 "SET_TX_QUEUE_PARAMS",
630 return (names
[code
]);
631 if (code
== WDCMSG_SET_DEFAULT_KEY
)
632 return ("SET_DEFAULT_KEY");
634 (void) snprintf(buf
, sizeof (buf
), "0x%02x", code
);
640 uath_fw_send(struct uath_softc
*sc
, usb_pipe_handle_t pipe
,
641 const void *data
, size_t len
)
643 usb_bulk_req_t
*send_req
;
647 send_req
= usb_alloc_bulk_req(sc
->sc_dev
, len
, USB_FLAGS_SLEEP
);
649 send_req
->bulk_len
= (int)len
;
650 send_req
->bulk_attributes
= USB_ATTRS_AUTOCLEARING
;
651 send_req
->bulk_timeout
= UATH_CMD_TIMEOUT
;
653 mblk
= send_req
->bulk_data
;
654 bcopy(data
, mblk
->b_wptr
, len
);
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
);
664 usb_free_bulk_req(send_req
);
665 return (UATH_SUCCESS
);
669 uath_fw_ack(struct uath_softc
*sc
, int len
)
671 struct uath_fwblock
*rxblock
;
676 req
= usb_alloc_bulk_req(sc
->sc_dev
, len
, USB_FLAGS_SLEEP
);
678 UATH_DEBUG(UATH_DBG_FW
,
679 "uath: uath_fw_ack(): "
680 "uath_rx_transfer(): failed to allocate req");
681 return (UATH_FAILURE
);
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
;
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
);
699 req
->bulk_data
= NULL
;
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
));
707 usb_free_bulk_req(req
);
709 return (UATH_SUCCESS
);
713 * find uath firmware module's "_start" "_end" symbols
717 uath_loadsym(ddi_modhandle_t modp
, char *sym
, char **start
, size_t *len
)
725 (void) snprintf(start_sym
, sizeof (start_sym
), "%s_start", sym
);
726 (void) snprintf(end_sym
, sizeof (end_sym
), "%s_end", sym
);
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
);
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
);
742 n
= _PTRDIFF(end
, p
);
746 return (UATH_SUCCESS
);
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
756 uath_loadfirmware(struct uath_softc
*sc
)
758 struct uath_fwblock txblock
;
759 ddi_modhandle_t modp
;
760 char *fw_index
, *fw_image
= NULL
;
762 int err
= DDI_SUCCESS
, rv
= 0;
764 modp
= ddi_modopen(uath_fwmod
, KRTLD_MODE_FIRST
, &rv
);
766 cmn_err(CE_WARN
, "uath: uath_loadfirmware(): "
767 "module %s not found\n", uath_fwmod
);
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");
778 fw_image
= 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");
786 (void) memcpy(fw_image
, fw_index
, fw_size
);
789 UATH_DEBUG(UATH_DBG_MSG
, "loading firmware size = %lu\n", fw_size
);
791 /* bzero(txblock, sizeof (struct uath_fwblock)); */
792 txblock
.flags
= BE_32(UATH_WRITE_BLOCK
);
793 txblock
.total
= BE_32(fw_size
);
796 size_t mlen
= min(len
, UATH_MAX_FWBLOCK_SIZE
);
798 txblock
.remain
= BE_32(len
- mlen
);
799 txblock
.len
= BE_32(mlen
);
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",
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");
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");
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() "
837 if (fw_image
!= NULL
)
838 kmem_free(fw_image
, fw_size
);
839 fw_image
= fw_index
= NULL
;
841 (void) ddi_modclose(modp
);
846 uath_alloc_cmd_list(struct uath_softc
*sc
, struct uath_cmd cmds
[],
851 for (i
= 0; i
< ncmd
; i
++) {
852 struct uath_cmd
*cmd
= &cmds
[i
];
854 cmd
->sc
= sc
; /* backpointer for callbacks */
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");
864 return (UATH_SUCCESS
);
867 uath_free_cmd_list(cmds
, ncmd
);
872 uath_init_cmd_list(struct uath_softc
*sc
)
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
);
884 return (UATH_SUCCESS
);
888 uath_free_cmd_list(struct uath_cmd cmds
[], int ncmd
)
892 for (i
= 0; i
< ncmd
; i
++)
893 if (cmds
[i
].buf
!= NULL
) {
894 kmem_free(cmds
[i
].buf
, UATH_MAX_CMDSZ
);
900 uath_host_available(struct uath_softc
*sc
)
902 struct uath_cmd_host_available setup
;
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));
914 uath_get_capability(struct uath_softc
*sc
, uint32_t cap
, uint32_t *val
)
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
)
924 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_get_capability(): "
925 "could not read capability %u\n", BE_32(cap
));
929 uath_get_devcap(struct uath_softc
*sc
)
931 struct uath_devcap
*cap
= &sc
->sc_devcap
;
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
,
940 uath_get_capability(sc
, CAP_MAC_REVISION
,
942 uath_get_capability(sc
, CAP_PHY_REVISION
,
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
,
950 uath_get_capability(sc
, CAP_REG_CAP_BITS
,
953 /* NB: not supported in rev 1.5 */
954 /* uath_get_capability(sc, CAP_COUNTRY_CODE, cap->countryCode); */
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
,
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
,
974 uath_get_capability(sc
, CAP_WME_SUPPORT
,
976 uath_get_capability(sc
, CAP_TOTAL_QUEUES
,
978 uath_get_capability(sc
, CAP_CONNECTION_ID_MAX
,
979 &cap
->connectionIdMax
);
981 uath_get_capability(sc
, CAP_LOW_5GHZ_CHAN
,
983 uath_get_capability(sc
, CAP_HIGH_5GHZ_CHAN
,
985 uath_get_capability(sc
, CAP_LOW_2GHZ_CHAN
,
987 uath_get_capability(sc
, CAP_HIGH_2GHZ_CHAN
,
989 uath_get_capability(sc
, CAP_TWICE_ANTENNAGAIN_5G
,
990 &cap
->twiceAntennaGain5G
);
991 uath_get_capability(sc
, CAP_TWICE_ANTENNAGAIN_2G
,
992 &cap
->twiceAntennaGain2G
);
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
);
1001 cap
->supportCipherWEP
= 1; /* NB: always available */
1002 return (UATH_SUCCESS
);
1006 uath_get_status(struct uath_softc
*sc
, uint32_t which
, void *odata
, int olen
)
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
));
1020 uath_get_devstatus(struct uath_softc
*sc
, uint8_t macaddr
[IEEE80211_ADDR_LEN
])
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");
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");
1040 return (UATH_SUCCESS
);
1044 * uath_cmd_lock: a special signal structure that is used for notification
1045 * that a callback function has been called.
1048 /* Initializes the uath_cmd_lock structure. */
1050 uath_cmd_lock_init(struct uath_cmd_lock
*lock
)
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
;
1058 /* Deinitalizes the uath_cb_lock structure. */
1060 uath_cmd_lock_destroy(struct uath_cmd_lock
*lock
)
1062 ASSERT(lock
!= NULL
);
1063 mutex_destroy(&lock
->mutex
);
1064 cv_destroy(&lock
->cv
);
1068 * Wait on lock until someone calls the "signal" function or the timeout
1069 * expires. Note: timeout is in microseconds.
1072 uath_cmd_lock_wait(struct uath_cmd_lock
*lock
, clock_t timeout
)
1077 ASSERT(lock
!= NULL
);
1078 mutex_enter(&lock
->mutex
);
1081 /* no timeout - wait as long as needed */
1082 while (lock
->done
== B_FALSE
)
1083 cv_wait(&lock
->cv
, &lock
->mutex
);
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;
1094 res
= (lock
->done
== B_TRUE
) ? UATH_SUCCESS
: UATH_FAILURE
;
1095 mutex_exit(&lock
->mutex
);
1100 /* Signal that the job (eg. callback) is done and unblock anyone who waits. */
1102 uath_cmd_lock_signal(struct uath_cmd_lock
*lock
)
1104 ASSERT(lock
!= NULL
);
1106 mutex_enter(&lock
->mutex
);
1107 lock
->done
= B_TRUE
;
1108 cv_broadcast(&lock
->cv
);
1109 mutex_exit(&lock
->mutex
);
1113 uath_cmd_read(struct uath_softc
*sc
, uint32_t code
, const void *idata
,
1114 int ilen
, void *odata
, int olen
, int flags
)
1116 flags
|= UATH_CMD_FLAG_READ
;
1117 return (uath_cmdsend(sc
, code
, idata
, ilen
, odata
, olen
, flags
));
1121 uath_cmd_write(struct uath_softc
*sc
, uint32_t code
, const void *data
,
1124 flags
&= ~UATH_CMD_FLAG_READ
;
1125 return (uath_cmdsend(sc
, code
, data
, len
, NULL
, 0, flags
));
1129 * Low-level function to send read or write commands to the firmware.
1132 uath_cmdsend(struct uath_softc
*sc
, uint32_t code
, const void *idata
, int ilen
,
1133 void *odata
, int olen
, int flags
)
1135 struct uath_cmd_hdr
*hdr
;
1136 struct uath_cmd
*cmd
;
1140 cmd
= &sc
->sc_cmd
[sc
->sc_cmdid
];
1143 /* always bulk-out a multiple of 4 bytes */
1144 cmd
->buflen
= (sizeof (struct uath_cmd_hdr
) + ilen
+ 3) & ~3;
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
);
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
);
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");
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
);
1174 sc
->sc_cmdid
= (sc
->sc_cmdid
+ 1) % UATH_CMD_LIST_COUNT
;
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
);
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
);
1194 uath_cmd_lock_destroy(&sc
->rlock
);
1198 return (UATH_SUCCESS
);
1203 uath_cmd_txeof(usb_pipe_handle_t pipe
, struct usb_bulk_req
*req
)
1205 struct uath_softc
*sc
= (struct uath_softc
*)req
->bulk_client_private
;
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
,
1214 if (req
->bulk_completion_reason
!= USB_CR_OK
)
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
);
1224 uath_tx_cmd_xfer(struct uath_softc
*sc
,
1225 usb_pipe_handle_t pipe
, const void *data
, uint_t len
)
1227 usb_bulk_req_t
*send_req
;
1231 send_req
= usb_alloc_bulk_req(sc
->sc_dev
, len
, USB_FLAGS_SLEEP
);
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;
1242 mblk
= send_req
->bulk_data
;
1243 bcopy(data
, mblk
->b_rptr
, len
);
1244 mblk
->b_wptr
+= len
;
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
);
1253 mutex_enter(&sc
->sc_txlock_cmd
);
1254 sc
->tx_cmd_queued
++;
1255 mutex_exit(&sc
->sc_txlock_cmd
);
1256 return (UATH_SUCCESS
);
1260 uath_cmdeof(struct uath_softc
*sc
, struct uath_cmd
*cmd
)
1262 struct uath_cmd_hdr
*hdr
;
1265 hdr
= (struct uath_cmd_hdr
*)cmd
->buf
;
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 */
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
),
1279 switch (hdr
->code
& 0xff) {
1280 /* reply to a read command */
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
);
1288 * The first response from the target after the
1289 * HOST_AVAILABLE has an invalid msgid so we must
1290 * treat it specially.
1292 if ((hdr
->msgid
< UATH_CMD_LIST_COUNT
) && (hdr
->code
!= 0x13)) {
1293 uint32_t *rp
= (uint32_t *)(hdr
+ 1);
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; "
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.
1312 if (dlen
>= sizeof (uint32_t)) {
1313 olen
= BE_32(rp
[0]);
1314 dlen
-= sizeof (uint32_t);
1316 /* convention is 0 =>'s one word */
1317 olen
= sizeof (uint32_t);
1318 /* XXX KASSERT(olen == dlen ) */
1323 if (cmd
->odata
!= NULL
) {
1324 /* NB: cmd->olen validated in uath_cmd */
1325 if (olen
> cmd
->olen
) {
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
);
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
);
1341 /* XXX have submitter do this */
1342 /* copy answer into caller's supplied buffer */
1343 bcopy(&rp
[1], cmd
->odata
, olen
);
1348 /* Just signal that something happened */
1349 uath_cmd_lock_signal(&sc
->rlock
);
1352 case WDCMSG_TARGET_START
:
1353 UATH_DEBUG(UATH_DBG_RX_CMD
, "uath: uath_cmdeof(): "
1354 "receive TARGET STAERT\n");
1356 if (hdr
->msgid
>= UATH_CMD_LIST_COUNT
) {
1360 dlen
= hdr
->len
- sizeof (*hdr
);
1361 if (dlen
!= sizeof (uint32_t)) {
1362 /* XXX something wrong */
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);
1370 /* wake up caller */
1371 uath_cmd_lock_signal(&sc
->rlock
);
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");
1380 case WDCMSG_TARGET_GET_STATS
:
1381 UATH_DEBUG(UATH_DBG_RX_CMD
, "uath: uath_cmdeof(): "
1382 "received device statistics\n");
1389 uath_cmd_rxeof(usb_pipe_handle_t pipe
, usb_bulk_req_t
*req
)
1391 struct uath_softc
*sc
= (struct uath_softc
*)req
->bulk_client_private
;
1392 struct uath_cmd_hdr
*hdr
;
1393 struct uath_cmd
*cmd
;
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
,
1405 req
->bulk_data
= NULL
;
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");
1413 if (m
->b_cont
!= NULL
) {
1414 /* Fragmented message, concatenate */
1415 mp
= msgpullup(m
, -1);
1422 if (len
< sizeof (struct uath_cmd_hdr
)) {
1423 UATH_DEBUG(UATH_DBG_RX_CMD
, "uath: uath_rx_cmdeof(): "
1424 "short xfer error\n");
1428 hdr
= (struct uath_cmd_hdr
*)m
->b_rptr
;
1429 if (BE_32(hdr
->code
) == 0x13)
1430 cmd
= &sc
->sc_cmd
[0];
1432 cmd
= &sc
->sc_cmd
[hdr
->msgid
];
1434 bcopy(m
->b_rptr
, cmd
->buf
, len
);
1435 uath_cmdeof(sc
, cmd
);
1436 (void) uath_rx_cmd_xfer(sc
);
1438 mutex_enter(&sc
->sc_rxlock_cmd
);
1439 sc
->rx_cmd_queued
--;
1440 mutex_exit(&sc
->sc_rxlock_cmd
);
1442 usb_free_bulk_req(req
);
1446 uath_rx_cmd_xfer(struct uath_softc
*sc
)
1448 usb_bulk_req_t
*req
;
1451 req
= usb_alloc_bulk_req(sc
->sc_dev
, UATH_MAX_CMDSZ
, USB_FLAGS_SLEEP
);
1453 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_rx_cmd_xfer(): "
1454 "failed to allocate req");
1455 return (UATH_FAILURE
);
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
;
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
);
1476 mutex_enter(&sc
->sc_rxlock_cmd
);
1477 sc
->rx_cmd_queued
++;
1478 mutex_exit(&sc
->sc_rxlock_cmd
);
1479 return (UATH_SUCCESS
);
1483 uath_init_data_queue(struct uath_softc
*sc
)
1485 sc
->tx_data_queued
= sc
->rx_data_queued
= 0;
1490 uath_data_txeof(usb_pipe_handle_t pipe
, usb_bulk_req_t
*req
)
1492 struct uath_softc
*sc
= (struct uath_softc
*)req
->bulk_client_private
;
1493 struct ieee80211com
*ic
= &sc
->sc_ic
;
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
,
1500 sc
->tx_data_queued
);
1502 if (req
->bulk_completion_reason
!= USB_CR_OK
)
1505 mutex_enter(&sc
->sc_txlock_data
);
1506 sc
->tx_data_queued
--;
1508 if (sc
->sc_need_sched
) {
1509 sc
->sc_need_sched
= 0;
1510 mac_tx_update(ic
->ic_mach
);
1513 mutex_exit(&sc
->sc_txlock_data
);
1514 usb_free_bulk_req(req
);
1518 uath_tx_data_xfer(struct uath_softc
*sc
, mblk_t
*mp
)
1520 usb_bulk_req_t
*req
;
1523 req
= usb_alloc_bulk_req(sc
->sc_dev
, 0, USB_FLAGS_SLEEP
);
1525 UATH_DEBUG(UATH_DBG_TX
, "uath: uath_tx_data_xfer(): "
1526 "uath_tx_data_xfer(): failed to allocate req");
1528 return (UATH_FAILURE
);
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;
1541 if ((err
= usb_pipe_bulk_xfer(sc
->tx_data_pipe
, req
, 0)) !=
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
);
1550 sc
->tx_data_queued
++;
1551 return (UATH_SUCCESS
);
1556 uath_data_rxeof(usb_pipe_handle_t pipe
, usb_bulk_req_t
*req
)
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
;
1569 mutex_enter(&sc
->sc_rxlock_data
);
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
,
1576 sc
->rx_data_queued
);
1578 mp
= req
->bulk_data
;
1579 req
->bulk_data
= NULL
;
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");
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
);
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
);
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
);
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
);
1628 /* if the frame is not final continue the transfer */
1629 if (!(chunk
->flags
& UATH_CFLAGS_FINAL
))
1630 sc
->sc_intrx_nextnum
++;
1633 * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is
1634 * located at the end, 32-bit aligned
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
));
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
));
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
);
1658 uath_update_rxstat(sc
, BE_32(desc
->status
));
1660 pktlen
= BE_32(desc
->framelen
) - UATH_RX_DUMMYSIZE
;
1662 if ((m
= allocb(pktlen
, BPRI_MED
)) == NULL
) {
1663 UATH_DEBUG(UATH_DBG_RX
, "uath: uath_data_rxeof(): "
1664 "allocate mblk failed.\n");
1668 bcopy((rxbuf
+ sizeof (struct uath_chunk
)), m
->b_rptr
, pktlen
);
1670 m
->b_wptr
= m
->b_rptr
+ pktlen
;
1671 wh
= (struct ieee80211_frame
*)m
->b_rptr
;
1672 ni
= ieee80211_find_rxnode(ic
, wh
);
1674 /* send the frame to the 802.11 layer */
1675 (void) ieee80211_input(ic
, m
, ni
, (int)BE_32(desc
->rssi
), 0);
1677 /* node is no longer needed */
1678 ieee80211_free_node(ni
);
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
);
1690 uath_rx_data_xfer(struct uath_softc
*sc
)
1692 usb_bulk_req_t
*req
;
1695 req
= usb_alloc_bulk_req(sc
->sc_dev
,
1696 IEEE80211_MAX_LEN
, USB_FLAGS_SLEEP
);
1698 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_rx_data_xfer(): "
1699 "failed to allocate req");
1700 return (UATH_SUCCESS
);
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
;
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
);
1721 mutex_enter(&sc
->sc_rxlock_data
);
1722 sc
->rx_data_queued
++;
1723 mutex_exit(&sc
->sc_rxlock_data
);
1724 return (UATH_SUCCESS
);
1728 uath_update_rxstat(struct uath_softc
*sc
, uint32_t status
)
1732 case UATH_STATUS_STOP_IN_PROGRESS
:
1733 UATH_STAT_INC(sc
, st_stopinprogress
);
1735 case UATH_STATUS_CRC_ERR
:
1736 UATH_STAT_INC(sc
, st_crcerr
);
1738 case UATH_STATUS_PHY_ERR
:
1739 UATH_STAT_INC(sc
, st_phyerr
);
1741 case UATH_STATUS_DECRYPT_CRC_ERR
:
1742 UATH_STAT_INC(sc
, st_decrypt_crcerr
);
1744 case UATH_STATUS_DECRYPT_MIC_ERR
:
1745 UATH_STAT_INC(sc
, st_decrypt_micerr
);
1747 case UATH_STATUS_DECOMP_ERR
:
1748 UATH_STAT_INC(sc
, st_decomperr
);
1750 case UATH_STATUS_KEY_ERR
:
1751 UATH_STAT_INC(sc
, st_keyerr
);
1753 case UATH_STATUS_ERR
:
1754 UATH_STAT_INC(sc
, st_err
);
1762 uath_next_scan(void *arg
)
1764 struct uath_softc
*sc
= arg
;
1765 struct ieee80211com
*ic
= &sc
->sc_ic
;
1767 if (ic
->ic_state
== IEEE80211_S_SCAN
)
1768 ieee80211_next_scan(ic
);
1774 uath_create_connection(struct uath_softc
*sc
, uint32_t connid
)
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
;
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
));
1789 create
.connattr
.rateset
.length
= rs
->ir_nrates
;
1790 bcopy(rs
->ir_rates
, &create
.connattr
.rateset
.set
[0],
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
);
1799 create
.connattr
.wlanmode
= BE_32(WLAN_MODE_11b
);
1801 err
= uath_cmd_write(sc
, WDCMSG_CREATE_CONNECTION
, &create
,
1802 sizeof (create
), 0);
1807 uath_set_rates(struct uath_softc
*sc
, const struct ieee80211_rateset
*rs
)
1809 struct uath_cmd_rates rates
;
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
);
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);
1827 uath_write_associd(struct uath_softc
*sc
)
1829 struct ieee80211com
*ic
= &sc
->sc_ic
;
1830 struct ieee80211_node
*ni
= ic
->ic_bss
;
1831 struct uath_cmd_set_associd associd
;
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);
1845 uath_set_ledsteady(struct uath_softc
*sc
, int lednum
, int ledmode
)
1847 struct uath_cmd_ledsteady led
;
1850 led
.lednum
= BE_32(lednum
);
1851 led
.ledmode
= BE_32(ledmode
);
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);
1862 uath_set_ledblink(struct uath_softc
*sc
, int lednum
, int ledmode
,
1863 int blinkrate
, int slowmode
)
1865 struct uath_cmd_ledblink led
;
1868 led
.lednum
= BE_32(lednum
);
1869 led
.ledmode
= BE_32(ledmode
);
1870 led
.blinkrate
= BE_32(blinkrate
);
1871 led
.slowmode
= BE_32(slowmode
);
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");
1878 err
= uath_cmd_write(sc
, WDCMSG_SET_LED_BLINK
,
1879 &led
, sizeof (led
), 0);
1885 uath_newstate(struct ieee80211com
*ic
, enum ieee80211_state nstate
, int arg
)
1887 struct uath_softc
*sc
= (struct uath_softc
*)ic
;
1888 struct ieee80211_node
*ni
= ic
->ic_bss
;
1889 enum ieee80211_state ostate
;
1892 ostate
= ic
->ic_state
;
1893 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_newstate(): "
1894 "%d -> %d\n", ostate
, nstate
);
1896 if (sc
->sc_scan_id
!= 0) {
1897 (void) untimeout(sc
->sc_scan_id
);
1903 if (UATH_IS_DISCONNECT(sc
) && (nstate
!= IEEE80211_S_INIT
)) {
1905 return (DDI_SUCCESS
);
1908 if (UATH_IS_SUSPEND(sc
) && (nstate
!= IEEE80211_S_INIT
)) {
1910 return (DDI_SUCCESS
);
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);
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");
1926 sc
->sc_scan_id
= timeout(uath_next_scan
, (void *)sc
,
1927 drv_usectohz(250000));
1929 case IEEE80211_S_AUTH
:
1930 /* XXX good place? set RTS threshold */
1931 uath_config(sc
, CFG_USER_RTS_THRESHOLD
, ic
->ic_rtsthreshold
);
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");
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");
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");
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);
1959 * Tx rate is controlled by firmware, report the maximum
1960 * negotiated rate in ifconfig output.
1962 ni
->in_txrate
= ni
->in_rates
.ir_nrates
- 1;
1964 if (uath_write_associd(sc
) != 0) {
1965 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_newstate(): "
1966 "could not write association id\n");
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
,
1974 /* set state to associated */
1975 (void) uath_set_ledstate(sc
, 1);
1981 err
= sc
->sc_newstate(ic
, nstate
, arg
);
1986 uath_send(ieee80211com_t
*ic
, mblk_t
*mp
, uint8_t type
)
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
;
1996 int err
, off
, mblen
;
1997 int pktlen
, framelen
, msglen
;
2001 mutex_enter(&sc
->sc_txlock_data
);
2003 if (UATH_IS_SUSPEND(sc
)) {
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;
2020 m
= allocb(UATH_MAX_TXBUFSZ
, BPRI_MED
);
2022 UATH_DEBUG(UATH_DBG_TX
, "uath: uath_send(): "
2023 "can't alloc mblk.\n");
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
);
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
);
2039 wh
= (struct ieee80211_frame
*)m
->b_rptr
;
2041 ni
= ieee80211_find_txnode(ic
, wh
->i_addr1
);
2048 if ((type
& IEEE80211_FC0_TYPE_MASK
) ==
2049 IEEE80211_FC0_TYPE_DATA
) {
2050 (void) ieee80211_encap(ic
, m
, ni
);
2053 if (wh
->i_fc
[1] & IEEE80211_FC1_WEP
) {
2054 k
= ieee80211_crypto_encap(ic
, m
);
2060 /* packet header may have moved, reset our local pointer */
2061 wh
= (struct ieee80211_frame
*)m
->b_rptr
;
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
);
2068 m
->b_rptr
-= sizeof (struct uath_chunk
) + sizeof (struct uath_tx_desc
);
2070 chunk
= (struct uath_chunk
*)m
->b_rptr
;
2071 desc
= (struct uath_tx_desc
*)(chunk
+ 1);
2073 /* one chunk only for now */
2075 chunk
->flags
= UATH_CFLAGS_FINAL
;
2076 chunk
->length
= BE_16(msglen
);
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
);
2091 desc
->txqid
= BE_32(WME_AC_BE
| UATH_TXQID_MINRATE
);
2093 case IEEE80211_FC0_TYPE_DATA
:
2094 /* XXX multicast frames should honor mcastrate */
2095 desc
->txqid
= BE_32(WME_AC_BE
);
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
);
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
);
2110 desc
->connid
= BE_32(UATH_ID_INVALID
);
2111 desc
->flags
= BE_32(0 /* no UATH_TX_NOTIFY */);
2112 desc
->buflen
= BE_32(pktlen
);
2114 (void) uath_tx_data_xfer(sc
, m
);
2116 sc
->sc_msgid
= (sc
->sc_msgid
+ 1) % UATH_TX_DATA_LIST_COUNT
;
2118 ic
->ic_stats
.is_tx_frags
++;
2119 ic
->ic_stats
.is_tx_bytes
+= pktlen
;
2123 ieee80211_free_node(ni
);
2125 ((type
& IEEE80211_FC0_TYPE_MASK
) != IEEE80211_FC0_TYPE_DATA
||
2129 mutex_exit(&sc
->sc_txlock_data
);
2134 uath_reconnect(dev_info_t
*devinfo
)
2136 struct uath_softc
*sc
;
2137 struct ieee80211com
*ic
;
2139 uint16_t vendor_id
, product_id
;
2141 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_reconnect(): "
2144 sc
= ddi_get_soft_state(uath_soft_state_p
, ddi_get_instance(devinfo
));
2146 ic
= (struct ieee80211com
*)&sc
->sc_ic
;
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
);
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
);
2163 uath_close_pipes(sc
);
2164 usb_client_detach(sc
->sc_dev
, sc
->sc_udev
);
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
);
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");
2179 err
= usb_get_dev_data(devinfo
, &sc
->sc_udev
,
2180 USB_PARSE_LVL_ALL
, 0);
2181 if (err
!= USB_SUCCESS
) {
2183 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_reconnect(): "
2184 "usb_get_dev_data failed\n");
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");
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
);
2200 sc
->sc_flags
|= UATH_FLAG_RECONNECT
;
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
);
2212 * Allocate xfers for firmware commands.
2214 err
= uath_alloc_cmd_list(sc
, sc
->sc_cmd
, UATH_CMD_LIST_COUNT
,
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
);
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
);
2230 * We're now ready to send+receive firmware commands.
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
);
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
);
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
);
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
);
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
);
2269 sc
->sc_flags
&= ~UATH_FLAG_RECONNECT
;
2270 sc
->sc_flags
&= ~UATH_FLAG_DISCONNECT
;
2271 sc
->sc_flags
|= UATH_FLAG_RUNNING
;
2275 return (DDI_SUCCESS
);
2279 uath_disconnect(dev_info_t
*devinfo
)
2281 struct uath_softc
*sc
;
2282 struct ieee80211com
*ic
;
2285 * We can't call uath_stop() here, since the hardware is removed,
2286 * we can't access the register anymore.
2288 sc
= ddi_get_soft_state(uath_soft_state_p
, ddi_get_instance(devinfo
));
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
);
2299 sc
->sc_flags
|= UATH_FLAG_DISCONNECT
;
2302 ic
= (struct ieee80211com
*)&sc
->sc_ic
;
2303 ieee80211_new_state(ic
, IEEE80211_S_INIT
, -1);
2306 sc
->sc_flags
&= ~UATH_FLAG_RUNNING
; /* STOP */
2309 /* abort and free xfers */
2310 uath_free_cmd_list(sc
->sc_cmd
, UATH_CMD_LIST_COUNT
);
2312 /* close Tx/Rx pipes */
2313 uath_close_pipes(sc
);
2315 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_disconnect(): "
2316 "offline success\n");
2318 return (DDI_SUCCESS
);
2322 uath_dataflush(struct uath_softc
*sc
)
2324 struct uath_chunk
*chunk
;
2325 struct uath_tx_desc
*desc
;
2329 buf
= kmem_alloc(UATH_MAX_TXBUFSZ
, KM_NOSLEEP
);
2331 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_dataflush(): "
2336 chunk
= (struct uath_chunk
*)buf
;
2337 desc
= (struct uath_tx_desc
*)(chunk
+ 1);
2339 /* one chunk only */
2341 chunk
->flags
= UATH_CFLAGS_FINAL
;
2342 chunk
->length
= BE_16(sizeof (struct uath_tx_desc
));
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);
2352 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_dataflush(): "
2353 "send flush ix %d\n", desc
->msgid
);
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
);
2363 kmem_free(buf
, UATH_MAX_TXBUFSZ
);
2364 sc
->sc_msgid
= (sc
->sc_msgid
+ 1) % UATH_TX_DATA_LIST_COUNT
;
2366 return (UATH_SUCCESS
);
2370 uath_cmdflush(struct uath_softc
*sc
)
2372 return (uath_cmd_write(sc
, WDCMSG_FLUSH
, NULL
, 0, 0));
2376 uath_flush(struct uath_softc
*sc
)
2380 err
= uath_dataflush(sc
);
2381 if (err
!= UATH_SUCCESS
)
2384 err
= uath_cmdflush(sc
);
2385 if (err
!= UATH_SUCCESS
)
2388 return (UATH_SUCCESS
);
2394 uath_set_ledstate(struct uath_softc
*sc
, int connected
)
2398 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_set_ledstate(): "
2399 "set led state %sconnected\n", connected
? "" : "!");
2401 connected
= BE_32(connected
);
2402 err
= uath_cmd_write(sc
, WDCMSG_SET_LED_STATE
,
2403 &connected
, sizeof (connected
), 0);
2408 uath_config_multi(struct uath_softc
*sc
, uint32_t reg
, const void *data
,
2411 struct uath_write_mac write
;
2414 write
.reg
= BE_32(reg
);
2415 write
.len
= BE_32(len
);
2416 bcopy(data
, write
.data
, len
);
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
);
2429 uath_config(struct uath_softc
*sc
, uint32_t reg
, uint32_t val
)
2431 struct uath_write_mac write
;
2434 write
.reg
= BE_32(reg
);
2435 write
.len
= BE_32(0); /* 0 = single write */
2436 *(uint32_t *)write
.data
= BE_32(val
);
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",
2448 uath_switch_channel(struct uath_softc
*sc
, struct ieee80211_channel
*c
)
2452 /* set radio frequency */
2453 err
= uath_set_chan(sc
, c
);
2455 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_switch_channel(): "
2456 "could not set channel\n");
2460 /* reset Tx rings */
2461 err
= uath_reset_tx_queues(sc
);
2463 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_switch_channel(): "
2464 "could not reset Tx queues\n");
2468 /* set Tx rings WME properties */
2469 err
= uath_wme_init(sc
);
2471 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_switch_channel(): "
2472 "could not init Tx queues\n");
2476 err
= uath_set_ledstate(sc
, 0);
2478 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_switch_channel(): "
2479 "could not set led state\n");
2483 err
= uath_flush(sc
);
2485 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_switch_channel(): "
2486 "could not flush pipes\n");
2495 uath_set_rxfilter(struct uath_softc
*sc
, uint32_t bits
, uint32_t op
)
2497 struct uath_cmd_rx_filter rxfilter
;
2499 rxfilter
.bits
= BE_32(bits
);
2500 rxfilter
.op
= BE_32(op
);
2502 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_set_rxfilter(): "
2503 "setting Rx filter=0x%x flags=0x%x\n", bits
, op
);
2505 return ((uath_cmd_write(sc
, WDCMSG_RX_FILTER
, &rxfilter
,
2506 sizeof (rxfilter
), 0)));
2510 uath_set_chan(struct uath_softc
*sc
, struct ieee80211_channel
*c
)
2512 struct ieee80211com
*ic
= &sc
->sc_ic
;
2513 struct uath_cmd_reset reset
;
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
);
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);
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
));
2539 return (uath_cmd_write(sc
, WDCMSG_RESET
, &reset
, sizeof (reset
), 0));
2543 uath_reset_tx_queues(struct uath_softc
*sc
)
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
,
2551 if (err
!= UATH_SUCCESS
)
2558 uath_wme_init(struct uath_softc
*sc
)
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 */
2568 struct uath_cmd_txq_setup qinfo
;
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
));
2583 err
= uath_cmd_write(sc
, WDCMSG_SETUP_TX_QUEUE
, &qinfo
,
2585 if (err
!= UATH_SUCCESS
)
2592 uath_stop_locked(void *arg
)
2594 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2596 /* flush data & control requests into the target */
2597 (void) uath_flush(sc
);
2599 /* set a LED status to the disconnected. */
2600 (void) uath_set_ledstate(sc
, 0);
2602 /* stop the target */
2603 (void) uath_cmd_write(sc
, WDCMSG_TARGET_STOP
, NULL
, 0, 0);
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);
2612 uath_init_locked(void *arg
)
2614 struct uath_softc
*sc
= arg
;
2615 struct ieee80211com
*ic
= &sc
->sc_ic
;
2619 if (UATH_IS_RUNNING(sc
))
2620 uath_stop_locked(sc
);
2622 uath_init_data_queue(sc
);
2624 /* reset variables */
2625 sc
->sc_intrx_nextnum
= sc
->sc_msgid
= 0;
2628 (void) uath_cmd_write(sc
, WDCMSG_BIND
, &val
, sizeof (val
), 0);
2630 /* set MAC address */
2631 (void) uath_config_multi(sc
, CFG_MAC_ADDR
,
2632 ic
->ic_macaddr
, IEEE80211_ADDR_LEN
);
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);
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);
2650 err
= uath_cmd_read(sc
, WDCMSG_TARGET_START
, NULL
, 0,
2651 &val
, sizeof (val
), UATH_CMD_FLAG_MAGIC
);
2653 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_init_locked(): "
2654 "could not start target\n");
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
));
2662 /* set default channel */
2663 err
= uath_switch_channel(sc
, ic
->ic_curchan
);
2665 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_init_locked(): "
2666 "could not switch channel, error %d\n", err
);
2670 val
= BE_32(TARGET_DEVICE_AWAKE
);
2671 (void) uath_cmd_write(sc
, WDCMSG_SET_PWR_MODE
, &val
, sizeof (val
), 0);
2673 (void) uath_cmd_write(sc
, WDCMSG_RESET_KEY_CACHE
, NULL
, 0, 0);
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
);
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
);
2691 return (UATH_SUCCESS
);
2694 uath_stop_locked(sc
);
2699 uath_init(struct uath_softc
*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");
2709 return (DDI_FAILURE
);
2712 return (DDI_SUCCESS
);
2716 uath_stop(struct uath_softc
*sc
)
2718 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_stop(): "
2722 uath_stop_locked(sc
);
2727 uath_resume(struct uath_softc
*sc
)
2731 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_resume(): "
2732 "uath resume now\n");
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");
2743 * initialize hardware
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");
2752 err
= uath_init(sc
);
2753 if (err
!= UATH_SUCCESS
) {
2754 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_resume(): "
2755 "hardware init failed\n");
2760 ieee80211_new_state(&sc
->sc_ic
, IEEE80211_S_INIT
, -1);
2762 sc
->sc_flags
&= ~UATH_FLAG_SUSPEND
;
2763 sc
->sc_flags
|= UATH_FLAG_RUNNING
;
2768 uath_m_start(void *arg
)
2770 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2771 struct ieee80211com
*ic
= &sc
->sc_ic
;
2775 * initialize hardware
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");
2785 ieee80211_new_state(ic
, IEEE80211_S_INIT
, -1);
2788 sc
->sc_flags
|= UATH_FLAG_RUNNING
;
2790 return (DDI_SUCCESS
);
2794 uath_m_stop(void *arg
)
2796 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2797 struct ieee80211com
*ic
= &sc
->sc_ic
;
2799 ieee80211_new_state(ic
, IEEE80211_S_INIT
, -1);
2801 if (!UATH_IS_DISCONNECT(sc
))
2805 sc
->sc_flags
&= ~UATH_FLAG_RUNNING
;
2810 uath_m_ioctl(void* arg
, queue_t
*wq
, mblk_t
*mp
)
2812 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2813 struct ieee80211com
*ic
= &sc
->sc_ic
;
2816 err
= ieee80211_ioctl(ic
, wq
, mp
);
2818 if (err
== ENETRESET
) {
2819 if (ic
->ic_des_esslen
) {
2820 if (UATH_IS_RUNNING(sc
)) {
2822 (void) uath_init(sc
);
2823 (void) ieee80211_new_state(ic
,
2824 IEEE80211_S_SCAN
, -1);
2834 uath_m_unicst(void *arg
, const uint8_t *macaddr
)
2841 uath_m_multicst(void *arg
, boolean_t add
, const uint8_t *mca
)
2848 uath_m_promisc(void *arg
, boolean_t on
)
2854 * callback functions for /get/set properties
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
)
2860 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2861 struct ieee80211com
*ic
= &sc
->sc_ic
;
2864 err
= ieee80211_setprop(ic
, pr_name
, wldp_pr_num
,
2865 wldp_length
, wldp_buf
);
2867 if (err
== ENETRESET
) {
2868 if (ic
->ic_des_esslen
&& UATH_IS_RUNNING(sc
)) {
2870 (void) uath_init(sc
);
2871 (void) ieee80211_new_state(ic
, IEEE80211_S_SCAN
, -1);
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
)
2884 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2887 err
= ieee80211_getprop(&sc
->sc_ic
, pr_name
, wldp_pr_num
,
2888 wldp_length
, wldp_buf
);
2893 uath_m_propinfo(void *arg
, const char *pr_name
, mac_prop_id_t wldp_pr_num
,
2894 mac_prop_info_handle_t prh
)
2896 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2898 ieee80211_propinfo(&sc
->sc_ic
, pr_name
, wldp_pr_num
, prh
);
2902 uath_m_stat(void *arg
, uint_t stat
, uint64_t *val
)
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
;
2911 case MAC_STAT_IFSPEED
:
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;
2918 case MAC_STAT_NOXMTBUF
:
2919 *val
= sc
->sc_tx_nobuf
;
2921 case MAC_STAT_NORCVBUF
:
2922 *val
= sc
->sc_rx_nobuf
;
2924 case MAC_STAT_IERRORS
:
2925 *val
= sc
->sc_rx_err
;
2927 case MAC_STAT_RBYTES
:
2928 *val
= ic
->ic_stats
.is_rx_bytes
;
2930 case MAC_STAT_IPACKETS
:
2931 *val
= ic
->ic_stats
.is_rx_frags
;
2933 case MAC_STAT_OBYTES
:
2934 *val
= ic
->ic_stats
.is_tx_bytes
;
2936 case MAC_STAT_OPACKETS
:
2937 *val
= ic
->ic_stats
.is_tx_frags
;
2939 case MAC_STAT_OERRORS
:
2940 case WIFI_STAT_TX_FAILED
:
2941 *val
= sc
->sc_tx_err
;
2943 case WIFI_STAT_TX_RETRANS
:
2944 *val
= sc
->sc_tx_retries
;
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
:
2957 return (ieee80211_stat(ic
, stat
, val
));
2968 uath_m_tx(void *arg
, mblk_t
*mp
)
2970 struct uath_softc
*sc
= (struct uath_softc
*)arg
;
2971 struct ieee80211com
*ic
= &sc
->sc_ic
;
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.
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
);
2987 while (mp
!= NULL
) {
2990 if (uath_send(ic
, mp
, IEEE80211_FC0_TYPE_DATA
) != DDI_SUCCESS
) {
3000 uath_attach(dev_info_t
*devinfo
, ddi_attach_cmd_t cmd
)
3002 struct uath_softc
*sc
;
3003 struct ieee80211com
*ic
;
3005 int i
, err
, instance
;
3007 uint16_t vendor_id
, product_id
;
3009 wifi_data_t wd
= { 0 };
3010 mac_register_t
*macp
;
3016 sc
= ddi_get_soft_state(uath_soft_state_p
,
3017 ddi_get_instance(devinfo
));
3020 return (DDI_SUCCESS
);
3022 return (DDI_FAILURE
);
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
);
3033 sc
= ddi_get_soft_state(uath_soft_state_p
, instance
);
3034 ic
= (ieee80211com_t
*)&sc
->sc_ic
;
3035 sc
->sc_dev
= devinfo
;
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");
3044 err
= usb_get_dev_data(devinfo
, &sc
->sc_udev
, USB_PARSE_LVL_ALL
, 0);
3045 if (err
!= USB_SUCCESS
) {
3047 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_attach(): "
3048 "usb_get_dev_data failed\n");
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");
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
);
3066 * We must open the pipes early because they're used to upload the
3067 * firmware (pre-firmware devices) or to send firmware commands.
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");
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
);
3085 uath_close_pipes(sc
);
3086 usb_client_detach(sc
->sc_dev
, sc
->sc_udev
);
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
);
3094 return (DDI_SUCCESS
);
3097 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_attach(): "
3098 "firmware download and re-attach successfully\n");
3101 * Only post-firmware devices here.
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
);
3110 * Allocate xfers for firmware commands.
3112 err
= uath_alloc_cmd_list(sc
, sc
->sc_cmd
, UATH_CMD_LIST_COUNT
,
3114 if (err
!= UATH_SUCCESS
) {
3115 UATH_DEBUG(UATH_DBG_ERR
, "uath: uath_attach(): "
3116 "could not allocate Tx command list\n");
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");
3128 * We're now ready to send+receive firmware commands.
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");
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");
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");
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]);
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
;
3160 ic
->ic_maxrssi
= 40;
3162 ic
->ic_xmit
= uath_send
;
3164 /* set device capabilities */
3166 IEEE80211_C_TXPMGT
| /* tx power management */
3167 IEEE80211_C_SHPREAMBLE
| /* short preamble supported */
3168 IEEE80211_C_SHSLOT
; /* short slot time supported */
3170 ic
->ic_caps
|= IEEE80211_C_WPA
; /* Support WPA/WPA2 */
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
;
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
;
3185 ieee80211_attach(ic
);
3187 /* register WPA door */
3188 ieee80211_register_door(ic
, ddi_driver_name(devinfo
),
3189 ddi_get_instance(devinfo
));
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;
3200 * Provide initial settings for the WiFi plugin; whenever this
3201 * information changes, we need to call mac_plugindata_update()
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
);
3207 if ((macp
= mac_alloc(MAC_VERSION
)) == NULL
) {
3208 UATH_DEBUG(UATH_DBG_ERR
, "uath_attach(): "
3209 "MAC version mismatch\n");
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
);
3223 err
= mac_register(macp
, &ic
->ic_mach
);
3226 UATH_DEBUG(UATH_DBG_ERR
, "uath_attach(): "
3227 "mac_register() error %x\n", err
);
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");
3240 * Create minor node of type DDI_NT_NET_WIFI
3242 (void) snprintf(strbuf
, sizeof (strbuf
), "%s%d",
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");
3251 * Notify link is down now
3253 mac_link_update(ic
->ic_mach
, LINK_STATE_DOWN
);
3255 UATH_DEBUG(UATH_DBG_MSG
, "uath: uath_attach(): "
3256 "attach success\n");
3257 return (DDI_SUCCESS
);
3260 (void) mac_unregister(ic
->ic_mach
);
3262 uath_free_cmd_list(sc
->sc_cmd
, UATH_CMD_LIST_COUNT
);
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
);
3270 uath_close_pipes(sc
);
3272 usb_client_detach(sc
->sc_dev
, sc
->sc_udev
);
3274 ddi_soft_state_free(uath_soft_state_p
, ddi_get_instance(devinfo
));
3275 return (DDI_FAILURE
);
3279 uath_detach(dev_info_t
*devinfo
, ddi_detach_cmd_t cmd
)
3281 struct uath_softc
*sc
;
3283 sc
= ddi_get_soft_state(uath_soft_state_p
, ddi_get_instance(devinfo
));
3290 if (UATH_IS_RUNNING(sc
)) {
3291 ieee80211_new_state(&sc
->sc_ic
, IEEE80211_S_INIT
, -1);
3295 sc
->sc_flags
&= ~UATH_FLAG_RUNNING
;
3296 sc
->sc_flags
|= UATH_FLAG_SUSPEND
;
3298 return (DDI_SUCCESS
);
3300 return (DDI_FAILURE
);
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
);
3309 if (!UATH_IS_DISCONNECT(sc
) && UATH_IS_RUNNING(sc
))
3312 uath_free_cmd_list(sc
->sc_cmd
, UATH_CMD_LIST_COUNT
);
3314 if (mac_disable(sc
->sc_ic
.ic_mach
) != 0)
3315 return (DDI_FAILURE
);
3318 * Unregister from the MAC layer subsystem
3320 if (mac_unregister(sc
->sc_ic
.ic_mach
) != 0)
3321 return (DDI_FAILURE
);
3324 * detach ieee80211 layer
3326 ieee80211_detach(&sc
->sc_ic
);
3328 /* close Tx/Rx pipes */
3329 uath_close_pipes(sc
);
3330 usb_unregister_hotplug_cbs(devinfo
);
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
);
3338 /* pipes will be close in uath_stop() */
3339 usb_client_detach(devinfo
, sc
->sc_udev
);
3342 ddi_remove_minor_node(devinfo
, NULL
);
3343 ddi_soft_state_free(uath_soft_state_p
, ddi_get_instance(devinfo
));
3345 return (DDI_SUCCESS
);
3349 _info(struct modinfo
*modinfop
)
3351 return (mod_info(&modlinkage
, modinfop
));
3359 status
= ddi_soft_state_init(&uath_soft_state_p
,
3360 sizeof (struct uath_softc
), 1);
3364 mac_init_ops(&uath_dev_ops
, "uath");
3365 status
= mod_install(&modlinkage
);
3367 mac_fini_ops(&uath_dev_ops
);
3368 ddi_soft_state_fini(&uath_soft_state_p
);
3378 status
= mod_remove(&modlinkage
);
3380 mac_fini_ops(&uath_dev_ops
);
3381 ddi_soft_state_fini(&uath_soft_state_p
);