summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2003-10-26 15:34:17 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2003-10-26 15:34:17 +0000
commit43782ab58acc9f9d055d1fc33d7069fe85857d90 (patch)
tree75ff040ecf49a4340cd89b95a47ff537576652da /sys/dev/usb
parentb62dde670d7c7927ce0448b2c885cb9fdd70e437 (diff)
Driver for PRISM 2.5/3 based (wifi) USB adapters. This is a work in progress,
it does not yet handle bulk data copies or hostap mode. Only one model currently supported, however driver may support other PRISM based adapters. ok millert@ fgsch@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/files.usb6
-rw-r--r--sys/dev/usb/if_wi_usb.c1941
-rw-r--r--sys/dev/usb/if_wi_usb.h161
3 files changed, 2107 insertions, 1 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index c3bbcfa5697..7ac467f9fe3 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,4 +1,4 @@
-# $OpenBSD: files.usb,v 1.32 2003/05/17 06:07:57 nate Exp $
+# $OpenBSD: files.usb,v 1.33 2003/10/26 15:34:16 drahn Exp $
# $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $
#
# Config file and device description for machine-independent USB code.
@@ -187,3 +187,7 @@ file dev/usb/uscanner.c uscanner needs-flag
device usscanner: scsi
attach usscanner at uhub
file dev/usb/usscanner.c usscanner
+
+# Prism3 WI @ USB
+attach wi at uhub with wi_usb
+file dev/usb/if_wi_usb.c wi_usb needs-flag
diff --git a/sys/dev/usb/if_wi_usb.c b/sys/dev/usb/if_wi_usb.c
new file mode 100644
index 00000000000..1d48681a158
--- /dev/null
+++ b/sys/dev/usb/if_wi_usb.c
@@ -0,0 +1,1941 @@
+/* $OpenBSD: if_wi_usb.c,v 1.1 2003/10/26 15:34:16 drahn Exp $ */
+
+/*
+ * Copyright (c) 2003 Dale Rahn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ */
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+#include <sys/kthread.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+
+#define ROUNDUP64(x) (((x)+63) & ~63)
+
+#include <net/if_ieee80211.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <machine/bus.h>
+
+#include <dev/rndvar.h>
+
+#include <dev/ic/if_wireg.h>
+#include <dev/ic/if_wi_ieee.h>
+#include <dev/ic/if_wivar.h>
+
+#include <wi_usb.h>
+#include <dev/usb/if_wi_usb.h>
+
+int wi_usb_do_transmit_sync(struct wi_usb_softc *wsc, struct wi_usb_chain *c,
+ void *ident);
+void wi_usb_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status);
+void wi_usb_txeof_frm(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status);
+void wi_usb_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status);
+void wi_usb_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status);
+void wi_usb_stop(struct wi_usb_softc *usc);
+int wi_usb_tx_list_init(struct wi_usb_softc *usc);
+int wi_usb_rx_list_init(struct wi_usb_softc *usc);
+int wi_usb_open_pipes(struct wi_usb_softc *usc);
+void wi_usb_cmdresp(struct wi_usb_chain *c);
+void wi_usb_rridresp(struct wi_usb_chain *c);
+void wi_usb_wridresp(struct wi_usb_chain *c);
+void wi_usb_infofrm(struct wi_usb_chain *c, int len);
+int wi_send_packet(struct wi_usb_softc *sc, int id);
+void wi_usb_rxfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
+void wi_usb_txfrm(struct wi_usb_softc *usc, wi_usb_usbin *uin, int total_len);
+void wi_usb_start_thread(void *);
+
+int wi_usb_tx_lock_try(struct wi_usb_softc *sc);
+void wi_usb_tx_lock(struct wi_usb_softc *usc);
+void wi_usb_tx_unlock(struct wi_usb_softc *usc);
+void wi_usb_ctl_lock(struct wi_usb_softc *usc);
+void wi_usb_ctl_unlock(struct wi_usb_softc *usc);
+
+void wi_dump_data(void *buffer, int len);
+
+void wi_usb_thread(void *arg);
+
+#define WI_USB_DEBUG
+#ifdef WI_USB_DEBUG
+#define DPRINTF(x) if (wi_usbdebug) logprintf x
+#define DPRINTFN(n,x) if (wi_usbdebug >= (n)) logprintf x
+int wi_usbdebug = 1;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+struct wi_usb_thread_info {
+ int status;
+ int dying;
+ int idle;
+};
+
+/* thread status flags */
+#define WI_START 0x01
+#define WI_DYING 0x02
+#define WI_INQUIRE 0x04
+#define WI_WATCHDOG 0x08
+
+
+struct wi_usb_softc {
+ struct wi_softc sc_wi;
+#define wi_usb_dev sc_wi.sc_dev
+
+ usb_callout_t wi_usb_stat_ch;
+
+ usbd_device_handle wi_usb_udev;
+ usbd_interface_handle wi_usb_iface;
+ u_int16_t wi_usb_vendor;
+ u_int16_t wi_usb_product;
+ int wi_usb_ed[WI_USB_ENDPT_MAX];
+ usbd_pipe_handle wi_usb_ep[WI_USB_ENDPT_MAX];
+
+ struct wi_usb_chain wi_usb_tx_chain[WI_USB_TX_LIST_CNT];
+ struct wi_usb_chain wi_usb_rx_chain[WI_USB_RX_LIST_CNT];
+
+ int wi_usb_refcnt;
+ char wi_usb_dying;
+ char wi_usb_attached;
+ int wi_usb_intr_errs;
+ struct timeval wi_usb_rx_notice;
+
+ int wi_usb_pollpending;
+
+ wi_usb_usbin wi_usb_ibuf;
+ int wi_usb_tx_prod;
+ int wi_usb_tx_cons;
+ int wi_usb_tx_cnt;
+ int wi_usb_rx_prod;
+
+ struct wi_ltv_gen *ridltv;
+ int ridresperr;
+
+ int cmdresp;
+ int cmdresperr;
+ int txresp;
+ int txresperr;
+
+ /* nummem (tx/mgmt) */
+ int wi_usb_nummem;
+#define MAX_WI_NMEM 3
+ void *wi_usb_txmem[MAX_WI_NMEM];
+ int wi_usb_txmemsize[MAX_WI_NMEM];
+ void *wi_usb_rxmem;
+ int wi_usb_rxmemsize;
+
+ void *wi_info;
+ void *wi_rxframe;
+
+ /* prevent multpile outstanding USB requests */
+ int wi_lock;
+ int wi_lockwait;
+
+ /* prevent multiple command requests */
+ int wi_ctllock;
+ int wi_ctllockwait;
+ struct proc *wi_curproc;
+
+ /* kthread */
+ struct wi_usb_thread_info *wi_thread_info;
+ int wi_resetonce;
+};
+
+struct wi_funcs wi_func_usb = {
+ wi_cmd_usb,
+ wi_read_record_usb,
+ wi_write_record_usb,
+ wi_alloc_nicmem_usb,
+ wi_read_data_usb,
+ wi_write_data_usb,
+ wi_get_fid_usb,
+ wi_init_usb,
+
+ wi_start_usb,
+ wi_ioctl_usb,
+ wi_watchdog_usb,
+ wi_inquire_usb,
+};
+
+/*
+ * Various supported device vendors/products.
+ */
+const struct wi_usb_type {
+ struct usb_devno wi_usb_device;
+ u_int16_t wi_usb_flags;
+ /* XXX */
+} wi_usb_devs[] = {
+ {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_MA111NA }, 0 }
+};
+#define wi_usb_lookup(v, p) ((struct wi_usb_type *)usb_lookup(wi_usb_devs, v, p))
+
+USB_DECLARE_DRIVER(wi_usb);
+
+USB_MATCH(wi_usb)
+{
+ USB_MATCH_START(wi_usb, uaa);
+
+ if (uaa->iface != NULL)
+ return (UMATCH_NONE);
+
+ return (wi_usb_lookup(uaa->vendor, uaa->product) != NULL ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+}
+
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+USB_ATTACH(wi_usb)
+{
+ USB_ATTACH_START(wi_usb, sc, uaa);
+ char devinfo[1024];
+/* int s; */
+ usbd_device_handle dev = uaa->device;
+ usbd_interface_handle iface;
+ usbd_status err;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ int i;
+
+ DPRINTFN(5,(" : wi_usb_attach: sc=%p", sc));
+
+ err = usbd_set_config_no(dev, WI_USB_CONFIG_NO, 1);
+ if (err) {
+ printf("%s: setting config no failed\n",
+ USBDEVNAME(sc->wi_usb_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ usbd_devinfo(dev, 0, devinfo, sizeof devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s\n", USBDEVNAME(sc->wi_usb_dev), devinfo);
+
+ /* XXX - any tasks? */
+
+ err = usbd_device2interface_handle(dev, WI_USB_IFACE_IDX, &iface);
+ if (err) {
+ printf("%s: getting interface handle failed\n",
+ USBDEVNAME(sc->wi_usb_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ /* XXX - flags? */
+
+ sc->wi_usb_udev = dev;
+ sc->wi_usb_iface = iface;
+ sc->wi_usb_product = uaa->product;
+ sc->wi_usb_vendor = uaa->vendor;
+
+ sc->sc_wi.wi_usb_cdata = sc;
+ sc->sc_wi.wi_flags |= WI_FLAGS_BUS_USB;
+
+ sc->wi_lock = 0;
+ sc->wi_lockwait = 0;
+ sc->wi_resetonce = 0;
+
+ id = usbd_get_interface_descriptor(iface);
+
+ /* Find endpoints. */
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(iface, i);
+ if (ed == NULL) {
+ printf("%s: couldn't get endpoint descriptor %d\n",
+ USBDEVNAME(sc->wi_usb_dev), i);
+ USB_ATTACH_ERROR_RETURN;
+ }
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+ sc->wi_usb_ed[WI_USB_ENDPT_RX] = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+ sc->wi_usb_ed[WI_USB_ENDPT_TX] = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
+ sc->wi_usb_ed[WI_USB_ENDPT_INTR] = ed->bEndpointAddress;
+ }
+ }
+
+ sc->wi_usb_nummem = 0;
+
+ /* attach wi device */
+
+ if (wi_usb_rx_list_init(sc)) {
+ printf("%s: rx list init failed\n",
+ USBDEVNAME(sc->wi_usb_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+ if (wi_usb_tx_list_init(sc)) {
+ printf("%s: tx list init failed\n",
+ USBDEVNAME(sc->wi_usb_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (wi_usb_open_pipes(sc)){
+ printf("%s: open pipes failed\n",
+ USBDEVNAME(sc->wi_usb_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ sc->wi_usb_attached = 1;
+
+ if (cold)
+ kthread_create_deferred(wi_usb_start_thread, sc);
+ else
+ wi_usb_start_thread(sc);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->wi_usb_udev,
+ USBDEV(sc->wi_usb_dev));
+
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+USB_DETACH(wi_usb)
+{
+ USB_DETACH_START(wi_usb, sc);
+ struct ifnet *ifp = WI_GET_IFP(sc);
+ struct wi_softc *wsc = &sc->sc_wi;
+ int s;
+
+ sc->wi_usb_dying = 1;
+ if (sc->wi_thread_info != NULL) {
+ sc->wi_thread_info->dying = 1;
+
+ sc->wi_thread_info->status |= WI_DYING;
+ if (sc->wi_thread_info->idle)
+ wakeup (sc->wi_thread_info);
+ }
+
+ if (!sc->wi_usb_attached) {
+ /* Detached before attach finished, so just bail out. */
+ return (0);
+ }
+ /* tasks? */
+
+ s = splusb();
+ /* detatch wi */
+
+ if (!(wsc->wi_flags & WI_FLAGS_ATTACHED)) {
+ printf("%s: already detached\n", USBDEVNAME(sc->wi_usb_dev));
+ splx(s);
+ return (0);
+ }
+
+ wi_detach(&sc->sc_wi);
+
+ wsc->wi_flags = 0;
+
+ ether_ifdetach(ifp);
+ if_detach(ifp);
+
+ sc->wi_usb_attached = 0;
+
+ if (--sc->wi_usb_refcnt >= 0) {
+ /* Wait for processes to go away. */
+ usb_detach_wait(USBDEV(sc->wi_usb_dev));
+ }
+
+ while (sc->wi_usb_nummem) {
+ sc->wi_usb_nummem--;
+ if (sc->wi_usb_txmem[sc->wi_usb_nummem] != NULL)
+ free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF);
+ sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
+ }
+
+ if (sc->wi_usb_ep[WI_USB_ENDPT_INTR] != NULL);
+ usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_INTR]);
+ if (sc->wi_usb_ep[WI_USB_ENDPT_TX] != NULL);
+ usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_TX]);
+ if (sc->wi_usb_ep[WI_USB_ENDPT_RX] != NULL);
+ usbd_abort_pipe(sc->wi_usb_ep[WI_USB_ENDPT_RX]);
+
+ splx(s);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->wi_usb_udev,
+ USBDEV(sc->wi_usb_dev));
+ return (0);
+}
+
+int
+wi_send_packet(struct wi_usb_softc *sc, int id)
+{
+ struct wi_usb_chain *c;
+ struct wi_frame *wibuf;
+ int total_len, rnd_len;
+ int err;
+
+ c = &sc->wi_usb_tx_chain[0];
+
+ DPRINTFN(10,("%s: %s: id=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, id));
+
+ /* assemble packet from write_data buffer */
+ if (id == 0 || id == 1) {
+ /* tx_lock acquired before wi_start() */
+ wibuf = sc->wi_usb_txmem[id];
+
+ total_len = sizeof (struct wi_frame) +
+ letoh16(wibuf->wi_dat_len);
+ rnd_len = ROUNDUP64(total_len);
+ if ((total_len > sc->wi_usb_txmemsize[id]) ||
+ (rnd_len > WI_USB_BUFSZ )){
+ printf("invalid packet len: %x memsz %x max %x\n",
+ total_len, sc->wi_usb_txmemsize[id], WI_USB_BUFSZ);
+ total_len = sc->wi_usb_txmemsize[id];
+
+ err = EIO;
+ goto err_ret;
+ }
+
+ sc->txresp = WI_CMD_TX;
+ sc->txresperr = 0;
+
+ bcopy(wibuf, c->wi_usb_buf, total_len);
+
+ bzero(((char *)c->wi_usb_buf)+total_len,
+ rnd_len - total_len);
+
+ total_len = rnd_len;
+
+ DPRINTFN(5,("%s: %s: id=%x len=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, id, total_len));
+
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
+ c, c->wi_usb_buf, rnd_len,
+ USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ WI_USB_TX_TIMEOUT, wi_usb_txeof_frm);
+
+ err = usbd_transfer(c->wi_usb_xfer);
+ if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
+ printf("%s: wi_usb_send error=%s\n",
+ USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err));
+ /* Stop the interface from process context. */
+ wi_usb_stop(sc);
+ err = EIO;
+ } else {
+ err = 0;
+ }
+
+ DPRINTFN(5,("%s: %s: exit err=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, err));
+err_ret:
+ return err;
+ }
+ printf("%s:%s: invalid packet id sent %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, id);
+ return 0;
+}
+
+int
+wi_cmd_usb(struct wi_softc *wsc, int cmd, int val0, int val1, int val2)
+{
+ struct wi_usb_chain *c;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+ struct wi_cmdreq *pcmd;
+ int total_len, rnd_len;
+ int err;
+
+ DPRINTFN(5,("%s: %s: enter cmd=%x %x %x %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, cmd, val0, val1, val2));
+
+ if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_TX) {
+ return wi_send_packet(sc, val0);
+ }
+
+
+ if ((cmd & WI_CMD_CODE_MASK) == WI_CMD_INI) {
+ /* free alloc_nicmem regions */
+ while (sc->wi_usb_nummem) {
+ sc->wi_usb_nummem--;
+ free(sc->wi_usb_txmem[sc->wi_usb_nummem], M_DEVBUF);
+ sc->wi_usb_txmem[sc->wi_usb_nummem] = NULL;
+ }
+
+#if 0
+ /* if this is the first time, init, otherwise do not?? */
+ if (sc->wi_resetonce) {
+ return 0;
+ } else
+ sc->wi_resetonce = 1;
+#endif
+ }
+
+ wi_usb_ctl_lock(sc);
+
+ wi_usb_tx_lock(sc);
+
+ c = &sc->wi_usb_tx_chain[0];
+ pcmd = c->wi_usb_buf;
+
+
+ total_len = sizeof (struct wi_cmdreq);
+ rnd_len = ROUNDUP64(total_len);
+ if (rnd_len > WI_USB_BUFSZ) {
+ printf("read_record buf size err %x %x\n",
+ rnd_len, WI_USB_BUFSZ);
+ err = EIO;
+ goto err_ret;
+ }
+
+ sc->cmdresp = cmd;
+ sc->cmdresperr = 0;
+
+ pcmd->type = htole16(WI_USB_CMDREQ);
+ pcmd->cmd = htole16(cmd);
+ pcmd->param0 = htole16(val0);
+ pcmd->param1 = htole16(val1);
+ pcmd->param2 = htole16(val2);
+
+ bzero(((char*)pcmd)+total_len, rnd_len - total_len);
+
+ total_len = rnd_len;
+
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
+ c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ WI_USB_TX_TIMEOUT, wi_usb_txeof);
+
+ err = wi_usb_do_transmit_sync(sc, c, &sc->cmdresperr);
+
+ if (err == 0)
+ err = sc->cmdresperr;
+
+ sc->cmdresperr = 0;
+
+err_ret:
+ wi_usb_tx_unlock(sc);
+
+ wi_usb_ctl_unlock(sc);
+
+ DPRINTFN(5,("%s: %s: exit err=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, err));
+ return err;
+}
+
+
+int
+wi_read_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
+{
+ struct wi_usb_chain *c;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+ struct wi_rridreq *prid;
+ int total_len, rnd_len;
+ int err;
+ struct wi_ltv_gen *oltv, p2ltv;
+
+ DPRINTFN(5,("%s: %s: enter rid=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, ltv->wi_type));
+
+ /* Do we need to deal with these here, as in _io version?
+ * WI_RID_ENCRYPTION -> WI_RID_P2_ENCRYPTION
+ * WI_RID_TX_CRYPT_KEY -> WI_RID_P2_TX_CRYPT_KEY
+ */
+ if (wsc->sc_firmware_type != WI_LUCENT) {
+ oltv = ltv;
+ switch (ltv->wi_type) {
+ case WI_RID_ENCRYPTION:
+ p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
+ p2ltv.wi_len = 2;
+ ltv = &p2ltv;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ if (ltv->wi_val > WI_NLTV_KEYS)
+ return (EINVAL);
+ p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
+ p2ltv.wi_len = 2;
+ ltv = &p2ltv;
+ break;
+ }
+ }
+
+ wi_usb_tx_lock(sc);
+
+ c = &sc->wi_usb_tx_chain[0];
+ prid = c->wi_usb_buf;
+
+ total_len = sizeof(struct wi_rridreq);
+ rnd_len = ROUNDUP64(total_len);
+
+ if (rnd_len > WI_USB_BUFSZ) {
+ printf("read_record buf size err %x %x\n",
+ rnd_len, WI_USB_BUFSZ);
+ return EIO;
+ }
+
+ sc->ridltv = ltv;
+ sc->ridresperr = 0;
+
+ prid->type = htole16(WI_USB_RRIDREQ);
+ prid->frmlen = htole16(2); /* variable size? */
+ prid->rid = htole16(ltv->wi_type);
+
+ bzero(((char*)prid)+total_len, rnd_len - total_len);
+
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
+ c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ WI_USB_TX_TIMEOUT, wi_usb_txeof);
+
+ DPRINTFN(10,("%s: %s: total_len=%x, wilen %d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, total_len, ltv->wi_len));
+
+ err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
+
+ /* Do we need to deal with these here, as in _io version?
+ *
+ * WI_RID_TX_RATE
+ * WI_RID_CUR_TX_RATE
+ * WI_RID_ENCRYPTION
+ * WI_RID_TX_CRYPT_KEY
+ * WI_RID_CNFAUTHMODE
+ */
+ if (ltv->wi_type == WI_RID_PORTTYPE && wsc->wi_ptype == WI_PORTTYPE_IBSS
+ && ltv->wi_val == wsc->wi_ibss_port) {
+ /*
+ * Convert vendor IBSS port type to WI_PORTTYPE_IBSS.
+ * Since Lucent uses port type 1 for BSS *and* IBSS we
+ * have to rely on wi_ptype to distinguish this for us.
+ */
+ ltv->wi_val = htole16(WI_PORTTYPE_IBSS);
+ } else if (wsc->sc_firmware_type != WI_LUCENT) {
+ int v;
+
+ switch (oltv->wi_type) {
+ case WI_RID_TX_RATE:
+ case WI_RID_CUR_TX_RATE:
+ switch (letoh16(ltv->wi_val)) {
+ case 1: v = 1; break;
+ case 2: v = 2; break;
+ case 3: v = 6; break;
+ case 4: v = 5; break;
+ case 7: v = 7; break;
+ case 8: v = 11; break;
+ case 15: v = 3; break;
+ default: v = 0x100 + letoh16(ltv->wi_val); break;
+ }
+ oltv->wi_val = htole16(v);
+ break;
+ case WI_RID_ENCRYPTION:
+ oltv->wi_len = 2;
+ if (ltv->wi_val & htole16(0x01))
+ oltv->wi_val = htole16(1);
+ else
+ oltv->wi_val = htole16(0);
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ case WI_RID_CNFAUTHMODE:
+ oltv->wi_len = 2;
+ oltv->wi_val = ltv->wi_val;
+ break;
+ }
+ }
+
+ if (err == 0)
+ err = sc->ridresperr;
+
+ sc->ridresperr = 0;
+
+ wi_usb_tx_unlock(sc);
+
+ DPRINTFN(5,("%s: %s: exit err=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, err));
+ return err;
+}
+
+int
+wi_write_record_usb(struct wi_softc *wsc, struct wi_ltv_gen *ltv)
+{
+ struct wi_usb_chain *c;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+ struct wi_wridreq *prid;
+ int total_len, rnd_len;
+ int err;
+ struct wi_ltv_gen p2ltv;
+ u_int16_t val = 0;
+ int i;
+
+ DPRINTFN(5,("%s: %s: enter rid=%x wi_len %d copying %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, ltv->wi_type, ltv->wi_len,
+ (ltv->wi_len-1)*2 ));
+
+ /* Do we need to deal with these here, as in _io version?
+ * WI_PORTTYPE_IBSS -> WI_RID_PORTTYPE
+ * RID_TX_RATE munging
+ * RID_ENCRYPTION
+ * WI_RID_TX_CRYPT_KEY
+ * WI_RID_DEFLT_CRYPT_KEYS
+ */
+ if (ltv->wi_type == WI_RID_PORTTYPE &&
+ letoh16(ltv->wi_val) == WI_PORTTYPE_IBSS) {
+ /* Convert WI_PORTTYPE_IBSS to vendor IBSS port type. */
+ p2ltv.wi_type = WI_RID_PORTTYPE;
+ p2ltv.wi_len = 2;
+ p2ltv.wi_val = wsc->wi_ibss_port;
+ ltv = &p2ltv;
+ } else if (wsc->sc_firmware_type != WI_LUCENT) {
+ int v;
+
+ switch (ltv->wi_type) {
+ case WI_RID_TX_RATE:
+ p2ltv.wi_type = WI_RID_TX_RATE;
+ p2ltv.wi_len = 2;
+ switch (letoh16(ltv->wi_val)) {
+ case 1: v = 1; break;
+ case 2: v = 2; break;
+ case 3: v = 15; break;
+ case 5: v = 4; break;
+ case 6: v = 3; break;
+ case 7: v = 7; break;
+ case 11: v = 8; break;
+ default: return EINVAL;
+ }
+ p2ltv.wi_val = htole16(v);
+ ltv = &p2ltv;
+ break;
+ case WI_RID_ENCRYPTION:
+ p2ltv.wi_type = WI_RID_P2_ENCRYPTION;
+ p2ltv.wi_len = 2;
+ if (ltv->wi_val & htole16(0x01)) {
+ val = PRIVACY_INVOKED;
+ /*
+ * If using shared key WEP we must set the
+ * EXCLUDE_UNENCRYPTED bit. Symbol cards
+ * need this bit set even when not using
+ * shared key. We can't just test for
+ * IEEE80211_AUTH_SHARED since Symbol cards
+ * have 2 shared key modes.
+ */
+ if (wsc->wi_authtype != IEEE80211_AUTH_OPEN ||
+ wsc->sc_firmware_type == WI_SYMBOL)
+ val |= EXCLUDE_UNENCRYPTED;
+
+ switch (wsc->wi_crypto_algorithm) {
+ case WI_CRYPTO_FIRMWARE_WEP:
+ /*
+ * TX encryption is broken in
+ * Host AP mode.
+ */
+ if (wsc->wi_ptype == WI_PORTTYPE_HOSTAP)
+ val |= HOST_ENCRYPT;
+ break;
+ case WI_CRYPTO_SOFTWARE_WEP:
+ val |= HOST_ENCRYPT|HOST_DECRYPT;
+ break;
+ }
+ p2ltv.wi_val = htole16(val);
+ } else
+ p2ltv.wi_val = htole16(HOST_ENCRYPT | HOST_DECRYPT);
+ ltv = &p2ltv;
+ break;
+ case WI_RID_TX_CRYPT_KEY:
+ if (ltv->wi_val > WI_NLTV_KEYS)
+ return (EINVAL);
+ p2ltv.wi_type = WI_RID_P2_TX_CRYPT_KEY;
+ p2ltv.wi_len = 2;
+ p2ltv.wi_val = ltv->wi_val;
+ ltv = &p2ltv;
+ break;
+ case WI_RID_DEFLT_CRYPT_KEYS: {
+ int error;
+ int keylen;
+ struct wi_ltv_str ws;
+ struct wi_ltv_keys *wk = (struct wi_ltv_keys *)ltv;
+ keylen = wk->wi_keys[wsc->wi_tx_key].wi_keylen;
+
+ for (i = 0; i < 4; i++) {
+ bzero(&ws, sizeof(ws));
+ ws.wi_len = (keylen > 5) ? 8 : 4;
+ ws.wi_type = WI_RID_P2_CRYPT_KEY0 + i;
+ bcopy(&wk->wi_keys[i].wi_keydat,
+ ws.wi_str, keylen);
+ error = wi_write_record_usb(wsc,
+ (struct wi_ltv_gen *)&ws);
+ if (error)
+ return (error);
+ }
+ }
+ return (0);
+ }
+ }
+
+ wi_usb_tx_lock(sc);
+
+ c = &sc->wi_usb_tx_chain[0];
+
+ prid = c->wi_usb_buf;
+
+ total_len = sizeof(prid->type) + sizeof(prid->frmlen) +
+ sizeof(prid->rid) + (ltv->wi_len-1)*2;
+ rnd_len = ROUNDUP64(total_len);
+ if (rnd_len > WI_USB_BUFSZ) {
+ printf("write_record buf size err %x %x\n",
+ rnd_len, WI_USB_BUFSZ);
+ return EIO;
+ }
+
+ prid->type = htole16(WI_USB_WRIDREQ);
+ prid->frmlen = htole16(ltv->wi_len);
+ prid->rid = htole16(ltv->wi_type);
+ if (ltv->wi_len > 1)
+ bcopy((u_int8_t *)&ltv->wi_val, (u_int8_t *)&prid->data[0],
+ (ltv->wi_len-1)*2);
+
+ bzero(((char*)prid)+total_len, rnd_len - total_len);
+
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_TX],
+ c, c->wi_usb_buf, rnd_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ WI_USB_TX_TIMEOUT, wi_usb_txeof);
+
+ err = wi_usb_do_transmit_sync(sc, c, &sc->ridresperr);
+
+ if (err == 0)
+ err = sc->ridresperr;
+
+ sc->ridresperr = 0;
+
+ wi_usb_tx_unlock(sc);
+
+ DPRINTFN(5,("%s: %s: exit err=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, err));
+ return err;
+}
+
+/*
+ * This is an ugly compat portion to emulate the I/O which writes
+ * a packet or management information
+ * The data is copied into local memory for the requested
+ * 'id' then on the wi_cmd WI_CMD_TX, the id argument
+ * will identify which buffer to use
+ */
+int
+wi_alloc_nicmem_usb(struct wi_softc *wsc, int len, int *id)
+{
+ int nmem;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+
+ DPRINTFN(10,("%s: %s: enter len=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, len));
+
+ /*
+ * NOTE THIS IS A USB DEVICE WHICH WILL LIKELY HAVE MANY
+ * CONNECTS/DISCONNECTS, FREE THIS MEMORY XXX XXX XXX !!! !!!
+ */
+ nmem = sc->wi_usb_nummem++;
+
+ if (nmem >= MAX_WI_NMEM) {
+ sc->wi_usb_nummem--;
+ return ENOMEM;
+ }
+
+ sc->wi_usb_txmem[nmem] = malloc(len, M_DEVBUF, M_WAITOK);
+ if (sc->wi_usb_txmem[nmem] == NULL) {
+ sc->wi_usb_nummem--;
+ return ENOMEM;
+ }
+ sc->wi_usb_txmemsize[nmem] = len;
+
+ *id = nmem;
+ return 0;
+}
+
+/*
+ * this is crazy, we skip the first 16 bits of the buf so that it
+ * can be used as the 'type' of the usb transfer.
+ */
+
+
+int
+wi_write_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
+{
+ u_int8_t *ptr;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+
+ DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, id, off, len));
+
+ if (id < 0 && id >= sc->wi_usb_nummem)
+ return EIO;
+
+ ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
+
+ if (len + off > sc->wi_usb_txmemsize[id])
+ return EIO;
+ DPRINTFN(10,("%s: %s: completed \n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ bcopy(buf, ptr, len);
+ return 0;
+}
+
+/*
+ * On the prism I/O, this read_data points to the hardware buffer
+ * which contains the
+ */
+int
+wi_read_data_usb(struct wi_softc *wsc, int id, int off, caddr_t buf, int len)
+{
+ u_int8_t *ptr;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+
+ DPRINTFN(10,("%s: %s: id %x off %x len %d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, id, off, len));
+
+ if (id == 0x1001 && sc->wi_info != NULL)
+ ptr = (u_int8_t *)sc->wi_info + off;
+ else if (id == 0x1000 && sc->wi_rxframe != NULL)
+ ptr = (u_int8_t *)sc->wi_rxframe + off;
+ else if (id >= 0 && id < sc->wi_usb_nummem) {
+
+ if (sc->wi_usb_txmem[id] == NULL)
+ return EIO;
+ if (len + off > sc->wi_usb_txmemsize[id])
+ return EIO;
+
+ ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
+ } else
+ return EIO;
+
+ if (id < sc->wi_usb_nummem) {
+ ptr = (u_int8_t *)(sc->wi_usb_txmem[id]) + off;
+
+ if (len + off > sc->wi_usb_txmemsize[id])
+ return EIO;
+ }
+
+ bcopy(ptr, buf, len);
+ return 0;
+}
+
+void
+wi_usb_stop(struct wi_usb_softc *sc)
+{
+ DPRINTFN(1,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev),__func__));
+ /* XXX */
+
+ /* Stop transfers */
+}
+
+int
+wi_usb_do_transmit_sync(struct wi_usb_softc *sc, struct wi_usb_chain *c,
+ void *ident)
+{
+ usbd_status err;
+
+ DPRINTFN(10,("%s: %s:\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ sc->wi_usb_refcnt++;
+ err = usbd_transfer(c->wi_usb_xfer);
+ if (err != USBD_IN_PROGRESS && err != USBD_NORMAL_COMPLETION) {
+ printf("%s: wi_usb_send error=%s\n",
+ USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err));
+ /* Stop the interface from process context. */
+ wi_usb_stop(sc);
+ err = EIO;
+ goto done;
+ }
+ err = tsleep(ident, PRIBIO, "wiTXsync", hz*1);
+ if (err) {
+ DPRINTFN(1,("%s: %s: err %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, err));
+ err = ETIMEDOUT;
+ }
+done:
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ return err;
+}
+
+
+/*
+ * A command/rrid/wrid was sent to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+void
+wi_usb_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct wi_usb_chain *c = priv;
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+
+ int s;
+
+ if (sc->wi_usb_dying)
+ return;
+
+ s = splnet();
+
+ DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__, status));
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ splx(s);
+ return;
+ }
+ printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->wi_usb_dev),
+ usbd_errstr(status));
+ if (status == USBD_STALLED) {
+ sc->wi_usb_refcnt++;
+ usbd_clear_endpoint_stall(
+ sc->wi_usb_ep[WI_USB_ENDPT_TX]);
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ }
+ splx(s);
+ return;
+ }
+
+ splx(s);
+}
+
+/*
+ * A packet was sent to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+void
+wi_usb_txeof_frm(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct wi_usb_chain *c = priv;
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+ struct wi_softc *wsc = &sc->sc_wi;
+ struct ifnet *ifp = &wsc->sc_arpcom.ac_if;
+
+ int s;
+ int err = 0;
+
+ if (sc->wi_usb_dying)
+ return;
+
+ s = splnet();
+
+ DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__, status));
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ splx(s);
+ return;
+ }
+ printf("%s: usb error on tx: %s\n", USBDEVNAME(sc->wi_usb_dev),
+ usbd_errstr(status));
+ if (status == USBD_STALLED) {
+ sc->wi_usb_refcnt++;
+ usbd_clear_endpoint_stall(
+ sc->wi_usb_ep[WI_USB_ENDPT_TX]);
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ }
+ splx(s);
+ return;
+ }
+
+ if (status)
+ err = WI_EV_TX_EXC;
+
+ wi_txeof(wsc, err);
+
+ wi_usb_tx_unlock(sc);
+
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ wi_start_usb(ifp);
+
+ splx(s);
+}
+
+int
+wi_usb_rx_list_init(struct wi_usb_softc *sc)
+{
+ struct wi_usb_chain *c;
+ int i;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
+ c = &sc->wi_usb_rx_chain[i];
+ c->wi_usb_sc = sc;
+ c->wi_usb_idx = i;
+ if (c->wi_usb_xfer != NULL) {
+ printf("UGH RX\n");
+ }
+ if (c->wi_usb_xfer == NULL) {
+ c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
+ if (c->wi_usb_xfer == NULL)
+ return (ENOBUFS);
+ c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
+ WI_USB_BUFSZ);
+ if (c->wi_usb_buf == NULL)
+ return (ENOBUFS); /* XXX free xfer */
+ }
+ }
+
+ return (0);
+}
+
+int
+wi_usb_tx_list_init(struct wi_usb_softc *sc)
+{
+ struct wi_usb_chain *c;
+ int i;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ for (i = 0; i < WI_USB_TX_LIST_CNT; i++) {
+ c = &sc->wi_usb_tx_chain[i];
+ c->wi_usb_sc = sc;
+ c->wi_usb_idx = i;
+ c->wi_usb_mbuf = NULL;
+ if (c->wi_usb_xfer != NULL) {
+ printf("UGH TX\n");
+ }
+ if (c->wi_usb_xfer == NULL) {
+ c->wi_usb_xfer = usbd_alloc_xfer(sc->wi_usb_udev);
+ if (c->wi_usb_xfer == NULL)
+ return (ENOBUFS);
+ c->wi_usb_buf = usbd_alloc_buffer(c->wi_usb_xfer,
+ WI_USB_BUFSZ);
+ if (c->wi_usb_buf == NULL)
+ return (ENOBUFS);
+ }
+ }
+
+ return (0);
+}
+
+int
+wi_usb_open_pipes(struct wi_usb_softc *sc)
+{
+ usbd_status err;
+ int error = 0;
+ struct wi_usb_chain *c;
+ int i;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev),__func__));
+
+ sc->wi_usb_refcnt++;
+
+ /* Open RX and TX pipes. */
+ err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_RX],
+ USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_RX]);
+ if (err) {
+ printf("%s: open rx pipe failed: %s\n",
+ USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+
+ err = usbd_open_pipe(sc->wi_usb_iface, sc->wi_usb_ed[WI_USB_ENDPT_TX],
+ USBD_EXCLUSIVE_USE, &sc->wi_usb_ep[WI_USB_ENDPT_TX]);
+ if (err) {
+ printf("%s: open tx pipe failed: %s\n",
+ USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+
+ /* is this used? */
+ err = usbd_open_pipe_intr(sc->wi_usb_iface,
+ sc->wi_usb_ed[WI_USB_ENDPT_INTR], USBD_EXCLUSIVE_USE,
+ &sc->wi_usb_ep[WI_USB_ENDPT_INTR], sc, &sc->wi_usb_ibuf,
+ WI_USB_INTR_PKTLEN, wi_usb_intr, WI_USB_INTR_INTERVAL);
+ if (err) {
+ printf("%s: open intr pipe failed: %s\n",
+ USBDEVNAME(sc->wi_usb_dev), usbd_errstr(err));
+ error = EIO;
+ goto done;
+ }
+
+ /* Start up the receive pipe. */
+ for (i = 0; i < WI_USB_RX_LIST_CNT; i++) {
+ c = &sc->wi_usb_rx_chain[i];
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
+ c, c->wi_usb_buf, WI_USB_BUFSZ,
+ USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
+ wi_usb_rxeof);
+ DPRINTFN(10,("%s: %s: start read\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__));
+ usbd_transfer(c->wi_usb_xfer);
+ }
+
+done:
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+
+ return (error);
+}
+
+/*
+ * This is a bit of a kludge, however wi_rxeof and wi_update_stats
+ * call wi_get_fid to determine where the data associated with
+ * the transaction is located, the returned id is then used to
+ * wi_read_data the information out.
+ *
+ * This code returns which 'fid' should be used. The results are only valid
+ * during a wi_usb_rxeof because the data is recieved packet is 'held'
+ * an a variable for reading by wi_read_data_usb for that period.
+ *
+ * for magic numbers this uses 0x1000, 0x1001 for rx/info
+ */
+
+int
+wi_get_fid_usb(struct wi_softc *sc, int fid)
+{
+ switch (fid) {
+ case WI_RX_FID:
+ return 0x1000;
+ case WI_INFO_FID:
+ return 0x1001;
+ default:
+ return 0x1111;
+ }
+
+}
+
+int
+wi_usb_activate(device_ptr_t self, enum devact act)
+{
+ struct wi_usb_softc *sc = (struct wi_usb_softc *)self;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return (EOPNOTSUPP);
+ break;
+
+ case DVACT_DEACTIVATE:
+ if_deactivate(&sc->sc_wi.wi_ec.ec_if);
+ sc->wi_usb_dying = 1;
+ sc->wi_thread_info->dying = 1;
+ break;
+ }
+ return (0);
+}
+
+#if 0
+void
+wi_dump_data(void *buffer, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (((i) % 16) == 0)
+ printf("\n %02x:", i);
+ printf(" %02x",
+ ((uint8_t *)(buffer))[i]);
+
+ }
+ printf("\n");
+
+}
+#endif
+
+/*
+ * A frame has been recieved.
+ */
+void
+wi_usb_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct wi_usb_chain *c = priv;
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+ wi_usb_usbin *uin;
+ int total_len = 0;
+ u_int16_t rtype;
+
+ if (sc->wi_usb_dying)
+ return;
+
+ DPRINTFN(10,("%s: %s: enter status=%d\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__, status));
+
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_IOERROR
+ || status == USBD_CANCELLED) {
+ printf("%s: %u usb errors on rx: %s\n",
+ USBDEVNAME(sc->wi_usb_dev), 1,
+ /* sc->wi_usb_rx_errs, */
+ usbd_errstr(status));
+ return;
+ }
+#if 0
+ sc->wi_usb_rx_errs++;
+ if (usbd_ratecheck(&sc->wi_usb_rx_notice)) {
+ printf("%s: %u usb errors on rx: %s\n",
+ USBDEVNAME(sc->wi_usb_dev), sc->wi_usb_rx_errs,
+ usbd_errstr(status));
+ sc->wi_usb_rx_errs = 0;
+ }
+#endif
+ if (status == USBD_STALLED) {
+ sc->wi_usb_refcnt++;
+ usbd_clear_endpoint_stall(
+ sc->wi_usb_ep[WI_USB_ENDPT_RX]);
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ }
+ goto done;
+ }
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
+
+ if (total_len < 6) /* short XXX */
+ goto done;
+
+ uin = (wi_usb_usbin *)(c->wi_usb_buf);
+
+ rtype = letoh16(uin->type);
+
+
+#if 0
+ wi_dump_data(c->wi_usb_buf, total_len);
+#endif
+
+ if (WI_USB_ISRXFRM(rtype)) {
+ wi_usb_rxfrm(sc, uin, total_len);
+ goto done;
+ }
+ if (WI_USB_ISTXFRM(rtype)) {
+ DPRINTFN(2,("%s: %s: txfrm type %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rtype));
+ wi_usb_txfrm(sc, uin, total_len);
+ goto done;
+ }
+
+ switch (rtype) {
+ case WI_USB_INFOFRM:
+ /* info packet, INFO_FID hmm */
+ DPRINTFN(10,("%s: %s: infofrm type %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rtype));
+ wi_usb_infofrm(c, total_len);
+ break;
+ case WI_USB_CMDRESP:
+ wi_usb_cmdresp(c);
+ break;
+ case WI_USB_WRIDRESP:
+ wi_usb_wridresp(c);
+ break;
+ case WI_USB_RRIDRESP:
+ wi_usb_rridresp(c);
+ break;
+ case WI_USB_WMEMRESP:
+ /* Not currently used */
+ DPRINTFN(2,("%s: %s: wmemresp type %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rtype));
+ break;
+ case WI_USB_RMEMRESP:
+ /* Not currently used */
+ DPRINTFN(2,("%s: %s: rmemresp type %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rtype));
+ break;
+ case WI_USB_BUFAVAIL:
+ printf("wi_usb: recieved USB_BUFAVAIL packet\n"); /* XXX */
+ break;
+ case WI_USB_ERROR:
+ printf("wi_usb: recieved USB_ERROR packet\n"); /* XXX */
+ break;
+ default:
+#if 0
+ printf("wi_usb: recieved Unknown packet 0x%x len %x\n",
+ rtype, total_len);
+ wi_dump_data(c->wi_usb_buf, total_len);
+#endif
+ }
+
+ done:
+ /* Setup new transfer. */
+ usbd_setup_xfer(c->wi_usb_xfer, sc->wi_usb_ep[WI_USB_ENDPT_RX],
+ c, c->wi_usb_buf, WI_USB_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
+ USBD_NO_TIMEOUT, wi_usb_rxeof);
+ sc->wi_usb_refcnt++;
+ usbd_transfer(c->wi_usb_xfer);
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+
+ DPRINTFN(10,("%s: %s: start rx\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__));
+}
+
+void
+wi_usb_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct wi_usb_softc *sc = priv;
+
+ DPRINTFN(2,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (sc->wi_usb_dying)
+ return;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+
+ if (status == USBD_STALLED) {
+ sc->wi_usb_refcnt++;
+ usbd_clear_endpoint_stall(
+ sc->wi_usb_ep[WI_USB_ENDPT_RX]);
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ }
+ return;
+ }
+ /* XXX oerrors or collisions? */
+}
+void
+wi_usb_cmdresp(struct wi_usb_chain *c)
+{
+ struct wi_cmdresp *presp = (struct wi_cmdresp *)(c->wi_usb_buf);
+ u_int16_t status = letoh16(presp->status);
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+ uint16_t type;
+ uint16_t cmdresperr;
+
+ type = htole16(presp->type);
+ cmdresperr = letoh16(presp->resp0);
+ DPRINTFN(10,("%s: %s: enter rid=%x status %x %x %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, type, status, sc->cmdresp,
+ cmdresperr));
+
+ if (sc->cmdresp != status) {
+ DPRINTFN(1,("%s:cmd ty %x st %x cmd %x failed %x\n",
+ USBDEVNAME(sc->wi_usb_dev),
+ type, status, sc->cmdresp, cmdresperr));
+ return;
+ }
+
+ if ((cmdresperr != 0) && ((sc->cmdresp == WI_CMD_INQUIRE) ||
+ (sc->cmdresp == WI_CMD_DISABLE)) ) {
+ /*
+ * For some reason MA111 does not like info frame requests,
+ * or some DISABLES
+ * It responds to the request with the info
+ * but it claims the request failed
+ * reset the error code.
+ */
+ cmdresperr = 0;
+ }
+
+ if (cmdresperr != 0) {
+ DPRINTFN(1,("%s:cmd ty %x st %x cmd %x failed %x\n",
+ USBDEVNAME(sc->wi_usb_dev),
+ type, status, sc->cmdresp, cmdresperr));
+ }
+
+ sc->cmdresperr = cmdresperr;
+
+ sc->cmdresp = 0; /* good value for idle == INI ?? XXX */
+
+ wakeup(&sc->cmdresperr);
+}
+void
+wi_usb_rridresp(struct wi_usb_chain *c)
+{
+ struct wi_rridresp *presp = (struct wi_rridresp *)(c->wi_usb_buf);
+ u_int16_t frmlen = letoh16(presp->frmlen);
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+ struct wi_ltv_gen *ltv;
+ uint16_t rid;
+
+ rid = letoh16(presp->rid);
+ ltv = sc->ridltv;
+
+ if (ltv == 0) {
+ DPRINTFN(5,("%s: %s: enter ltv = 0 rid=%x len %d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rid,
+ frmlen));
+ return;
+ }
+
+ DPRINTFN(5,("%s: %s: enter rid=%x expecting %x len %d exptlen %d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, rid, ltv->wi_type,
+ frmlen, ltv->wi_len));
+
+ rid = letoh16(presp->rid);
+
+ if (rid != ltv->wi_type) {
+ sc->ridresperr = EIO;
+ return;
+ }
+
+ /* XXX */
+ if (rid == WI_RID_DATA_RATES)
+ frmlen = 2;
+
+ if (frmlen > ltv->wi_len) {
+ sc->ridresperr = ENOSPC;
+ sc->ridltv = 0;
+ wakeup(&sc->ridresperr);
+ return;
+ }
+
+ ltv->wi_len = frmlen;
+
+ DPRINTFN(10,("%s: %s: copying %x frmlen %d s %x d %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, (ltv->wi_len-1)*2,
+ frmlen));
+
+ if (ltv->wi_len > 1)
+ bcopy(&presp->data[0], (u_int8_t *)&ltv->wi_val,
+ (ltv->wi_len-1)*2);
+
+ sc->ridresperr = 0;
+ sc->ridltv = 0;
+ wakeup(&sc->ridresperr);
+
+}
+
+void
+wi_usb_wridresp(struct wi_usb_chain *c)
+{
+ struct wi_wridresp *presp = (struct wi_wridresp *)(c->wi_usb_buf);
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+ uint16_t status;
+
+ status = letoh16(presp->status);
+
+ DPRINTFN(10,("%s: %s: enter status=%x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, status));
+
+ sc->ridresperr = status;
+ sc->ridltv = 0;
+ wakeup(&sc->ridresperr);
+}
+
+void
+wi_usb_infofrm(struct wi_usb_chain *c, int len)
+{
+ struct wi_usb_softc *sc = c->wi_usb_sc;
+
+ DPRINTFN(10,("%s: %s: enter\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ sc->wi_info = ((char *)c->wi_usb_buf) + 2;
+ wi_update_stats(&sc->sc_wi);
+ sc->wi_info = NULL;
+}
+
+void
+wi_usb_txfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
+{
+ u_int16_t status;
+ int s;
+ struct wi_softc *wsc = &sc->sc_wi;
+ struct ifnet *ifp = &wsc->sc_arpcom.ac_if;
+
+ s = splnet();
+ status = letoh16(uin->type); /* XXX -- type == status */
+
+
+ DPRINTFN(2,("%s: %s: enter status=%d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, status));
+
+ if (sc->txresp == WI_CMD_TX) {
+ sc->txresperr=status;
+ sc->txresp = 0;
+ wakeup(&sc->txresperr);
+ } else {
+ if (status != 0) /* XXX */
+ wi_watchdog_usb(ifp);
+ DPRINTFN(1,("%s: %s: txresp not expected status=%d \n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, status));
+ }
+
+ splx(s);
+}
+void
+wi_usb_rxfrm(struct wi_usb_softc *sc, wi_usb_usbin *uin, int total_len)
+{
+ int s;
+
+ DPRINTFN(5,("%s: %s: enter len=%d\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, total_len));
+
+ s = splnet();
+
+ sc->wi_rxframe = (void *)uin;
+
+ wi_rxeof(&sc->sc_wi);
+
+ sc->wi_rxframe = NULL;
+
+ splx(s);
+
+}
+
+
+void
+wi_usb_start_thread(void *arg)
+{
+ struct wi_usb_softc *sc = arg;
+ kthread_create (wi_usb_thread, arg, NULL, USBDEVNAME(sc->wi_usb_dev));
+}
+
+void
+wi_start_usb(struct ifnet *ifp)
+{
+ struct wi_softc *wsc;
+ struct wi_usb_softc *sc;
+ int s;
+
+ wsc = ifp->if_softc;
+ sc = wsc->wi_usb_cdata;
+
+ s = splimp();
+
+ DPRINTFN(5,("%s: %s:\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (wi_usb_tx_lock_try(sc)) {
+ /* lock acquired do start now */
+ wi_func_io.f_start(ifp);
+ } else {
+ sc->wi_thread_info->status |= WI_START;
+ if (sc->wi_thread_info->idle)
+ wakeup (sc->wi_thread_info);
+ }
+
+ splx(s);
+}
+
+/*
+ * inquire is called from interrupt context (timeout)
+ * It is not possible to sleep in interrupt context so it is necessary
+ * to signal the kernel thread to perform the action.
+ */
+void
+wi_init_usb(struct wi_softc *wsc)
+{
+ DPRINTFN(5,("%s: %s:\n", WI_PRT_ARG(wsc), __func__));
+
+ wi_usb_ctl_lock(wsc->wi_usb_cdata);
+ wi_func_io.f_init(wsc);
+ wi_usb_ctl_unlock(wsc->wi_usb_cdata);
+}
+
+
+/*
+ * inquire is called from interrupt context (timeout)
+ * It is not possible to sleep in interrupt context so it is necessary
+ * to signal the kernel thread to perform the action.
+ */
+void
+wi_inquire_usb(void *xsc)
+{
+ struct wi_softc *wsc = xsc;
+ struct wi_usb_softc *sc = wsc->wi_usb_cdata;
+ int s;
+
+
+ s = splimp();
+
+ DPRINTFN(2,("%s: %s:\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ sc->wi_thread_info->status |= WI_INQUIRE;
+
+ if (sc->wi_thread_info->idle)
+ wakeup (sc->wi_thread_info);
+ splx(s);
+}
+
+/*
+ * Watchdog is normally called from interrupt context (timeout)
+ * It is not possible to sleep in interrupt context so it is necessary
+ * to signal the kernel thread to perform the action.
+ */
+void
+wi_watchdog_usb(struct ifnet *ifp)
+{
+ struct wi_softc *wsc;
+ struct wi_usb_softc *sc;
+ int s;
+
+ wsc = ifp->if_softc;
+ sc = wsc->wi_usb_cdata;
+
+ s = splimp();
+
+ DPRINTFN(5,("%s: %s: ifp %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__, ifp));
+
+ sc->wi_thread_info->status |= WI_WATCHDOG;
+
+ if (sc->wi_thread_info->idle)
+ wakeup (sc->wi_thread_info);
+ splx(s);
+}
+
+/*
+ * ioctl will always be called from a user context,
+ * therefore is is possible to sleep in the calling context
+ * acquire the lock and call the real ioctl fucntion directly
+ */
+int
+wi_ioctl_usb(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct wi_softc *wsc;
+ int err;
+
+ wsc = ifp->if_softc;
+
+ wi_usb_ctl_lock(wsc->wi_usb_cdata);
+ err = wi_func_io.f_ioctl(ifp, command, data);
+ wi_usb_ctl_unlock(wsc->wi_usb_cdata);
+ return err;
+}
+
+void
+wi_usb_thread(void *arg)
+{
+ struct wi_usb_softc *sc = arg;
+ struct wi_usb_thread_info *wi_thread_info;
+ int s;
+
+ wi_thread_info = malloc(sizeof(*wi_thread_info), M_DEVBUF, M_WAITOK);
+
+ /*
+ * is there a remote possibility that the device could
+ * be removed before the kernel thread starts up?
+ */
+
+ sc->wi_usb_refcnt++;
+
+ sc->wi_thread_info = wi_thread_info;
+ wi_thread_info->dying = 0;
+ wi_thread_info->status = 0;
+
+ wi_usb_ctl_lock(sc);
+
+ wi_attach(&sc->sc_wi, &wi_func_usb);
+
+ wi_usb_ctl_unlock(sc);
+
+ for(;;) {
+ if (wi_thread_info->dying) {
+ if (--sc->wi_usb_refcnt < 0)
+ usb_detach_wakeup(USBDEV(sc->wi_usb_dev));
+ kthread_exit(0);
+ }
+
+ DPRINTFN(5,("%s: %s: dying %x status %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__,
+ wi_thread_info->dying, wi_thread_info->status));
+
+ wi_usb_ctl_lock(sc);
+
+ DPRINTFN(5,("%s: %s: starting %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__,
+ wi_thread_info->status));
+
+ s = splusb();
+ if (wi_thread_info->status & WI_START) {
+ wi_thread_info->status &= ~WI_START;
+ wi_usb_tx_lock(sc);
+ wi_func_io.f_start(&sc->sc_wi.sc_arpcom.ac_if);
+ /*
+ * tx_unlock is explictly missing here
+ * is is done in txeof_frm
+ */
+ } else if (wi_thread_info->status & WI_INQUIRE) {
+ wi_thread_info->status &= ~WI_INQUIRE;
+ wi_func_io.f_inquire(&sc->sc_wi);
+ } else if (wi_thread_info->status & WI_WATCHDOG) {
+ wi_thread_info->status &= ~WI_WATCHDOG;
+ wi_func_io.f_watchdog( &sc->sc_wi.sc_arpcom.ac_if);
+ }
+ splx(s);
+
+ DPRINTFN(5,("%s: %s: ending %x\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__,
+ wi_thread_info->status));
+ wi_usb_ctl_unlock(sc);
+
+ if (wi_thread_info->status == 0) {
+ s = splimp();
+ wi_thread_info->idle = 1;
+ tsleep(wi_thread_info, PRIBIO, "wiIDL", 0);
+ wi_thread_info->idle = 0;
+ splx(s);
+ }
+ }
+}
+
+int
+wi_usb_tx_lock_try(struct wi_usb_softc *sc)
+{
+ int s;
+
+ s = splimp(); /* right priority? */
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (sc->wi_lock != 0) {
+ return 0; /* failed to aquire lock */
+ }
+
+ sc->wi_lock = 1;
+
+ splx(s);
+
+ return 1;
+}
+void
+wi_usb_tx_lock(struct wi_usb_softc *sc)
+{
+ int s;
+
+ s = splimp(); /* right priority? */
+
+ again:
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (sc->wi_lock != 0) {
+ sc->wi_lockwait++;
+ DPRINTFN(10,("%s: %s: busy %d\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__, sc->wi_lockwait ));
+ tsleep(&sc->wi_lock, PRIBIO, "witxl", 0);
+ }
+
+ if (sc->wi_lock != 0)
+ goto again;
+ sc->wi_lock = 1;
+
+ splx(s);
+
+ return;
+
+}
+
+void
+wi_usb_tx_unlock(struct wi_usb_softc *sc)
+{
+ int s;
+ s = splimp(); /* right priority? */
+
+ sc->wi_lock = 0;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (sc->wi_lockwait) {
+ DPRINTFN(10,("%s: %s: waking\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+ sc->wi_lockwait = 0;
+ wakeup(&sc->wi_lock);
+ }
+
+ splx(s);
+}
+
+void
+wi_usb_ctl_lock(struct wi_usb_softc *sc)
+{
+ int s;
+
+ s = splimp(); /* right priority? */
+
+ again:
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__));
+
+ if (sc->wi_ctllock != 0) {
+ if (curproc == sc->wi_curproc) {
+ /* allow recursion */
+ sc->wi_ctllock++;
+ splx(s);
+ return;
+ }
+ sc->wi_ctllockwait++;
+ DPRINTFN(10,("%s: %s: busy %d\n", USBDEVNAME(sc->wi_usb_dev),
+ __func__, sc->wi_ctllockwait ));
+ tsleep(&sc->wi_ctllock, PRIBIO, "wiusbthr", 0);
+ }
+
+ if (sc->wi_ctllock != 0)
+ goto again;
+ sc->wi_ctllock++;
+ sc->wi_curproc = curproc;
+
+ splx(s);
+
+ return;
+
+}
+
+void
+wi_usb_ctl_unlock(struct wi_usb_softc *sc)
+{
+ int s;
+
+ s = splimp(); /* right priority? */
+
+ sc->wi_ctllock--;
+
+ DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->wi_usb_dev), __func__));
+
+ if (sc->wi_ctllock == 0 && sc->wi_ctllockwait) {
+ DPRINTFN(10,("%s: %s: waking\n",
+ USBDEVNAME(sc->wi_usb_dev), __func__));
+ sc->wi_ctllockwait = 0;
+ sc->wi_curproc = 0;
+ wakeup(&sc->wi_ctllock);
+ }
+
+ splx(s);
+}
diff --git a/sys/dev/usb/if_wi_usb.h b/sys/dev/usb/if_wi_usb.h
new file mode 100644
index 00000000000..41ca871b350
--- /dev/null
+++ b/sys/dev/usb/if_wi_usb.h
@@ -0,0 +1,161 @@
+/* $OpenBSD: if_wi_usb.h,v 1.1 2003/10/26 15:34:16 drahn Exp $ */
+
+/*
+ * Copyright (c) 2003 Dale Rahn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Effort sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
+ */
+
+#define WI_USB_CONFIG_NO 1
+
+#define WI_USB_ENDPT_TX 1
+#define WI_USB_ENDPT_RX 2
+#define WI_USB_ENDPT_INTR 3
+#define WI_USB_ENDPT_MAX 4
+
+#define WI_USB_IFACE_IDX 0
+
+
+/* XXX */
+#define WI_USB_DATA_MAXLEN WI_DEFAULT_DATALEN
+#define WI_USB_BUFSZ 2368 /* MAX PACKET LEN ??? n%64 == 0 */
+#define WI_USB_INTR_INTERVAL 100 /* ms */
+
+struct wi_usb_softc;
+
+struct wi_usb_chain {
+ struct wi_usb_softc *wi_usb_sc;
+ struct usbd_xfer *wi_usb_xfer;
+ void *wi_usb_buf;
+ struct mbuf *wi_usb_mbuf;
+ int wi_usb_idx;
+};
+#define WI_USB_TX_LIST_CNT 1
+#define WI_USB_RX_LIST_CNT 1
+
+struct wi_rridreq {
+ u_int16_t type; /* 0x00 */
+ u_int16_t frmlen; /* 0x02 */
+ u_int16_t rid; /* 0x04 */
+ u_int8_t pad[58]; /* 0x06 + sizeof(.) == 64 */
+};
+struct wi_rridresp {
+ u_int16_t type; /* 0x00 */
+ u_int16_t frmlen; /* 0x02 */
+ u_int16_t rid; /* 0x04 */
+ u_int8_t data[1658]; /* 0x06 */
+ /* sizeof(struct wi_rridresp) == WI_USB_BUFSZ */
+};
+struct wi_wridreq {
+ u_int16_t type; /* 0x00 */
+ u_int16_t frmlen; /* 0x02 */
+ u_int16_t rid; /* 0x04 */
+ u_int8_t data[2048]; /* 0x06 */
+};
+struct wi_wridresp {
+ u_int16_t type;
+ u_int16_t status;
+ u_int16_t resp0;
+ u_int16_t resp1;
+ u_int16_t resp2;
+};
+struct wi_info {
+ u_int16_t type;
+ u_int16_t info;
+};
+
+
+#define WI_USB_CMD_INIT 0x0
+#define WI_USB_CMD_ENABLE 0x1
+#define WI_USB_CMD_DISABLE 0x2
+#define WI_USB_CMD_DIAG 0x3
+
+struct wi_cmdreq {
+ u_int16_t type;
+ u_int16_t cmd;
+ u_int16_t param0;
+ u_int16_t param1;
+ u_int16_t param2;
+ u_int8_t pad[54];
+};
+struct wi_cmdresp {
+ u_int16_t type;
+ u_int16_t status;
+ u_int16_t resp0;
+ u_int16_t resp1;
+ u_int16_t resp2;
+};
+
+typedef union {
+ u_int16_t type;
+ struct wi_rridreq rridreq;
+ struct wi_rridresp rridresp;
+ struct wi_cmdreq cmdreq;
+ struct wi_cmdresp cmdresp;
+} wi_usb_usbin;
+#define WI_USB_INTR_PKTLEN 8
+
+#define WI_USB_TX_TIMEOUT 10000 /* ms */
+
+
+/* Should be sent to the bulkout endpoint */
+#define WI_USB_TXFRM 0
+#define WI_USB_CMDREQ 1
+#define WI_USB_WRIDREQ 2
+#define WI_USB_RRIDREQ 3
+#define WI_USB_WMEMREQ 4
+#define WI_USB_RMEMREQ 5
+
+/* Received from the bulkin endpoint */
+#define WI_USB_ISTXFRM(a) (((a) & 0xf000) == 0x0000)
+#define WI_USB_ISRXFRM(a) (((a) & 0xf000) == 0x2000)
+
+#define WI_USB_INFOFRM 0x8000
+#define WI_USB_CMDRESP 0x8001
+#define WI_USB_WRIDRESP 0x8002
+#define WI_USB_RRIDRESP 0x8003
+#define WI_USB_WMEMRESP 0x8004
+#define WI_USB_RMEMRESP 0x8005
+#define WI_USB_BUFAVAIL 0x8006
+#define WI_USB_ERROR 0x8007
+
+#define WI_GET_IFP(sc) &(sc)->sc_wi.sc_arpcom.ac_if
+
+/* USB */
+int wi_cmd_usb(struct wi_softc *sc, int cmd, int val0, int val1, int val2);
+int wi_read_record_usb(struct wi_softc *sc, struct wi_ltv_gen *ltv);
+int wi_write_record_usb(struct wi_softc *sc, struct wi_ltv_gen *ltv);
+int wi_read_data_usb(struct wi_softc *sc, int id, int off, caddr_t buf,
+ int len);
+int wi_write_data_usb(struct wi_softc *sc, int id, int off, caddr_t buf,
+ int len);
+int wi_alloc_nicmem_usb(struct wi_softc *sc, int len, int *id);
+int wi_get_fid_usb(struct wi_softc *sc, int fid);
+void wi_init_usb(struct wi_softc *sc);
+
+void wi_start_usb(struct ifnet *ifp);
+int wi_ioctl_usb(struct ifnet *, u_long, caddr_t);
+void wi_inquire_usb(void *xsc);
+void wi_watchdog_usb(struct ifnet *ifp);