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