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