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(<v->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], <v->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