summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/macppc/dev/if_wi_obio.c4
-rw-r--r--sys/dev/ic/if_wi.c128
-rw-r--r--sys/dev/ic/if_wi_ieee.h8
-rw-r--r--sys/dev/ic/if_wivar.h43
-rw-r--r--sys/dev/pci/if_wi_pci.c4
-rw-r--r--sys/dev/pcmcia/if_wi_pcmcia.c4
-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
9 files changed, 2249 insertions, 50 deletions
diff --git a/sys/arch/macppc/dev/if_wi_obio.c b/sys/arch/macppc/dev/if_wi_obio.c
index c16fb3d992d..023475dd172 100644
--- a/sys/arch/macppc/dev/if_wi_obio.c
+++ b/sys/arch/macppc/dev/if_wi_obio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi_obio.c,v 1.8 2002/09/15 09:01:58 deraadt Exp $ */
+/* $OpenBSD: if_wi_obio.c,v 1.9 2003/10/26 15:34:16 drahn Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -129,7 +129,7 @@ wi_obio_attach(parent, self, aux)
wi_obio_enable(sc);
- wi_attach(sc);
+ wi_attach(sc, &wi_func_io);
}
int
diff --git a/sys/dev/ic/if_wi.c b/sys/dev/ic/if_wi.c
index f1ece1d0899..260c8d9e8a6 100644
--- a/sys/dev/ic/if_wi.c
+++ b/sys/dev/ic/if_wi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi.c,v 1.100 2003/10/21 18:58:49 jmc Exp $ */
+/* $OpenBSD: if_wi.c,v 1.101 2003/10/26 15:34:15 drahn Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -126,7 +126,7 @@ u_int32_t widebug = WIDEBUG;
#if !defined(lint) && !defined(__OpenBSD__)
static const char rcsid[] =
- "$OpenBSD: if_wi.c,v 1.100 2003/10/21 18:58:49 jmc Exp $";
+ "$OpenBSD: if_wi.c,v 1.101 2003/10/26 15:34:15 drahn Exp $";
#endif /* lint */
#ifdef foo
@@ -135,6 +135,7 @@ static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
STATIC void wi_reset(struct wi_softc *);
STATIC int wi_ioctl(struct ifnet *, u_long, caddr_t);
+STATIC void wi_init_io(struct wi_softc *);
STATIC void wi_start(struct ifnet *);
STATIC void wi_watchdog(struct ifnet *);
STATIC void wi_shutdown(void *);
@@ -143,15 +144,15 @@ STATIC void wi_txeof(struct wi_softc *, int);
STATIC void wi_update_stats(struct wi_softc *);
STATIC void wi_setmulti(struct wi_softc *);
-STATIC int wi_cmd(struct wi_softc *, int, int, int, int);
-STATIC int wi_read_record(struct wi_softc *, struct wi_ltv_gen *);
-STATIC int wi_write_record(struct wi_softc *, struct wi_ltv_gen *);
-STATIC int wi_read_data(struct wi_softc *, int,
+STATIC int wi_cmd_io(struct wi_softc *, int, int, int, int);
+STATIC int wi_read_record_io(struct wi_softc *, struct wi_ltv_gen *);
+STATIC int wi_write_record_io(struct wi_softc *, struct wi_ltv_gen *);
+STATIC int wi_read_data_io(struct wi_softc *, int,
int, caddr_t, int);
-STATIC int wi_write_data(struct wi_softc *, int,
+STATIC int wi_write_data_io(struct wi_softc *, int,
int, caddr_t, int);
STATIC int wi_seek(struct wi_softc *, int, int, int);
-STATIC int wi_alloc_nicmem(struct wi_softc *, int, int *);
+
STATIC void wi_inquire(void *);
STATIC int wi_setdef(struct wi_softc *, struct wi_req *);
STATIC void wi_get_id(struct wi_softc *);
@@ -172,6 +173,11 @@ STATIC int wi_set_debug(struct wi_softc *, struct wi_req *);
STATIC void wi_do_hostencrypt(struct wi_softc *, caddr_t, int);
STATIC int wi_do_hostdecrypt(struct wi_softc *, caddr_t, int);
+STATIC int wi_alloc_nicmem_io(struct wi_softc *, int, int *);
+STATIC int wi_get_fid_io(struct wi_softc *sc, int fid);
+STATIC void wi_intr_enable(struct wi_softc *sc, int mode);
+STATIC void wi_intr_ack(struct wi_softc *sc, int mode);
+
/* Autoconfig definition of driver back-end */
struct cfdriver wi_cd = {
NULL, "wi", DV_IFNET
@@ -181,15 +187,32 @@ const struct wi_card_ident wi_card_ident[] = {
WI_CARD_IDS
};
+struct wi_funcs wi_func_io = {
+ wi_cmd_io,
+ wi_read_record_io,
+ wi_write_record_io,
+ wi_alloc_nicmem_io,
+ wi_read_data_io,
+ wi_write_data_io,
+ wi_get_fid_io,
+ wi_init_io,
+
+ wi_start,
+ wi_ioctl,
+ wi_watchdog,
+ wi_inquire,
+};
+
int
-wi_attach(sc)
- struct wi_softc *sc;
+wi_attach(struct wi_softc *sc, struct wi_funcs *funcs)
{
struct wi_ltv_macaddr mac;
struct wi_ltv_gen gen;
struct ifnet *ifp;
int error;
+ sc->sc_funcs = funcs;
+
wi_reset(sc);
/* Read the station address. */
@@ -210,9 +233,9 @@ wi_attach(sc)
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
ifp->if_softc = sc;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = wi_ioctl;
- ifp->if_start = wi_start;
- ifp->if_watchdog = wi_watchdog;
+ ifp->if_ioctl = funcs->f_ioctl;
+ ifp->if_start = funcs->f_start;
+ ifp->if_watchdog = funcs->f_watchdog;
ifp->if_baudrate = 10000000;
IFQ_SET_READY(&ifp->if_snd);
@@ -292,7 +315,7 @@ wi_attach(sc)
gen.wi_len = 2;
if (wi_read_record(sc, &gen) == 0 && gen.wi_val != htole16(0))
sc->wi_flags |= WI_FLAGS_HAS_WEP;
- timeout_set(&sc->sc_timo, wi_inquire, sc);
+ timeout_set(&sc->sc_timo, funcs->f_inquire, sc);
bzero((char *)&sc->wi_stats, sizeof(sc->wi_stats));
@@ -401,6 +424,20 @@ wi_attach(sc)
return (0);
}
+STATIC void
+wi_intr_enable(struct wi_softc *sc, int mode)
+{
+ if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
+ CSR_WRITE_2(sc, WI_INT_EN, mode);
+}
+
+STATIC void
+wi_intr_ack(struct wi_softc *sc, int mode)
+{
+ if (!(sc->wi_flags & WI_FLAGS_BUS_USB))
+ CSR_WRITE_2(sc, WI_EVENT_ACK, mode);
+}
+
int
wi_intr(vsc)
void *vsc;
@@ -466,7 +503,14 @@ wi_intr(vsc)
return (1);
}
-STATIC void
+STATIC int
+wi_get_fid_io(struct wi_softc *sc, int fid)
+{
+ return CSR_READ_2(sc, fid);
+}
+
+
+void
wi_rxeof(sc)
struct wi_softc *sc;
{
@@ -480,7 +524,7 @@ wi_rxeof(sc)
ifp = &sc->sc_arpcom.ac_if;
- id = CSR_READ_2(sc, WI_RX_FID);
+ id = wi_get_fid(sc, WI_RX_FID);
if (sc->wi_procframe || sc->wi_debug.wi_monitor) {
struct wi_frame *rx_frame;
@@ -774,7 +818,7 @@ wi_rxeof(sc)
return;
}
-STATIC void
+void
wi_txeof(sc, status)
struct wi_softc *sc;
int status;
@@ -834,7 +878,7 @@ wi_update_stats(sc)
ifp = &sc->sc_arpcom.ac_if;
- id = CSR_READ_2(sc, WI_INFO_FID);
+ id = wi_get_fid(sc, WI_INFO_FID);
wi_read_data(sc, id, 0, (char *)&gen, 4);
@@ -853,7 +897,11 @@ wi_update_stats(sc)
ptr = (u_int32_t *)&sc->wi_stats;
for (i = 0; i < len; i++) {
- t = CSR_READ_2(sc, WI_DATA1);
+ if (sc->wi_flags & WI_FLAGS_BUS_USB) {
+ wi_read_data(sc, id, 4 + i*2, (char *)&t, 2);
+ t = letoh16(t);
+ } else
+ t = CSR_READ_2(sc, WI_DATA1);
#ifdef WI_HERMES_STATS_WAR
if (t > 0xF000)
t = ~t & 0xFFFF;
@@ -869,7 +917,7 @@ wi_update_stats(sc)
}
STATIC int
-wi_cmd(sc, cmd, val0, val1, val2)
+wi_cmd_io(sc, cmd, val0, val1, val2)
struct wi_softc *sc;
int cmd;
int val0;
@@ -932,8 +980,8 @@ wi_reset(sc)
else
sc->wi_flags |= WI_FLAGS_INITIALIZED;
- CSR_WRITE_2(sc, WI_INT_EN, 0);
- CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
+ wi_intr_enable(sc, 0);
+ wi_intr_ack(sc, 0xffff);
/* Calibrate timer. */
WI_SETVAL(WI_RID_TICK_TIME, 8);
@@ -973,7 +1021,7 @@ wi_cor_reset(sc)
* Read an LTV record from the NIC.
*/
STATIC int
-wi_read_record(sc, ltv)
+wi_read_record_io(sc, ltv)
struct wi_softc *sc;
struct wi_ltv_gen *ltv;
{
@@ -1075,7 +1123,7 @@ wi_read_record(sc, ltv)
* Same as read, except we inject data instead of reading it.
*/
STATIC int
-wi_write_record(sc, ltv)
+wi_write_record_io(sc, ltv)
struct wi_softc *sc;
struct wi_ltv_gen *ltv;
{
@@ -1230,7 +1278,7 @@ wi_seek(sc, id, off, chan)
}
STATIC int
-wi_read_data(sc, id, off, buf, len)
+wi_read_data_io(sc, id, off, buf, len)
struct wi_softc *sc;
int id, off;
caddr_t buf;
@@ -1260,7 +1308,7 @@ wi_read_data(sc, id, off, buf, len)
* we expect them, we preform the transfer over again.
*/
STATIC int
-wi_write_data(sc, id, off, buf, len)
+wi_write_data_io(sc, id, off, buf, len)
struct wi_softc *sc;
int id, off;
caddr_t buf;
@@ -1298,7 +1346,7 @@ again:
* it out.
*/
STATIC int
-wi_alloc_nicmem(sc, len, id)
+wi_alloc_nicmem_io(sc, len, id)
struct wi_softc *sc;
int len;
int *id;
@@ -1792,7 +1840,7 @@ wi_ioctl(ifp, command, data)
}
STATIC void
-wi_init(sc)
+wi_init_io(sc)
struct wi_softc *sc;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
@@ -1922,7 +1970,7 @@ wi_init(sc)
sc->wi_tx_mgmt_id = id;
/* enable interrupts */
- CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
+ wi_intr_enable(sc, WI_INTRS);
wihap_init(sc);
@@ -2116,7 +2164,7 @@ wi_do_hostdecrypt(struct wi_softc *sc, caddr_t buf, int len)
return 0;
}
-STATIC void
+void
wi_start(ifp)
struct ifnet *ifp;
{
@@ -2258,9 +2306,6 @@ nextpkt:
m_freem(m0);
- if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
- printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
-
ifp->if_flags |= IFF_OACTIVE;
/*
@@ -2268,6 +2313,9 @@ nextpkt:
*/
ifp->if_timer = 5;
+ if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id, 0, 0))
+ printf(WI_PRT_FMT ": wi_start: xmit failed\n", WI_PRT_ARG(sc));
+
return;
}
@@ -2312,7 +2360,7 @@ wi_mgmt_xmit(sc, data, len)
return(0);
}
-STATIC void
+void
wi_stop(sc)
struct wi_softc *sc;
{
@@ -2329,7 +2377,7 @@ wi_stop(sc)
ifp = &sc->sc_arpcom.ac_if;
- CSR_WRITE_2(sc, WI_INT_EN, 0);
+ wi_intr_enable(sc, 0);
wi_cmd(sc, WI_CMD_DISABLE|sc->wi_portnum, 0, 0, 0);
ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
@@ -2338,7 +2386,8 @@ wi_stop(sc)
return;
}
-STATIC void
+
+void
wi_watchdog(ifp)
struct ifnet *ifp;
{
@@ -2366,9 +2415,10 @@ wi_detach(sc)
if (ifp->if_flags & IFF_RUNNING)
wi_stop(sc);
- sc->wi_flags &= ~WI_FLAGS_ATTACHED;
- shutdownhook_disestablish(sc->sc_sdhook);
-
+ if (sc->wi_flags & WI_FLAGS_ATTACHED) {
+ sc->wi_flags &= ~WI_FLAGS_ATTACHED;
+ shutdownhook_disestablish(sc->sc_sdhook);
+ }
}
STATIC void
diff --git a/sys/dev/ic/if_wi_ieee.h b/sys/dev/ic/if_wi_ieee.h
index e134293c4a8..9a888d5b486 100644
--- a/sys/dev/ic/if_wi_ieee.h
+++ b/sys/dev/ic/if_wi_ieee.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi_ieee.h,v 1.18 2003/10/21 18:58:49 jmc Exp $ */
+/* $OpenBSD: if_wi_ieee.h,v 1.19 2003/10/26 15:34:15 drahn Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -797,6 +797,8 @@ struct wi_scan_p2_hdr {
#define WI_NIC_P3_MINI_ATL 0x8023
#define WI_NIC_P3_MINI_ATS 0x8024
+#define WI_NIC_P3_USB_NETGEAR 0x8026 /* Prism3 USB */
+
struct wi_card_ident {
const u_int16_t card_id;
const char *card_name;
@@ -933,6 +935,10 @@ struct wi_card_ident {
"PRISM3 ISL37300P(PCI)", \
WI_INTERSIL \
}, { \
+ WI_NIC_P3_USB_NETGEAR, \
+ "PRISM3 (USB)", \
+ WI_INTERSIL \
+ }, { \
0, \
NULL, \
WI_NOTYPE \
diff --git a/sys/dev/ic/if_wivar.h b/sys/dev/ic/if_wivar.h
index f4c2edd94c2..8710a630c79 100644
--- a/sys/dev/ic/if_wivar.h
+++ b/sys/dev/ic/if_wivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wivar.h,v 1.21 2003/09/06 20:53:57 drahn Exp $ */
+/* $OpenBSD: if_wivar.h,v 1.22 2003/10/26 15:34:15 drahn Exp $ */
/*
* Copyright (c) 1997, 1998, 1999
@@ -109,7 +109,18 @@ struct wi_softc {
u_int16_t wi_confbits_param0;
} wi_debug;
void *sc_sdhook;
+ struct wi_usb_softc *wi_usb_cdata;
+
+ struct wi_funcs *sc_funcs;
};
+#define wi_cmd sc->sc_funcs->f_cmd
+#define wi_read_record sc->sc_funcs->f_read_record
+#define wi_write_record sc->sc_funcs->f_write_record
+#define wi_alloc_nicmem sc->sc_funcs->f_alloc_nicmem
+#define wi_read_data sc->sc_funcs->f_read_data
+#define wi_write_data sc->sc_funcs->f_write_data
+#define wi_get_fid sc->sc_funcs->f_get_fid
+#define wi_init sc->sc_funcs->f_init
/* Values for wi_flags. */
#define WI_FLAGS_ATTACHED 0x0001
@@ -122,14 +133,40 @@ struct wi_softc {
#define WI_FLAGS_HAS_DIVERSITY 0x0080
#define WI_FLAGS_HAS_HOSTAP 0x0100
#define WI_FLAGS_BUS_PCMCIA 0x0200
+#define WI_FLAGS_BUS_USB 0x0400
#define WI_PRT_FMT "%s"
#define WI_PRT_ARG(sc) (sc)->sc_dev.dv_xname
-int wi_attach(struct wi_softc *);
+struct wi_funcs {
+ int (*f_cmd)(struct wi_softc *sc, int cmd, int val0, int val1,
+ int val2);
+ int (*f_read_record)(struct wi_softc *sc, struct wi_ltv_gen *ltv);
+ int (*f_write_record)(struct wi_softc *sc,
+ struct wi_ltv_gen *ltv);
+ int (*f_alloc_nicmem)(struct wi_softc *sc, int len, int *id);
+ int (*f_read_data)(struct wi_softc *sc, int id, int off,
+ caddr_t buf, int len);
+ int (*f_write_data)(struct wi_softc *sc, int id, int off,
+ caddr_t buf, int len);
+ int (*f_get_fid)(struct wi_softc *sc, int fid);
+ void (*f_init)(struct wi_softc *sc);
+
+ void (*f_start)(struct ifnet *ifp);
+ int (*f_ioctl)(struct ifnet *, u_long, caddr_t);
+ void (*f_watchdog)(struct ifnet *ifp);
+ void (*f_inquire)(void *xsc);
+};
+
+extern struct wi_funcs wi_func_io;
+
+int wi_attach(struct wi_softc *, struct wi_funcs *);
void wi_detach(struct wi_softc *);
int wi_intr(void *);
-void wi_init(struct wi_softc *);
void wi_stop(struct wi_softc *);
void wi_cor_reset(struct wi_softc *);
int wi_mgmt_xmit(struct wi_softc *, caddr_t, int);
+
+void wi_update_stats(struct wi_softc *sc);
+void wi_rxeof(struct wi_softc *sc);
+void wi_txeof(struct wi_softc *sc, int status);
diff --git a/sys/dev/pci/if_wi_pci.c b/sys/dev/pci/if_wi_pci.c
index ea21ec7b05f..4da9e155386 100644
--- a/sys/dev/pci/if_wi_pci.c
+++ b/sys/dev/pci/if_wi_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi_pci.c,v 1.35 2003/06/17 21:56:25 millert Exp $ */
+/* $OpenBSD: if_wi_pci.c,v 1.36 2003/10/26 15:34:15 drahn Exp $ */
/*
* Copyright (c) 2001-2003 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -135,7 +135,7 @@ wi_pci_attach(struct device *parent, struct device *self, void *aux)
pp = wi_pci_lookup(pa);
if (pp->pp_attach(pa, sc) != 0)
return;
- wi_attach(sc);
+ wi_attach(sc, &wi_func_io);
}
/*
diff --git a/sys/dev/pcmcia/if_wi_pcmcia.c b/sys/dev/pcmcia/if_wi_pcmcia.c
index 008f4aa5a1b..89d99f968bc 100644
--- a/sys/dev/pcmcia/if_wi_pcmcia.c
+++ b/sys/dev/pcmcia/if_wi_pcmcia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_wi_pcmcia.c,v 1.43 2003/09/06 20:53:57 drahn Exp $ */
+/* $OpenBSD: if_wi_pcmcia.c,v 1.44 2003/10/26 15:34:16 drahn Exp $ */
/* $NetBSD: if_wi_pcmcia.c,v 1.14 2001/11/26 04:34:56 ichiro Exp $ */
/*
@@ -391,7 +391,7 @@ wi_pcmcia_attach(parent, self, aux)
goto bad;
}
- wi_attach(sc);
+ wi_attach(sc, &wi_func_io);
return;
bad:
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);