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