xref: /openbsd/sys/dev/usb/if_wi_usb.c (revision 73471bf0)
1 /*	$OpenBSD: if_wi_usb.c,v 1.75 2021/11/22 10:17:14 mglocker Exp $ */
2 
3 /*
4  * Copyright (c) 2003 Dale Rahn. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Effort sponsored in part by the Defense Advanced Research Projects
27  * Agency (DARPA) and Air Force Research Laboratory, Air Force
28  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
29  */
30 #include "bpfilter.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sockio.h>
35 #include <sys/mbuf.h>
36 #include <sys/malloc.h>
37 #include <sys/kernel.h>
38 #include <sys/socket.h>
39 #include <sys/device.h>
40 #include <sys/timeout.h>
41 #include <sys/kthread.h>
42 #include <sys/tree.h>
43 
44 #include <net/if.h>
45 #include <net/if_media.h>
46 
47 #include <netinet/in.h>
48 #include <netinet/if_ether.h>
49 
50 #include <dev/usb/usb.h>
51 #include <dev/usb/usbdi.h>
52 #include <dev/usb/usbdi_util.h>
53 #include <dev/usb/usbdevs.h>
54 
55 #define ROUNDUP64(x) (((x)+63) & ~63)
56 
57 #include <net80211/ieee80211_var.h>
58 #include <net80211/ieee80211_ioctl.h>
59 
60 #if NBPFILTER > 0
61 #include <net/bpf.h>
62 #endif
63 
64 #include <machine/bus.h>
65 
66 #include <dev/ic/if_wireg.h>
67 #include <dev/ic/if_wi_ieee.h>
68 #include <dev/ic/if_wivar.h>
69 
70 #include <dev/usb/if_wi_usb.h>
71 
72 int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c,
73     void *ident);
74 void wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
75     usbd_status status);
76 void wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
77     usbd_status status);
78 void wi_usb_rxeof(struct usbd_xfer *xfer, void *priv,
79     usbd_status status);
80 void wi_usb_intr(struct usbd_xfer *xfer, void *priv,
81     usbd_status status);
82 void wi_usb_stop(struct wi_usb_softc *usc);
83 int wi_usb_tx_list_init(struct wi_usb_softc *usc);
84 int wi_usb_rx_list_init(struct wi_usb_softc *usc);
85 int wi_usb_open_pipes(struct wi_usb_softc *usc);
86 void wi_usb_cmdresp(struct wi_usb_chain *c);
87 void wi_usb_rridresp(struct wi_usb_chain *c);
88 void wi_usb_wridresp(struct wi_usb_chain *c);
89 void wi_usb_infofrm(struct wi_usb_chain *c, int len);
90 int wi_send_packet(struct wi_usb_softc *sc, int id);
91 void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
92 void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
93 void wi_usb_start_thread(void *);
94 
95 int wi_usb_tx_lock_try(struct wi_usb_softc *sc);
96 void wi_usb_tx_lock(struct wi_usb_softc *usc);
97 void wi_usb_tx_unlock(struct wi_usb_softc *usc);
98 void wi_usb_ctl_lock(struct wi_usb_softc *usc);
99 void wi_usb_ctl_unlock(struct wi_usb_softc *usc);
100 
101 void wi_dump_data(void *buffer, int len);
102 
103 void wi_usb_thread(void *arg);
104 
105 #ifdef WI_USB_DEBUG
106 #define DPRINTF(x)      do { if (wi_usbdebug) printf x; } while (0)
107 #define DPRINTFN(n,x)   do { if (wi_usbdebug >= (n)) printf x; } while (0)
108 int     wi_usbdebug = 1;
109 #else
110 #define DPRINTF(x)
111 #define DPRINTFN(n,x)
112 #endif
113 
114 struct wi_usb_thread_info {
115 	int status;
116 	int dying;
117 	int idle;
118 };
119 
120 /* thread status flags */
121 #define WI_START	0x01
122 #define WI_DYING	0x02
123 #define WI_INQUIRE	0x04
124 #define WI_WATCHDOG	0x08
125 
126 
127 struct wi_usb_softc {
128 	struct wi_softc		sc_wi;
129 #define wi_usb_dev sc_wi.sc_dev
130 
131 	struct timeout		wi_usb_stat_ch;
132 
133 	struct usbd_device	*wi_usb_udev;
134 	struct usbd_interface	*wi_usb_iface;
135 	u_int16_t		wi_usb_vendor;
136 	u_int16_t		wi_usb_product;
137 	int			wi_usb_ed[WI_USB_ENDPT_MAX];
138 	struct usbd_pipe	*wi_usb_ep[WI_USB_ENDPT_MAX];
139 
140 	struct wi_usb_chain	wi_usb_tx_chain[WI_USB_TX_LIST_CNT];
141 	struct wi_usb_chain	wi_usb_rx_chain[WI_USB_RX_LIST_CNT];
142 
143 	int			wi_usb_refcnt;
144 	char			wi_usb_attached;
145 	int			wi_usb_intr_errs;
146 	struct timeval		wi_usb_rx_notice;
147 
148 	int			wi_usb_pollpending;
149 
150 	wi_usb_usbin		wi_usb_ibuf;
151 	int			wi_usb_tx_prod;
152 	int			wi_usb_tx_cons;
153 	int			wi_usb_tx_cnt;
154 	int			wi_usb_rx_prod;
155 
156 	struct wi_ltv_gen	*ridltv;
157 	int			ridresperr;
158 
159 	int			cmdresp;
160 	int			cmdresperr;
161 	int			txresp;
162 	int			txresperr;
163 
164 	/* nummem (tx/mgmt) */
165 	int			wi_usb_nummem;
166 #define MAX_WI_NMEM 3
167 	void			*wi_usb_txmem[MAX_WI_NMEM];
168 	int			wi_usb_txmemsize[MAX_WI_NMEM];
169 	void			*wi_usb_rxmem;
170 	int			wi_usb_rxmemsize;
171 
172 	void			*wi_info;
173 	void			*wi_rxframe;
174 
175 	/* prevent multiple outstanding USB requests */
176 	int			wi_lock;
177 	int			wi_lockwait;
178 
179 	/* prevent multiple command requests */
180 	int			wi_ctllock;
181 	int			wi_ctllockwait;
182 	struct proc		*wi_curproc;
183 
184 	/* kthread */
185 	struct wi_usb_thread_info	*wi_thread_info;
186 	int			wi_resetonce;
187 };
188 
189 struct wi_funcs wi_func_usb = {
190         wi_cmd_usb,
191         wi_read_record_usb,
192         wi_write_record_usb,
193         wi_alloc_nicmem_usb,
194         wi_read_data_usb,
195         wi_write_data_usb,
196         wi_get_fid_usb,
197         wi_init_usb,
198 
199         wi_start_usb,
200         wi_ioctl_usb,
201         wi_watchdog_usb,
202         wi_inquire_usb,
203 };
204 
205 /*
206  * Various supported device vendors/products.
207  */
208 const struct wi_usb_type {
209 	struct usb_devno	wi_usb_device;
210 	u_int16_t	wi_usb_flags;
211 	/* XXX */
212 } wi_usb_devs[] = {
213 	{{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_111 }, 0 },
214 	{{ USB_VENDOR_ACERW, USB_PRODUCT_ACERW_WARPLINK }, 0 },
215 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_FREELAN }, 0 },
216 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25 }, 0 },
217 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25A }, 0 },
218 	{{ USB_VENDOR_ADAPTEC, USB_PRODUCT_ADAPTEC_AWN8020 }, 0 },
219 	{{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_WLAN }, 0 },
220 	{{ USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL140 }, 0 },
221 	{{ USB_VENDOR_AVERATEC, USB_PRODUCT_AVERATEC_USBWLAN }, 0 },
222 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W100 }, 0 },
223 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W200 }, 0 },
224 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLANUSB }, 0 },
225 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_KEY }, 0 },
226 	{{ USB_VENDOR_DELL, USB_PRODUCT_DELL_TM1180 }, 0 },
227 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120F }, 0 },
228 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL122 }, 0 },
229 	{{ USB_VENDOR_INTEL, USB_PRODUCT_INTEL_I2011B }, 0 },
230 	{{ USB_VENDOR_INTERSIL, USB_PRODUCT_INTERSIL_PRISM_2X }, 0 },
231 	{{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11 }, 0 },
232 	{{ USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_XP7250_WL }, 0 },
233 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11_25 }, 0 },
234 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB12_11 }, 0 },
235 	{{ USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V30 }, 0 },
236 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KB11 }, 0 },
237 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KS11G }, 0 },
238 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_S11 }, 0 },
239 	{{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN510 }, 0 },
240 	{{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 },
241 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WL503IA }, 0 },
242 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WM168B }, 0 },
243 	{{ USB_VENDOR_PLANEX, USB_PRODUCT_PLANEX_GW_US11H }, 0 },
244 	{{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM22 }, 0 },
245 	{{ USB_VENDOR_SITECOM2, USB_PRODUCT_SITECOM2_WL022 }, 0 },
246 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_0193 }, 0 },
247 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZYAIR_B200 }, 0 },
248 	{{ USB_VENDOR_USR, USB_PRODUCT_USR_USR1120 }, 0 },
249 	{{ USB_VENDOR_VIEWSONIC, USB_PRODUCT_VIEWSONIC_AIRSYNC }, 0 },
250 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI725 }, 0 },
251 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI735 }, 0 }
252 };
253 #define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p))
254 
255 int wi_usb_match(struct device *, void *, void *);
256 void wi_usb_attach(struct device *, struct device *, void *);
257 int wi_usb_detach(struct device *, int);
258 
259 struct cfdriver wi_usb_cd = {
260 	NULL, "wi_usb", DV_IFNET
261 };
262 
263 const struct cfattach wi_usb_ca = {
264 	sizeof(struct wi_usb_softc), wi_usb_match, wi_usb_attach, wi_usb_detach
265 };
266 
267 int
268 wi_usb_match(struct device *parent, void *match, void *aux)
269 {
270 	struct usb_attach_arg	*uaa = aux;
271 
272 	if (uaa->iface == NULL || uaa->configno != 1)
273 		return (UMATCH_NONE);
274 
275 	return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ?
276 		UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
277 }
278 
279 
280 /*
281  * Attach the interface. Allocate softc structures, do ifmedia
282  * setup and ethernet/BPF attach.
283  */
284 void
285 wi_usb_attach(struct device *parent, struct device *self, void *aux)
286 {
287 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
288 	struct usb_attach_arg	*uaa = aux;
289 /*	int			s; */
290 	struct usbd_device	*dev = uaa->device;
291 	struct usbd_interface	*iface = uaa->iface;
292 	usb_interface_descriptor_t	*id;
293 	usb_endpoint_descriptor_t	*ed;
294 	int			 i;
295 
296 	DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc));
297 
298 	/* XXX - any tasks? */
299 
300 	/* XXX - flags? */
301 
302 	sc->wi_usb_udev = dev;
303 	sc->wi_usb_iface = iface;
304 	sc->wi_usb_product = uaa->product;
305 	sc->wi_usb_vendor = uaa->vendor;
306 
307 	sc->sc_wi.wi_usb_cdata = sc;
308 	sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB;
309 
310 	sc->wi_lock = 0;
311 	sc->wi_lockwait = 0;
312 	sc->wi_resetonce = 0;
313 
314 	id = usbd_get_interface_descriptor(iface);
315 
316 	/* Find endpoints. */
317 	for (i = 0; i < id->bNumEndpoints; i++) {
318 		ed = usbd_interface2endpoint_descriptor(iface, i);
319 		if (ed == NULL) {
320 			printf("%s: couldn't get endpoint descriptor %d\n",
321 			    sc->wi_usb_dev.dv_xname, i);
322 			return;
323 		}
324 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
325 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
326 			sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress;
327 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
328 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
329 			sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress;
330 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
331 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
332 			sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress;
333 		}
334 	}
335 
336 	sc->wi_usb_nummem = 0;
337 
338 	/* attach wi device */
339 
340 	if (wi_usb_rx_list_init(sc)) {
341 		printf("%s: rx list init failed\n",
342 		    sc->wi_usb_dev.dv_xname);
343 		return;
344 	}
345 	if (wi_usb_tx_list_init(sc)) {
346 		printf("%s: tx list init failed\n",
347 		    sc->wi_usb_dev.dv_xname);
348 		return;
349 	}
350 
351 	if (wi_usb_open_pipes(sc)){
352 		printf("%s: open pipes failed\n",
353 		    sc->wi_usb_dev.dv_xname);
354 		return;
355 	}
356 
357 	sc->wi_usb_attached = 1;
358 
359 	kthread_create_deferred(wi_usb_start_thread, sc);
360 }
361 
362 int
363 wi_usb_detach(struct device *self, int flags)
364 {
365 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
366 	struct ifnet		*ifp = WI_GET_IFP(sc);
367 	struct wi_softc		*wsc = &sc->sc_wi;
368 	int s;
369 	int err;
370 
371 	/* Detached before attach finished, so just bail out. */
372 	if (!sc->wi_usb_attached)
373 		return (0);
374 
375 	if (sc->wi_thread_info != NULL) {
376 		sc->wi_thread_info->dying = 1;
377 
378 		sc->wi_thread_info->status |= WI_DYING;
379 		if (sc->wi_thread_info->idle)
380 			wakeup(sc->wi_thread_info);
381 	}
382 
383 	/* tasks? */
384 
385 	s = splusb();
386 	/* detach wi */
387 
388 	if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) {
389 		printf("%s: already detached\n", sc->wi_usb_dev.dv_xname);
390 		splx(s);
391 		return (0);
392 	}
393 
394 	wi_detach(&sc->sc_wi);
395 
396 	wsc->wi_flags = 0;
397 
398 	if (ifp->if_softc != NULL) {
399 		ether_ifdetach(ifp);
400 		if_detach(ifp);
401 	}
402 
403 	sc->wi_usb_attached = 0;
404 
405 	if (--sc->wi_usb_refcnt >= 0) {
406 		/* Wait for processes to go away. */
407 		usb_detach_wait(&sc->wi_usb_dev);
408 	}
409 
410 	while (sc->wi_usb_nummem) {
411 		sc->wi_usb_nummem--;
412 		free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
413 		  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
414 		sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
415 		sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
416 	}
417 
418 	if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL) {
419 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
420 		if (err) {
421 			printf("%s: close intr pipe failed: %s\n",
422 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
423 		}
424 		sc->wi_usb_ep[WI_USB_ENDPT_INTR] = NULL;
425 	}
426 	if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL) {
427 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
428 		if (err) {
429 			printf("%s: close tx pipe failed: %s\n",
430 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
431 		}
432 		sc->wi_usb_ep[WI_USB_ENDPT_TX] = NULL;
433 	}
434 	if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL) {
435 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
436 		if (err) {
437 			printf("%s: close rx pipe failed: %s\n",
438 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
439 		}
440 		sc->wi_usb_ep[WI_USB_ENDPT_RX] = NULL;
441 	}
442 
443 	splx(s);
444 
445 	return (0);
446 }
447 
448 int
449 wi_send_packet(struct wi_usb_softc *sc, int id)
450 {
451 	struct wi_usb_chain	*c;
452 	struct wi_frame		*wibuf;
453 	int			total_len, rnd_len;
454 	int			err;
455 
456 	c = &sc->wi_usb_tx_chain[0];
457 
458 	DPRINTFN(10,("%s: %s: id=%x\n",
459 	    sc->wi_usb_dev.dv_xname, __func__, id));
460 
461 	/* assemble packet from write_data buffer */
462 	if (id == 0 || id == 1) {
463 		/* tx_lock acquired before wi_start() */
464 		wibuf = sc->wi_usb_txmem[id];
465 
466 		total_len = sizeof (struct wi_frame) +
467 		    letoh16(wibuf->wi_dat_len);
468 		rnd_len = ROUNDUP64(total_len);
469 		if ((total_len > sc->wi_usb_txmemsize[id]) ||
470 		   (rnd_len > WI_USB_BUFSZ )){
471 			printf("invalid packet len: %x memsz %x max %x\n",
472 			    total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
473 
474 			err = EIO;
475 			goto err_ret;
476 		}
477 
478 		sc->txresp = WI_CMD_TX;
479 		sc->txresperr = 0;
480 
481 		bcopy(wibuf, c->wi_usb_buf, total_len);
482 
483 		bzero(((char *)c->wi_usb_buf)+total_len,
484 		    rnd_len - total_len);
485 
486 		/* zero old packet for next TX */
487 		bzero(wibuf, total_len);
488 
489 		total_len = rnd_len;
490 
491 		DPRINTFN(5,("%s: %s: id=%x len=%x\n",
492 		    sc->wi_usb_dev.dv_xname, __func__, id, total_len));
493 
494 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
495 		    c, c->wi_usb_buf, rnd_len,
496 		    USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
497 		    WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
498 
499 		err = usbd_transfer(c->wi_usb_xfer);
500 		if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
501 			printf("%s: %s: error=%s\n",
502 			    sc->wi_usb_dev.dv_xname, __func__,
503 			    usbd_errstr(err));
504 			/* Stop the interface from process context. */
505 			wi_usb_stop(sc);
506 			err = EIO;
507 		} else {
508 			err = 0;
509 		}
510 
511 		DPRINTFN(5,("%s: %s: exit err=%x\n",
512 		    sc->wi_usb_dev.dv_xname, __func__, err));
513 err_ret:
514 		return err;
515 	}
516 	printf("%s:%s: invalid packet id sent %x\n",
517 	    sc->wi_usb_dev.dv_xname, __func__, id);
518 	return 0;
519 }
520 
521 int
522 wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
523 {
524 	struct wi_usb_chain	*c;
525 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
526 	struct wi_cmdreq	*pcmd;
527 	int			total_len, rnd_len;
528 	int			err;
529 
530 	DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
531 	    sc->wi_usb_dev.dv_xname, __func__, cmd, val0, val1, val2));
532 
533 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
534 		return wi_send_packet(sc, val0);
535 	}
536 
537 
538 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
539 		/* free alloc_nicmem regions */
540 		while (sc->wi_usb_nummem) {
541 			sc->wi_usb_nummem--;
542 			free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
543 			  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
544 			sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
545 			sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
546 		}
547 
548 #if 0
549 		/* if this is the first time, init, otherwise do not?? */
550 		if (sc->wi_resetonce) {
551 			return 0;
552 		} else
553 			sc->wi_resetonce = 1;
554 #endif
555 	}
556 
557 	wi_usb_ctl_lock(sc);
558 
559 	wi_usb_tx_lock(sc);
560 
561 	c = &sc->wi_usb_tx_chain[0];
562 	pcmd = c->wi_usb_buf;
563 
564 
565 	total_len = sizeof (struct wi_cmdreq);
566 	rnd_len = ROUNDUP64(total_len);
567 	if (rnd_len > WI_USB_BUFSZ) {
568 		printf("read_record buf size err %x %x\n",
569 		    rnd_len, WI_USB_BUFSZ);
570 		err = EIO;
571 		goto err_ret;
572 	}
573 
574 	sc->cmdresp = cmd;
575 	sc->cmdresperr = 0;
576 
577 	pcmd->type = htole16(WI_USB_CMDREQ);
578 	pcmd->cmd  = htole16(cmd);
579 	pcmd->param0  = htole16(val0);
580 	pcmd->param1  = htole16(val1);
581 	pcmd->param2  = htole16(val2);
582 
583 	bzero(((char*)pcmd)+total_len, rnd_len - total_len);
584 
585 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
586 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
587 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
588 
589 	err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
590 
591 	if (err == 0)
592 		err = sc->cmdresperr;
593 
594 	sc->cmdresperr = 0;
595 
596 err_ret:
597 	wi_usb_tx_unlock(sc);
598 
599 	wi_usb_ctl_unlock(sc);
600 
601 	DPRINTFN(5,("%s: %s: exit err=%x\n",
602 	    sc->wi_usb_dev.dv_xname, __func__, err));
603 	return err;
604 }
605 
606 
607 int
608 wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
609 {
610 	struct wi_usb_chain	*c;
611 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
612 	struct wi_rridreq	*prid;
613 	int			total_len, rnd_len;
614 	int			err;
615 	struct wi_ltv_gen	*oltv = NULL, p2ltv;
616 
617 	DPRINTFN(5,("%s: %s: enter rid=%x\n",
618 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type));
619 
620 	/* Do we need to deal with these here, as in _io version?
621 	 * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
622 	 * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
623 	 */
624 	if (wsc->sc_firmware_type != WI_LUCENT) {
625 		oltv = ltv;
626 		switch (ltv->wi_type) {
627 		case WI_RID_ENCRYPTION:
628 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
629 			p2ltv.wi_len = 2;
630 			ltv = &p2ltv;
631 			break;
632 		case WI_RID_TX_CRYPT_KEY:
633 			if (ltv->wi_val > WI_NLTV_KEYS)
634 				return (EINVAL);
635 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
636 			p2ltv.wi_len = 2;
637 			ltv = &p2ltv;
638 			break;
639 		}
640 	}
641 
642 	wi_usb_tx_lock(sc);
643 
644 	c = &sc->wi_usb_tx_chain[0];
645 	prid = c->wi_usb_buf;
646 
647 	total_len = sizeof(struct wi_rridreq);
648 	rnd_len = ROUNDUP64(total_len);
649 
650 	if (rnd_len > WI_USB_BUFSZ) {
651 		printf("read_record buf size err %x %x\n",
652 		    rnd_len, WI_USB_BUFSZ);
653 		wi_usb_tx_unlock(sc);
654 		return EIO;
655 	}
656 
657 	sc->ridltv = ltv;
658 	sc->ridresperr = 0;
659 
660 	prid->type = htole16(WI_USB_RRIDREQ);
661 	prid->frmlen = htole16(2);	/* variable size? */
662 	prid->rid  = htole16(ltv->wi_type);
663 
664 	bzero(((char*)prid)+total_len, rnd_len - total_len);
665 
666 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
667 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
668 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
669 
670 	DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
671 	    sc->wi_usb_dev.dv_xname, __func__, total_len, ltv->wi_len));
672 
673 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
674 
675 	/* Do we need to deal with these here, as in _io version?
676 	 *
677 	 * WI_RID_TX_RATE
678 	 * WI_RID_CUR_TX_RATE
679 	 * WI_RID_ENCRYPTION
680 	 * WI_RID_TX_CRYPT_KEY
681 	 * WI_RID_CNFAUTHMODE
682 	 */
683 	if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
684 	    && ltv->wi_val == wsc->wi_ibss_port) {
685 		/*
686 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
687 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
688 		 * have to rely on wi_ptype to distinguish this for us.
689 		 */
690 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
691 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
692 		int v;
693 
694 		switch (oltv->wi_type) {
695 		case WI_RID_TX_RATE:
696 		case WI_RID_CUR_TX_RATE:
697 			switch (letoh16(ltv->wi_val)) {
698 			case 1: v = 1; break;
699 			case 2: v = 2; break;
700 			case 3:	v = 6; break;
701 			case 4: v = 5; break;
702 			case 7: v = 7; break;
703 			case 8: v = 11; break;
704 			case 15: v = 3; break;
705 			default: v = 0x100 + letoh16(ltv->wi_val); break;
706 			}
707 			oltv->wi_val = htole16(v);
708 			break;
709 		case WI_RID_ENCRYPTION:
710 			oltv->wi_len = 2;
711 			if (ltv->wi_val & htole16(0x01))
712 				oltv->wi_val = htole16(1);
713 			else
714 				oltv->wi_val = htole16(0);
715 			break;
716 		case WI_RID_TX_CRYPT_KEY:
717 		case WI_RID_CNFAUTHMODE:
718 			oltv->wi_len = 2;
719 			oltv->wi_val = ltv->wi_val;
720 			break;
721 		}
722 	}
723 
724 	if (err == 0)
725 		err = sc->ridresperr;
726 
727 	sc->ridresperr = 0;
728 
729 	wi_usb_tx_unlock(sc);
730 
731 	DPRINTFN(5,("%s: %s: exit err=%x\n",
732 	    sc->wi_usb_dev.dv_xname, __func__, err));
733 	return err;
734 }
735 
736 int
737 wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
738 {
739 	struct wi_usb_chain	*c;
740 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
741 	struct wi_wridreq	*prid;
742 	int			total_len, rnd_len;
743 	int			err;
744 	struct wi_ltv_gen	p2ltv;
745 	u_int16_t		val = 0;
746 	int			i;
747 
748 	DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
749 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
750 	    (ltv->wi_len-1)*2 ));
751 
752 	/* Do we need to deal with these here, as in _io version?
753 	 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
754 	 * RID_TX_RATE munging
755 	 * RID_ENCRYPTION
756 	 * WI_RID_TX_CRYPT_KEY
757 	 * WI_RID_DEFLT_CRYPT_KEYS
758 	 */
759 	if (ltv->wi_type == WI_RID_PORTTYPE &&
760 	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
761 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
762 		p2ltv.wi_type = WI_RID_PORTTYPE;
763 		p2ltv.wi_len = 2;
764 		p2ltv.wi_val = wsc->wi_ibss_port;
765 		ltv = &p2ltv;
766 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
767 		int v;
768 
769 		switch (ltv->wi_type) {
770 		case WI_RID_TX_RATE:
771 			p2ltv.wi_type = WI_RID_TX_RATE;
772 			p2ltv.wi_len = 2;
773 			switch (letoh16(ltv->wi_val)) {
774 			case 1: v = 1; break;
775 			case 2: v = 2; break;
776 			case 3:	v = 15; break;
777 			case 5: v = 4; break;
778 			case 6: v = 3; break;
779 			case 7: v = 7; break;
780 			case 11: v = 8; break;
781 			default: return EINVAL;
782 			}
783 			p2ltv.wi_val = htole16(v);
784 			ltv = &p2ltv;
785 			break;
786 		case WI_RID_ENCRYPTION:
787 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
788 			p2ltv.wi_len = 2;
789 			if (ltv->wi_val & htole16(0x01)) {
790 				val = PRIVACY_INVOKED;
791 				/*
792 				 * If using shared key WEP we must set the
793 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
794 				 * need this bit set even when not using
795 				 * shared key. We can't just test for
796 				 * IEEE80211_AUTH_SHARED since Symbol cards
797 				 * have 2 shared key modes.
798 				 */
799 				if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
800 				    wsc->sc_firmware_type == WI_SYMBOL)
801 					val |= EXCLUDE_UNENCRYPTED;
802 
803 				switch (wsc->wi_crypto_algorithm) {
804 				case WI_CRYPTO_FIRMWARE_WEP:
805 					/*
806 					 * TX encryption is broken in
807 					 * Host AP mode.
808 					 */
809 					if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
810 						val |= HOST_ENCRYPT;
811 					break;
812 				case WI_CRYPTO_SOFTWARE_WEP:
813 					val |= HOST_ENCRYPT|HOST_DECRYPT;
814 					break;
815 				}
816 				p2ltv.wi_val = htole16(val);
817 			} else
818 				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
819 			ltv = &p2ltv;
820 			break;
821 		case WI_RID_TX_CRYPT_KEY:
822 			if (ltv->wi_val > WI_NLTV_KEYS)
823 				return (EINVAL);
824 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
825 			p2ltv.wi_len = 2;
826 			p2ltv.wi_val = ltv->wi_val;
827 			ltv = &p2ltv;
828 			break;
829 		case WI_RID_DEFLT_CRYPT_KEYS: {
830 				int error;
831 				int keylen;
832 				struct wi_ltv_str ws;
833 				struct wi_ltv_keys *wk;
834 
835 				wk = (struct wi_ltv_keys *)ltv;
836 				keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
837 				keylen = letoh16(keylen);
838 
839 				for (i = 0; i < 4; i++) {
840 					bzero(&ws, sizeof(ws));
841 					ws.wi_len = (keylen > 5) ? 8 : 4;
842 					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
843 					bcopy(&wk->wi_keys[i].wi_keydat,
844 					    ws.wi_str, keylen);
845 					error = wi_write_record_usb(wsc,
846 					    (struct wi_ltv_gen *)&ws);
847 					if (error)
848 						return (error);
849 				}
850 			}
851 			return (0);
852 		}
853 	}
854 
855 	wi_usb_tx_lock(sc);
856 
857 	c = &sc->wi_usb_tx_chain[0];
858 
859 	prid = c->wi_usb_buf;
860 
861 	total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
862 	    sizeof(prid->rid) + (ltv->wi_len-1)*2;
863 	rnd_len = ROUNDUP64(total_len);
864 	if (rnd_len > WI_USB_BUFSZ) {
865 		printf("write_record buf size err %x %x\n",
866 		    rnd_len, WI_USB_BUFSZ);
867 		wi_usb_tx_unlock(sc);
868 		return EIO;
869 	}
870 
871 	prid->type = htole16(WI_USB_WRIDREQ);
872 	prid->frmlen = htole16(ltv->wi_len);
873 	prid->rid  = htole16(ltv->wi_type);
874 	if (ltv->wi_len > 1)
875 		bcopy(&ltv->wi_val, &prid->data[0], (ltv->wi_len-1)*2);
876 
877 	bzero(((char*)prid)+total_len, rnd_len - total_len);
878 
879 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
880 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
881 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
882 
883 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
884 
885 	if (err == 0)
886 		err = sc->ridresperr;
887 
888 	sc->ridresperr = 0;
889 
890 	wi_usb_tx_unlock(sc);
891 
892 	DPRINTFN(5,("%s: %s: exit err=%x\n",
893 	    sc->wi_usb_dev.dv_xname, __func__, err));
894 	return err;
895 }
896 
897 /*
898  * This is an ugly compat portion to emulate the I/O which writes
899  * a packet or management information
900  * The data is copied into local memory for the requested
901  * 'id' then on the wi_cmd WI_CMD_TX, the id argument
902  * will identify which buffer to use
903  */
904 int
905 wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
906 {
907 	int nmem;
908 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
909 
910 	DPRINTFN(10,("%s: %s: enter len=%x\n",
911 	    sc->wi_usb_dev.dv_xname, __func__, len));
912 
913 	/*
914 	 * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
915 	 * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
916 	 */
917 	nmem = sc->wi_usb_nummem++;
918 
919 	if (nmem >= MAX_WI_NMEM) {
920 		sc->wi_usb_nummem--;
921 		return ENOMEM;
922 	}
923 
924 	sc->wi_usb_txmem[nmem] = malloc(len, M_USBDEV, M_WAITOK | M_CANFAIL);
925 	if (sc->wi_usb_txmem[nmem] == NULL) {
926 		sc->wi_usb_nummem--;
927 		return ENOMEM;
928 	}
929 	sc->wi_usb_txmemsize[nmem] = len;
930 
931 	*id = nmem;
932 	return 0;
933 }
934 
935 /*
936  * this is crazy, we skip the first 16 bits of the buf so that it
937  * can be used as the 'type' of the usb transfer.
938  */
939 
940 
941 int
942 wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
943 {
944 	u_int8_t	*ptr;
945 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
946 
947 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
948 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
949 
950 	if (id < 0 && id >= sc->wi_usb_nummem)
951 		return EIO;
952 
953 	ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
954 
955 	if (len + off > sc->wi_usb_txmemsize[id])
956 		return EIO;
957 	DPRINTFN(10,("%s: %s: completed \n",
958 	    sc->wi_usb_dev.dv_xname, __func__));
959 
960 	bcopy(buf, ptr, len);
961 	return 0;
962 }
963 
964 /*
965  * On the prism I/O, this read_data points to the hardware buffer
966  * which contains the
967  */
968 int
969 wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
970 {
971 	u_int8_t	*ptr;
972 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
973 
974 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
975 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
976 
977 	if (id == 0x1001 && sc->wi_info != NULL)
978 		ptr = (u_int8_t *)sc->wi_info + off;
979 	else if (id == 0x1000 && sc->wi_rxframe != NULL)
980 		ptr = (u_int8_t *)sc->wi_rxframe + off;
981 	else if (id >= 0 && id < sc->wi_usb_nummem) {
982 
983 		if (sc->wi_usb_txmem[id] == NULL)
984 			return EIO;
985 		if (len + off > sc->wi_usb_txmemsize[id])
986 			return EIO;
987 
988 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
989 	} else
990 		return EIO;
991 
992 	if (id < sc->wi_usb_nummem) {
993 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
994 
995 		if (len + off > sc->wi_usb_txmemsize[id])
996 			return EIO;
997 	}
998 
999 	bcopy(ptr, buf, len);
1000 	return 0;
1001 }
1002 
1003 void
1004 wi_usb_stop(struct wi_usb_softc *sc)
1005 {
1006 	DPRINTFN(1,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1007 	/* XXX */
1008 
1009 	/* Stop transfers */
1010 }
1011 
1012 int
1013 wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
1014     void *ident)
1015 {
1016 	usbd_status		err;
1017 
1018 	DPRINTFN(10,("%s: %s:\n",
1019 	    sc->wi_usb_dev.dv_xname, __func__));
1020 
1021 	sc->wi_usb_refcnt++;
1022 	err = usbd_transfer(c->wi_usb_xfer);
1023 	if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
1024 		printf("%s: %s error=%s\n",
1025 		    sc->wi_usb_dev.dv_xname, __func__,
1026 		    usbd_errstr(err));
1027 		/* Stop the interface from process context. */
1028 		wi_usb_stop(sc);
1029 		err = EIO;
1030 		goto done;
1031 	}
1032 	err = tsleep_nsec(ident, PRIBIO, "wiTXsync", SEC_TO_NSEC(1));
1033 	if (err) {
1034 		DPRINTFN(1,("%s: %s: err %x\n",
1035 		    sc->wi_usb_dev.dv_xname, __func__, err));
1036 		err = ETIMEDOUT;
1037 	}
1038 done:
1039 	if (--sc->wi_usb_refcnt < 0)
1040 		usb_detach_wakeup(&sc->wi_usb_dev);
1041 	return err;
1042 }
1043 
1044 
1045 /*
1046  * A command/rrid/wrid  was sent to the chip. It's safe for us to clean up
1047  * the list buffers.
1048  */
1049 
1050 void
1051 wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
1052     usbd_status status)
1053 {
1054 	struct wi_usb_chain	*c = priv;
1055 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1056 
1057 	int			s;
1058 
1059 	if (usbd_is_dying(sc->wi_usb_udev))
1060 		return;
1061 
1062 	s = splnet();
1063 
1064 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1065 		    __func__, status));
1066 
1067 	if (status != USBD_NORMAL_COMPLETION) {
1068 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1069 			splx(s);
1070 			return;
1071 		}
1072 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1073 		    usbd_errstr(status));
1074 		if (status == USBD_STALLED) {
1075 			sc->wi_usb_refcnt++;
1076 			usbd_clear_endpoint_stall_async(
1077 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1078 			if (--sc->wi_usb_refcnt < 0)
1079 				usb_detach_wakeup(&sc->wi_usb_dev);
1080 		}
1081 		splx(s);
1082 		return;
1083 	}
1084 
1085 	splx(s);
1086 }
1087 
1088 /*
1089  * A packet was sent to the chip. It's safe for us to clean up
1090  * the list buffers.
1091  */
1092 
1093 void
1094 wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
1095     usbd_status status)
1096 {
1097 	struct wi_usb_chain	*c = priv;
1098 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1099 	struct wi_softc		*wsc = &sc->sc_wi;
1100 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1101 
1102 	int			s;
1103 	int			err = 0;
1104 
1105 	if (usbd_is_dying(sc->wi_usb_udev))
1106 		return;
1107 
1108 	s = splnet();
1109 
1110 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1111 		    __func__, status));
1112 
1113 	if (status != USBD_NORMAL_COMPLETION) {
1114 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1115 			splx(s);
1116 			return;
1117 		}
1118 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1119 		    usbd_errstr(status));
1120 		if (status == USBD_STALLED) {
1121 			sc->wi_usb_refcnt++;
1122 			usbd_clear_endpoint_stall_async(
1123 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1124 			if (--sc->wi_usb_refcnt < 0)
1125 				usb_detach_wakeup(&sc->wi_usb_dev);
1126 		}
1127 		splx(s);
1128 		return;
1129 	}
1130 
1131 	if (status)
1132 		err = WI_EV_TX_EXC;
1133 
1134 	wi_txeof(wsc, err);
1135 
1136 	wi_usb_tx_unlock(sc);
1137 
1138 	if (!ifq_empty(&ifp->if_snd))
1139 		wi_start_usb(ifp);
1140 
1141 	splx(s);
1142 }
1143 
1144 int
1145 wi_usb_rx_list_init(struct wi_usb_softc *sc)
1146 {
1147 	struct wi_usb_chain	*c;
1148 	int			i;
1149 
1150 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1151 
1152 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1153 		c = &sc->wi_usb_rx_chain[i];
1154 		c->wi_usb_sc = sc;
1155 		c->wi_usb_idx = i;
1156 		if (c->wi_usb_xfer != NULL) {
1157 			printf("UGH RX\n");
1158 		}
1159 		if (c->wi_usb_xfer == NULL) {
1160 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1161 			if (c->wi_usb_xfer == NULL)
1162 				return (ENOBUFS);
1163 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1164 			    WI_USB_BUFSZ);
1165 			if (c->wi_usb_buf == NULL)
1166 				return (ENOBUFS); /* XXX free xfer */
1167 		}
1168 	}
1169 
1170 	return (0);
1171 }
1172 
1173 int
1174 wi_usb_tx_list_init(struct wi_usb_softc *sc)
1175 {
1176 	struct wi_usb_chain	*c;
1177 	int			i;
1178 
1179 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1180 
1181 	for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
1182 		c = &sc->wi_usb_tx_chain[i];
1183 		c->wi_usb_sc = sc;
1184 		c->wi_usb_idx = i;
1185 		c->wi_usb_mbuf = NULL;
1186 		if (c->wi_usb_xfer != NULL) {
1187 			printf("UGH TX\n");
1188 		}
1189 		if (c->wi_usb_xfer == NULL) {
1190 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1191 			if (c->wi_usb_xfer == NULL)
1192 				return (ENOBUFS);
1193 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1194 			    WI_USB_BUFSZ);
1195 			if (c->wi_usb_buf == NULL)
1196 				return (ENOBUFS);
1197 		}
1198 	}
1199 
1200 	return (0);
1201 }
1202 
1203 int
1204 wi_usb_open_pipes(struct wi_usb_softc *sc)
1205 {
1206 	usbd_status		err;
1207 	int			error = 0;
1208 	struct wi_usb_chain	*c;
1209 	int			i;
1210 
1211 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1212 
1213 	sc->wi_usb_refcnt++;
1214 
1215 	/* Open RX and TX pipes. */
1216 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
1217 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1218 	if (err) {
1219 		printf("%s: open rx pipe failed: %s\n",
1220 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1221 		error = EIO;
1222 		goto done;
1223 	}
1224 
1225 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
1226 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1227 	if (err) {
1228 		printf("%s: open tx pipe failed: %s\n",
1229 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1230 		error = EIO;
1231 		goto done;
1232 	}
1233 
1234 	/* is this used? */
1235 	err = usbd_open_pipe_intr(sc->wi_usb_iface,
1236 	    sc->wi_usb_ed[WI_USB_ENDPT_INTR], 0,
1237 	    &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
1238 	    WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
1239 	if (err) {
1240 		printf("%s: open intr pipe failed: %s\n",
1241 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1242 		error = EIO;
1243 		goto done;
1244 	}
1245 
1246 	/* Start up the receive pipe. */
1247 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1248 		c = &sc->wi_usb_rx_chain[i];
1249 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1250 		    c, c->wi_usb_buf, WI_USB_BUFSZ,
1251 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1252 		    wi_usb_rxeof);
1253 		DPRINTFN(10,("%s: %s: start read\n", sc->wi_usb_dev.dv_xname,
1254 			    __func__));
1255 		usbd_transfer(c->wi_usb_xfer);
1256 	}
1257 
1258 done:
1259 	if (--sc->wi_usb_refcnt < 0)
1260 		usb_detach_wakeup(&sc->wi_usb_dev);
1261 
1262 	return (error);
1263 }
1264 
1265 /*
1266  * This is a bit of a kludge, however wi_rxeof and wi_update_stats
1267  * call wi_get_fid to determine where the data associated with
1268  * the transaction is located, the returned id is then used to
1269  * wi_read_data the information out.
1270  *
1271  * This code returns which 'fid' should be used. The results are only valid
1272  * during a wi_usb_rxeof because the data is received packet is 'held'
1273  * an a variable for reading by wi_read_data_usb for that period.
1274  *
1275  * for magic numbers this uses  0x1000, 0x1001 for rx/info
1276  */
1277 
1278 int
1279 wi_get_fid_usb(struct wi_softc *sc, int fid)
1280 {
1281 	switch (fid) {
1282 	case WI_RX_FID:
1283 		return 0x1000;
1284 	case WI_INFO_FID:
1285 		return 0x1001;
1286 	default:
1287 		return 0x1111;
1288 	}
1289 
1290 }
1291 
1292 #if 0
1293 void
1294 wi_dump_data(void *buffer, int len)
1295 {
1296 	int i;
1297 	for (i = 0; i < len; i++) {
1298 		if (((i) % 16) == 0)
1299 			printf("\n %02x:", i);
1300 		printf(" %02x",
1301 		    ((uint8_t *)(buffer))[i]);
1302 
1303 	}
1304 	printf("\n");
1305 
1306 }
1307 #endif
1308 
1309 /*
1310  * A frame has been received.
1311  */
1312 void
1313 wi_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1314 {
1315 	struct wi_usb_chain	*c = priv;
1316 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1317 	wi_usb_usbin		*uin;
1318 	int			total_len = 0;
1319 	u_int16_t		rtype;
1320 
1321 	if (usbd_is_dying(sc->wi_usb_udev))
1322 		return;
1323 
1324 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1325 		    __func__, status));
1326 
1327 
1328 	if (status != USBD_NORMAL_COMPLETION) {
1329 		if (status == USBD_NOT_STARTED || status == USBD_IOERROR
1330 		    || status == USBD_CANCELLED) {
1331 			printf("%s: %u usb errors on rx: %s\n",
1332 			    sc->wi_usb_dev.dv_xname, 1,
1333 			    /* sc->wi_usb_rx_errs, */
1334 			    usbd_errstr(status));
1335 			return;
1336 		}
1337 #if 0
1338 		sc->wi_usb_rx_errs++;
1339 		if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
1340 			printf("%s: %u usb errors on rx: %s\n",
1341 			    sc->wi_usb_dev.dv_xname, sc->wi_usb_rx_errs,
1342 			    usbd_errstr(status));
1343 			sc->wi_usb_rx_errs = 0;
1344 		}
1345 #endif
1346 		if (status == USBD_STALLED) {
1347 			sc->wi_usb_refcnt++;
1348 			usbd_clear_endpoint_stall_async(
1349 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1350 			if (--sc->wi_usb_refcnt < 0)
1351 				usb_detach_wakeup(&sc->wi_usb_dev);
1352 		}
1353 		goto done;
1354 	}
1355 
1356 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1357 
1358 	if (total_len < 6) /* short XXX */
1359 		goto done;
1360 
1361 	uin = (wi_usb_usbin *)(c->wi_usb_buf);
1362 
1363 	rtype = letoh16(uin->type);
1364 
1365 
1366 #if 0
1367 	wi_dump_data(c->wi_usb_buf, total_len);
1368 #endif
1369 
1370 	if (WI_USB_ISRXFRM(rtype)) {
1371 		wi_usb_rxfrm(sc, uin, total_len);
1372 		goto done;
1373 	}
1374 	if (WI_USB_ISTXFRM(rtype)) {
1375 		DPRINTFN(2,("%s: %s: txfrm type %x\n",
1376 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1377 		wi_usb_txfrm(sc, uin, total_len);
1378 		goto done;
1379 	}
1380 
1381 	switch (rtype) {
1382 	case WI_USB_INFOFRM:
1383 		/* info packet, INFO_FID hmm */
1384 		DPRINTFN(10,("%s: %s: infofrm type %x\n",
1385 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1386 		wi_usb_infofrm(c, total_len);
1387 		break;
1388 	case WI_USB_CMDRESP:
1389 		wi_usb_cmdresp(c);
1390 		break;
1391 	case WI_USB_WRIDRESP:
1392 		wi_usb_wridresp(c);
1393 		break;
1394 	case WI_USB_RRIDRESP:
1395 		wi_usb_rridresp(c);
1396 		break;
1397 	case WI_USB_WMEMRESP:
1398 		/* Not currently used */
1399 		DPRINTFN(2,("%s: %s: wmemresp type %x\n",
1400 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1401 		break;
1402 	case WI_USB_RMEMRESP:
1403 		/* Not currently used */
1404 		DPRINTFN(2,("%s: %s: rmemresp type %x\n",
1405 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1406 		break;
1407 	case WI_USB_BUFAVAIL:
1408 		printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */
1409 		break;
1410 	case WI_USB_ERROR:
1411 		printf("wi_usb: received USB_ERROR packet\n"); /* XXX */
1412 		break;
1413 #if 0
1414 	default:
1415 		printf("wi_usb: received Unknown packet 0x%x len %x\n",
1416 		    rtype, total_len);
1417 		wi_dump_data(c->wi_usb_buf, total_len);
1418 #endif
1419 	}
1420 
1421  done:
1422 	/* Setup new transfer. */
1423 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1424 	    c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
1425 	    USBD_NO_TIMEOUT, wi_usb_rxeof);
1426 	sc->wi_usb_refcnt++;
1427 	usbd_transfer(c->wi_usb_xfer);
1428 	if (--sc->wi_usb_refcnt < 0)
1429 		usb_detach_wakeup(&sc->wi_usb_dev);
1430 
1431 	DPRINTFN(10,("%s: %s: start rx\n", sc->wi_usb_dev.dv_xname,
1432 		    __func__));
1433 }
1434 
1435 void
1436 wi_usb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
1437 {
1438 	struct wi_usb_softc	*sc = priv;
1439 
1440 	DPRINTFN(2,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1441 
1442 	if (usbd_is_dying(sc->wi_usb_udev))
1443 		return;
1444 
1445 	if (status != USBD_NORMAL_COMPLETION) {
1446 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1447 			return;
1448 
1449 		if (status == USBD_STALLED) {
1450 			sc->wi_usb_refcnt++;
1451 			usbd_clear_endpoint_stall_async(
1452 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1453 			if (--sc->wi_usb_refcnt < 0)
1454 				usb_detach_wakeup(&sc->wi_usb_dev);
1455 		}
1456 		return;
1457 	}
1458 	/* XXX oerrors or collisions? */
1459 }
1460 void
1461 wi_usb_cmdresp(struct wi_usb_chain *c)
1462 {
1463 	struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
1464 	u_int16_t status = letoh16(presp->status);
1465 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1466 	uint16_t type;
1467 	uint16_t cmdresperr;
1468 
1469 	type = htole16(presp->type);
1470 	cmdresperr = letoh16(presp->resp0);
1471 	DPRINTFN(10,("%s: %s: enter type=%x, status=%x, cmdresp=%x, "
1472 	    "resp=%x,%x,%x\n",
1473 	    sc->wi_usb_dev.dv_xname, __func__, type, status, sc->cmdresp,
1474 	    cmdresperr, letoh16(presp->resp1),
1475 	    letoh16(presp->resp2)));
1476 
1477 	/* XXX */
1478 	if (sc->cmdresp != (status & WI_STAT_CMD_CODE)) {
1479 		DPRINTFN(1,("%s: cmd ty %x st %x cmd %x failed %x\n",
1480 		    sc->wi_usb_dev.dv_xname,
1481 			type, status, sc->cmdresp, cmdresperr));
1482 		return;
1483 	}
1484 
1485 	sc->cmdresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1486 
1487 	sc->cmdresp = 0; /* good value for idle == INI ?? XXX  */
1488 
1489 	wakeup(&sc->cmdresperr);
1490 }
1491 void
1492 wi_usb_rridresp(struct wi_usb_chain *c)
1493 {
1494 	struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
1495 	u_int16_t frmlen = letoh16(presp->frmlen);
1496 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1497 	struct wi_ltv_gen *ltv;
1498 	uint16_t rid;
1499 
1500 	rid = letoh16(presp->rid);
1501 	ltv =  sc->ridltv;
1502 
1503 	if (ltv == 0) {
1504 		DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
1505 		    sc->wi_usb_dev.dv_xname, __func__, rid,
1506 		    frmlen));
1507 		return;
1508 	}
1509 
1510 	DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
1511 	    sc->wi_usb_dev.dv_xname, __func__, rid, ltv->wi_type,
1512 	    frmlen, ltv->wi_len));
1513 
1514 	rid = letoh16(presp->rid);
1515 
1516 	if (rid != ltv->wi_type) {
1517 		sc->ridresperr = EIO;
1518 		return;
1519 	}
1520 
1521 	if (frmlen > ltv->wi_len) {
1522 		sc->ridresperr = ENOSPC;
1523 		sc->ridltv = 0;
1524 		wakeup(&sc->ridresperr);
1525 		return;
1526 	}
1527 
1528 	ltv->wi_len = frmlen;
1529 
1530 	DPRINTFN(10,("%s: %s: copying %d frmlen %d\n",
1531 	    sc->wi_usb_dev.dv_xname, __func__, (ltv->wi_len-1)*2,
1532 	    frmlen));
1533 
1534 	if (ltv->wi_len > 1)
1535 		bcopy(&presp->data[0], &ltv->wi_val,
1536 		    (ltv->wi_len-1)*2);
1537 
1538 	sc->ridresperr = 0;
1539 	sc->ridltv = 0;
1540 	wakeup(&sc->ridresperr);
1541 
1542 }
1543 
1544 void
1545 wi_usb_wridresp(struct wi_usb_chain *c)
1546 {
1547 	struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
1548 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1549 	uint16_t status;
1550 
1551 	status = letoh16(presp->status);
1552 
1553 	DPRINTFN(10,("%s: %s: enter status=%x\n",
1554 	    sc->wi_usb_dev.dv_xname, __func__, status));
1555 
1556 	sc->ridresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1557 	sc->ridltv = 0;
1558 	wakeup(&sc->ridresperr);
1559 }
1560 
1561 void
1562 wi_usb_infofrm(struct wi_usb_chain *c, int len)
1563 {
1564 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1565 
1566 	DPRINTFN(10,("%s: %s: enter\n",
1567 	    sc->wi_usb_dev.dv_xname, __func__));
1568 
1569 	sc->wi_info = ((char *)c->wi_usb_buf) + 2;
1570 	wi_update_stats(&sc->sc_wi);
1571 	sc->wi_info = NULL;
1572 }
1573 
1574 void
1575 wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1576 {
1577 	u_int16_t		status;
1578 	int 			s;
1579 	struct wi_softc		*wsc = &sc->sc_wi;
1580 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1581 
1582 	s = splnet();
1583 	status = letoh16(uin->type); /* XXX -- type == status */
1584 
1585 
1586 	DPRINTFN(2,("%s: %s: enter status=%d\n",
1587 	    sc->wi_usb_dev.dv_xname, __func__, status));
1588 
1589 	if (sc->txresp == WI_CMD_TX) {
1590 		sc->txresperr=status;
1591 		sc->txresp = 0;
1592 		wakeup(&sc->txresperr);
1593 	} else {
1594 		if (status != 0) /* XXX */
1595 			wi_watchdog_usb(ifp);
1596 	DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
1597 	    sc->wi_usb_dev.dv_xname, __func__, status));
1598 	}
1599 
1600 	splx(s);
1601 }
1602 void
1603 wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1604 {
1605 	int s;
1606 
1607 	DPRINTFN(5,("%s: %s: enter len=%d\n",
1608 	    sc->wi_usb_dev.dv_xname, __func__, total_len));
1609 
1610 	s = splnet();
1611 
1612 	sc->wi_rxframe = (void *)uin;
1613 
1614 	wi_rxeof(&sc->sc_wi);
1615 
1616 	sc->wi_rxframe = NULL;
1617 
1618 	splx(s);
1619 
1620 }
1621 
1622 
1623 void
1624 wi_usb_start_thread(void *arg)
1625 {
1626 	struct wi_usb_softc	*sc = arg;
1627 	kthread_create (wi_usb_thread, arg, NULL, sc->wi_usb_dev.dv_xname);
1628 }
1629 
1630 void
1631 wi_start_usb(struct ifnet *ifp)
1632 {
1633 	struct wi_softc		*wsc;
1634 	struct wi_usb_softc	*sc;
1635 	int s;
1636 
1637 	wsc = ifp->if_softc;
1638 	sc  = wsc->wi_usb_cdata;
1639 
1640 	s = splnet();
1641 
1642 	DPRINTFN(5,("%s: %s:\n",
1643 	    sc->wi_usb_dev.dv_xname, __func__));
1644 
1645 	if (wi_usb_tx_lock_try(sc)) {
1646 		/* lock acquired do start now */
1647 		wi_func_io.f_start(ifp);
1648 	} else {
1649 		sc->wi_thread_info->status |= WI_START;
1650 		if (sc->wi_thread_info->idle)
1651 			wakeup(sc->wi_thread_info);
1652 	}
1653 
1654 	splx(s);
1655 }
1656 
1657 /*
1658  * inquire is called from interrupt context (timeout)
1659  * It is not possible to sleep in interrupt context so it is necessary
1660  * to signal the kernel thread to perform the action.
1661  */
1662 void
1663 wi_init_usb(struct wi_softc *wsc)
1664 {
1665 	DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
1666 
1667 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1668 	wi_func_io.f_init(wsc);
1669 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1670 }
1671 
1672 
1673 /*
1674  * inquire is called from interrupt context (timeout)
1675  * It is not possible to sleep in interrupt context so it is necessary
1676  * to signal the kernel thread to perform the action.
1677  */
1678 void
1679 wi_inquire_usb(void *xsc)
1680 {
1681 	struct wi_softc		*wsc = xsc;
1682 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
1683 	int s;
1684 
1685 
1686 	s = splnet();
1687 
1688 	DPRINTFN(2,("%s: %s:\n",
1689 	    sc->wi_usb_dev.dv_xname, __func__));
1690 
1691 	sc->wi_thread_info->status |= WI_INQUIRE;
1692 
1693 	if (sc->wi_thread_info->idle)
1694 		wakeup(sc->wi_thread_info);
1695 	splx(s);
1696 }
1697 
1698 /*
1699  * Watchdog is normally called from interrupt context (timeout)
1700  * It is not possible to sleep in interrupt context so it is necessary
1701  * to signal the kernel thread to perform the action.
1702  */
1703 void
1704 wi_watchdog_usb(struct ifnet *ifp)
1705 {
1706 	struct wi_softc		*wsc;
1707 	struct wi_usb_softc	*sc;
1708 	int s;
1709 
1710 	wsc = ifp->if_softc;
1711 	sc = wsc->wi_usb_cdata;
1712 
1713 	s = splnet();
1714 
1715 	DPRINTFN(5,("%s: %s: ifp %x\n",
1716 	    sc->wi_usb_dev.dv_xname, __func__, ifp));
1717 
1718 	sc->wi_thread_info->status |= WI_WATCHDOG;
1719 
1720 	if (sc->wi_thread_info->idle)
1721 		wakeup(sc->wi_thread_info);
1722 	splx(s);
1723 }
1724 
1725 /*
1726  * ioctl will always be called from a user context,
1727  * therefore it is possible to sleep in the calling context
1728  * acquire the lock and call the real ioctl function directly
1729  */
1730 int
1731 wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
1732 {
1733 	struct wi_softc		*wsc;
1734 	int err;
1735 
1736 	wsc = ifp->if_softc;
1737 
1738 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1739 	err = wi_func_io.f_ioctl(ifp, command, data);
1740 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1741 	return err;
1742 }
1743 
1744 void
1745 wi_usb_thread(void *arg)
1746 {
1747 	struct wi_usb_softc *sc = arg;
1748 	struct wi_usb_thread_info *wi_thread_info;
1749 	int s;
1750 
1751 	wi_thread_info = malloc(sizeof(*wi_thread_info), M_USBDEV, M_WAITOK);
1752 
1753 	/*
1754 	 * is there a remote possibility that the device could
1755 	 * be removed before the kernel thread starts up?
1756 	 */
1757 
1758 	sc->wi_usb_refcnt++;
1759 
1760 	sc->wi_thread_info = wi_thread_info;
1761 	wi_thread_info->dying = 0;
1762 	wi_thread_info->status = 0;
1763 
1764 	wi_usb_ctl_lock(sc);
1765 
1766 	wi_attach(&sc->sc_wi, &wi_func_usb);
1767 
1768 	wi_usb_ctl_unlock(sc);
1769 
1770 	for(;;) {
1771 		if (wi_thread_info->dying) {
1772 			if (--sc->wi_usb_refcnt < 0)
1773 				usb_detach_wakeup(&sc->wi_usb_dev);
1774 			kthread_exit(0);
1775 		}
1776 
1777 		DPRINTFN(5,("%s: %s: dying %x status %x\n",
1778 		    sc->wi_usb_dev.dv_xname, __func__,
1779 			wi_thread_info->dying, wi_thread_info->status));
1780 
1781 		wi_usb_ctl_lock(sc);
1782 
1783 		DPRINTFN(5,("%s: %s: starting %x\n",
1784 		    sc->wi_usb_dev.dv_xname, __func__,
1785 		    wi_thread_info->status));
1786 
1787 		s = splusb();
1788 		if (wi_thread_info->status & WI_START) {
1789 			wi_thread_info->status &= ~WI_START;
1790 			wi_usb_tx_lock(sc);
1791 			wi_func_io.f_start(&sc->sc_wi.sc_ic.ic_if);
1792 			/*
1793 			 * tx_unlock is explicitly missing here
1794 			 * it is done in txeof_frm
1795 			 */
1796 		} else if (wi_thread_info->status & WI_INQUIRE) {
1797 			wi_thread_info->status &= ~WI_INQUIRE;
1798 			wi_func_io.f_inquire(&sc->sc_wi);
1799 		} else if (wi_thread_info->status & WI_WATCHDOG) {
1800 			wi_thread_info->status &= ~WI_WATCHDOG;
1801 			wi_func_io.f_watchdog( &sc->sc_wi.sc_ic.ic_if);
1802 		}
1803 		splx(s);
1804 
1805 		DPRINTFN(5,("%s: %s: ending %x\n",
1806 		    sc->wi_usb_dev.dv_xname, __func__,
1807 		    wi_thread_info->status));
1808 		wi_usb_ctl_unlock(sc);
1809 
1810 		if (wi_thread_info->status == 0) {
1811 			s = splnet();
1812 			wi_thread_info->idle = 1;
1813 			tsleep_nsec(wi_thread_info, PRIBIO, "wiIDL", INFSLP);
1814 			wi_thread_info->idle = 0;
1815 			splx(s);
1816 		}
1817 	}
1818 }
1819 
1820 int
1821 wi_usb_tx_lock_try(struct wi_usb_softc *sc)
1822 {
1823 	int s;
1824 
1825 	s = splnet();
1826 
1827 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1828 
1829 	if (sc->wi_lock != 0) {
1830 		splx(s);
1831 		return 0; /* failed to aquire lock */
1832 	}
1833 
1834 	sc->wi_lock = 1;
1835 
1836 	splx(s);
1837 
1838 	return 1;
1839 }
1840 void
1841 wi_usb_tx_lock(struct wi_usb_softc *sc)
1842 {
1843 	int s;
1844 
1845 	s = splnet();
1846 
1847 	again:
1848 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1849 
1850 	if (sc->wi_lock != 0) {
1851 		sc->wi_lockwait++;
1852 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1853 		__func__, sc->wi_lockwait ));
1854 		tsleep_nsec(&sc->wi_lock, PRIBIO, "witxl", INFSLP);
1855 	}
1856 
1857 	if (sc->wi_lock != 0)
1858 		goto again;
1859 	sc->wi_lock = 1;
1860 
1861 	splx(s);
1862 
1863 	return;
1864 
1865 }
1866 
1867 void
1868 wi_usb_tx_unlock(struct wi_usb_softc *sc)
1869 {
1870 	int s;
1871 	s = splnet();
1872 
1873 	sc->wi_lock = 0;
1874 
1875 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1876 
1877 	if (sc->wi_lockwait) {
1878 		DPRINTFN(10,("%s: %s: waking\n",
1879 		    sc->wi_usb_dev.dv_xname, __func__));
1880 		sc->wi_lockwait = 0;
1881 		wakeup(&sc->wi_lock);
1882 	}
1883 
1884 	splx(s);
1885 }
1886 
1887 void
1888 wi_usb_ctl_lock(struct wi_usb_softc *sc)
1889 {
1890 	int s;
1891 
1892 	s = splnet();
1893 
1894 	again:
1895 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,
1896 	    __func__));
1897 
1898 	if (sc->wi_ctllock != 0) {
1899 		if (curproc == sc->wi_curproc) {
1900 			/* allow recursion */
1901 			sc->wi_ctllock++;
1902 			splx(s);
1903 			return;
1904 		}
1905 		sc->wi_ctllockwait++;
1906 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1907 		__func__, sc->wi_ctllockwait ));
1908 		tsleep_nsec(&sc->wi_ctllock, PRIBIO, "wiusbthr", INFSLP);
1909 	}
1910 
1911 	if (sc->wi_ctllock != 0)
1912 		goto again;
1913 	sc->wi_ctllock++;
1914 	sc->wi_curproc = curproc;
1915 
1916 	splx(s);
1917 
1918 	return;
1919 
1920 }
1921 
1922 void
1923 wi_usb_ctl_unlock(struct wi_usb_softc *sc)
1924 {
1925 	int s;
1926 
1927 	s = splnet();
1928 
1929 	sc->wi_ctllock--;
1930 
1931 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1932 
1933 	if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
1934 		DPRINTFN(10,("%s: %s: waking\n",
1935 		    sc->wi_usb_dev.dv_xname, __func__));
1936 		sc->wi_ctllockwait = 0;
1937 		sc->wi_curproc = 0;
1938 		wakeup(&sc->wi_ctllock);
1939 	}
1940 
1941 	splx(s);
1942 }
1943