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