xref: /openbsd-src/sys/dev/usb/if_wi_usb.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: if_wi_usb.c,v 1.71 2019/11/27 11:16:59 mpi 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_DEVBUF,
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 		usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
420 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
421 		if (err) {
422 			printf("%s: close intr pipe failed: %s\n",
423 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
424 		}
425 		sc->wi_usb_ep[WI_USB_ENDPT_INTR] = NULL;
426 	}
427 	if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL) {
428 		usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
429 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
430 		if (err) {
431 			printf("%s: close tx pipe failed: %s\n",
432 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
433 		}
434 		sc->wi_usb_ep[WI_USB_ENDPT_TX] = NULL;
435 	}
436 	if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL) {
437 		usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
438 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
439 		if (err) {
440 			printf("%s: close rx pipe failed: %s\n",
441 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
442 		}
443 		sc->wi_usb_ep[WI_USB_ENDPT_RX] = NULL;
444 	}
445 
446 	splx(s);
447 
448 	return (0);
449 }
450 
451 int
452 wi_send_packet(struct wi_usb_softc *sc, int id)
453 {
454 	struct wi_usb_chain	*c;
455 	struct wi_frame		*wibuf;
456 	int			total_len, rnd_len;
457 	int			err;
458 
459 	c = &sc->wi_usb_tx_chain[0];
460 
461 	DPRINTFN(10,("%s: %s: id=%x\n",
462 	    sc->wi_usb_dev.dv_xname, __func__, id));
463 
464 	/* assemble packet from write_data buffer */
465 	if (id == 0 || id == 1) {
466 		/* tx_lock acquired before wi_start() */
467 		wibuf = sc->wi_usb_txmem[id];
468 
469 		total_len = sizeof (struct wi_frame) +
470 		    letoh16(wibuf->wi_dat_len);
471 		rnd_len = ROUNDUP64(total_len);
472 		if ((total_len > sc->wi_usb_txmemsize[id]) ||
473 		   (rnd_len > WI_USB_BUFSZ )){
474 			printf("invalid packet len: %x memsz %x max %x\n",
475 			    total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
476 
477 			err = EIO;
478 			goto err_ret;
479 		}
480 
481 		sc->txresp = WI_CMD_TX;
482 		sc->txresperr = 0;
483 
484 		bcopy(wibuf, c->wi_usb_buf, total_len);
485 
486 		bzero(((char *)c->wi_usb_buf)+total_len,
487 		    rnd_len - total_len);
488 
489 		/* zero old packet for next TX */
490 		bzero(wibuf, total_len);
491 
492 		total_len = rnd_len;
493 
494 		DPRINTFN(5,("%s: %s: id=%x len=%x\n",
495 		    sc->wi_usb_dev.dv_xname, __func__, id, total_len));
496 
497 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
498 		    c, c->wi_usb_buf, rnd_len,
499 		    USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
500 		    WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
501 
502 		err = usbd_transfer(c->wi_usb_xfer);
503 		if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
504 			printf("%s: %s: error=%s\n",
505 			    sc->wi_usb_dev.dv_xname, __func__,
506 			    usbd_errstr(err));
507 			/* Stop the interface from process context. */
508 			wi_usb_stop(sc);
509 			err = EIO;
510 		} else {
511 			err = 0;
512 		}
513 
514 		DPRINTFN(5,("%s: %s: exit err=%x\n",
515 		    sc->wi_usb_dev.dv_xname, __func__, err));
516 err_ret:
517 		return err;
518 	}
519 	printf("%s:%s: invalid packet id sent %x\n",
520 	    sc->wi_usb_dev.dv_xname, __func__, id);
521 	return 0;
522 }
523 
524 int
525 wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
526 {
527 	struct wi_usb_chain	*c;
528 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
529 	struct wi_cmdreq	*pcmd;
530 	int			total_len, rnd_len;
531 	int			err;
532 
533 	DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
534 	    sc->wi_usb_dev.dv_xname, __func__, cmd, val0, val1, val2));
535 
536 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
537 		return wi_send_packet(sc, val0);
538 	}
539 
540 
541 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
542 		/* free alloc_nicmem regions */
543 		while (sc->wi_usb_nummem) {
544 			sc->wi_usb_nummem--;
545 			free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF,
546 			  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
547 			sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
548 			sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
549 		}
550 
551 #if 0
552 		/* if this is the first time, init, otherwise do not?? */
553 		if (sc->wi_resetonce) {
554 			return 0;
555 		} else
556 			sc->wi_resetonce = 1;
557 #endif
558 	}
559 
560 	wi_usb_ctl_lock(sc);
561 
562 	wi_usb_tx_lock(sc);
563 
564 	c = &sc->wi_usb_tx_chain[0];
565 	pcmd = c->wi_usb_buf;
566 
567 
568 	total_len = sizeof (struct wi_cmdreq);
569 	rnd_len = ROUNDUP64(total_len);
570 	if (rnd_len > WI_USB_BUFSZ) {
571 		printf("read_record buf size err %x %x\n",
572 		    rnd_len, WI_USB_BUFSZ);
573 		err = EIO;
574 		goto err_ret;
575 	}
576 
577 	sc->cmdresp = cmd;
578 	sc->cmdresperr = 0;
579 
580 	pcmd->type = htole16(WI_USB_CMDREQ);
581 	pcmd->cmd  = htole16(cmd);
582 	pcmd->param0  = htole16(val0);
583 	pcmd->param1  = htole16(val1);
584 	pcmd->param2  = htole16(val2);
585 
586 	bzero(((char*)pcmd)+total_len, rnd_len - total_len);
587 
588 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
589 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
590 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
591 
592 	err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
593 
594 	if (err == 0)
595 		err = sc->cmdresperr;
596 
597 	sc->cmdresperr = 0;
598 
599 err_ret:
600 	wi_usb_tx_unlock(sc);
601 
602 	wi_usb_ctl_unlock(sc);
603 
604 	DPRINTFN(5,("%s: %s: exit err=%x\n",
605 	    sc->wi_usb_dev.dv_xname, __func__, err));
606 	return err;
607 }
608 
609 
610 int
611 wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
612 {
613 	struct wi_usb_chain	*c;
614 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
615 	struct wi_rridreq	*prid;
616 	int			total_len, rnd_len;
617 	int			err;
618 	struct wi_ltv_gen	*oltv = NULL, p2ltv;
619 
620 	DPRINTFN(5,("%s: %s: enter rid=%x\n",
621 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type));
622 
623 	/* Do we need to deal with these here, as in _io version?
624 	 * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
625 	 * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
626 	 */
627 	if (wsc->sc_firmware_type != WI_LUCENT) {
628 		oltv = ltv;
629 		switch (ltv->wi_type) {
630 		case WI_RID_ENCRYPTION:
631 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
632 			p2ltv.wi_len = 2;
633 			ltv = &p2ltv;
634 			break;
635 		case WI_RID_TX_CRYPT_KEY:
636 			if (ltv->wi_val > WI_NLTV_KEYS)
637 				return (EINVAL);
638 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
639 			p2ltv.wi_len = 2;
640 			ltv = &p2ltv;
641 			break;
642 		}
643 	}
644 
645 	wi_usb_tx_lock(sc);
646 
647 	c = &sc->wi_usb_tx_chain[0];
648 	prid = c->wi_usb_buf;
649 
650 	total_len = sizeof(struct wi_rridreq);
651 	rnd_len = ROUNDUP64(total_len);
652 
653 	if (rnd_len > WI_USB_BUFSZ) {
654 		printf("read_record buf size err %x %x\n",
655 		    rnd_len, WI_USB_BUFSZ);
656 		wi_usb_tx_unlock(sc);
657 		return EIO;
658 	}
659 
660 	sc->ridltv = ltv;
661 	sc->ridresperr = 0;
662 
663 	prid->type = htole16(WI_USB_RRIDREQ);
664 	prid->frmlen = htole16(2);	/* variable size? */
665 	prid->rid  = htole16(ltv->wi_type);
666 
667 	bzero(((char*)prid)+total_len, rnd_len - total_len);
668 
669 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
670 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
671 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
672 
673 	DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
674 	    sc->wi_usb_dev.dv_xname, __func__, total_len, ltv->wi_len));
675 
676 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
677 
678 	/* Do we need to deal with these here, as in _io version?
679 	 *
680 	 * WI_RID_TX_RATE
681 	 * WI_RID_CUR_TX_RATE
682 	 * WI_RID_ENCRYPTION
683 	 * WI_RID_TX_CRYPT_KEY
684 	 * WI_RID_CNFAUTHMODE
685 	 */
686 	if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
687 	    && ltv->wi_val == wsc->wi_ibss_port) {
688 		/*
689 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
690 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
691 		 * have to rely on wi_ptype to distinguish this for us.
692 		 */
693 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
694 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
695 		int v;
696 
697 		switch (oltv->wi_type) {
698 		case WI_RID_TX_RATE:
699 		case WI_RID_CUR_TX_RATE:
700 			switch (letoh16(ltv->wi_val)) {
701 			case 1: v = 1; break;
702 			case 2: v = 2; break;
703 			case 3:	v = 6; break;
704 			case 4: v = 5; break;
705 			case 7: v = 7; break;
706 			case 8: v = 11; break;
707 			case 15: v = 3; break;
708 			default: v = 0x100 + letoh16(ltv->wi_val); break;
709 			}
710 			oltv->wi_val = htole16(v);
711 			break;
712 		case WI_RID_ENCRYPTION:
713 			oltv->wi_len = 2;
714 			if (ltv->wi_val & htole16(0x01))
715 				oltv->wi_val = htole16(1);
716 			else
717 				oltv->wi_val = htole16(0);
718 			break;
719 		case WI_RID_TX_CRYPT_KEY:
720 		case WI_RID_CNFAUTHMODE:
721 			oltv->wi_len = 2;
722 			oltv->wi_val = ltv->wi_val;
723 			break;
724 		}
725 	}
726 
727 	if (err == 0)
728 		err = sc->ridresperr;
729 
730 	sc->ridresperr = 0;
731 
732 	wi_usb_tx_unlock(sc);
733 
734 	DPRINTFN(5,("%s: %s: exit err=%x\n",
735 	    sc->wi_usb_dev.dv_xname, __func__, err));
736 	return err;
737 }
738 
739 int
740 wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
741 {
742 	struct wi_usb_chain	*c;
743 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
744 	struct wi_wridreq	*prid;
745 	int			total_len, rnd_len;
746 	int			err;
747 	struct wi_ltv_gen	p2ltv;
748 	u_int16_t		val = 0;
749 	int			i;
750 
751 	DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
752 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
753 	    (ltv->wi_len-1)*2 ));
754 
755 	/* Do we need to deal with these here, as in _io version?
756 	 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
757 	 * RID_TX_RATE munging
758 	 * RID_ENCRYPTION
759 	 * WI_RID_TX_CRYPT_KEY
760 	 * WI_RID_DEFLT_CRYPT_KEYS
761 	 */
762 	if (ltv->wi_type == WI_RID_PORTTYPE &&
763 	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
764 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
765 		p2ltv.wi_type = WI_RID_PORTTYPE;
766 		p2ltv.wi_len = 2;
767 		p2ltv.wi_val = wsc->wi_ibss_port;
768 		ltv = &p2ltv;
769 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
770 		int v;
771 
772 		switch (ltv->wi_type) {
773 		case WI_RID_TX_RATE:
774 			p2ltv.wi_type = WI_RID_TX_RATE;
775 			p2ltv.wi_len = 2;
776 			switch (letoh16(ltv->wi_val)) {
777 			case 1: v = 1; break;
778 			case 2: v = 2; break;
779 			case 3:	v = 15; break;
780 			case 5: v = 4; break;
781 			case 6: v = 3; break;
782 			case 7: v = 7; break;
783 			case 11: v = 8; break;
784 			default: return EINVAL;
785 			}
786 			p2ltv.wi_val = htole16(v);
787 			ltv = &p2ltv;
788 			break;
789 		case WI_RID_ENCRYPTION:
790 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
791 			p2ltv.wi_len = 2;
792 			if (ltv->wi_val & htole16(0x01)) {
793 				val = PRIVACY_INVOKED;
794 				/*
795 				 * If using shared key WEP we must set the
796 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
797 				 * need this bit set even when not using
798 				 * shared key. We can't just test for
799 				 * IEEE80211_AUTH_SHARED since Symbol cards
800 				 * have 2 shared key modes.
801 				 */
802 				if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
803 				    wsc->sc_firmware_type == WI_SYMBOL)
804 					val |= EXCLUDE_UNENCRYPTED;
805 
806 				switch (wsc->wi_crypto_algorithm) {
807 				case WI_CRYPTO_FIRMWARE_WEP:
808 					/*
809 					 * TX encryption is broken in
810 					 * Host AP mode.
811 					 */
812 					if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
813 						val |= HOST_ENCRYPT;
814 					break;
815 				case WI_CRYPTO_SOFTWARE_WEP:
816 					val |= HOST_ENCRYPT|HOST_DECRYPT;
817 					break;
818 				}
819 				p2ltv.wi_val = htole16(val);
820 			} else
821 				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
822 			ltv = &p2ltv;
823 			break;
824 		case WI_RID_TX_CRYPT_KEY:
825 			if (ltv->wi_val > WI_NLTV_KEYS)
826 				return (EINVAL);
827 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
828 			p2ltv.wi_len = 2;
829 			p2ltv.wi_val = ltv->wi_val;
830 			ltv = &p2ltv;
831 			break;
832 		case WI_RID_DEFLT_CRYPT_KEYS: {
833 				int error;
834 				int keylen;
835 				struct wi_ltv_str ws;
836 				struct wi_ltv_keys *wk;
837 
838 				wk = (struct wi_ltv_keys *)ltv;
839 				keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
840 				keylen = letoh16(keylen);
841 
842 				for (i = 0; i < 4; i++) {
843 					bzero(&ws, sizeof(ws));
844 					ws.wi_len = (keylen > 5) ? 8 : 4;
845 					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
846 					bcopy(&wk->wi_keys[i].wi_keydat,
847 					    ws.wi_str, keylen);
848 					error = wi_write_record_usb(wsc,
849 					    (struct wi_ltv_gen *)&ws);
850 					if (error)
851 						return (error);
852 				}
853 			}
854 			return (0);
855 		}
856 	}
857 
858 	wi_usb_tx_lock(sc);
859 
860 	c = &sc->wi_usb_tx_chain[0];
861 
862 	prid = c->wi_usb_buf;
863 
864 	total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
865 	    sizeof(prid->rid) + (ltv->wi_len-1)*2;
866 	rnd_len = ROUNDUP64(total_len);
867 	if (rnd_len > WI_USB_BUFSZ) {
868 		printf("write_record buf size err %x %x\n",
869 		    rnd_len, WI_USB_BUFSZ);
870 		wi_usb_tx_unlock(sc);
871 		return EIO;
872 	}
873 
874 	prid->type = htole16(WI_USB_WRIDREQ);
875 	prid->frmlen = htole16(ltv->wi_len);
876 	prid->rid  = htole16(ltv->wi_type);
877 	if (ltv->wi_len > 1)
878 		bcopy(&ltv->wi_val, &prid->data[0], (ltv->wi_len-1)*2);
879 
880 	bzero(((char*)prid)+total_len, rnd_len - total_len);
881 
882 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
883 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
884 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
885 
886 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
887 
888 	if (err == 0)
889 		err = sc->ridresperr;
890 
891 	sc->ridresperr = 0;
892 
893 	wi_usb_tx_unlock(sc);
894 
895 	DPRINTFN(5,("%s: %s: exit err=%x\n",
896 	    sc->wi_usb_dev.dv_xname, __func__, err));
897 	return err;
898 }
899 
900 /*
901  * This is an ugly compat portion to emulate the I/O which writes
902  * a packet or management information
903  * The data is copied into local memory for the requested
904  * 'id' then on the wi_cmd WI_CMD_TX, the id argument
905  * will identify which buffer to use
906  */
907 int
908 wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
909 {
910 	int nmem;
911 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
912 
913 	DPRINTFN(10,("%s: %s: enter len=%x\n",
914 	    sc->wi_usb_dev.dv_xname, __func__, len));
915 
916 	/*
917 	 * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
918 	 * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
919 	 */
920 	nmem = sc->wi_usb_nummem++;
921 
922 	if (nmem >= MAX_WI_NMEM) {
923 		sc->wi_usb_nummem--;
924 		return ENOMEM;
925 	}
926 
927 	sc->wi_usb_txmem[nmem] = malloc(len, M_DEVBUF, M_WAITOK | M_CANFAIL);
928 	if (sc->wi_usb_txmem[nmem] == NULL) {
929 		sc->wi_usb_nummem--;
930 		return ENOMEM;
931 	}
932 	sc->wi_usb_txmemsize[nmem] = len;
933 
934 	*id = nmem;
935 	return 0;
936 }
937 
938 /*
939  * this is crazy, we skip the first 16 bits of the buf so that it
940  * can be used as the 'type' of the usb transfer.
941  */
942 
943 
944 int
945 wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
946 {
947 	u_int8_t	*ptr;
948 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
949 
950 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
951 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
952 
953 	if (id < 0 && id >= sc->wi_usb_nummem)
954 		return EIO;
955 
956 	ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
957 
958 	if (len + off > sc->wi_usb_txmemsize[id])
959 		return EIO;
960 	DPRINTFN(10,("%s: %s: completed \n",
961 	    sc->wi_usb_dev.dv_xname, __func__));
962 
963 	bcopy(buf, ptr, len);
964 	return 0;
965 }
966 
967 /*
968  * On the prism I/O, this read_data points to the hardware buffer
969  * which contains the
970  */
971 int
972 wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
973 {
974 	u_int8_t	*ptr;
975 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
976 
977 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
978 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
979 
980 	if (id == 0x1001 && sc->wi_info != NULL)
981 		ptr = (u_int8_t *)sc->wi_info + off;
982 	else if (id == 0x1000 && sc->wi_rxframe != NULL)
983 		ptr = (u_int8_t *)sc->wi_rxframe + off;
984 	else if (id >= 0 && id < sc->wi_usb_nummem) {
985 
986 		if (sc->wi_usb_txmem[id] == NULL)
987 			return EIO;
988 		if (len + off > sc->wi_usb_txmemsize[id])
989 			return EIO;
990 
991 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
992 	} else
993 		return EIO;
994 
995 	if (id < sc->wi_usb_nummem) {
996 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
997 
998 		if (len + off > sc->wi_usb_txmemsize[id])
999 			return EIO;
1000 	}
1001 
1002 	bcopy(ptr, buf, len);
1003 	return 0;
1004 }
1005 
1006 void
1007 wi_usb_stop(struct wi_usb_softc *sc)
1008 {
1009 	DPRINTFN(1,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1010 	/* XXX */
1011 
1012 	/* Stop transfers */
1013 }
1014 
1015 int
1016 wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
1017     void *ident)
1018 {
1019 	usbd_status		err;
1020 
1021 	DPRINTFN(10,("%s: %s:\n",
1022 	    sc->wi_usb_dev.dv_xname, __func__));
1023 
1024 	sc->wi_usb_refcnt++;
1025 	err = usbd_transfer(c->wi_usb_xfer);
1026 	if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
1027 		printf("%s: %s error=%s\n",
1028 		    sc->wi_usb_dev.dv_xname, __func__,
1029 		    usbd_errstr(err));
1030 		/* Stop the interface from process context. */
1031 		wi_usb_stop(sc);
1032 		err = EIO;
1033 		goto done;
1034 	}
1035 	err = tsleep_nsec(ident, PRIBIO, "wiTXsync", SEC_TO_NSEC(1));
1036 	if (err) {
1037 		DPRINTFN(1,("%s: %s: err %x\n",
1038 		    sc->wi_usb_dev.dv_xname, __func__, err));
1039 		err = ETIMEDOUT;
1040 	}
1041 done:
1042 	if (--sc->wi_usb_refcnt < 0)
1043 		usb_detach_wakeup(&sc->wi_usb_dev);
1044 	return err;
1045 }
1046 
1047 
1048 /*
1049  * A command/rrid/wrid  was sent to the chip. It's safe for us to clean up
1050  * the list buffers.
1051  */
1052 
1053 void
1054 wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
1055     usbd_status status)
1056 {
1057 	struct wi_usb_chain	*c = priv;
1058 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1059 
1060 	int			s;
1061 
1062 	if (usbd_is_dying(sc->wi_usb_udev))
1063 		return;
1064 
1065 	s = splnet();
1066 
1067 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1068 		    __func__, status));
1069 
1070 	if (status != USBD_NORMAL_COMPLETION) {
1071 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1072 			splx(s);
1073 			return;
1074 		}
1075 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1076 		    usbd_errstr(status));
1077 		if (status == USBD_STALLED) {
1078 			sc->wi_usb_refcnt++;
1079 			usbd_clear_endpoint_stall_async(
1080 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1081 			if (--sc->wi_usb_refcnt < 0)
1082 				usb_detach_wakeup(&sc->wi_usb_dev);
1083 		}
1084 		splx(s);
1085 		return;
1086 	}
1087 
1088 	splx(s);
1089 }
1090 
1091 /*
1092  * A packet was sent to the chip. It's safe for us to clean up
1093  * the list buffers.
1094  */
1095 
1096 void
1097 wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
1098     usbd_status status)
1099 {
1100 	struct wi_usb_chain	*c = priv;
1101 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1102 	struct wi_softc		*wsc = &sc->sc_wi;
1103 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1104 
1105 	int			s;
1106 	int			err = 0;
1107 
1108 	if (usbd_is_dying(sc->wi_usb_udev))
1109 		return;
1110 
1111 	s = splnet();
1112 
1113 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1114 		    __func__, status));
1115 
1116 	if (status != USBD_NORMAL_COMPLETION) {
1117 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1118 			splx(s);
1119 			return;
1120 		}
1121 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
1122 		    usbd_errstr(status));
1123 		if (status == USBD_STALLED) {
1124 			sc->wi_usb_refcnt++;
1125 			usbd_clear_endpoint_stall_async(
1126 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1127 			if (--sc->wi_usb_refcnt < 0)
1128 				usb_detach_wakeup(&sc->wi_usb_dev);
1129 		}
1130 		splx(s);
1131 		return;
1132 	}
1133 
1134 	if (status)
1135 		err = WI_EV_TX_EXC;
1136 
1137 	wi_txeof(wsc, err);
1138 
1139 	wi_usb_tx_unlock(sc);
1140 
1141 	if (!IFQ_IS_EMPTY(&ifp->if_snd))
1142 		wi_start_usb(ifp);
1143 
1144 	splx(s);
1145 }
1146 
1147 int
1148 wi_usb_rx_list_init(struct wi_usb_softc *sc)
1149 {
1150 	struct wi_usb_chain	*c;
1151 	int			i;
1152 
1153 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1154 
1155 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1156 		c = &sc->wi_usb_rx_chain[i];
1157 		c->wi_usb_sc = sc;
1158 		c->wi_usb_idx = i;
1159 		if (c->wi_usb_xfer != NULL) {
1160 			printf("UGH RX\n");
1161 		}
1162 		if (c->wi_usb_xfer == NULL) {
1163 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1164 			if (c->wi_usb_xfer == NULL)
1165 				return (ENOBUFS);
1166 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1167 			    WI_USB_BUFSZ);
1168 			if (c->wi_usb_buf == NULL)
1169 				return (ENOBUFS); /* XXX free xfer */
1170 		}
1171 	}
1172 
1173 	return (0);
1174 }
1175 
1176 int
1177 wi_usb_tx_list_init(struct wi_usb_softc *sc)
1178 {
1179 	struct wi_usb_chain	*c;
1180 	int			i;
1181 
1182 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1183 
1184 	for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
1185 		c = &sc->wi_usb_tx_chain[i];
1186 		c->wi_usb_sc = sc;
1187 		c->wi_usb_idx = i;
1188 		c->wi_usb_mbuf = NULL;
1189 		if (c->wi_usb_xfer != NULL) {
1190 			printf("UGH TX\n");
1191 		}
1192 		if (c->wi_usb_xfer == NULL) {
1193 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
1194 			if (c->wi_usb_xfer == NULL)
1195 				return (ENOBUFS);
1196 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
1197 			    WI_USB_BUFSZ);
1198 			if (c->wi_usb_buf == NULL)
1199 				return (ENOBUFS);
1200 		}
1201 	}
1202 
1203 	return (0);
1204 }
1205 
1206 int
1207 wi_usb_open_pipes(struct wi_usb_softc *sc)
1208 {
1209 	usbd_status		err;
1210 	int			error = 0;
1211 	struct wi_usb_chain	*c;
1212 	int			i;
1213 
1214 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
1215 
1216 	sc->wi_usb_refcnt++;
1217 
1218 	/* Open RX and TX pipes. */
1219 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
1220 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1221 	if (err) {
1222 		printf("%s: open rx pipe failed: %s\n",
1223 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1224 		error = EIO;
1225 		goto done;
1226 	}
1227 
1228 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
1229 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
1230 	if (err) {
1231 		printf("%s: open tx pipe failed: %s\n",
1232 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1233 		error = EIO;
1234 		goto done;
1235 	}
1236 
1237 	/* is this used? */
1238 	err = usbd_open_pipe_intr(sc->wi_usb_iface,
1239 	    sc->wi_usb_ed[WI_USB_ENDPT_INTR], USBD_EXCLUSIVE_USE,
1240 	    &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
1241 	    WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
1242 	if (err) {
1243 		printf("%s: open intr pipe failed: %s\n",
1244 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
1245 		error = EIO;
1246 		goto done;
1247 	}
1248 
1249 	/* Start up the receive pipe. */
1250 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
1251 		c = &sc->wi_usb_rx_chain[i];
1252 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1253 		    c, c->wi_usb_buf, WI_USB_BUFSZ,
1254 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1255 		    wi_usb_rxeof);
1256 		DPRINTFN(10,("%s: %s: start read\n", sc->wi_usb_dev.dv_xname,
1257 			    __func__));
1258 		usbd_transfer(c->wi_usb_xfer);
1259 	}
1260 
1261 done:
1262 	if (--sc->wi_usb_refcnt < 0)
1263 		usb_detach_wakeup(&sc->wi_usb_dev);
1264 
1265 	return (error);
1266 }
1267 
1268 /*
1269  * This is a bit of a kludge, however wi_rxeof and wi_update_stats
1270  * call wi_get_fid to determine where the data associated with
1271  * the transaction is located, the returned id is then used to
1272  * wi_read_data the information out.
1273  *
1274  * This code returns which 'fid' should be used. The results are only valid
1275  * during a wi_usb_rxeof because the data is received packet is 'held'
1276  * an a variable for reading by wi_read_data_usb for that period.
1277  *
1278  * for magic numbers this uses  0x1000, 0x1001 for rx/info
1279  */
1280 
1281 int
1282 wi_get_fid_usb(struct wi_softc *sc, int fid)
1283 {
1284 	switch (fid) {
1285 	case WI_RX_FID:
1286 		return 0x1000;
1287 	case WI_INFO_FID:
1288 		return 0x1001;
1289 	default:
1290 		return 0x1111;
1291 	}
1292 
1293 }
1294 
1295 #if 0
1296 void
1297 wi_dump_data(void *buffer, int len)
1298 {
1299 	int i;
1300 	for (i = 0; i < len; i++) {
1301 		if (((i) % 16) == 0)
1302 			printf("\n %02x:", i);
1303 		printf(" %02x",
1304 		    ((uint8_t *)(buffer))[i]);
1305 
1306 	}
1307 	printf("\n");
1308 
1309 }
1310 #endif
1311 
1312 /*
1313  * A frame has been received.
1314  */
1315 void
1316 wi_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1317 {
1318 	struct wi_usb_chain	*c = priv;
1319 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1320 	wi_usb_usbin		*uin;
1321 	int			total_len = 0;
1322 	u_int16_t		rtype;
1323 
1324 	if (usbd_is_dying(sc->wi_usb_udev))
1325 		return;
1326 
1327 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
1328 		    __func__, status));
1329 
1330 
1331 	if (status != USBD_NORMAL_COMPLETION) {
1332 		if (status == USBD_NOT_STARTED || status == USBD_IOERROR
1333 		    || status == USBD_CANCELLED) {
1334 			printf("%s: %u usb errors on rx: %s\n",
1335 			    sc->wi_usb_dev.dv_xname, 1,
1336 			    /* sc->wi_usb_rx_errs, */
1337 			    usbd_errstr(status));
1338 			return;
1339 		}
1340 #if 0
1341 		sc->wi_usb_rx_errs++;
1342 		if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
1343 			printf("%s: %u usb errors on rx: %s\n",
1344 			    sc->wi_usb_dev.dv_xname, sc->wi_usb_rx_errs,
1345 			    usbd_errstr(status));
1346 			sc->wi_usb_rx_errs = 0;
1347 		}
1348 #endif
1349 		if (status == USBD_STALLED) {
1350 			sc->wi_usb_refcnt++;
1351 			usbd_clear_endpoint_stall_async(
1352 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1353 			if (--sc->wi_usb_refcnt < 0)
1354 				usb_detach_wakeup(&sc->wi_usb_dev);
1355 		}
1356 		goto done;
1357 	}
1358 
1359 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1360 
1361 	if (total_len < 6) /* short XXX */
1362 		goto done;
1363 
1364 	uin = (wi_usb_usbin *)(c->wi_usb_buf);
1365 
1366 	rtype = letoh16(uin->type);
1367 
1368 
1369 #if 0
1370 	wi_dump_data(c->wi_usb_buf, total_len);
1371 #endif
1372 
1373 	if (WI_USB_ISRXFRM(rtype)) {
1374 		wi_usb_rxfrm(sc, uin, total_len);
1375 		goto done;
1376 	}
1377 	if (WI_USB_ISTXFRM(rtype)) {
1378 		DPRINTFN(2,("%s: %s: txfrm type %x\n",
1379 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1380 		wi_usb_txfrm(sc, uin, total_len);
1381 		goto done;
1382 	}
1383 
1384 	switch (rtype) {
1385 	case WI_USB_INFOFRM:
1386 		/* info packet, INFO_FID hmm */
1387 		DPRINTFN(10,("%s: %s: infofrm type %x\n",
1388 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1389 		wi_usb_infofrm(c, total_len);
1390 		break;
1391 	case WI_USB_CMDRESP:
1392 		wi_usb_cmdresp(c);
1393 		break;
1394 	case WI_USB_WRIDRESP:
1395 		wi_usb_wridresp(c);
1396 		break;
1397 	case WI_USB_RRIDRESP:
1398 		wi_usb_rridresp(c);
1399 		break;
1400 	case WI_USB_WMEMRESP:
1401 		/* Not currently used */
1402 		DPRINTFN(2,("%s: %s: wmemresp type %x\n",
1403 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1404 		break;
1405 	case WI_USB_RMEMRESP:
1406 		/* Not currently used */
1407 		DPRINTFN(2,("%s: %s: rmemresp type %x\n",
1408 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
1409 		break;
1410 	case WI_USB_BUFAVAIL:
1411 		printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */
1412 		break;
1413 	case WI_USB_ERROR:
1414 		printf("wi_usb: received USB_ERROR packet\n"); /* XXX */
1415 		break;
1416 #if 0
1417 	default:
1418 		printf("wi_usb: received Unknown packet 0x%x len %x\n",
1419 		    rtype, total_len);
1420 		wi_dump_data(c->wi_usb_buf, total_len);
1421 #endif
1422 	}
1423 
1424  done:
1425 	/* Setup new transfer. */
1426 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
1427 	    c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
1428 	    USBD_NO_TIMEOUT, wi_usb_rxeof);
1429 	sc->wi_usb_refcnt++;
1430 	usbd_transfer(c->wi_usb_xfer);
1431 	if (--sc->wi_usb_refcnt < 0)
1432 		usb_detach_wakeup(&sc->wi_usb_dev);
1433 
1434 	DPRINTFN(10,("%s: %s: start rx\n", sc->wi_usb_dev.dv_xname,
1435 		    __func__));
1436 }
1437 
1438 void
1439 wi_usb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
1440 {
1441 	struct wi_usb_softc	*sc = priv;
1442 
1443 	DPRINTFN(2,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1444 
1445 	if (usbd_is_dying(sc->wi_usb_udev))
1446 		return;
1447 
1448 	if (status != USBD_NORMAL_COMPLETION) {
1449 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1450 			return;
1451 
1452 		if (status == USBD_STALLED) {
1453 			sc->wi_usb_refcnt++;
1454 			usbd_clear_endpoint_stall_async(
1455 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
1456 			if (--sc->wi_usb_refcnt < 0)
1457 				usb_detach_wakeup(&sc->wi_usb_dev);
1458 		}
1459 		return;
1460 	}
1461 	/* XXX oerrors or collisions? */
1462 }
1463 void
1464 wi_usb_cmdresp(struct wi_usb_chain *c)
1465 {
1466 	struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
1467 	u_int16_t status = letoh16(presp->status);
1468 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1469 	uint16_t type;
1470 	uint16_t cmdresperr;
1471 
1472 	type = htole16(presp->type);
1473 	cmdresperr = letoh16(presp->resp0);
1474 	DPRINTFN(10,("%s: %s: enter type=%x, status=%x, cmdresp=%x, "
1475 	    "resp=%x,%x,%x\n",
1476 	    sc->wi_usb_dev.dv_xname, __func__, type, status, sc->cmdresp,
1477 	    cmdresperr, letoh16(presp->resp1),
1478 	    letoh16(presp->resp2)));
1479 
1480 	/* XXX */
1481 	if (sc->cmdresp != (status & WI_STAT_CMD_CODE)) {
1482 		DPRINTFN(1,("%s: cmd ty %x st %x cmd %x failed %x\n",
1483 		    sc->wi_usb_dev.dv_xname,
1484 			type, status, sc->cmdresp, cmdresperr));
1485 		return;
1486 	}
1487 
1488 	sc->cmdresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1489 
1490 	sc->cmdresp = 0; /* good value for idle == INI ?? XXX  */
1491 
1492 	wakeup(&sc->cmdresperr);
1493 }
1494 void
1495 wi_usb_rridresp(struct wi_usb_chain *c)
1496 {
1497 	struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
1498 	u_int16_t frmlen = letoh16(presp->frmlen);
1499 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1500 	struct wi_ltv_gen *ltv;
1501 	uint16_t rid;
1502 
1503 	rid = letoh16(presp->rid);
1504 	ltv =  sc->ridltv;
1505 
1506 	if (ltv == 0) {
1507 		DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
1508 		    sc->wi_usb_dev.dv_xname, __func__, rid,
1509 		    frmlen));
1510 		return;
1511 	}
1512 
1513 	DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
1514 	    sc->wi_usb_dev.dv_xname, __func__, rid, ltv->wi_type,
1515 	    frmlen, ltv->wi_len));
1516 
1517 	rid = letoh16(presp->rid);
1518 
1519 	if (rid != ltv->wi_type) {
1520 		sc->ridresperr = EIO;
1521 		return;
1522 	}
1523 
1524 	if (frmlen > ltv->wi_len) {
1525 		sc->ridresperr = ENOSPC;
1526 		sc->ridltv = 0;
1527 		wakeup(&sc->ridresperr);
1528 		return;
1529 	}
1530 
1531 	ltv->wi_len = frmlen;
1532 
1533 	DPRINTFN(10,("%s: %s: copying %d frmlen %d\n",
1534 	    sc->wi_usb_dev.dv_xname, __func__, (ltv->wi_len-1)*2,
1535 	    frmlen));
1536 
1537 	if (ltv->wi_len > 1)
1538 		bcopy(&presp->data[0], &ltv->wi_val,
1539 		    (ltv->wi_len-1)*2);
1540 
1541 	sc->ridresperr = 0;
1542 	sc->ridltv = 0;
1543 	wakeup(&sc->ridresperr);
1544 
1545 }
1546 
1547 void
1548 wi_usb_wridresp(struct wi_usb_chain *c)
1549 {
1550 	struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
1551 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1552 	uint16_t status;
1553 
1554 	status = letoh16(presp->status);
1555 
1556 	DPRINTFN(10,("%s: %s: enter status=%x\n",
1557 	    sc->wi_usb_dev.dv_xname, __func__, status));
1558 
1559 	sc->ridresperr = (status & WI_STAT_CMD_RESULT) >> 8;
1560 	sc->ridltv = 0;
1561 	wakeup(&sc->ridresperr);
1562 }
1563 
1564 void
1565 wi_usb_infofrm(struct wi_usb_chain *c, int len)
1566 {
1567 	struct wi_usb_softc	*sc = c->wi_usb_sc;
1568 
1569 	DPRINTFN(10,("%s: %s: enter\n",
1570 	    sc->wi_usb_dev.dv_xname, __func__));
1571 
1572 	sc->wi_info = ((char *)c->wi_usb_buf) + 2;
1573 	wi_update_stats(&sc->sc_wi);
1574 	sc->wi_info = NULL;
1575 }
1576 
1577 void
1578 wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1579 {
1580 	u_int16_t		status;
1581 	int 			s;
1582 	struct wi_softc		*wsc = &sc->sc_wi;
1583 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
1584 
1585 	s = splnet();
1586 	status = letoh16(uin->type); /* XXX -- type == status */
1587 
1588 
1589 	DPRINTFN(2,("%s: %s: enter status=%d\n",
1590 	    sc->wi_usb_dev.dv_xname, __func__, status));
1591 
1592 	if (sc->txresp == WI_CMD_TX) {
1593 		sc->txresperr=status;
1594 		sc->txresp = 0;
1595 		wakeup(&sc->txresperr);
1596 	} else {
1597 		if (status != 0) /* XXX */
1598 			wi_watchdog_usb(ifp);
1599 	DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
1600 	    sc->wi_usb_dev.dv_xname, __func__, status));
1601 	}
1602 
1603 	splx(s);
1604 }
1605 void
1606 wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
1607 {
1608 	int s;
1609 
1610 	DPRINTFN(5,("%s: %s: enter len=%d\n",
1611 	    sc->wi_usb_dev.dv_xname, __func__, total_len));
1612 
1613 	s = splnet();
1614 
1615 	sc->wi_rxframe = (void *)uin;
1616 
1617 	wi_rxeof(&sc->sc_wi);
1618 
1619 	sc->wi_rxframe = NULL;
1620 
1621 	splx(s);
1622 
1623 }
1624 
1625 
1626 void
1627 wi_usb_start_thread(void *arg)
1628 {
1629 	struct wi_usb_softc	*sc = arg;
1630 	kthread_create (wi_usb_thread, arg, NULL, sc->wi_usb_dev.dv_xname);
1631 }
1632 
1633 void
1634 wi_start_usb(struct ifnet *ifp)
1635 {
1636 	struct wi_softc		*wsc;
1637 	struct wi_usb_softc	*sc;
1638 	int s;
1639 
1640 	wsc = ifp->if_softc;
1641 	sc  = wsc->wi_usb_cdata;
1642 
1643 	s = splnet();
1644 
1645 	DPRINTFN(5,("%s: %s:\n",
1646 	    sc->wi_usb_dev.dv_xname, __func__));
1647 
1648 	if (wi_usb_tx_lock_try(sc)) {
1649 		/* lock acquired do start now */
1650 		wi_func_io.f_start(ifp);
1651 	} else {
1652 		sc->wi_thread_info->status |= WI_START;
1653 		if (sc->wi_thread_info->idle)
1654 			wakeup(sc->wi_thread_info);
1655 	}
1656 
1657 	splx(s);
1658 }
1659 
1660 /*
1661  * inquire is called from interrupt context (timeout)
1662  * It is not possible to sleep in interrupt context so it is necessary
1663  * to signal the kernel thread to perform the action.
1664  */
1665 void
1666 wi_init_usb(struct wi_softc *wsc)
1667 {
1668 	DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
1669 
1670 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1671 	wi_func_io.f_init(wsc);
1672 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1673 }
1674 
1675 
1676 /*
1677  * inquire is called from interrupt context (timeout)
1678  * It is not possible to sleep in interrupt context so it is necessary
1679  * to signal the kernel thread to perform the action.
1680  */
1681 void
1682 wi_inquire_usb(void *xsc)
1683 {
1684 	struct wi_softc		*wsc = xsc;
1685 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
1686 	int s;
1687 
1688 
1689 	s = splnet();
1690 
1691 	DPRINTFN(2,("%s: %s:\n",
1692 	    sc->wi_usb_dev.dv_xname, __func__));
1693 
1694 	sc->wi_thread_info->status |= WI_INQUIRE;
1695 
1696 	if (sc->wi_thread_info->idle)
1697 		wakeup(sc->wi_thread_info);
1698 	splx(s);
1699 }
1700 
1701 /*
1702  * Watchdog is normally called from interrupt context (timeout)
1703  * It is not possible to sleep in interrupt context so it is necessary
1704  * to signal the kernel thread to perform the action.
1705  */
1706 void
1707 wi_watchdog_usb(struct ifnet *ifp)
1708 {
1709 	struct wi_softc		*wsc;
1710 	struct wi_usb_softc	*sc;
1711 	int s;
1712 
1713 	wsc = ifp->if_softc;
1714 	sc = wsc->wi_usb_cdata;
1715 
1716 	s = splnet();
1717 
1718 	DPRINTFN(5,("%s: %s: ifp %x\n",
1719 	    sc->wi_usb_dev.dv_xname, __func__, ifp));
1720 
1721 	sc->wi_thread_info->status |= WI_WATCHDOG;
1722 
1723 	if (sc->wi_thread_info->idle)
1724 		wakeup(sc->wi_thread_info);
1725 	splx(s);
1726 }
1727 
1728 /*
1729  * ioctl will always be called from a user context,
1730  * therefore it is possible to sleep in the calling context
1731  * acquire the lock and call the real ioctl function directly
1732  */
1733 int
1734 wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
1735 {
1736 	struct wi_softc		*wsc;
1737 	int err;
1738 
1739 	wsc = ifp->if_softc;
1740 
1741 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
1742 	err = wi_func_io.f_ioctl(ifp, command, data);
1743 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
1744 	return err;
1745 }
1746 
1747 void
1748 wi_usb_thread(void *arg)
1749 {
1750 	struct wi_usb_softc *sc = arg;
1751 	struct wi_usb_thread_info *wi_thread_info;
1752 	int s;
1753 
1754 	wi_thread_info = malloc(sizeof(*wi_thread_info), M_DEVBUF, M_WAITOK);
1755 
1756 	/*
1757 	 * is there a remote possibility that the device could
1758 	 * be removed before the kernel thread starts up?
1759 	 */
1760 
1761 	sc->wi_usb_refcnt++;
1762 
1763 	sc->wi_thread_info = wi_thread_info;
1764 	wi_thread_info->dying = 0;
1765 	wi_thread_info->status = 0;
1766 
1767 	wi_usb_ctl_lock(sc);
1768 
1769 	wi_attach(&sc->sc_wi, &wi_func_usb);
1770 
1771 	wi_usb_ctl_unlock(sc);
1772 
1773 	for(;;) {
1774 		if (wi_thread_info->dying) {
1775 			if (--sc->wi_usb_refcnt < 0)
1776 				usb_detach_wakeup(&sc->wi_usb_dev);
1777 			kthread_exit(0);
1778 		}
1779 
1780 		DPRINTFN(5,("%s: %s: dying %x status %x\n",
1781 		    sc->wi_usb_dev.dv_xname, __func__,
1782 			wi_thread_info->dying, wi_thread_info->status));
1783 
1784 		wi_usb_ctl_lock(sc);
1785 
1786 		DPRINTFN(5,("%s: %s: starting %x\n",
1787 		    sc->wi_usb_dev.dv_xname, __func__,
1788 		    wi_thread_info->status));
1789 
1790 		s = splusb();
1791 		if (wi_thread_info->status & WI_START) {
1792 			wi_thread_info->status &= ~WI_START;
1793 			wi_usb_tx_lock(sc);
1794 			wi_func_io.f_start(&sc->sc_wi.sc_ic.ic_if);
1795 			/*
1796 			 * tx_unlock is explicitly missing here
1797 			 * it is done in txeof_frm
1798 			 */
1799 		} else if (wi_thread_info->status & WI_INQUIRE) {
1800 			wi_thread_info->status &= ~WI_INQUIRE;
1801 			wi_func_io.f_inquire(&sc->sc_wi);
1802 		} else if (wi_thread_info->status & WI_WATCHDOG) {
1803 			wi_thread_info->status &= ~WI_WATCHDOG;
1804 			wi_func_io.f_watchdog( &sc->sc_wi.sc_ic.ic_if);
1805 		}
1806 		splx(s);
1807 
1808 		DPRINTFN(5,("%s: %s: ending %x\n",
1809 		    sc->wi_usb_dev.dv_xname, __func__,
1810 		    wi_thread_info->status));
1811 		wi_usb_ctl_unlock(sc);
1812 
1813 		if (wi_thread_info->status == 0) {
1814 			s = splnet();
1815 			wi_thread_info->idle = 1;
1816 			tsleep_nsec(wi_thread_info, PRIBIO, "wiIDL", INFSLP);
1817 			wi_thread_info->idle = 0;
1818 			splx(s);
1819 		}
1820 	}
1821 }
1822 
1823 int
1824 wi_usb_tx_lock_try(struct wi_usb_softc *sc)
1825 {
1826 	int s;
1827 
1828 	s = splnet();
1829 
1830 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1831 
1832 	if (sc->wi_lock != 0) {
1833 		splx(s);
1834 		return 0; /* failed to aquire lock */
1835 	}
1836 
1837 	sc->wi_lock = 1;
1838 
1839 	splx(s);
1840 
1841 	return 1;
1842 }
1843 void
1844 wi_usb_tx_lock(struct wi_usb_softc *sc)
1845 {
1846 	int s;
1847 
1848 	s = splnet();
1849 
1850 	again:
1851 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1852 
1853 	if (sc->wi_lock != 0) {
1854 		sc->wi_lockwait++;
1855 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1856 		__func__, sc->wi_lockwait ));
1857 		tsleep_nsec(&sc->wi_lock, PRIBIO, "witxl", INFSLP);
1858 	}
1859 
1860 	if (sc->wi_lock != 0)
1861 		goto again;
1862 	sc->wi_lock = 1;
1863 
1864 	splx(s);
1865 
1866 	return;
1867 
1868 }
1869 
1870 void
1871 wi_usb_tx_unlock(struct wi_usb_softc *sc)
1872 {
1873 	int s;
1874 	s = splnet();
1875 
1876 	sc->wi_lock = 0;
1877 
1878 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1879 
1880 	if (sc->wi_lockwait) {
1881 		DPRINTFN(10,("%s: %s: waking\n",
1882 		    sc->wi_usb_dev.dv_xname, __func__));
1883 		sc->wi_lockwait = 0;
1884 		wakeup(&sc->wi_lock);
1885 	}
1886 
1887 	splx(s);
1888 }
1889 
1890 void
1891 wi_usb_ctl_lock(struct wi_usb_softc *sc)
1892 {
1893 	int s;
1894 
1895 	s = splnet();
1896 
1897 	again:
1898 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,
1899 	    __func__));
1900 
1901 	if (sc->wi_ctllock != 0) {
1902 		if (curproc == sc->wi_curproc) {
1903 			/* allow recursion */
1904 			sc->wi_ctllock++;
1905 			splx(s);
1906 			return;
1907 		}
1908 		sc->wi_ctllockwait++;
1909 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
1910 		__func__, sc->wi_ctllockwait ));
1911 		tsleep_nsec(&sc->wi_ctllock, PRIBIO, "wiusbthr", INFSLP);
1912 	}
1913 
1914 	if (sc->wi_ctllock != 0)
1915 		goto again;
1916 	sc->wi_ctllock++;
1917 	sc->wi_curproc = curproc;
1918 
1919 	splx(s);
1920 
1921 	return;
1922 
1923 }
1924 
1925 void
1926 wi_usb_ctl_unlock(struct wi_usb_softc *sc)
1927 {
1928 	int s;
1929 
1930 	s = splnet();
1931 
1932 	sc->wi_ctllock--;
1933 
1934 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
1935 
1936 	if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
1937 		DPRINTFN(10,("%s: %s: waking\n",
1938 		    sc->wi_usb_dev.dv_xname, __func__));
1939 		sc->wi_ctllockwait = 0;
1940 		sc->wi_curproc = 0;
1941 		wakeup(&sc->wi_ctllock);
1942 	}
1943 
1944 	splx(s);
1945 }
1946