xref: /openbsd/sys/dev/usb/if_wi_usb.c (revision 3a81c204)
1*3a81c204Sjsg /*	$OpenBSD: if_wi_usb.c,v 1.78 2024/10/06 01:28:39 jsg Exp $ */
237837c73Sdrahn 
337837c73Sdrahn /*
437837c73Sdrahn  * Copyright (c) 2003 Dale Rahn. All rights reserved.
537837c73Sdrahn  *
637837c73Sdrahn  * Redistribution and use in source and binary forms, with or without
737837c73Sdrahn  * modification, are permitted provided that the following conditions
837837c73Sdrahn  * are met:
937837c73Sdrahn  * 1. Redistributions of source code must retain the above copyright
1037837c73Sdrahn  *    notice, this list of conditions and the following disclaimer.
1137837c73Sdrahn  * 2. Redistributions in binary form must reproduce the above copyright
1237837c73Sdrahn  *    notice, this list of conditions and the following disclaimer in the
1337837c73Sdrahn  *    documentation and/or other materials provided with the distribution.
1437837c73Sdrahn  *
1537837c73Sdrahn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1637837c73Sdrahn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1737837c73Sdrahn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1837837c73Sdrahn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1937837c73Sdrahn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2037837c73Sdrahn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2137837c73Sdrahn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2237837c73Sdrahn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2337837c73Sdrahn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2437837c73Sdrahn  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2537837c73Sdrahn  *
2637837c73Sdrahn  * Effort sponsored in part by the Defense Advanced Research Projects
2737837c73Sdrahn  * Agency (DARPA) and Air Force Research Laboratory, Air Force
2837837c73Sdrahn  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
2937837c73Sdrahn  */
3037837c73Sdrahn 
3137837c73Sdrahn #include <sys/param.h>
3237837c73Sdrahn #include <sys/systm.h>
3337837c73Sdrahn #include <sys/malloc.h>
3437837c73Sdrahn #include <sys/device.h>
35048a3a61Skrw #include <sys/timeout.h>
3637837c73Sdrahn #include <sys/kthread.h>
3737837c73Sdrahn 
3837837c73Sdrahn #include <net/if.h>
3937837c73Sdrahn #include <net/if_media.h>
4037837c73Sdrahn 
4137837c73Sdrahn #include <netinet/in.h>
4237837c73Sdrahn #include <netinet/if_ether.h>
4337837c73Sdrahn 
4437837c73Sdrahn #include <dev/usb/usb.h>
4537837c73Sdrahn #include <dev/usb/usbdi.h>
4637837c73Sdrahn #include <dev/usb/usbdi_util.h>
4737837c73Sdrahn #include <dev/usb/usbdevs.h>
4837837c73Sdrahn 
4937837c73Sdrahn #define ROUNDUP64(x) (((x)+63) & ~63)
5037837c73Sdrahn 
5155f29f42Sjsg #include <net80211/ieee80211_var.h>
52660f41e3Sderaadt #include <net80211/ieee80211_ioctl.h>
5337837c73Sdrahn 
5437837c73Sdrahn #include <machine/bus.h>
5537837c73Sdrahn 
5637837c73Sdrahn #include <dev/ic/if_wireg.h>
5737837c73Sdrahn #include <dev/ic/if_wi_ieee.h>
5837837c73Sdrahn #include <dev/ic/if_wivar.h>
5937837c73Sdrahn 
6037837c73Sdrahn #include <dev/usb/if_wi_usb.h>
6137837c73Sdrahn 
6237837c73Sdrahn int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c,
6337837c73Sdrahn     void *ident);
64ab0b1be7Smglocker void wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
6537837c73Sdrahn     usbd_status status);
66ab0b1be7Smglocker void wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
6737837c73Sdrahn     usbd_status status);
68ab0b1be7Smglocker void wi_usb_rxeof(struct usbd_xfer *xfer, void *priv,
6937837c73Sdrahn     usbd_status status);
70ab0b1be7Smglocker void wi_usb_intr(struct usbd_xfer *xfer, void *priv,
7137837c73Sdrahn     usbd_status status);
7237837c73Sdrahn void wi_usb_stop(struct wi_usb_softc *usc);
7337837c73Sdrahn int wi_usb_tx_list_init(struct wi_usb_softc *usc);
7437837c73Sdrahn int wi_usb_rx_list_init(struct wi_usb_softc *usc);
7537837c73Sdrahn int wi_usb_open_pipes(struct wi_usb_softc *usc);
7637837c73Sdrahn void wi_usb_cmdresp(struct wi_usb_chain *c);
7737837c73Sdrahn void wi_usb_rridresp(struct wi_usb_chain *c);
7837837c73Sdrahn void wi_usb_wridresp(struct wi_usb_chain *c);
7937837c73Sdrahn void wi_usb_infofrm(struct wi_usb_chain *c, int len);
8037837c73Sdrahn int wi_send_packet(struct wi_usb_softc *sc, int id);
8137837c73Sdrahn void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
8237837c73Sdrahn void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
8337837c73Sdrahn void wi_usb_start_thread(void *);
8437837c73Sdrahn 
8537837c73Sdrahn int wi_usb_tx_lock_try(struct wi_usb_softc *sc);
8637837c73Sdrahn void wi_usb_tx_lock(struct wi_usb_softc *usc);
8737837c73Sdrahn void wi_usb_tx_unlock(struct wi_usb_softc *usc);
8837837c73Sdrahn void wi_usb_ctl_lock(struct wi_usb_softc *usc);
8937837c73Sdrahn void wi_usb_ctl_unlock(struct wi_usb_softc *usc);
9037837c73Sdrahn 
9137837c73Sdrahn void wi_dump_data(void *buffer, int len);
9237837c73Sdrahn 
9337837c73Sdrahn void wi_usb_thread(void *arg);
9437837c73Sdrahn 
9537837c73Sdrahn #ifdef WI_USB_DEBUG
96695146ceSjsg #define DPRINTF(x)      do { if (wi_usbdebug) printf x; } while (0)
97695146ceSjsg #define DPRINTFN(n,x)   do { if (wi_usbdebug >= (n)) printf x; } while (0)
9837837c73Sdrahn int     wi_usbdebug = 1;
9937837c73Sdrahn #else
10037837c73Sdrahn #define DPRINTF(x)
10137837c73Sdrahn #define DPRINTFN(n,x)
10237837c73Sdrahn #endif
10337837c73Sdrahn 
10437837c73Sdrahn struct wi_usb_thread_info {
10537837c73Sdrahn 	int status;
10637837c73Sdrahn 	int dying;
10737837c73Sdrahn 	int idle;
10837837c73Sdrahn };
10937837c73Sdrahn 
11037837c73Sdrahn /* thread status flags */
11137837c73Sdrahn #define WI_START	0x01
11237837c73Sdrahn #define WI_DYING	0x02
11337837c73Sdrahn #define WI_INQUIRE	0x04
11437837c73Sdrahn #define WI_WATCHDOG	0x08
11537837c73Sdrahn 
11637837c73Sdrahn 
11737837c73Sdrahn struct wi_usb_softc {
11837837c73Sdrahn 	struct wi_softc		sc_wi;
11937837c73Sdrahn #define wi_usb_dev sc_wi.sc_dev
12037837c73Sdrahn 
12134eef271Smbalmer 	struct timeout		wi_usb_stat_ch;
12237837c73Sdrahn 
123ab0b1be7Smglocker 	struct usbd_device	*wi_usb_udev;
124ab0b1be7Smglocker 	struct usbd_interface	*wi_usb_iface;
12537837c73Sdrahn 	u_int16_t		wi_usb_vendor;
12637837c73Sdrahn 	u_int16_t		wi_usb_product;
12737837c73Sdrahn 	int			wi_usb_ed[WI_USB_ENDPT_MAX];
128ab0b1be7Smglocker 	struct usbd_pipe	*wi_usb_ep[WI_USB_ENDPT_MAX];
12937837c73Sdrahn 
13037837c73Sdrahn 	struct wi_usb_chain	wi_usb_tx_chain[WI_USB_TX_LIST_CNT];
13137837c73Sdrahn 	struct wi_usb_chain	wi_usb_rx_chain[WI_USB_RX_LIST_CNT];
13237837c73Sdrahn 
13337837c73Sdrahn 	int			wi_usb_refcnt;
13437837c73Sdrahn 	char			wi_usb_attached;
13537837c73Sdrahn 	int			wi_usb_intr_errs;
13637837c73Sdrahn 	struct timeval		wi_usb_rx_notice;
13737837c73Sdrahn 
13837837c73Sdrahn 	int			wi_usb_pollpending;
13937837c73Sdrahn 
14037837c73Sdrahn 	wi_usb_usbin		wi_usb_ibuf;
14137837c73Sdrahn 	int			wi_usb_tx_prod;
14237837c73Sdrahn 	int			wi_usb_tx_cons;
14337837c73Sdrahn 	int			wi_usb_tx_cnt;
14437837c73Sdrahn 	int			wi_usb_rx_prod;
14537837c73Sdrahn 
14637837c73Sdrahn 	struct wi_ltv_gen	*ridltv;
14737837c73Sdrahn 	int			ridresperr;
14837837c73Sdrahn 
14937837c73Sdrahn 	int			cmdresp;
15037837c73Sdrahn 	int			cmdresperr;
15137837c73Sdrahn 	int			txresp;
15237837c73Sdrahn 	int			txresperr;
15337837c73Sdrahn 
15437837c73Sdrahn 	/* nummem (tx/mgmt) */
15537837c73Sdrahn 	int			wi_usb_nummem;
15637837c73Sdrahn #define MAX_WI_NMEM 3
15737837c73Sdrahn 	void			*wi_usb_txmem[MAX_WI_NMEM];
15837837c73Sdrahn 	int			wi_usb_txmemsize[MAX_WI_NMEM];
15937837c73Sdrahn 	void			*wi_usb_rxmem;
16037837c73Sdrahn 	int			wi_usb_rxmemsize;
16137837c73Sdrahn 
16237837c73Sdrahn 	void			*wi_info;
16337837c73Sdrahn 	void			*wi_rxframe;
16437837c73Sdrahn 
1653284c8d8Sray 	/* prevent multiple outstanding USB requests */
16637837c73Sdrahn 	int			wi_lock;
16737837c73Sdrahn 	int			wi_lockwait;
16837837c73Sdrahn 
16937837c73Sdrahn 	/* prevent multiple command requests */
17037837c73Sdrahn 	int			wi_ctllock;
17137837c73Sdrahn 	int			wi_ctllockwait;
17237837c73Sdrahn 	struct proc		*wi_curproc;
17337837c73Sdrahn 
17437837c73Sdrahn 	/* kthread */
17537837c73Sdrahn 	struct wi_usb_thread_info	*wi_thread_info;
17637837c73Sdrahn 	int			wi_resetonce;
17737837c73Sdrahn };
17837837c73Sdrahn 
17937837c73Sdrahn struct wi_funcs wi_func_usb = {
18037837c73Sdrahn         wi_cmd_usb,
18137837c73Sdrahn         wi_read_record_usb,
18237837c73Sdrahn         wi_write_record_usb,
18337837c73Sdrahn         wi_alloc_nicmem_usb,
18437837c73Sdrahn         wi_read_data_usb,
18537837c73Sdrahn         wi_write_data_usb,
18637837c73Sdrahn         wi_get_fid_usb,
18737837c73Sdrahn         wi_init_usb,
18837837c73Sdrahn 
18937837c73Sdrahn         wi_start_usb,
19037837c73Sdrahn         wi_ioctl_usb,
19137837c73Sdrahn         wi_watchdog_usb,
19237837c73Sdrahn         wi_inquire_usb,
19337837c73Sdrahn };
19437837c73Sdrahn 
19537837c73Sdrahn /*
19637837c73Sdrahn  * Various supported device vendors/products.
19737837c73Sdrahn  */
19837837c73Sdrahn const struct wi_usb_type {
19937837c73Sdrahn 	struct usb_devno	wi_usb_device;
20037837c73Sdrahn 	u_int16_t	wi_usb_flags;
20137837c73Sdrahn 	/* XXX */
20237837c73Sdrahn } wi_usb_devs[] = {
20395d21e50Sjsg 	{{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_111 }, 0 },
2043a8f5df9Sdrahn 	{{ USB_VENDOR_ACERW, USB_PRODUCT_ACERW_WARPLINK }, 0 },
20595d21e50Sjsg 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_FREELAN }, 0 },
20695d21e50Sjsg 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25 }, 0 },
2073a8f5df9Sdrahn 	{{ USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_PRISM_25A }, 0 },
20895d21e50Sjsg 	{{ USB_VENDOR_ADAPTEC, USB_PRODUCT_ADAPTEC_AWN8020 }, 0 },
209c140c263Sjsg 	{{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_WLAN }, 0 },
210f8b2d8efSjsg 	{{ USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL140 }, 0 },
21195d21e50Sjsg 	{{ USB_VENDOR_AVERATEC, USB_PRODUCT_AVERATEC_USBWLAN }, 0 },
212f2da6502Sdlg 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W100 }, 0 },
213f2da6502Sdlg 	{{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_W200 }, 0 },
2143a8f5df9Sdrahn 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLANUSB }, 0 },
21595d21e50Sjsg 	{{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_KEY }, 0 },
21695d21e50Sjsg 	{{ USB_VENDOR_DELL, USB_PRODUCT_DELL_TM1180 }, 0 },
217f8b2d8efSjsg 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120F }, 0 },
2187c96149aSpedro 	{{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL122 }, 0 },
2193a8f5df9Sdrahn 	{{ USB_VENDOR_INTEL, USB_PRODUCT_INTEL_I2011B }, 0 },
2203a8f5df9Sdrahn 	{{ USB_VENDOR_INTERSIL, USB_PRODUCT_INTERSIL_PRISM_2X }, 0 },
2213a8f5df9Sdrahn 	{{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11 }, 0 },
222a55fba47Shenning 	{{ USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_XP7250_WL }, 0 },
22395d21e50Sjsg 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11_25 }, 0 },
2243a8f5df9Sdrahn 	{{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB12_11 }, 0 },
225f8b2d8efSjsg 	{{ USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V30 }, 0 },
22695d21e50Sjsg 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KB11 }, 0 },
22795d21e50Sjsg 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_KS11G }, 0 },
2283a8f5df9Sdrahn 	{{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_S11 }, 0 },
2293a8f5df9Sdrahn 	{{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN510 }, 0 },
2303a8f5df9Sdrahn 	{{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 },
231c140c263Sjsg 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WL503IA }, 0 },
232f8b2d8efSjsg 	{{ USB_VENDOR_PHEENET, USB_PRODUCT_PHEENET_WM168B }, 0 },
23395d21e50Sjsg 	{{ USB_VENDOR_PLANEX, USB_PRODUCT_PLANEX_GW_US11H }, 0 },
2344eb2ba74Sderaadt 	{{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM22 }, 0 },
235c140c263Sjsg 	{{ USB_VENDOR_SITECOM2, USB_PRODUCT_SITECOM2_WL022 }, 0 },
23695d21e50Sjsg 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_0193 }, 0 },
23795d21e50Sjsg 	{{ USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZYAIR_B200 }, 0 },
23895d21e50Sjsg 	{{ USB_VENDOR_USR, USB_PRODUCT_USR_USR1120 }, 0 },
2391e1333b7Sjsg 	{{ USB_VENDOR_VIEWSONIC, USB_PRODUCT_VIEWSONIC_AIRSYNC }, 0 },
240f8b2d8efSjsg 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI725 }, 0 },
241f8b2d8efSjsg 	{{ USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_XI735 }, 0 }
24237837c73Sdrahn };
24337837c73Sdrahn #define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p))
24437837c73Sdrahn 
2459f5f6d50Smbalmer int wi_usb_match(struct device *, void *, void *);
2469f5f6d50Smbalmer void wi_usb_attach(struct device *, struct device *, void *);
2479f5f6d50Smbalmer int wi_usb_detach(struct device *, int);
2489f5f6d50Smbalmer 
2499f5f6d50Smbalmer const struct cfattach wi_usb_ca = {
25053c6612dSmpi 	sizeof(struct wi_usb_softc), wi_usb_match, wi_usb_attach, wi_usb_detach
2519f5f6d50Smbalmer };
25237837c73Sdrahn 
253de5d9ff0Sjsg int
wi_usb_match(struct device * parent,void * match,void * aux)254de5d9ff0Sjsg wi_usb_match(struct device *parent, void *match, void *aux)
25537837c73Sdrahn {
256de5d9ff0Sjsg 	struct usb_attach_arg	*uaa = aux;
25737837c73Sdrahn 
2587ebc5b51Smpi 	if (uaa->iface == NULL || uaa->configno != 1)
25937837c73Sdrahn 		return (UMATCH_NONE);
26037837c73Sdrahn 
26137837c73Sdrahn 	return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ?
2627ebc5b51Smpi 		UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
26337837c73Sdrahn }
26437837c73Sdrahn 
26537837c73Sdrahn 
26637837c73Sdrahn /*
26737837c73Sdrahn  * Attach the interface. Allocate softc structures, do ifmedia
26837837c73Sdrahn  * setup and ethernet/BPF attach.
26937837c73Sdrahn  */
270de5d9ff0Sjsg void
wi_usb_attach(struct device * parent,struct device * self,void * aux)271de5d9ff0Sjsg wi_usb_attach(struct device *parent, struct device *self, void *aux)
27237837c73Sdrahn {
273de5d9ff0Sjsg 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
274de5d9ff0Sjsg 	struct usb_attach_arg	*uaa = aux;
27537837c73Sdrahn /*	int			s; */
276ab0b1be7Smglocker 	struct usbd_device	*dev = uaa->device;
2777ebc5b51Smpi 	struct usbd_interface	*iface = uaa->iface;
27837837c73Sdrahn 	usb_interface_descriptor_t	*id;
27937837c73Sdrahn 	usb_endpoint_descriptor_t	*ed;
28037837c73Sdrahn 	int			 i;
28137837c73Sdrahn 
28237837c73Sdrahn 	DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc));
28337837c73Sdrahn 
28437837c73Sdrahn 	/* XXX - any tasks? */
28537837c73Sdrahn 
28637837c73Sdrahn 	/* XXX - flags? */
28737837c73Sdrahn 
28837837c73Sdrahn 	sc->wi_usb_udev = dev;
28937837c73Sdrahn 	sc->wi_usb_iface = iface;
29037837c73Sdrahn 	sc->wi_usb_product = uaa->product;
29137837c73Sdrahn 	sc->wi_usb_vendor = uaa->vendor;
29237837c73Sdrahn 
29337837c73Sdrahn 	sc->sc_wi.wi_usb_cdata = sc;
29437837c73Sdrahn 	sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB;
29537837c73Sdrahn 
29637837c73Sdrahn 	sc->wi_lock = 0;
29737837c73Sdrahn 	sc->wi_lockwait = 0;
29837837c73Sdrahn 	sc->wi_resetonce = 0;
29937837c73Sdrahn 
30037837c73Sdrahn 	id = usbd_get_interface_descriptor(iface);
30137837c73Sdrahn 
30237837c73Sdrahn 	/* Find endpoints. */
30337837c73Sdrahn 	for (i = 0; i < id->bNumEndpoints; i++) {
30437837c73Sdrahn 		ed = usbd_interface2endpoint_descriptor(iface, i);
30537837c73Sdrahn 		if (ed == NULL) {
30637837c73Sdrahn 			printf("%s: couldn't get endpoint descriptor %d\n",
3074ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, i);
308de5d9ff0Sjsg 			return;
30937837c73Sdrahn 		}
31037837c73Sdrahn 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
31137837c73Sdrahn 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
31237837c73Sdrahn 			sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress;
31337837c73Sdrahn 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
31437837c73Sdrahn 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
31537837c73Sdrahn 			sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress;
31637837c73Sdrahn 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
31737837c73Sdrahn 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
31837837c73Sdrahn 			sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress;
31937837c73Sdrahn 		}
32037837c73Sdrahn 	}
32137837c73Sdrahn 
32237837c73Sdrahn 	sc->wi_usb_nummem = 0;
32337837c73Sdrahn 
32437837c73Sdrahn 	/* attach wi device */
32537837c73Sdrahn 
32637837c73Sdrahn 	if (wi_usb_rx_list_init(sc)) {
32737837c73Sdrahn 		printf("%s: rx list init failed\n",
3284ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname);
329de5d9ff0Sjsg 		return;
33037837c73Sdrahn 	}
33137837c73Sdrahn 	if (wi_usb_tx_list_init(sc)) {
33237837c73Sdrahn 		printf("%s: tx list init failed\n",
3334ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname);
334de5d9ff0Sjsg 		return;
33537837c73Sdrahn 	}
33637837c73Sdrahn 
33737837c73Sdrahn 	if (wi_usb_open_pipes(sc)){
33837837c73Sdrahn 		printf("%s: open pipes failed\n",
3394ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname);
340de5d9ff0Sjsg 		return;
34137837c73Sdrahn 	}
34237837c73Sdrahn 
34337837c73Sdrahn 	sc->wi_usb_attached = 1;
34437837c73Sdrahn 
34537837c73Sdrahn 	kthread_create_deferred(wi_usb_start_thread, sc);
34637837c73Sdrahn }
34737837c73Sdrahn 
348de5d9ff0Sjsg int
wi_usb_detach(struct device * self,int flags)349de5d9ff0Sjsg wi_usb_detach(struct device *self, int flags)
35037837c73Sdrahn {
351de5d9ff0Sjsg 	struct wi_usb_softc	*sc = (struct wi_usb_softc *)self;
35237837c73Sdrahn 	struct ifnet		*ifp = WI_GET_IFP(sc);
35337837c73Sdrahn 	struct wi_softc		*wsc = &sc->sc_wi;
35437837c73Sdrahn 	int s;
355ae4204aaSdrahn 	int err;
35637837c73Sdrahn 
35770e15fe7Syuo 	/* Detached before attach finished, so just bail out. */
35870e15fe7Syuo 	if (!sc->wi_usb_attached)
35970e15fe7Syuo 		return (0);
36070e15fe7Syuo 
36137837c73Sdrahn 	if (sc->wi_thread_info != NULL) {
36237837c73Sdrahn 		sc->wi_thread_info->dying = 1;
36337837c73Sdrahn 
36437837c73Sdrahn 		sc->wi_thread_info->status |= WI_DYING;
36537837c73Sdrahn 		if (sc->wi_thread_info->idle)
36637837c73Sdrahn 			wakeup(sc->wi_thread_info);
36737837c73Sdrahn 	}
36837837c73Sdrahn 
36937837c73Sdrahn 	/* tasks? */
37037837c73Sdrahn 
37137837c73Sdrahn 	s = splusb();
372c063904eSmk 	/* detach wi */
37337837c73Sdrahn 
37437837c73Sdrahn 	if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) {
3754ab2b9feSmbalmer 		printf("%s: already detached\n", sc->wi_usb_dev.dv_xname);
37637837c73Sdrahn 		splx(s);
37737837c73Sdrahn 		return (0);
37837837c73Sdrahn 	}
37937837c73Sdrahn 
38037837c73Sdrahn 	wi_detach(&sc->sc_wi);
38137837c73Sdrahn 
38237837c73Sdrahn 	wsc->wi_flags = 0;
38337837c73Sdrahn 
3845dd621eeSjakemsr 	if (ifp->if_softc != NULL) {
38537837c73Sdrahn 		ether_ifdetach(ifp);
38637837c73Sdrahn 		if_detach(ifp);
3875dd621eeSjakemsr 	}
38837837c73Sdrahn 
38937837c73Sdrahn 	sc->wi_usb_attached = 0;
39037837c73Sdrahn 
39137837c73Sdrahn 	if (--sc->wi_usb_refcnt >= 0) {
39237837c73Sdrahn 		/* Wait for processes to go away. */
3931596fc1eSmbalmer 		usb_detach_wait(&sc->wi_usb_dev);
39437837c73Sdrahn 	}
39537837c73Sdrahn 
39637837c73Sdrahn 	while (sc->wi_usb_nummem) {
39737837c73Sdrahn 		sc->wi_usb_nummem--;
3988985a220Smglocker 		free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
39998d77b56Smpi 		  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
40037837c73Sdrahn 		sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
40198d77b56Smpi 		sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
40237837c73Sdrahn 	}
40337837c73Sdrahn 
404ae4204aaSdrahn 	if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL) {
405ae4204aaSdrahn 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
406ae4204aaSdrahn 		if (err) {
407ae4204aaSdrahn 			printf("%s: close intr pipe failed: %s\n",
4084ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
409ae4204aaSdrahn 		}
410ae4204aaSdrahn 		sc->wi_usb_ep[WI_USB_ENDPT_INTR] = NULL;
411ae4204aaSdrahn 	}
412ae4204aaSdrahn 	if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL) {
413ae4204aaSdrahn 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
414ae4204aaSdrahn 		if (err) {
415ae4204aaSdrahn 			printf("%s: close tx pipe failed: %s\n",
4164ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
417ae4204aaSdrahn 		}
418ae4204aaSdrahn 		sc->wi_usb_ep[WI_USB_ENDPT_TX] = NULL;
419ae4204aaSdrahn 	}
420ae4204aaSdrahn 	if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL) {
421ae4204aaSdrahn 		err = usbd_close_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
422ae4204aaSdrahn 		if (err) {
423ae4204aaSdrahn 			printf("%s: close rx pipe failed: %s\n",
4244ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
425ae4204aaSdrahn 		}
426ae4204aaSdrahn 		sc->wi_usb_ep[WI_USB_ENDPT_RX] = NULL;
427ae4204aaSdrahn 	}
42837837c73Sdrahn 
42937837c73Sdrahn 	splx(s);
43037837c73Sdrahn 
43137837c73Sdrahn 	return (0);
43237837c73Sdrahn }
43337837c73Sdrahn 
43437837c73Sdrahn int
wi_send_packet(struct wi_usb_softc * sc,int id)43537837c73Sdrahn wi_send_packet(struct wi_usb_softc *sc, int id)
43637837c73Sdrahn {
43737837c73Sdrahn 	struct wi_usb_chain	*c;
43837837c73Sdrahn 	struct wi_frame		*wibuf;
43937837c73Sdrahn 	int			total_len, rnd_len;
44037837c73Sdrahn 	int			err;
44137837c73Sdrahn 
44237837c73Sdrahn 	c = &sc->wi_usb_tx_chain[0];
44337837c73Sdrahn 
44437837c73Sdrahn 	DPRINTFN(10,("%s: %s: id=%x\n",
4454ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, id));
44637837c73Sdrahn 
44737837c73Sdrahn 	/* assemble packet from write_data buffer */
44837837c73Sdrahn 	if (id == 0 || id == 1) {
44937837c73Sdrahn 		/* tx_lock acquired before wi_start() */
45037837c73Sdrahn 		wibuf = sc->wi_usb_txmem[id];
45137837c73Sdrahn 
45237837c73Sdrahn 		total_len = sizeof (struct wi_frame) +
45337837c73Sdrahn 		    letoh16(wibuf->wi_dat_len);
45437837c73Sdrahn 		rnd_len = ROUNDUP64(total_len);
45537837c73Sdrahn 		if ((total_len > sc->wi_usb_txmemsize[id]) ||
45637837c73Sdrahn 		   (rnd_len > WI_USB_BUFSZ )){
45737837c73Sdrahn 			printf("invalid packet len: %x memsz %x max %x\n",
45837837c73Sdrahn 			    total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
45937837c73Sdrahn 
46037837c73Sdrahn 			err = EIO;
46137837c73Sdrahn 			goto err_ret;
46237837c73Sdrahn 		}
46337837c73Sdrahn 
46437837c73Sdrahn 		sc->txresp = WI_CMD_TX;
46537837c73Sdrahn 		sc->txresperr = 0;
46637837c73Sdrahn 
46737837c73Sdrahn 		bcopy(wibuf, c->wi_usb_buf, total_len);
46837837c73Sdrahn 
46937837c73Sdrahn 		bzero(((char *)c->wi_usb_buf)+total_len,
47037837c73Sdrahn 		    rnd_len - total_len);
47137837c73Sdrahn 
4727394dbbbSdrahn 		/* zero old packet for next TX */
4737394dbbbSdrahn 		bzero(wibuf, total_len);
4747394dbbbSdrahn 
47537837c73Sdrahn 		total_len = rnd_len;
47637837c73Sdrahn 
47737837c73Sdrahn 		DPRINTFN(5,("%s: %s: id=%x len=%x\n",
4784ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, id, total_len));
47937837c73Sdrahn 
48037837c73Sdrahn 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
48137837c73Sdrahn 		    c, c->wi_usb_buf, rnd_len,
48237837c73Sdrahn 		    USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
48337837c73Sdrahn 		    WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
48437837c73Sdrahn 
48537837c73Sdrahn 		err = usbd_transfer(c->wi_usb_xfer);
48637837c73Sdrahn 		if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
4878f9651bbSfgsch 			printf("%s: %s: error=%s\n",
4884ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, __func__,
4898f9651bbSfgsch 			    usbd_errstr(err));
49037837c73Sdrahn 			/* Stop the interface from process context. */
49137837c73Sdrahn 			wi_usb_stop(sc);
49237837c73Sdrahn 			err = EIO;
49337837c73Sdrahn 		} else {
49437837c73Sdrahn 			err = 0;
49537837c73Sdrahn 		}
49637837c73Sdrahn 
49737837c73Sdrahn 		DPRINTFN(5,("%s: %s: exit err=%x\n",
4984ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, err));
49937837c73Sdrahn err_ret:
50037837c73Sdrahn 		return err;
50137837c73Sdrahn 	}
50237837c73Sdrahn 	printf("%s:%s: invalid packet id sent %x\n",
5034ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, id);
50437837c73Sdrahn 	return 0;
50537837c73Sdrahn }
50637837c73Sdrahn 
50737837c73Sdrahn int
wi_cmd_usb(struct wi_softc * wsc,int cmd,int val0,int val1,int val2)50837837c73Sdrahn wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
50937837c73Sdrahn {
51037837c73Sdrahn 	struct wi_usb_chain	*c;
51137837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
51237837c73Sdrahn 	struct wi_cmdreq	*pcmd;
51337837c73Sdrahn 	int			total_len, rnd_len;
51437837c73Sdrahn 	int			err;
51537837c73Sdrahn 
51637837c73Sdrahn 	DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
5174ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, cmd, val0, val1, val2));
51837837c73Sdrahn 
51937837c73Sdrahn 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
52037837c73Sdrahn 		return wi_send_packet(sc, val0);
52137837c73Sdrahn 	}
52237837c73Sdrahn 
52337837c73Sdrahn 
52437837c73Sdrahn 	if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
52537837c73Sdrahn 		/* free alloc_nicmem regions */
52637837c73Sdrahn 		while (sc->wi_usb_nummem) {
52737837c73Sdrahn 			sc->wi_usb_nummem--;
5288985a220Smglocker 			free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_USBDEV,
52998d77b56Smpi 			  sc->wi_usb_txmemsize[sc->wi_usb_nummem]);
53037837c73Sdrahn 			sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
53198d77b56Smpi 			sc->wi_usb_txmemsize[sc->wi_usb_nummem] = 0;
53237837c73Sdrahn 		}
53337837c73Sdrahn 
53437837c73Sdrahn #if 0
53537837c73Sdrahn 		/* if this is the first time, init, otherwise do not?? */
53637837c73Sdrahn 		if (sc->wi_resetonce) {
53737837c73Sdrahn 			return 0;
53837837c73Sdrahn 		} else
53937837c73Sdrahn 			sc->wi_resetonce = 1;
54037837c73Sdrahn #endif
54137837c73Sdrahn 	}
54237837c73Sdrahn 
54337837c73Sdrahn 	wi_usb_ctl_lock(sc);
54437837c73Sdrahn 
54537837c73Sdrahn 	wi_usb_tx_lock(sc);
54637837c73Sdrahn 
54737837c73Sdrahn 	c = &sc->wi_usb_tx_chain[0];
54837837c73Sdrahn 	pcmd = c->wi_usb_buf;
54937837c73Sdrahn 
55037837c73Sdrahn 
55137837c73Sdrahn 	total_len = sizeof (struct wi_cmdreq);
55237837c73Sdrahn 	rnd_len = ROUNDUP64(total_len);
55337837c73Sdrahn 	if (rnd_len > WI_USB_BUFSZ) {
55437837c73Sdrahn 		printf("read_record buf size err %x %x\n",
55537837c73Sdrahn 		    rnd_len, WI_USB_BUFSZ);
55637837c73Sdrahn 		err = EIO;
55737837c73Sdrahn 		goto err_ret;
55837837c73Sdrahn 	}
55937837c73Sdrahn 
56037837c73Sdrahn 	sc->cmdresp = cmd;
56137837c73Sdrahn 	sc->cmdresperr = 0;
56237837c73Sdrahn 
56337837c73Sdrahn 	pcmd->type = htole16(WI_USB_CMDREQ);
56437837c73Sdrahn 	pcmd->cmd  = htole16(cmd);
56537837c73Sdrahn 	pcmd->param0  = htole16(val0);
56637837c73Sdrahn 	pcmd->param1  = htole16(val1);
56737837c73Sdrahn 	pcmd->param2  = htole16(val2);
56837837c73Sdrahn 
56937837c73Sdrahn 	bzero(((char*)pcmd)+total_len, rnd_len - total_len);
57037837c73Sdrahn 
57137837c73Sdrahn 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
57237837c73Sdrahn 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
57337837c73Sdrahn 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
57437837c73Sdrahn 
57537837c73Sdrahn 	err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
57637837c73Sdrahn 
57737837c73Sdrahn 	if (err == 0)
57837837c73Sdrahn 		err = sc->cmdresperr;
57937837c73Sdrahn 
58037837c73Sdrahn 	sc->cmdresperr = 0;
58137837c73Sdrahn 
58237837c73Sdrahn err_ret:
58337837c73Sdrahn 	wi_usb_tx_unlock(sc);
58437837c73Sdrahn 
58537837c73Sdrahn 	wi_usb_ctl_unlock(sc);
58637837c73Sdrahn 
58737837c73Sdrahn 	DPRINTFN(5,("%s: %s: exit err=%x\n",
5884ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, err));
58937837c73Sdrahn 	return err;
59037837c73Sdrahn }
59137837c73Sdrahn 
59237837c73Sdrahn 
59337837c73Sdrahn int
wi_read_record_usb(struct wi_softc * wsc,struct wi_ltv_gen * ltv)59437837c73Sdrahn wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
59537837c73Sdrahn {
59637837c73Sdrahn 	struct wi_usb_chain	*c;
59737837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
59837837c73Sdrahn 	struct wi_rridreq	*prid;
59937837c73Sdrahn 	int			total_len, rnd_len;
60037837c73Sdrahn 	int			err;
601c8fc8278Stedu 	struct wi_ltv_gen	*oltv = NULL, p2ltv;
60237837c73Sdrahn 
60337837c73Sdrahn 	DPRINTFN(5,("%s: %s: enter rid=%x\n",
6044ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type));
60537837c73Sdrahn 
60637837c73Sdrahn 	/* Do we need to deal with these here, as in _io version?
60737837c73Sdrahn 	 * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
60837837c73Sdrahn 	 * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
60937837c73Sdrahn 	 */
61037837c73Sdrahn 	if (wsc->sc_firmware_type != WI_LUCENT) {
61137837c73Sdrahn 		oltv = ltv;
61237837c73Sdrahn 		switch (ltv->wi_type) {
61337837c73Sdrahn 		case WI_RID_ENCRYPTION:
61437837c73Sdrahn 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
61537837c73Sdrahn 			p2ltv.wi_len = 2;
61637837c73Sdrahn 			ltv = &p2ltv;
61737837c73Sdrahn 			break;
61837837c73Sdrahn 		case WI_RID_TX_CRYPT_KEY:
61937837c73Sdrahn 			if (ltv->wi_val > WI_NLTV_KEYS)
62037837c73Sdrahn 				return (EINVAL);
62137837c73Sdrahn 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
62237837c73Sdrahn 			p2ltv.wi_len = 2;
62337837c73Sdrahn 			ltv = &p2ltv;
62437837c73Sdrahn 			break;
62537837c73Sdrahn 		}
62637837c73Sdrahn 	}
62737837c73Sdrahn 
62837837c73Sdrahn 	wi_usb_tx_lock(sc);
62937837c73Sdrahn 
63037837c73Sdrahn 	c = &sc->wi_usb_tx_chain[0];
63137837c73Sdrahn 	prid = c->wi_usb_buf;
63237837c73Sdrahn 
63337837c73Sdrahn 	total_len = sizeof(struct wi_rridreq);
63437837c73Sdrahn 	rnd_len = ROUNDUP64(total_len);
63537837c73Sdrahn 
63637837c73Sdrahn 	if (rnd_len > WI_USB_BUFSZ) {
63737837c73Sdrahn 		printf("read_record buf size err %x %x\n",
63837837c73Sdrahn 		    rnd_len, WI_USB_BUFSZ);
63957431d2dStedu 		wi_usb_tx_unlock(sc);
64037837c73Sdrahn 		return EIO;
64137837c73Sdrahn 	}
64237837c73Sdrahn 
64337837c73Sdrahn 	sc->ridltv = ltv;
64437837c73Sdrahn 	sc->ridresperr = 0;
64537837c73Sdrahn 
64637837c73Sdrahn 	prid->type = htole16(WI_USB_RRIDREQ);
64737837c73Sdrahn 	prid->frmlen = htole16(2);	/* variable size? */
64837837c73Sdrahn 	prid->rid  = htole16(ltv->wi_type);
64937837c73Sdrahn 
65037837c73Sdrahn 	bzero(((char*)prid)+total_len, rnd_len - total_len);
65137837c73Sdrahn 
65237837c73Sdrahn 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
65337837c73Sdrahn 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
65437837c73Sdrahn 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
65537837c73Sdrahn 
65637837c73Sdrahn 	DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
6574ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, total_len, ltv->wi_len));
65837837c73Sdrahn 
65937837c73Sdrahn 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
66037837c73Sdrahn 
66137837c73Sdrahn 	/* Do we need to deal with these here, as in _io version?
66237837c73Sdrahn 	 *
66337837c73Sdrahn 	 * WI_RID_TX_RATE
66437837c73Sdrahn 	 * WI_RID_CUR_TX_RATE
66537837c73Sdrahn 	 * WI_RID_ENCRYPTION
66637837c73Sdrahn 	 * WI_RID_TX_CRYPT_KEY
66737837c73Sdrahn 	 * WI_RID_CNFAUTHMODE
66837837c73Sdrahn 	 */
66937837c73Sdrahn 	if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
67037837c73Sdrahn 	    && ltv->wi_val == wsc->wi_ibss_port) {
67137837c73Sdrahn 		/*
67237837c73Sdrahn 		 * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
67337837c73Sdrahn 		 * Since Lucent uses port type 1 for BSS *and* IBSS we
67437837c73Sdrahn 		 * have to rely on wi_ptype to distinguish this for us.
67537837c73Sdrahn 		 */
67637837c73Sdrahn 		ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
67737837c73Sdrahn 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
67837837c73Sdrahn 		int v;
67937837c73Sdrahn 
68037837c73Sdrahn 		switch (oltv->wi_type) {
68137837c73Sdrahn 		case WI_RID_TX_RATE:
68237837c73Sdrahn 		case WI_RID_CUR_TX_RATE:
68337837c73Sdrahn 			switch (letoh16(ltv->wi_val)) {
68437837c73Sdrahn 			case 1: v = 1; break;
68537837c73Sdrahn 			case 2: v = 2; break;
68637837c73Sdrahn 			case 3:	v = 6; break;
68737837c73Sdrahn 			case 4: v = 5; break;
68837837c73Sdrahn 			case 7: v = 7; break;
68937837c73Sdrahn 			case 8: v = 11; break;
69037837c73Sdrahn 			case 15: v = 3; break;
69137837c73Sdrahn 			default: v = 0x100 + letoh16(ltv->wi_val); break;
69237837c73Sdrahn 			}
69337837c73Sdrahn 			oltv->wi_val = htole16(v);
69437837c73Sdrahn 			break;
69537837c73Sdrahn 		case WI_RID_ENCRYPTION:
69637837c73Sdrahn 			oltv->wi_len = 2;
69737837c73Sdrahn 			if (ltv->wi_val & htole16(0x01))
69837837c73Sdrahn 				oltv->wi_val = htole16(1);
69937837c73Sdrahn 			else
70037837c73Sdrahn 				oltv->wi_val = htole16(0);
70137837c73Sdrahn 			break;
70237837c73Sdrahn 		case WI_RID_TX_CRYPT_KEY:
70337837c73Sdrahn 		case WI_RID_CNFAUTHMODE:
70437837c73Sdrahn 			oltv->wi_len = 2;
70537837c73Sdrahn 			oltv->wi_val = ltv->wi_val;
70637837c73Sdrahn 			break;
70737837c73Sdrahn 		}
70837837c73Sdrahn 	}
70937837c73Sdrahn 
71037837c73Sdrahn 	if (err == 0)
71137837c73Sdrahn 		err = sc->ridresperr;
71237837c73Sdrahn 
71337837c73Sdrahn 	sc->ridresperr = 0;
71437837c73Sdrahn 
71537837c73Sdrahn 	wi_usb_tx_unlock(sc);
71637837c73Sdrahn 
71737837c73Sdrahn 	DPRINTFN(5,("%s: %s: exit err=%x\n",
7184ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, err));
71937837c73Sdrahn 	return err;
72037837c73Sdrahn }
72137837c73Sdrahn 
72237837c73Sdrahn int
wi_write_record_usb(struct wi_softc * wsc,struct wi_ltv_gen * ltv)72337837c73Sdrahn wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
72437837c73Sdrahn {
72537837c73Sdrahn 	struct wi_usb_chain	*c;
72637837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
72737837c73Sdrahn 	struct wi_wridreq	*prid;
72837837c73Sdrahn 	int			total_len, rnd_len;
72937837c73Sdrahn 	int			err;
73037837c73Sdrahn 	struct wi_ltv_gen	p2ltv;
73137837c73Sdrahn 	u_int16_t		val = 0;
73237837c73Sdrahn 	int			i;
73337837c73Sdrahn 
73437837c73Sdrahn 	DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
7354ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, ltv->wi_type, ltv->wi_len,
73637837c73Sdrahn 	    (ltv->wi_len-1)*2 ));
73737837c73Sdrahn 
73837837c73Sdrahn 	/* Do we need to deal with these here, as in _io version?
73937837c73Sdrahn 	 * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
74037837c73Sdrahn 	 * RID_TX_RATE munging
74137837c73Sdrahn 	 * RID_ENCRYPTION
74237837c73Sdrahn 	 * WI_RID_TX_CRYPT_KEY
74337837c73Sdrahn 	 * WI_RID_DEFLT_CRYPT_KEYS
74437837c73Sdrahn 	 */
74537837c73Sdrahn 	if (ltv->wi_type == WI_RID_PORTTYPE &&
74637837c73Sdrahn 	    letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
74737837c73Sdrahn 		/* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
74837837c73Sdrahn 		p2ltv.wi_type = WI_RID_PORTTYPE;
74937837c73Sdrahn 		p2ltv.wi_len = 2;
75037837c73Sdrahn 		p2ltv.wi_val = wsc->wi_ibss_port;
75137837c73Sdrahn 		ltv = &p2ltv;
75237837c73Sdrahn 	} else if (wsc->sc_firmware_type != WI_LUCENT) {
75337837c73Sdrahn 		int v;
75437837c73Sdrahn 
75537837c73Sdrahn 		switch (ltv->wi_type) {
75637837c73Sdrahn 		case WI_RID_TX_RATE:
75737837c73Sdrahn 			p2ltv.wi_type = WI_RID_TX_RATE;
75837837c73Sdrahn 			p2ltv.wi_len = 2;
75937837c73Sdrahn 			switch (letoh16(ltv->wi_val)) {
76037837c73Sdrahn 			case 1: v = 1; break;
76137837c73Sdrahn 			case 2: v = 2; break;
76237837c73Sdrahn 			case 3:	v = 15; break;
76337837c73Sdrahn 			case 5: v = 4; break;
76437837c73Sdrahn 			case 6: v = 3; break;
76537837c73Sdrahn 			case 7: v = 7; break;
76637837c73Sdrahn 			case 11: v = 8; break;
76737837c73Sdrahn 			default: return EINVAL;
76837837c73Sdrahn 			}
76937837c73Sdrahn 			p2ltv.wi_val = htole16(v);
77037837c73Sdrahn 			ltv = &p2ltv;
77137837c73Sdrahn 			break;
77237837c73Sdrahn 		case WI_RID_ENCRYPTION:
77337837c73Sdrahn 			p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
77437837c73Sdrahn 			p2ltv.wi_len = 2;
77537837c73Sdrahn 			if (ltv->wi_val & htole16(0x01)) {
77637837c73Sdrahn 				val = PRIVACY_INVOKED;
77737837c73Sdrahn 				/*
77837837c73Sdrahn 				 * If using shared key WEP we must set the
77937837c73Sdrahn 				 * EXCLUDE_UNENCRYPTED bit.  Symbol cards
78037837c73Sdrahn 				 * need this bit set even when not using
78137837c73Sdrahn 				 * shared key. We can't just test for
78237837c73Sdrahn 				 * IEEE80211_AUTH_SHARED since Symbol cards
78337837c73Sdrahn 				 * have 2 shared key modes.
78437837c73Sdrahn 				 */
78537837c73Sdrahn 				if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
78637837c73Sdrahn 				    wsc->sc_firmware_type == WI_SYMBOL)
78737837c73Sdrahn 					val |= EXCLUDE_UNENCRYPTED;
78837837c73Sdrahn 
78937837c73Sdrahn 				switch (wsc->wi_crypto_algorithm) {
79037837c73Sdrahn 				case WI_CRYPTO_FIRMWARE_WEP:
79137837c73Sdrahn 					/*
79237837c73Sdrahn 					 * TX encryption is broken in
79337837c73Sdrahn 					 * Host AP mode.
79437837c73Sdrahn 					 */
79537837c73Sdrahn 					if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
79637837c73Sdrahn 						val |= HOST_ENCRYPT;
79737837c73Sdrahn 					break;
79837837c73Sdrahn 				case WI_CRYPTO_SOFTWARE_WEP:
79937837c73Sdrahn 					val |= HOST_ENCRYPT|HOST_DECRYPT;
80037837c73Sdrahn 					break;
80137837c73Sdrahn 				}
80237837c73Sdrahn 				p2ltv.wi_val = htole16(val);
80337837c73Sdrahn 			} else
80437837c73Sdrahn 				p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
80537837c73Sdrahn 			ltv = &p2ltv;
80637837c73Sdrahn 			break;
80737837c73Sdrahn 		case WI_RID_TX_CRYPT_KEY:
80837837c73Sdrahn 			if (ltv->wi_val > WI_NLTV_KEYS)
80937837c73Sdrahn 				return (EINVAL);
81037837c73Sdrahn 			p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
81137837c73Sdrahn 			p2ltv.wi_len = 2;
81237837c73Sdrahn 			p2ltv.wi_val = ltv->wi_val;
81337837c73Sdrahn 			ltv = &p2ltv;
81437837c73Sdrahn 			break;
81537837c73Sdrahn 		case WI_RID_DEFLT_CRYPT_KEYS: {
81637837c73Sdrahn 				int error;
81737837c73Sdrahn 				int keylen;
81837837c73Sdrahn 				struct wi_ltv_str ws;
81920605236Sdrahn 				struct wi_ltv_keys *wk;
82020605236Sdrahn 
82120605236Sdrahn 				wk = (struct wi_ltv_keys *)ltv;
82237837c73Sdrahn 				keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
82320605236Sdrahn 				keylen = letoh16(keylen);
82437837c73Sdrahn 
82537837c73Sdrahn 				for (i = 0; i < 4; i++) {
82637837c73Sdrahn 					bzero(&ws, sizeof(ws));
82737837c73Sdrahn 					ws.wi_len = (keylen > 5) ? 8 : 4;
82837837c73Sdrahn 					ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
82937837c73Sdrahn 					bcopy(&wk->wi_keys[i].wi_keydat,
83037837c73Sdrahn 					    ws.wi_str, keylen);
83137837c73Sdrahn 					error = wi_write_record_usb(wsc,
83237837c73Sdrahn 					    (struct wi_ltv_gen *)&ws);
83337837c73Sdrahn 					if (error)
83437837c73Sdrahn 						return (error);
83537837c73Sdrahn 				}
83637837c73Sdrahn 			}
83737837c73Sdrahn 			return (0);
83837837c73Sdrahn 		}
83937837c73Sdrahn 	}
84037837c73Sdrahn 
84137837c73Sdrahn 	wi_usb_tx_lock(sc);
84237837c73Sdrahn 
84337837c73Sdrahn 	c = &sc->wi_usb_tx_chain[0];
84437837c73Sdrahn 
84537837c73Sdrahn 	prid = c->wi_usb_buf;
84637837c73Sdrahn 
84737837c73Sdrahn 	total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
84837837c73Sdrahn 	    sizeof(prid->rid) + (ltv->wi_len-1)*2;
84937837c73Sdrahn 	rnd_len = ROUNDUP64(total_len);
85037837c73Sdrahn 	if (rnd_len > WI_USB_BUFSZ) {
85137837c73Sdrahn 		printf("write_record buf size err %x %x\n",
85237837c73Sdrahn 		    rnd_len, WI_USB_BUFSZ);
85357431d2dStedu 		wi_usb_tx_unlock(sc);
85437837c73Sdrahn 		return EIO;
85537837c73Sdrahn 	}
85637837c73Sdrahn 
85737837c73Sdrahn 	prid->type = htole16(WI_USB_WRIDREQ);
85837837c73Sdrahn 	prid->frmlen = htole16(ltv->wi_len);
85937837c73Sdrahn 	prid->rid  = htole16(ltv->wi_type);
86037837c73Sdrahn 	if (ltv->wi_len > 1)
861a768fe4bStedu 		bcopy(&ltv->wi_val, &prid->data[0], (ltv->wi_len-1)*2);
86237837c73Sdrahn 
86337837c73Sdrahn 	bzero(((char*)prid)+total_len, rnd_len - total_len);
86437837c73Sdrahn 
86537837c73Sdrahn 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
86637837c73Sdrahn 	    c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
86737837c73Sdrahn 	    WI_USB_TX_TIMEOUT, wi_usb_txeof);
86837837c73Sdrahn 
86937837c73Sdrahn 	err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
87037837c73Sdrahn 
87137837c73Sdrahn 	if (err == 0)
87237837c73Sdrahn 		err = sc->ridresperr;
87337837c73Sdrahn 
87437837c73Sdrahn 	sc->ridresperr = 0;
87537837c73Sdrahn 
87637837c73Sdrahn 	wi_usb_tx_unlock(sc);
87737837c73Sdrahn 
87837837c73Sdrahn 	DPRINTFN(5,("%s: %s: exit err=%x\n",
8794ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, err));
88037837c73Sdrahn 	return err;
88137837c73Sdrahn }
88237837c73Sdrahn 
88337837c73Sdrahn /*
88437837c73Sdrahn  * This is an ugly compat portion to emulate the I/O which writes
88537837c73Sdrahn  * a packet or management information
88637837c73Sdrahn  * The data is copied into local memory for the requested
88737837c73Sdrahn  * 'id' then on the wi_cmd WI_CMD_TX, the id argument
88837837c73Sdrahn  * will identify which buffer to use
88937837c73Sdrahn  */
89037837c73Sdrahn int
wi_alloc_nicmem_usb(struct wi_softc * wsc,int len,int * id)89137837c73Sdrahn wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
89237837c73Sdrahn {
89337837c73Sdrahn 	int nmem;
89437837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
89537837c73Sdrahn 
89637837c73Sdrahn 	DPRINTFN(10,("%s: %s: enter len=%x\n",
8974ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, len));
89837837c73Sdrahn 
89937837c73Sdrahn 	/*
90037837c73Sdrahn 	 * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
90137837c73Sdrahn 	 * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
90237837c73Sdrahn 	 */
90337837c73Sdrahn 	nmem = sc->wi_usb_nummem++;
90437837c73Sdrahn 
90537837c73Sdrahn 	if (nmem >= MAX_WI_NMEM) {
90637837c73Sdrahn 		sc->wi_usb_nummem--;
90737837c73Sdrahn 		return ENOMEM;
90837837c73Sdrahn 	}
90937837c73Sdrahn 
9108985a220Smglocker 	sc->wi_usb_txmem[nmem] = malloc(len, M_USBDEV, M_WAITOK | M_CANFAIL);
91137837c73Sdrahn 	if (sc->wi_usb_txmem[nmem] == NULL) {
91237837c73Sdrahn 		sc->wi_usb_nummem--;
91337837c73Sdrahn 		return ENOMEM;
91437837c73Sdrahn 	}
91537837c73Sdrahn 	sc->wi_usb_txmemsize[nmem] = len;
91637837c73Sdrahn 
91737837c73Sdrahn 	*id = nmem;
91837837c73Sdrahn 	return 0;
91937837c73Sdrahn }
92037837c73Sdrahn 
92137837c73Sdrahn /*
92237837c73Sdrahn  * this is crazy, we skip the first 16 bits of the buf so that it
92337837c73Sdrahn  * can be used as the 'type' of the usb transfer.
92437837c73Sdrahn  */
92537837c73Sdrahn 
92637837c73Sdrahn 
92737837c73Sdrahn int
wi_write_data_usb(struct wi_softc * wsc,int id,int off,caddr_t buf,int len)92837837c73Sdrahn wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
92937837c73Sdrahn {
93037837c73Sdrahn 	u_int8_t	*ptr;
93137837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
93237837c73Sdrahn 
93337837c73Sdrahn 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
9344ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
93537837c73Sdrahn 
93637837c73Sdrahn 	if (id < 0 && id >= sc->wi_usb_nummem)
93737837c73Sdrahn 		return EIO;
93837837c73Sdrahn 
93937837c73Sdrahn 	ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
94037837c73Sdrahn 
94137837c73Sdrahn 	if (len + off > sc->wi_usb_txmemsize[id])
94237837c73Sdrahn 		return EIO;
94337837c73Sdrahn 	DPRINTFN(10,("%s: %s: completed \n",
9444ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__));
94537837c73Sdrahn 
94637837c73Sdrahn 	bcopy(buf, ptr, len);
94737837c73Sdrahn 	return 0;
94837837c73Sdrahn }
94937837c73Sdrahn 
95037837c73Sdrahn /*
95137837c73Sdrahn  * On the prism I/O, this read_data points to the hardware buffer
95237837c73Sdrahn  * which contains the
95337837c73Sdrahn  */
95437837c73Sdrahn int
wi_read_data_usb(struct wi_softc * wsc,int id,int off,caddr_t buf,int len)95537837c73Sdrahn wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
95637837c73Sdrahn {
95737837c73Sdrahn 	u_int8_t	*ptr;
95837837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
95937837c73Sdrahn 
96037837c73Sdrahn 	DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
9614ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, id, off, len));
96237837c73Sdrahn 
96337837c73Sdrahn 	if (id == 0x1001 && sc->wi_info != NULL)
96437837c73Sdrahn 		ptr = (u_int8_t *)sc->wi_info + off;
96537837c73Sdrahn 	else if (id == 0x1000 && sc->wi_rxframe != NULL)
96637837c73Sdrahn 		ptr = (u_int8_t *)sc->wi_rxframe + off;
96737837c73Sdrahn 	else if (id >= 0 && id < sc->wi_usb_nummem) {
96837837c73Sdrahn 
96937837c73Sdrahn 		if (sc->wi_usb_txmem[id] == NULL)
97037837c73Sdrahn 			return EIO;
97137837c73Sdrahn 		if (len + off > sc->wi_usb_txmemsize[id])
97237837c73Sdrahn 			return EIO;
97337837c73Sdrahn 
97437837c73Sdrahn 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
97537837c73Sdrahn 	} else
97637837c73Sdrahn 		return EIO;
97737837c73Sdrahn 
97837837c73Sdrahn 	if (id < sc->wi_usb_nummem) {
97937837c73Sdrahn 		ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
98037837c73Sdrahn 
98137837c73Sdrahn 		if (len + off > sc->wi_usb_txmemsize[id])
98237837c73Sdrahn 			return EIO;
98337837c73Sdrahn 	}
98437837c73Sdrahn 
98537837c73Sdrahn 	bcopy(ptr, buf, len);
98637837c73Sdrahn 	return 0;
98737837c73Sdrahn }
98837837c73Sdrahn 
98937837c73Sdrahn void
wi_usb_stop(struct wi_usb_softc * sc)99037837c73Sdrahn wi_usb_stop(struct wi_usb_softc *sc)
99137837c73Sdrahn {
9924ab2b9feSmbalmer 	DPRINTFN(1,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
99337837c73Sdrahn 	/* XXX */
99437837c73Sdrahn 
99537837c73Sdrahn 	/* Stop transfers */
99637837c73Sdrahn }
99737837c73Sdrahn 
99837837c73Sdrahn int
wi_usb_do_transmit_sync(struct wi_usb_softc * sc,struct wi_usb_chain * c,void * ident)99937837c73Sdrahn wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
100037837c73Sdrahn     void *ident)
100137837c73Sdrahn {
100237837c73Sdrahn 	usbd_status		err;
100337837c73Sdrahn 
100437837c73Sdrahn 	DPRINTFN(10,("%s: %s:\n",
10054ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__));
100637837c73Sdrahn 
100737837c73Sdrahn 	sc->wi_usb_refcnt++;
100837837c73Sdrahn 	err = usbd_transfer(c->wi_usb_xfer);
100937837c73Sdrahn 	if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
10108f9651bbSfgsch 		printf("%s: %s error=%s\n",
10114ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__,
10128f9651bbSfgsch 		    usbd_errstr(err));
101337837c73Sdrahn 		/* Stop the interface from process context. */
101437837c73Sdrahn 		wi_usb_stop(sc);
101537837c73Sdrahn 		err = EIO;
101637837c73Sdrahn 		goto done;
101737837c73Sdrahn 	}
101800f6cb32Smpi 	err = tsleep_nsec(ident, PRIBIO, "wiTXsync", SEC_TO_NSEC(1));
101937837c73Sdrahn 	if (err) {
102037837c73Sdrahn 		DPRINTFN(1,("%s: %s: err %x\n",
10214ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, err));
102237837c73Sdrahn 		err = ETIMEDOUT;
102337837c73Sdrahn 	}
102437837c73Sdrahn done:
102537837c73Sdrahn 	if (--sc->wi_usb_refcnt < 0)
10261596fc1eSmbalmer 		usb_detach_wakeup(&sc->wi_usb_dev);
102737837c73Sdrahn 	return err;
102837837c73Sdrahn }
102937837c73Sdrahn 
103037837c73Sdrahn 
103137837c73Sdrahn /*
103237837c73Sdrahn  * A command/rrid/wrid  was sent to the chip. It's safe for us to clean up
103337837c73Sdrahn  * the list buffers.
103437837c73Sdrahn  */
103537837c73Sdrahn 
103637837c73Sdrahn void
wi_usb_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1037ab0b1be7Smglocker wi_usb_txeof(struct usbd_xfer *xfer, void *priv,
103837837c73Sdrahn     usbd_status status)
103937837c73Sdrahn {
104037837c73Sdrahn 	struct wi_usb_chain	*c = priv;
104137837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
104237837c73Sdrahn 
104337837c73Sdrahn 	int			s;
104437837c73Sdrahn 
10459c6c4aa3Spirofti 	if (usbd_is_dying(sc->wi_usb_udev))
104637837c73Sdrahn 		return;
104737837c73Sdrahn 
104837837c73Sdrahn 	s = splnet();
104937837c73Sdrahn 
10504ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
105137837c73Sdrahn 		    __func__, status));
105237837c73Sdrahn 
105337837c73Sdrahn 	if (status != USBD_NORMAL_COMPLETION) {
105437837c73Sdrahn 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
105537837c73Sdrahn 			splx(s);
105637837c73Sdrahn 			return;
105737837c73Sdrahn 		}
10584ab2b9feSmbalmer 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
105937837c73Sdrahn 		    usbd_errstr(status));
106037837c73Sdrahn 		if (status == USBD_STALLED) {
106137837c73Sdrahn 			sc->wi_usb_refcnt++;
10622c1b7be2Sbrad 			usbd_clear_endpoint_stall_async(
106337837c73Sdrahn 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
106437837c73Sdrahn 			if (--sc->wi_usb_refcnt < 0)
10651596fc1eSmbalmer 				usb_detach_wakeup(&sc->wi_usb_dev);
106637837c73Sdrahn 		}
106737837c73Sdrahn 		splx(s);
106837837c73Sdrahn 		return;
106937837c73Sdrahn 	}
107037837c73Sdrahn 
107137837c73Sdrahn 	splx(s);
107237837c73Sdrahn }
107337837c73Sdrahn 
107437837c73Sdrahn /*
107537837c73Sdrahn  * A packet was sent to the chip. It's safe for us to clean up
107637837c73Sdrahn  * the list buffers.
107737837c73Sdrahn  */
107837837c73Sdrahn 
107937837c73Sdrahn void
wi_usb_txeof_frm(struct usbd_xfer * xfer,void * priv,usbd_status status)1080ab0b1be7Smglocker wi_usb_txeof_frm(struct usbd_xfer *xfer, void *priv,
108137837c73Sdrahn     usbd_status status)
108237837c73Sdrahn {
108337837c73Sdrahn 	struct wi_usb_chain	*c = priv;
108437837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
108537837c73Sdrahn 	struct wi_softc		*wsc = &sc->sc_wi;
108655f29f42Sjsg 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
108737837c73Sdrahn 
108837837c73Sdrahn 	int			s;
108937837c73Sdrahn 	int			err = 0;
109037837c73Sdrahn 
10919c6c4aa3Spirofti 	if (usbd_is_dying(sc->wi_usb_udev))
109237837c73Sdrahn 		return;
109337837c73Sdrahn 
109437837c73Sdrahn 	s = splnet();
109537837c73Sdrahn 
10964ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
109737837c73Sdrahn 		    __func__, status));
109837837c73Sdrahn 
109937837c73Sdrahn 	if (status != USBD_NORMAL_COMPLETION) {
110037837c73Sdrahn 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
110137837c73Sdrahn 			splx(s);
110237837c73Sdrahn 			return;
110337837c73Sdrahn 		}
11044ab2b9feSmbalmer 		printf("%s: usb error on tx: %s\n", sc->wi_usb_dev.dv_xname,
110537837c73Sdrahn 		    usbd_errstr(status));
110637837c73Sdrahn 		if (status == USBD_STALLED) {
110737837c73Sdrahn 			sc->wi_usb_refcnt++;
11082c1b7be2Sbrad 			usbd_clear_endpoint_stall_async(
110937837c73Sdrahn 			    sc->wi_usb_ep[WI_USB_ENDPT_TX]);
111037837c73Sdrahn 			if (--sc->wi_usb_refcnt < 0)
11111596fc1eSmbalmer 				usb_detach_wakeup(&sc->wi_usb_dev);
111237837c73Sdrahn 		}
111337837c73Sdrahn 		splx(s);
111437837c73Sdrahn 		return;
111537837c73Sdrahn 	}
111637837c73Sdrahn 
111737837c73Sdrahn 	if (status)
111837837c73Sdrahn 		err = WI_EV_TX_EXC;
111937837c73Sdrahn 
112037837c73Sdrahn 	wi_txeof(wsc, err);
112137837c73Sdrahn 
112237837c73Sdrahn 	wi_usb_tx_unlock(sc);
112337837c73Sdrahn 
11240cae21bdSpatrick 	if (!ifq_empty(&ifp->if_snd))
112537837c73Sdrahn 		wi_start_usb(ifp);
112637837c73Sdrahn 
112737837c73Sdrahn 	splx(s);
112837837c73Sdrahn }
112937837c73Sdrahn 
113037837c73Sdrahn int
wi_usb_rx_list_init(struct wi_usb_softc * sc)113137837c73Sdrahn wi_usb_rx_list_init(struct wi_usb_softc *sc)
113237837c73Sdrahn {
113337837c73Sdrahn 	struct wi_usb_chain	*c;
113437837c73Sdrahn 	int			i;
113537837c73Sdrahn 
11364ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
113737837c73Sdrahn 
113837837c73Sdrahn 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
113937837c73Sdrahn 		c = &sc->wi_usb_rx_chain[i];
114037837c73Sdrahn 		c->wi_usb_sc = sc;
114137837c73Sdrahn 		c->wi_usb_idx = i;
114237837c73Sdrahn 		if (c->wi_usb_xfer != NULL) {
114337837c73Sdrahn 			printf("UGH RX\n");
114437837c73Sdrahn 		}
114537837c73Sdrahn 		if (c->wi_usb_xfer == NULL) {
114637837c73Sdrahn 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
114737837c73Sdrahn 			if (c->wi_usb_xfer == NULL)
114837837c73Sdrahn 				return (ENOBUFS);
114937837c73Sdrahn 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
115037837c73Sdrahn 			    WI_USB_BUFSZ);
115137837c73Sdrahn 			if (c->wi_usb_buf == NULL)
115237837c73Sdrahn 				return (ENOBUFS); /* XXX free xfer */
115337837c73Sdrahn 		}
115437837c73Sdrahn 	}
115537837c73Sdrahn 
115637837c73Sdrahn 	return (0);
115737837c73Sdrahn }
115837837c73Sdrahn 
115937837c73Sdrahn int
wi_usb_tx_list_init(struct wi_usb_softc * sc)116037837c73Sdrahn wi_usb_tx_list_init(struct wi_usb_softc *sc)
116137837c73Sdrahn {
116237837c73Sdrahn 	struct wi_usb_chain	*c;
116337837c73Sdrahn 	int			i;
116437837c73Sdrahn 
11654ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
116637837c73Sdrahn 
116737837c73Sdrahn 	for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
116837837c73Sdrahn 		c = &sc->wi_usb_tx_chain[i];
116937837c73Sdrahn 		c->wi_usb_sc = sc;
117037837c73Sdrahn 		c->wi_usb_idx = i;
117137837c73Sdrahn 		c->wi_usb_mbuf = NULL;
117237837c73Sdrahn 		if (c->wi_usb_xfer != NULL) {
117337837c73Sdrahn 			printf("UGH TX\n");
117437837c73Sdrahn 		}
117537837c73Sdrahn 		if (c->wi_usb_xfer == NULL) {
117637837c73Sdrahn 			c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
117737837c73Sdrahn 			if (c->wi_usb_xfer == NULL)
117837837c73Sdrahn 				return (ENOBUFS);
117937837c73Sdrahn 			c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
118037837c73Sdrahn 			    WI_USB_BUFSZ);
118137837c73Sdrahn 			if (c->wi_usb_buf == NULL)
118237837c73Sdrahn 				return (ENOBUFS);
118337837c73Sdrahn 		}
118437837c73Sdrahn 	}
118537837c73Sdrahn 
118637837c73Sdrahn 	return (0);
118737837c73Sdrahn }
118837837c73Sdrahn 
118937837c73Sdrahn int
wi_usb_open_pipes(struct wi_usb_softc * sc)119037837c73Sdrahn wi_usb_open_pipes(struct wi_usb_softc *sc)
119137837c73Sdrahn {
119237837c73Sdrahn 	usbd_status		err;
119337837c73Sdrahn 	int			error = 0;
119437837c73Sdrahn 	struct wi_usb_chain	*c;
119537837c73Sdrahn 	int			i;
119637837c73Sdrahn 
11974ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,__func__));
119837837c73Sdrahn 
119937837c73Sdrahn 	sc->wi_usb_refcnt++;
120037837c73Sdrahn 
120137837c73Sdrahn 	/* Open RX and TX pipes. */
120237837c73Sdrahn 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
120337837c73Sdrahn 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
120437837c73Sdrahn 	if (err) {
120537837c73Sdrahn 		printf("%s: open rx pipe failed: %s\n",
12064ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
120737837c73Sdrahn 		error = EIO;
120837837c73Sdrahn 		goto done;
120937837c73Sdrahn 	}
121037837c73Sdrahn 
121137837c73Sdrahn 	err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
121237837c73Sdrahn 	    USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
121337837c73Sdrahn 	if (err) {
121437837c73Sdrahn 		printf("%s: open tx pipe failed: %s\n",
12154ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
121637837c73Sdrahn 		error = EIO;
121737837c73Sdrahn 		goto done;
121837837c73Sdrahn 	}
121937837c73Sdrahn 
122037837c73Sdrahn 	/* is this used? */
122137837c73Sdrahn 	err = usbd_open_pipe_intr(sc->wi_usb_iface,
12229d477d68Sjmatthew 	    sc->wi_usb_ed[WI_USB_ENDPT_INTR], 0,
122337837c73Sdrahn 	    &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
122437837c73Sdrahn 	    WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
122537837c73Sdrahn 	if (err) {
122637837c73Sdrahn 		printf("%s: open intr pipe failed: %s\n",
12274ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, usbd_errstr(err));
122837837c73Sdrahn 		error = EIO;
122937837c73Sdrahn 		goto done;
123037837c73Sdrahn 	}
123137837c73Sdrahn 
123237837c73Sdrahn 	/* Start up the receive pipe. */
123337837c73Sdrahn 	for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
123437837c73Sdrahn 		c = &sc->wi_usb_rx_chain[i];
123537837c73Sdrahn 		usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
123637837c73Sdrahn 		    c, c->wi_usb_buf, WI_USB_BUFSZ,
123737837c73Sdrahn 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
123837837c73Sdrahn 		    wi_usb_rxeof);
12394ab2b9feSmbalmer 		DPRINTFN(10,("%s: %s: start read\n", sc->wi_usb_dev.dv_xname,
124037837c73Sdrahn 			    __func__));
124137837c73Sdrahn 		usbd_transfer(c->wi_usb_xfer);
124237837c73Sdrahn 	}
124337837c73Sdrahn 
124437837c73Sdrahn done:
124537837c73Sdrahn 	if (--sc->wi_usb_refcnt < 0)
12461596fc1eSmbalmer 		usb_detach_wakeup(&sc->wi_usb_dev);
124737837c73Sdrahn 
124837837c73Sdrahn 	return (error);
124937837c73Sdrahn }
125037837c73Sdrahn 
125137837c73Sdrahn /*
125237837c73Sdrahn  * This is a bit of a kludge, however wi_rxeof and wi_update_stats
125337837c73Sdrahn  * call wi_get_fid to determine where the data associated with
125437837c73Sdrahn  * the transaction is located, the returned id is then used to
125537837c73Sdrahn  * wi_read_data the information out.
125637837c73Sdrahn  *
125737837c73Sdrahn  * This code returns which 'fid' should be used. The results are only valid
12586957a4a4Sjmc  * during a wi_usb_rxeof because the data is received packet is 'held'
125937837c73Sdrahn  * an a variable for reading by wi_read_data_usb for that period.
126037837c73Sdrahn  *
126137837c73Sdrahn  * for magic numbers this uses  0x1000, 0x1001 for rx/info
126237837c73Sdrahn  */
126337837c73Sdrahn 
126437837c73Sdrahn int
wi_get_fid_usb(struct wi_softc * sc,int fid)126537837c73Sdrahn wi_get_fid_usb(struct wi_softc *sc, int fid)
126637837c73Sdrahn {
126737837c73Sdrahn 	switch (fid) {
126837837c73Sdrahn 	case WI_RX_FID:
126937837c73Sdrahn 		return 0x1000;
127037837c73Sdrahn 	case WI_INFO_FID:
127137837c73Sdrahn 		return 0x1001;
127237837c73Sdrahn 	default:
127337837c73Sdrahn 		return 0x1111;
127437837c73Sdrahn 	}
127537837c73Sdrahn 
127637837c73Sdrahn }
127737837c73Sdrahn 
127837837c73Sdrahn #if 0
127937837c73Sdrahn void
128037837c73Sdrahn wi_dump_data(void *buffer, int len)
128137837c73Sdrahn {
128237837c73Sdrahn 	int i;
128337837c73Sdrahn 	for (i = 0; i < len; i++) {
128437837c73Sdrahn 		if (((i) % 16) == 0)
128537837c73Sdrahn 			printf("\n %02x:", i);
128637837c73Sdrahn 		printf(" %02x",
128737837c73Sdrahn 		    ((uint8_t *)(buffer))[i]);
128837837c73Sdrahn 
128937837c73Sdrahn 	}
129037837c73Sdrahn 	printf("\n");
129137837c73Sdrahn 
129237837c73Sdrahn }
129337837c73Sdrahn #endif
129437837c73Sdrahn 
129537837c73Sdrahn /*
12966957a4a4Sjmc  * A frame has been received.
129737837c73Sdrahn  */
129837837c73Sdrahn void
wi_usb_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)1299ab0b1be7Smglocker wi_usb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
130037837c73Sdrahn {
130137837c73Sdrahn 	struct wi_usb_chain	*c = priv;
130237837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
130337837c73Sdrahn 	wi_usb_usbin		*uin;
130437837c73Sdrahn 	int			total_len = 0;
130537837c73Sdrahn 	u_int16_t		rtype;
130637837c73Sdrahn 
13079c6c4aa3Spirofti 	if (usbd_is_dying(sc->wi_usb_udev))
130837837c73Sdrahn 		return;
130937837c73Sdrahn 
13104ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->wi_usb_dev.dv_xname,
131137837c73Sdrahn 		    __func__, status));
131237837c73Sdrahn 
131337837c73Sdrahn 
131437837c73Sdrahn 	if (status != USBD_NORMAL_COMPLETION) {
131537837c73Sdrahn 		if (status == USBD_NOT_STARTED || status == USBD_IOERROR
131637837c73Sdrahn 		    || status == USBD_CANCELLED) {
131737837c73Sdrahn 			printf("%s: %u usb errors on rx: %s\n",
13184ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, 1,
131937837c73Sdrahn 			    /* sc->wi_usb_rx_errs, */
132037837c73Sdrahn 			    usbd_errstr(status));
132137837c73Sdrahn 			return;
132237837c73Sdrahn 		}
132337837c73Sdrahn #if 0
132437837c73Sdrahn 		sc->wi_usb_rx_errs++;
132537837c73Sdrahn 		if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
132637837c73Sdrahn 			printf("%s: %u usb errors on rx: %s\n",
13274ab2b9feSmbalmer 			    sc->wi_usb_dev.dv_xname, sc->wi_usb_rx_errs,
132837837c73Sdrahn 			    usbd_errstr(status));
132937837c73Sdrahn 			sc->wi_usb_rx_errs = 0;
133037837c73Sdrahn 		}
133137837c73Sdrahn #endif
133237837c73Sdrahn 		if (status == USBD_STALLED) {
133337837c73Sdrahn 			sc->wi_usb_refcnt++;
13342c1b7be2Sbrad 			usbd_clear_endpoint_stall_async(
133537837c73Sdrahn 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
133637837c73Sdrahn 			if (--sc->wi_usb_refcnt < 0)
13371596fc1eSmbalmer 				usb_detach_wakeup(&sc->wi_usb_dev);
133837837c73Sdrahn 		}
133937837c73Sdrahn 		goto done;
134037837c73Sdrahn 	}
134137837c73Sdrahn 
134237837c73Sdrahn 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
134337837c73Sdrahn 
134437837c73Sdrahn 	if (total_len < 6) /* short XXX */
134537837c73Sdrahn 		goto done;
134637837c73Sdrahn 
134737837c73Sdrahn 	uin = (wi_usb_usbin *)(c->wi_usb_buf);
134837837c73Sdrahn 
134937837c73Sdrahn 	rtype = letoh16(uin->type);
135037837c73Sdrahn 
135137837c73Sdrahn 
135237837c73Sdrahn #if 0
135337837c73Sdrahn 	wi_dump_data(c->wi_usb_buf, total_len);
135437837c73Sdrahn #endif
135537837c73Sdrahn 
135637837c73Sdrahn 	if (WI_USB_ISRXFRM(rtype)) {
135737837c73Sdrahn 		wi_usb_rxfrm(sc, uin, total_len);
135837837c73Sdrahn 		goto done;
135937837c73Sdrahn 	}
136037837c73Sdrahn 	if (WI_USB_ISTXFRM(rtype)) {
136137837c73Sdrahn 		DPRINTFN(2,("%s: %s: txfrm type %x\n",
13624ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
136337837c73Sdrahn 		wi_usb_txfrm(sc, uin, total_len);
136437837c73Sdrahn 		goto done;
136537837c73Sdrahn 	}
136637837c73Sdrahn 
136737837c73Sdrahn 	switch (rtype) {
136837837c73Sdrahn 	case WI_USB_INFOFRM:
136937837c73Sdrahn 		/* info packet, INFO_FID hmm */
137037837c73Sdrahn 		DPRINTFN(10,("%s: %s: infofrm type %x\n",
13714ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
137237837c73Sdrahn 		wi_usb_infofrm(c, total_len);
137337837c73Sdrahn 		break;
137437837c73Sdrahn 	case WI_USB_CMDRESP:
137537837c73Sdrahn 		wi_usb_cmdresp(c);
137637837c73Sdrahn 		break;
137737837c73Sdrahn 	case WI_USB_WRIDRESP:
137837837c73Sdrahn 		wi_usb_wridresp(c);
137937837c73Sdrahn 		break;
138037837c73Sdrahn 	case WI_USB_RRIDRESP:
138137837c73Sdrahn 		wi_usb_rridresp(c);
138237837c73Sdrahn 		break;
138337837c73Sdrahn 	case WI_USB_WMEMRESP:
138437837c73Sdrahn 		/* Not currently used */
138537837c73Sdrahn 		DPRINTFN(2,("%s: %s: wmemresp type %x\n",
13864ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
138737837c73Sdrahn 		break;
138837837c73Sdrahn 	case WI_USB_RMEMRESP:
138937837c73Sdrahn 		/* Not currently used */
139037837c73Sdrahn 		DPRINTFN(2,("%s: %s: rmemresp type %x\n",
13914ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, rtype));
139237837c73Sdrahn 		break;
139337837c73Sdrahn 	case WI_USB_BUFAVAIL:
13946957a4a4Sjmc 		printf("wi_usb: received USB_BUFAVAIL packet\n"); /* XXX */
139537837c73Sdrahn 		break;
139637837c73Sdrahn 	case WI_USB_ERROR:
13976957a4a4Sjmc 		printf("wi_usb: received USB_ERROR packet\n"); /* XXX */
139837837c73Sdrahn 		break;
139937837c73Sdrahn #if 0
140020605236Sdrahn 	default:
14016957a4a4Sjmc 		printf("wi_usb: received Unknown packet 0x%x len %x\n",
140237837c73Sdrahn 		    rtype, total_len);
140337837c73Sdrahn 		wi_dump_data(c->wi_usb_buf, total_len);
140437837c73Sdrahn #endif
140537837c73Sdrahn 	}
140637837c73Sdrahn 
140737837c73Sdrahn  done:
140837837c73Sdrahn 	/* Setup new transfer. */
140937837c73Sdrahn 	usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
141037837c73Sdrahn 	    c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
141137837c73Sdrahn 	    USBD_NO_TIMEOUT, wi_usb_rxeof);
141237837c73Sdrahn 	sc->wi_usb_refcnt++;
141337837c73Sdrahn 	usbd_transfer(c->wi_usb_xfer);
141437837c73Sdrahn 	if (--sc->wi_usb_refcnt < 0)
14151596fc1eSmbalmer 		usb_detach_wakeup(&sc->wi_usb_dev);
141637837c73Sdrahn 
14174ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: start rx\n", sc->wi_usb_dev.dv_xname,
141837837c73Sdrahn 		    __func__));
141937837c73Sdrahn }
142037837c73Sdrahn 
142137837c73Sdrahn void
wi_usb_intr(struct usbd_xfer * xfer,void * priv,usbd_status status)1422ab0b1be7Smglocker wi_usb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
142337837c73Sdrahn {
142437837c73Sdrahn 	struct wi_usb_softc	*sc = priv;
142537837c73Sdrahn 
14264ab2b9feSmbalmer 	DPRINTFN(2,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
142737837c73Sdrahn 
14289c6c4aa3Spirofti 	if (usbd_is_dying(sc->wi_usb_udev))
142937837c73Sdrahn 		return;
143037837c73Sdrahn 
143137837c73Sdrahn 	if (status != USBD_NORMAL_COMPLETION) {
143237837c73Sdrahn 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
143337837c73Sdrahn 			return;
143437837c73Sdrahn 
143537837c73Sdrahn 		if (status == USBD_STALLED) {
143637837c73Sdrahn 			sc->wi_usb_refcnt++;
14372c1b7be2Sbrad 			usbd_clear_endpoint_stall_async(
143837837c73Sdrahn 			    sc->wi_usb_ep[WI_USB_ENDPT_RX]);
143937837c73Sdrahn 			if (--sc->wi_usb_refcnt < 0)
14401596fc1eSmbalmer 				usb_detach_wakeup(&sc->wi_usb_dev);
144137837c73Sdrahn 		}
144237837c73Sdrahn 		return;
144337837c73Sdrahn 	}
144437837c73Sdrahn 	/* XXX oerrors or collisions? */
144537837c73Sdrahn }
144637837c73Sdrahn void
wi_usb_cmdresp(struct wi_usb_chain * c)144737837c73Sdrahn wi_usb_cmdresp(struct wi_usb_chain *c)
144837837c73Sdrahn {
144937837c73Sdrahn 	struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
145037837c73Sdrahn 	u_int16_t status = letoh16(presp->status);
145137837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
145237837c73Sdrahn 	uint16_t type;
145337837c73Sdrahn 	uint16_t cmdresperr;
145437837c73Sdrahn 
145537837c73Sdrahn 	type = htole16(presp->type);
145637837c73Sdrahn 	cmdresperr = letoh16(presp->resp0);
145765df7dacSfgsch 	DPRINTFN(10,("%s: %s: enter type=%x, status=%x, cmdresp=%x, "
145865df7dacSfgsch 	    "resp=%x,%x,%x\n",
14594ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, type, status, sc->cmdresp,
146065df7dacSfgsch 	    cmdresperr, letoh16(presp->resp1),
146165df7dacSfgsch 	    letoh16(presp->resp2)));
146237837c73Sdrahn 
146365df7dacSfgsch 	/* XXX */
146465df7dacSfgsch 	if (sc->cmdresp != (status & WI_STAT_CMD_CODE)) {
146537837c73Sdrahn 		DPRINTFN(1,("%s: cmd ty %x st %x cmd %x failed %x\n",
14664ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname,
146737837c73Sdrahn 			type, status, sc->cmdresp, cmdresperr));
146837837c73Sdrahn 		return;
146937837c73Sdrahn 	}
147037837c73Sdrahn 
147165df7dacSfgsch 	sc->cmdresperr = (status & WI_STAT_CMD_RESULT) >> 8;
147237837c73Sdrahn 
147337837c73Sdrahn 	sc->cmdresp = 0; /* good value for idle == INI ?? XXX  */
147437837c73Sdrahn 
147537837c73Sdrahn 	wakeup(&sc->cmdresperr);
147637837c73Sdrahn }
147737837c73Sdrahn void
wi_usb_rridresp(struct wi_usb_chain * c)147837837c73Sdrahn wi_usb_rridresp(struct wi_usb_chain *c)
147937837c73Sdrahn {
148037837c73Sdrahn 	struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
148137837c73Sdrahn 	u_int16_t frmlen = letoh16(presp->frmlen);
148237837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
148337837c73Sdrahn 	struct wi_ltv_gen *ltv;
148437837c73Sdrahn 	uint16_t rid;
148537837c73Sdrahn 
148637837c73Sdrahn 	rid = letoh16(presp->rid);
148737837c73Sdrahn 	ltv =  sc->ridltv;
148837837c73Sdrahn 
148937837c73Sdrahn 	if (ltv == 0) {
149037837c73Sdrahn 		DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
14914ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__, rid,
149237837c73Sdrahn 		    frmlen));
149337837c73Sdrahn 		return;
149437837c73Sdrahn 	}
149537837c73Sdrahn 
149637837c73Sdrahn 	DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
14974ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, rid, ltv->wi_type,
149837837c73Sdrahn 	    frmlen, ltv->wi_len));
149937837c73Sdrahn 
150037837c73Sdrahn 	rid = letoh16(presp->rid);
150137837c73Sdrahn 
150237837c73Sdrahn 	if (rid != ltv->wi_type) {
150337837c73Sdrahn 		sc->ridresperr = EIO;
150437837c73Sdrahn 		return;
150537837c73Sdrahn 	}
150637837c73Sdrahn 
150737837c73Sdrahn 	if (frmlen > ltv->wi_len) {
150837837c73Sdrahn 		sc->ridresperr = ENOSPC;
150937837c73Sdrahn 		sc->ridltv = 0;
151037837c73Sdrahn 		wakeup(&sc->ridresperr);
151137837c73Sdrahn 		return;
151237837c73Sdrahn 	}
151337837c73Sdrahn 
151437837c73Sdrahn 	ltv->wi_len = frmlen;
151537837c73Sdrahn 
151665df7dacSfgsch 	DPRINTFN(10,("%s: %s: copying %d frmlen %d\n",
15174ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, (ltv->wi_len-1)*2,
151837837c73Sdrahn 	    frmlen));
151937837c73Sdrahn 
152037837c73Sdrahn 	if (ltv->wi_len > 1)
1521a768fe4bStedu 		bcopy(&presp->data[0], &ltv->wi_val,
152237837c73Sdrahn 		    (ltv->wi_len-1)*2);
152337837c73Sdrahn 
152437837c73Sdrahn 	sc->ridresperr = 0;
152537837c73Sdrahn 	sc->ridltv = 0;
152637837c73Sdrahn 	wakeup(&sc->ridresperr);
152737837c73Sdrahn 
152837837c73Sdrahn }
152937837c73Sdrahn 
153037837c73Sdrahn void
wi_usb_wridresp(struct wi_usb_chain * c)153137837c73Sdrahn wi_usb_wridresp(struct wi_usb_chain *c)
153237837c73Sdrahn {
153337837c73Sdrahn 	struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
153437837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
153537837c73Sdrahn 	uint16_t status;
153637837c73Sdrahn 
153737837c73Sdrahn 	status = letoh16(presp->status);
153837837c73Sdrahn 
153937837c73Sdrahn 	DPRINTFN(10,("%s: %s: enter status=%x\n",
15404ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, status));
154137837c73Sdrahn 
154265df7dacSfgsch 	sc->ridresperr = (status & WI_STAT_CMD_RESULT) >> 8;
154337837c73Sdrahn 	sc->ridltv = 0;
154437837c73Sdrahn 	wakeup(&sc->ridresperr);
154537837c73Sdrahn }
154637837c73Sdrahn 
154737837c73Sdrahn void
wi_usb_infofrm(struct wi_usb_chain * c,int len)154837837c73Sdrahn wi_usb_infofrm(struct wi_usb_chain *c, int len)
154937837c73Sdrahn {
155037837c73Sdrahn 	struct wi_usb_softc	*sc = c->wi_usb_sc;
155137837c73Sdrahn 
155237837c73Sdrahn 	DPRINTFN(10,("%s: %s: enter\n",
15534ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__));
155437837c73Sdrahn 
155537837c73Sdrahn 	sc->wi_info = ((char *)c->wi_usb_buf) + 2;
155637837c73Sdrahn 	wi_update_stats(&sc->sc_wi);
155737837c73Sdrahn 	sc->wi_info = NULL;
155837837c73Sdrahn }
155937837c73Sdrahn 
156037837c73Sdrahn void
wi_usb_txfrm(struct wi_usb_softc * sc,wi_usb_usbin * uin,int total_len)156137837c73Sdrahn wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
156237837c73Sdrahn {
156337837c73Sdrahn 	u_int16_t		status;
156437837c73Sdrahn 	int 			s;
156537837c73Sdrahn 	struct wi_softc		*wsc = &sc->sc_wi;
156655f29f42Sjsg 	struct ifnet		*ifp = &wsc->sc_ic.ic_if;
156737837c73Sdrahn 
156837837c73Sdrahn 	s = splnet();
156937837c73Sdrahn 	status = letoh16(uin->type); /* XXX -- type == status */
157037837c73Sdrahn 
157137837c73Sdrahn 
157237837c73Sdrahn 	DPRINTFN(2,("%s: %s: enter status=%d\n",
15734ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, status));
157437837c73Sdrahn 
157537837c73Sdrahn 	if (sc->txresp == WI_CMD_TX) {
157637837c73Sdrahn 		sc->txresperr=status;
157737837c73Sdrahn 		sc->txresp = 0;
157837837c73Sdrahn 		wakeup(&sc->txresperr);
157937837c73Sdrahn 	} else {
158037837c73Sdrahn 		if (status != 0) /* XXX */
158137837c73Sdrahn 			wi_watchdog_usb(ifp);
158237837c73Sdrahn 	DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
15834ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, status));
158437837c73Sdrahn 	}
158537837c73Sdrahn 
158637837c73Sdrahn 	splx(s);
158737837c73Sdrahn }
158837837c73Sdrahn void
wi_usb_rxfrm(struct wi_usb_softc * sc,wi_usb_usbin * uin,int total_len)158937837c73Sdrahn wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
159037837c73Sdrahn {
159137837c73Sdrahn 	int s;
159237837c73Sdrahn 
159337837c73Sdrahn 	DPRINTFN(5,("%s: %s: enter len=%d\n",
15944ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, total_len));
159537837c73Sdrahn 
159637837c73Sdrahn 	s = splnet();
159737837c73Sdrahn 
159837837c73Sdrahn 	sc->wi_rxframe = (void *)uin;
159937837c73Sdrahn 
160037837c73Sdrahn 	wi_rxeof(&sc->sc_wi);
160137837c73Sdrahn 
160237837c73Sdrahn 	sc->wi_rxframe = NULL;
160337837c73Sdrahn 
160437837c73Sdrahn 	splx(s);
160537837c73Sdrahn 
160637837c73Sdrahn }
160737837c73Sdrahn 
160837837c73Sdrahn 
160937837c73Sdrahn void
wi_usb_start_thread(void * arg)161037837c73Sdrahn wi_usb_start_thread(void *arg)
161137837c73Sdrahn {
161237837c73Sdrahn 	struct wi_usb_softc	*sc = arg;
16134ab2b9feSmbalmer 	kthread_create (wi_usb_thread, arg, NULL, sc->wi_usb_dev.dv_xname);
161437837c73Sdrahn }
161537837c73Sdrahn 
161637837c73Sdrahn void
wi_start_usb(struct ifnet * ifp)161737837c73Sdrahn wi_start_usb(struct ifnet *ifp)
161837837c73Sdrahn {
161937837c73Sdrahn 	struct wi_softc		*wsc;
162037837c73Sdrahn 	struct wi_usb_softc	*sc;
162137837c73Sdrahn 	int s;
162237837c73Sdrahn 
162337837c73Sdrahn 	wsc = ifp->if_softc;
162437837c73Sdrahn 	sc  = wsc->wi_usb_cdata;
162537837c73Sdrahn 
16261a63d5b5Sbrad 	s = splnet();
162737837c73Sdrahn 
162837837c73Sdrahn 	DPRINTFN(5,("%s: %s:\n",
16294ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__));
163037837c73Sdrahn 
163137837c73Sdrahn 	if (wi_usb_tx_lock_try(sc)) {
163237837c73Sdrahn 		/* lock acquired do start now */
163337837c73Sdrahn 		wi_func_io.f_start(ifp);
163437837c73Sdrahn 	} else {
163537837c73Sdrahn 		sc->wi_thread_info->status |= WI_START;
163637837c73Sdrahn 		if (sc->wi_thread_info->idle)
163737837c73Sdrahn 			wakeup(sc->wi_thread_info);
163837837c73Sdrahn 	}
163937837c73Sdrahn 
164037837c73Sdrahn 	splx(s);
164137837c73Sdrahn }
164237837c73Sdrahn 
164337837c73Sdrahn /*
164437837c73Sdrahn  * inquire is called from interrupt context (timeout)
164537837c73Sdrahn  * It is not possible to sleep in interrupt context so it is necessary
164637837c73Sdrahn  * to signal the kernel thread to perform the action.
164737837c73Sdrahn  */
164837837c73Sdrahn void
wi_init_usb(struct wi_softc * wsc)164937837c73Sdrahn wi_init_usb(struct wi_softc *wsc)
165037837c73Sdrahn {
165137837c73Sdrahn 	DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
165237837c73Sdrahn 
165337837c73Sdrahn 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
165437837c73Sdrahn 	wi_func_io.f_init(wsc);
165537837c73Sdrahn 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
165637837c73Sdrahn }
165737837c73Sdrahn 
165837837c73Sdrahn 
165937837c73Sdrahn /*
166037837c73Sdrahn  * inquire is called from interrupt context (timeout)
166137837c73Sdrahn  * It is not possible to sleep in interrupt context so it is necessary
166237837c73Sdrahn  * to signal the kernel thread to perform the action.
166337837c73Sdrahn  */
166437837c73Sdrahn void
wi_inquire_usb(void * xsc)166537837c73Sdrahn wi_inquire_usb(void *xsc)
166637837c73Sdrahn {
166737837c73Sdrahn 	struct wi_softc		*wsc = xsc;
166837837c73Sdrahn 	struct wi_usb_softc	*sc = wsc->wi_usb_cdata;
166937837c73Sdrahn 	int s;
167037837c73Sdrahn 
167137837c73Sdrahn 
16721a63d5b5Sbrad 	s = splnet();
167337837c73Sdrahn 
167437837c73Sdrahn 	DPRINTFN(2,("%s: %s:\n",
16754ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__));
167637837c73Sdrahn 
167737837c73Sdrahn 	sc->wi_thread_info->status |= WI_INQUIRE;
167837837c73Sdrahn 
167937837c73Sdrahn 	if (sc->wi_thread_info->idle)
168037837c73Sdrahn 		wakeup(sc->wi_thread_info);
168137837c73Sdrahn 	splx(s);
168237837c73Sdrahn }
168337837c73Sdrahn 
168437837c73Sdrahn /*
168537837c73Sdrahn  * Watchdog is normally called from interrupt context (timeout)
168637837c73Sdrahn  * It is not possible to sleep in interrupt context so it is necessary
168737837c73Sdrahn  * to signal the kernel thread to perform the action.
168837837c73Sdrahn  */
168937837c73Sdrahn void
wi_watchdog_usb(struct ifnet * ifp)169037837c73Sdrahn wi_watchdog_usb(struct ifnet *ifp)
169137837c73Sdrahn {
169237837c73Sdrahn 	struct wi_softc		*wsc;
169337837c73Sdrahn 	struct wi_usb_softc	*sc;
169437837c73Sdrahn 	int s;
169537837c73Sdrahn 
169637837c73Sdrahn 	wsc = ifp->if_softc;
169737837c73Sdrahn 	sc = wsc->wi_usb_cdata;
169837837c73Sdrahn 
16991a63d5b5Sbrad 	s = splnet();
170037837c73Sdrahn 
170137837c73Sdrahn 	DPRINTFN(5,("%s: %s: ifp %x\n",
17024ab2b9feSmbalmer 	    sc->wi_usb_dev.dv_xname, __func__, ifp));
170337837c73Sdrahn 
170437837c73Sdrahn 	sc->wi_thread_info->status |= WI_WATCHDOG;
170537837c73Sdrahn 
170637837c73Sdrahn 	if (sc->wi_thread_info->idle)
170737837c73Sdrahn 		wakeup(sc->wi_thread_info);
170837837c73Sdrahn 	splx(s);
170937837c73Sdrahn }
171037837c73Sdrahn 
171137837c73Sdrahn /*
171237837c73Sdrahn  * ioctl will always be called from a user context,
1713dcd88536Stom  * therefore it is possible to sleep in the calling context
17148fc45048Smiod  * acquire the lock and call the real ioctl function directly
171537837c73Sdrahn  */
171637837c73Sdrahn int
wi_ioctl_usb(struct ifnet * ifp,u_long command,caddr_t data)171737837c73Sdrahn wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
171837837c73Sdrahn {
171937837c73Sdrahn 	struct wi_softc		*wsc;
172037837c73Sdrahn 	int err;
172137837c73Sdrahn 
172237837c73Sdrahn 	wsc = ifp->if_softc;
172337837c73Sdrahn 
172437837c73Sdrahn 	wi_usb_ctl_lock(wsc->wi_usb_cdata);
172537837c73Sdrahn 	err = wi_func_io.f_ioctl(ifp, command, data);
172637837c73Sdrahn 	wi_usb_ctl_unlock(wsc->wi_usb_cdata);
172737837c73Sdrahn 	return err;
172837837c73Sdrahn }
172937837c73Sdrahn 
173037837c73Sdrahn void
wi_usb_thread(void * arg)173137837c73Sdrahn wi_usb_thread(void *arg)
173237837c73Sdrahn {
173337837c73Sdrahn 	struct wi_usb_softc *sc = arg;
173437837c73Sdrahn 	struct wi_usb_thread_info *wi_thread_info;
173537837c73Sdrahn 	int s;
173637837c73Sdrahn 
17378985a220Smglocker 	wi_thread_info = malloc(sizeof(*wi_thread_info), M_USBDEV, M_WAITOK);
173837837c73Sdrahn 
173937837c73Sdrahn 	/*
174037837c73Sdrahn 	 * is there a remote possibility that the device could
174137837c73Sdrahn 	 * be removed before the kernel thread starts up?
174237837c73Sdrahn 	 */
174337837c73Sdrahn 
174437837c73Sdrahn 	sc->wi_usb_refcnt++;
174537837c73Sdrahn 
174637837c73Sdrahn 	sc->wi_thread_info = wi_thread_info;
174737837c73Sdrahn 	wi_thread_info->dying = 0;
174837837c73Sdrahn 	wi_thread_info->status = 0;
174937837c73Sdrahn 
175037837c73Sdrahn 	wi_usb_ctl_lock(sc);
175137837c73Sdrahn 
175237837c73Sdrahn 	wi_attach(&sc->sc_wi, &wi_func_usb);
175337837c73Sdrahn 
175437837c73Sdrahn 	wi_usb_ctl_unlock(sc);
175537837c73Sdrahn 
175637837c73Sdrahn 	for(;;) {
175737837c73Sdrahn 		if (wi_thread_info->dying) {
175837837c73Sdrahn 			if (--sc->wi_usb_refcnt < 0)
17591596fc1eSmbalmer 				usb_detach_wakeup(&sc->wi_usb_dev);
176037837c73Sdrahn 			kthread_exit(0);
176137837c73Sdrahn 		}
176237837c73Sdrahn 
176337837c73Sdrahn 		DPRINTFN(5,("%s: %s: dying %x status %x\n",
17644ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__,
176537837c73Sdrahn 			wi_thread_info->dying, wi_thread_info->status));
176637837c73Sdrahn 
176737837c73Sdrahn 		wi_usb_ctl_lock(sc);
176837837c73Sdrahn 
176937837c73Sdrahn 		DPRINTFN(5,("%s: %s: starting %x\n",
17704ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__,
177137837c73Sdrahn 		    wi_thread_info->status));
177237837c73Sdrahn 
177337837c73Sdrahn 		s = splusb();
177437837c73Sdrahn 		if (wi_thread_info->status & WI_START) {
177537837c73Sdrahn 			wi_thread_info->status &= ~WI_START;
177637837c73Sdrahn 			wi_usb_tx_lock(sc);
177755f29f42Sjsg 			wi_func_io.f_start(&sc->sc_wi.sc_ic.ic_if);
177837837c73Sdrahn 			/*
177963bebe7fSjmc 			 * tx_unlock is explicitly missing here
1780dcd88536Stom 			 * it is done in txeof_frm
178137837c73Sdrahn 			 */
178237837c73Sdrahn 		} else if (wi_thread_info->status & WI_INQUIRE) {
178337837c73Sdrahn 			wi_thread_info->status &= ~WI_INQUIRE;
178437837c73Sdrahn 			wi_func_io.f_inquire(&sc->sc_wi);
178537837c73Sdrahn 		} else if (wi_thread_info->status & WI_WATCHDOG) {
178637837c73Sdrahn 			wi_thread_info->status &= ~WI_WATCHDOG;
178755f29f42Sjsg 			wi_func_io.f_watchdog( &sc->sc_wi.sc_ic.ic_if);
178837837c73Sdrahn 		}
178937837c73Sdrahn 		splx(s);
179037837c73Sdrahn 
179137837c73Sdrahn 		DPRINTFN(5,("%s: %s: ending %x\n",
17924ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__,
179337837c73Sdrahn 		    wi_thread_info->status));
179437837c73Sdrahn 		wi_usb_ctl_unlock(sc);
179537837c73Sdrahn 
179637837c73Sdrahn 		if (wi_thread_info->status == 0) {
17971a63d5b5Sbrad 			s = splnet();
179837837c73Sdrahn 			wi_thread_info->idle = 1;
1799a2ef69b7Smpi 			tsleep_nsec(wi_thread_info, PRIBIO, "wiIDL", INFSLP);
180037837c73Sdrahn 			wi_thread_info->idle = 0;
180137837c73Sdrahn 			splx(s);
180237837c73Sdrahn 		}
180337837c73Sdrahn 	}
180437837c73Sdrahn }
180537837c73Sdrahn 
180637837c73Sdrahn int
wi_usb_tx_lock_try(struct wi_usb_softc * sc)180737837c73Sdrahn wi_usb_tx_lock_try(struct wi_usb_softc *sc)
180837837c73Sdrahn {
180937837c73Sdrahn 	int s;
181037837c73Sdrahn 
18111a63d5b5Sbrad 	s = splnet();
181237837c73Sdrahn 
18134ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
181437837c73Sdrahn 
181537837c73Sdrahn 	if (sc->wi_lock != 0) {
1816ecd5c595Skrw 		splx(s);
18174b1a56afSjsg 		return 0; /* failed to acquire lock */
181837837c73Sdrahn 	}
181937837c73Sdrahn 
182037837c73Sdrahn 	sc->wi_lock = 1;
182137837c73Sdrahn 
182237837c73Sdrahn 	splx(s);
182337837c73Sdrahn 
182437837c73Sdrahn 	return 1;
182537837c73Sdrahn }
182637837c73Sdrahn void
wi_usb_tx_lock(struct wi_usb_softc * sc)182737837c73Sdrahn wi_usb_tx_lock(struct wi_usb_softc *sc)
182837837c73Sdrahn {
182937837c73Sdrahn 	int s;
183037837c73Sdrahn 
18311a63d5b5Sbrad 	s = splnet();
183237837c73Sdrahn 
183337837c73Sdrahn 	again:
18344ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
183537837c73Sdrahn 
183637837c73Sdrahn 	if (sc->wi_lock != 0) {
183737837c73Sdrahn 		sc->wi_lockwait++;
18384ab2b9feSmbalmer 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
183937837c73Sdrahn 		__func__, sc->wi_lockwait ));
1840a2ef69b7Smpi 		tsleep_nsec(&sc->wi_lock, PRIBIO, "witxl", INFSLP);
184137837c73Sdrahn 	}
184237837c73Sdrahn 
184337837c73Sdrahn 	if (sc->wi_lock != 0)
184437837c73Sdrahn 		goto again;
184537837c73Sdrahn 	sc->wi_lock = 1;
184637837c73Sdrahn 
184737837c73Sdrahn 	splx(s);
184837837c73Sdrahn 
184937837c73Sdrahn 	return;
185037837c73Sdrahn 
185137837c73Sdrahn }
185237837c73Sdrahn 
185337837c73Sdrahn void
wi_usb_tx_unlock(struct wi_usb_softc * sc)185437837c73Sdrahn wi_usb_tx_unlock(struct wi_usb_softc *sc)
185537837c73Sdrahn {
185637837c73Sdrahn 	int s;
18571a63d5b5Sbrad 	s = splnet();
185837837c73Sdrahn 
185937837c73Sdrahn 	sc->wi_lock = 0;
186037837c73Sdrahn 
18614ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
186237837c73Sdrahn 
186337837c73Sdrahn 	if (sc->wi_lockwait) {
186437837c73Sdrahn 		DPRINTFN(10,("%s: %s: waking\n",
18654ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__));
186637837c73Sdrahn 		sc->wi_lockwait = 0;
186737837c73Sdrahn 		wakeup(&sc->wi_lock);
186837837c73Sdrahn 	}
186937837c73Sdrahn 
187037837c73Sdrahn 	splx(s);
187137837c73Sdrahn }
187237837c73Sdrahn 
187337837c73Sdrahn void
wi_usb_ctl_lock(struct wi_usb_softc * sc)187437837c73Sdrahn wi_usb_ctl_lock(struct wi_usb_softc *sc)
187537837c73Sdrahn {
187637837c73Sdrahn 	int s;
187737837c73Sdrahn 
18781a63d5b5Sbrad 	s = splnet();
187937837c73Sdrahn 
188037837c73Sdrahn 	again:
18814ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname,
188237837c73Sdrahn 	    __func__));
188337837c73Sdrahn 
188437837c73Sdrahn 	if (sc->wi_ctllock != 0) {
188537837c73Sdrahn 		if (curproc == sc->wi_curproc) {
188637837c73Sdrahn 			/* allow recursion */
188737837c73Sdrahn 			sc->wi_ctllock++;
188837837c73Sdrahn 			splx(s);
188937837c73Sdrahn 			return;
189037837c73Sdrahn 		}
189137837c73Sdrahn 		sc->wi_ctllockwait++;
18924ab2b9feSmbalmer 		DPRINTFN(10,("%s: %s: busy %d\n", sc->wi_usb_dev.dv_xname,
189337837c73Sdrahn 		__func__, sc->wi_ctllockwait ));
1894a2ef69b7Smpi 		tsleep_nsec(&sc->wi_ctllock, PRIBIO, "wiusbthr", INFSLP);
189537837c73Sdrahn 	}
189637837c73Sdrahn 
189737837c73Sdrahn 	if (sc->wi_ctllock != 0)
189837837c73Sdrahn 		goto again;
189937837c73Sdrahn 	sc->wi_ctllock++;
190037837c73Sdrahn 	sc->wi_curproc = curproc;
190137837c73Sdrahn 
190237837c73Sdrahn 	splx(s);
190337837c73Sdrahn 
190437837c73Sdrahn 	return;
190537837c73Sdrahn 
190637837c73Sdrahn }
190737837c73Sdrahn 
190837837c73Sdrahn void
wi_usb_ctl_unlock(struct wi_usb_softc * sc)190937837c73Sdrahn wi_usb_ctl_unlock(struct wi_usb_softc *sc)
191037837c73Sdrahn {
191137837c73Sdrahn 	int s;
191237837c73Sdrahn 
19131a63d5b5Sbrad 	s = splnet();
191437837c73Sdrahn 
191537837c73Sdrahn 	sc->wi_ctllock--;
191637837c73Sdrahn 
19174ab2b9feSmbalmer 	DPRINTFN(10,("%s: %s: enter\n", sc->wi_usb_dev.dv_xname, __func__));
191837837c73Sdrahn 
191937837c73Sdrahn 	if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
192037837c73Sdrahn 		DPRINTFN(10,("%s: %s: waking\n",
19214ab2b9feSmbalmer 		    sc->wi_usb_dev.dv_xname, __func__));
192237837c73Sdrahn 		sc->wi_ctllockwait = 0;
192337837c73Sdrahn 		sc->wi_curproc = 0;
192437837c73Sdrahn 		wakeup(&sc->wi_ctllock);
192537837c73Sdrahn 	}
192637837c73Sdrahn 
192737837c73Sdrahn 	splx(s);
192837837c73Sdrahn }
1929