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