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