summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/am79c930.c380
-rw-r--r--sys/dev/ic/am79c930reg.h375
-rw-r--r--sys/dev/ic/am79c930var.h79
-rw-r--r--sys/dev/ic/awi.c2622
-rw-r--r--sys/dev/ic/awireg.h510
-rw-r--r--sys/dev/ic/awivar.h183
-rw-r--r--sys/dev/pcmcia/files.pcmcia10
-rw-r--r--sys/dev/pcmcia/if_awi_pcmcia.c412
8 files changed, 4570 insertions, 1 deletions
diff --git a/sys/dev/ic/am79c930.c b/sys/dev/ic/am79c930.c
new file mode 100644
index 00000000000..4e8a524c08c
--- /dev/null
+++ b/sys/dev/ic/am79c930.c
@@ -0,0 +1,380 @@
+/* $NetBSD: am79c930.c,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: am79c930.c,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * Am79c930 chip driver.
+ *
+ * This is used by the awi driver to use the shared
+ * memory attached to the 79c930 to communicate with the firmware running
+ * in the 930's on-board 80188 core.
+ *
+ * The 79c930 can be mapped into just I/O space, or also have a
+ * memory mapping; the mapping must be set up by the bus front-end
+ * before am79c930_init is called.
+ */
+
+/*
+ * operations:
+ *
+ * read_8, read_16, read_32, read_64, read_bytes
+ * write_8, write_16, write_32, write_64, write_bytes
+ * (two versions, depending on whether memory-space or i/o space is in use).
+ *
+ * interrupt E.C.
+ * start isr
+ * end isr
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+
+#define AM930_DELAY(x) /*nothing*/;
+
+void am79c930_regdump __P((struct am79c930_softc *sc));
+
+static void io_write_1 __P((struct am79c930_softc *, u_int32_t, u_int8_t));
+static void io_write_2 __P((struct am79c930_softc *, u_int32_t, u_int16_t));
+static void io_write_4 __P((struct am79c930_softc *, u_int32_t, u_int32_t));
+static void io_write_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+
+static u_int8_t io_read_1 __P((struct am79c930_softc *, u_int32_t));
+static u_int16_t io_read_2 __P((struct am79c930_softc *, u_int32_t));
+static u_int32_t io_read_4 __P((struct am79c930_softc *, u_int32_t));
+static void io_read_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+
+static void mem_write_1 __P((struct am79c930_softc *, u_int32_t, u_int8_t));
+static void mem_write_2 __P((struct am79c930_softc *, u_int32_t, u_int16_t));
+static void mem_write_4 __P((struct am79c930_softc *, u_int32_t, u_int32_t));
+static void mem_write_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+
+static u_int8_t mem_read_1 __P((struct am79c930_softc *, u_int32_t));
+static u_int16_t mem_read_2 __P((struct am79c930_softc *, u_int32_t));
+static u_int32_t mem_read_4 __P((struct am79c930_softc *, u_int32_t));
+static void mem_read_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+
+static struct am79c930_ops iospace_ops = {
+ io_write_1,
+ io_write_2,
+ io_write_4,
+ io_write_bytes,
+ io_read_1,
+ io_read_2,
+ io_read_4,
+ io_read_bytes
+};
+
+struct am79c930_ops memspace_ops = {
+ mem_write_1,
+ mem_write_2,
+ mem_write_4,
+ mem_write_bytes,
+ mem_read_1,
+ mem_read_2,
+ mem_read_4,
+ mem_read_bytes
+};
+
+static void io_write_1 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t val;
+{
+ /* XXX bank-switching? */
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI,
+ ((off>>8)& 0x7f));
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff));
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA, val);
+ AM930_DELAY(1);
+}
+
+static void io_write_2 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int16_t val;
+{
+ io_write_1(sc, off, val & 0xff);
+ io_write_1(sc, off+1, (val >> 8) & 0xff);
+}
+
+static void io_write_4 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int32_t val;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ io_write_1(sc, off, val & 0xff);
+ io_write_1(sc, off+1, (val >> 8) & 0xff);
+ io_write_1(sc, off+2, (val >> 16) & 0xff);
+ io_write_1(sc, off+3, (val >> 24) & 0xff);
+}
+
+static void io_write_bytes (sc, off, ptr, len)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t *ptr;
+ size_t len;
+{
+ int i;
+ /* XXX higher offset values needed for bank-switching! */
+
+ for (i=0; i<len; i++)
+ io_write_1 (sc, off+i, ptr[i]);
+}
+
+static u_int8_t io_read_1 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ u_int8_t val;
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI,
+ ((off>>8)& 0x7f));
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff));
+ AM930_DELAY(1);
+ val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA);
+ AM930_DELAY(1);
+ return val;
+}
+
+static u_int16_t io_read_2 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ return io_read_1 (sc, off) |
+ (io_read_1 (sc, off+1) << 8);
+}
+
+static u_int32_t io_read_4 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ /* XXX bank-switching? */
+ return io_read_1 (sc, off) |
+ (io_read_1 (sc, off+1) << 8) |
+ (io_read_1 (sc, off+2) << 16) |
+ (io_read_1 (sc, off+3) << 24);
+}
+
+static void io_read_bytes (sc, off, ptr, len)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t *ptr;
+ size_t len;
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ ptr[i] = io_read_1(sc, off+i);
+}
+
+
+
+static void mem_write_1 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t val;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val);
+}
+
+static void mem_write_2 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int16_t val;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff);
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff);
+}
+
+static void mem_write_4 (sc, off, val)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int32_t val;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff);
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff);
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off+2, (val >> 16) & 0xff);
+ bus_space_write_1(sc->sc_memt, sc->sc_memh, off+3, (val >> 24) & 0xff);
+}
+
+static void mem_write_bytes (sc, off, ptr, len)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t *ptr;
+ size_t len;
+{
+ int i;
+ /* XXX higher offset values needed for bank-switching! */
+
+ for (i=0; i<len; i++)
+ bus_space_write_1 (sc->sc_memt, sc->sc_memh, off+i, ptr[i]);
+}
+
+
+static u_int8_t mem_read_1 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ return bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
+}
+
+static u_int16_t mem_read_2 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ return
+ bus_space_read_1(sc->sc_memt, sc->sc_memh, off) |
+ (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8);
+}
+
+static u_int32_t mem_read_4 (sc, off)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+{
+ /* XXX higher offset values needed for bank-switching! */
+ return
+ bus_space_read_1(sc->sc_memt, sc->sc_memh, off) |
+ (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8)|
+ (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+2) <<16) |
+ (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24);
+}
+
+
+
+static void mem_read_bytes (sc, off, ptr, len)
+ struct am79c930_softc *sc;
+ u_int32_t off;
+ u_int8_t *ptr;
+ size_t len;
+{
+ int i;
+
+ /* XXX higher offset values needed for bank-switching! */
+
+ for (i=0; i<len; i++)
+ ptr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh, off+i);
+}
+
+
+
+
+/*
+ * Set bits in GCR.
+ */
+
+void am79c930_gcr_setbits (sc, bits)
+ struct am79c930_softc *sc;
+ u_int8_t bits;
+{
+ u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR);
+
+ gcr |= bits;
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr);
+}
+
+/*
+ * Clear bits in GCR.
+ */
+
+void am79c930_gcr_clearbits (sc, bits)
+ struct am79c930_softc *sc;
+ u_int8_t bits;
+{
+ u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR);
+
+ gcr &= ~bits;
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr);
+}
+
+u_int8_t am79c930_gcr_read (sc)
+ struct am79c930_softc *sc;
+{
+ return bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR);
+}
+
+#if 0
+void am79c930_regdump (sc)
+ struct am79c930_softc *sc;
+{
+ u_int8_t buf[8];
+ int i;
+
+ AM930_DELAY(5);
+ for (i=0; i<8; i++) {
+ buf[i] = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, i);
+ AM930_DELAY(5);
+ }
+ printf("am79c930: regdump:");
+ for (i=0; i<8; i++) {
+ printf(" %02x", buf[i]);
+ }
+ printf("\n");
+}
+#endif
+
+void am79c930_chip_init (sc, how)
+ struct am79c930_softc *sc;
+{
+ /* zero the bank select register, and leave it that way.. */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_BSS, 0);
+ if (how)
+ sc->sc_ops = &memspace_ops;
+ else
+ sc->sc_ops = &iospace_ops;
+}
diff --git a/sys/dev/ic/am79c930reg.h b/sys/dev/ic/am79c930reg.h
new file mode 100644
index 00000000000..9dfcd537086
--- /dev/null
+++ b/sys/dev/ic/am79c930reg.h
@@ -0,0 +1,375 @@
+/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * Device register definitions gleaned from from the AMD "Am79C930
+ * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller"
+ * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997.
+ *
+ * As of 1999/10/23, this was available from AMD's web site in PDF
+ * form.
+ */
+
+
+/*
+ * The 79c930 contains a bus interface unit, a media access
+ * controller, and a tranceiver attachment interface.
+ * The MAC contains an 80188 CPU core.
+ * typical devices built around this chip typically add 32k or 64k of
+ * memory for buffers.
+ *
+ * The 80188 runs firmware which handles most of the 802.11 gorp, and
+ * communicates with the host using shared data structures in this
+ * memory; the specifics of the shared memory layout are not covered
+ * in this source file; see <dev/ic/am80211fw.h> for details of that layer.
+ */
+
+/*
+ * Device Registers
+ */
+
+#define AM79C930_IO_BASE 0
+#define AM79C930_IO_SIZE 16
+#define AM79C930_IO_SIZE_BIG 40
+
+
+#define AM79C930_GCR 0 /* General Config Register */
+
+#define AM79C930_GCR_SWRESET 0x80 /* software reset */
+#define AM79C930_GCR_CORESET 0x40 /* core reset */
+#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */
+#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */
+#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */
+#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */
+#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */
+#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */
+
+#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET"
+
+#define AM79C930_BSS 1 /* Bank Switching Select register */
+
+#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */
+#define AM79C930_BSS_FS 0x20 /* Flash Select */
+#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */
+#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */
+#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */
+
+#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */
+
+#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */
+
+ /* set this bit to turn off ISAPnP version */
+#define AM79C930_LMA_HI_ISAPWRDWN 0x80
+
+/*
+ * mmm, inconsistancy in chip documentation:
+ * According to page 79--80, all four of the following are equivalent
+ * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO}
+ * According to tables on p63 and p67, they're the LSB through MSB
+ * of a 32-bit word.
+ */
+
+#define AM79C930_IODPA 4 /* I/O Data port A */
+#define AM79C930_IODPB 5 /* I/O Data port B */
+#define AM79C930_IODPC 6 /* I/O Data port C */
+#define AM79C930_IODPD 7 /* I/O Data port D */
+
+
+/*
+ * Tranceiver Attachment Interface Registers (TIR space)
+ * (omitted for now, since host access to them is for diagnostic
+ * purposes only).
+ */
+
+/*
+ * memory space goo.
+ */
+
+#define AM79C930_MEM_SIZE 0x8000 /* 32k */
+#define AM79C930_MEM_BASE 0x0 /* starting at 0 */
+/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * Device register definitions gleaned from from the AMD "Am79C930
+ * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller"
+ * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997.
+ *
+ * As of 1999/10/23, this was available from AMD's web site in PDF
+ * form.
+ */
+
+
+/*
+ * The 79c930 contains a bus interface unit, a media access
+ * controller, and a tranceiver attachment interface.
+ * The MAC contains an 80188 CPU core.
+ * typical devices built around this chip typically add 32k or 64k of
+ * memory for buffers.
+ *
+ * The 80188 runs firmware which handles most of the 802.11 gorp, and
+ * communicates with the host using shared data structures in this
+ * memory; the specifics of the shared memory layout are not covered
+ * in this source file; see <dev/ic/am80211fw.h> for details of that layer.
+ */
+
+/*
+ * Device Registers
+ */
+
+#define AM79C930_IO_BASE 0
+#define AM79C930_IO_SIZE 16
+#define AM79C930_IO_SIZE_BIG 40
+
+
+#define AM79C930_GCR 0 /* General Config Register */
+
+#define AM79C930_GCR_SWRESET 0x80 /* software reset */
+#define AM79C930_GCR_CORESET 0x40 /* core reset */
+#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */
+#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */
+#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */
+#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */
+#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */
+#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */
+
+#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET"
+
+#define AM79C930_BSS 1 /* Bank Switching Select register */
+
+#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */
+#define AM79C930_BSS_FS 0x20 /* Flash Select */
+#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */
+#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */
+#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */
+
+#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */
+
+#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */
+
+ /* set this bit to turn off ISAPnP version */
+#define AM79C930_LMA_HI_ISAPWRDWN 0x80
+
+/*
+ * mmm, inconsistancy in chip documentation:
+ * According to page 79--80, all four of the following are equivalent
+ * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO}
+ * According to tables on p63 and p67, they're the LSB through MSB
+ * of a 32-bit word.
+ */
+
+#define AM79C930_IODPA 4 /* I/O Data port A */
+#define AM79C930_IODPB 5 /* I/O Data port B */
+#define AM79C930_IODPC 6 /* I/O Data port C */
+#define AM79C930_IODPD 7 /* I/O Data port D */
+
+
+/*
+ * Tranceiver Attachment Interface Registers (TIR space)
+ * (omitted for now, since host access to them is for diagnostic
+ * purposes only).
+ */
+
+/*
+ * memory space goo.
+ */
+
+#define AM79C930_MEM_SIZE 0x8000 /* 32k */
+#define AM79C930_MEM_BASE 0x0 /* starting at 0 */
+/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: am79c930reg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * Device register definitions gleaned from from the AMD "Am79C930
+ * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller"
+ * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997.
+ *
+ * As of 1999/10/23, this was available from AMD's web site in PDF
+ * form.
+ */
+
+
+/*
+ * The 79c930 contains a bus interface unit, a media access
+ * controller, and a tranceiver attachment interface.
+ * The MAC contains an 80188 CPU core.
+ * typical devices built around this chip typically add 32k or 64k of
+ * memory for buffers.
+ *
+ * The 80188 runs firmware which handles most of the 802.11 gorp, and
+ * communicates with the host using shared data structures in this
+ * memory; the specifics of the shared memory layout are not covered
+ * in this source file; see <dev/ic/am80211fw.h> for details of that layer.
+ */
+
+/*
+ * Device Registers
+ */
+
+#define AM79C930_IO_BASE 0
+#define AM79C930_IO_SIZE 16
+#define AM79C930_IO_SIZE_BIG 40
+
+
+#define AM79C930_GCR 0 /* General Config Register */
+
+#define AM79C930_GCR_SWRESET 0x80 /* software reset */
+#define AM79C930_GCR_CORESET 0x40 /* core reset */
+#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */
+#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */
+#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */
+#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */
+#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */
+#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */
+
+#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET"
+
+#define AM79C930_BSS 1 /* Bank Switching Select register */
+
+#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */
+#define AM79C930_BSS_FS 0x20 /* Flash Select */
+#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */
+#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */
+#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */
+
+#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */
+
+#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */
+
+ /* set this bit to turn off ISAPnP version */
+#define AM79C930_LMA_HI_ISAPWRDWN 0x80
+
+/*
+ * mmm, inconsistancy in chip documentation:
+ * According to page 79--80, all four of the following are equivalent
+ * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO}
+ * According to tables on p63 and p67, they're the LSB through MSB
+ * of a 32-bit word.
+ */
+
+#define AM79C930_IODPA 4 /* I/O Data port A */
+#define AM79C930_IODPB 5 /* I/O Data port B */
+#define AM79C930_IODPC 6 /* I/O Data port C */
+#define AM79C930_IODPD 7 /* I/O Data port D */
+
+
+/*
+ * Tranceiver Attachment Interface Registers (TIR space)
+ * (omitted for now, since host access to them is for diagnostic
+ * purposes only).
+ */
+
+/*
+ * memory space goo.
+ */
+
+#define AM79C930_MEM_SIZE 0x8000 /* 32k */
+#define AM79C930_MEM_BASE 0x0 /* starting at 0 */
diff --git a/sys/dev/ic/am79c930var.h b/sys/dev/ic/am79c930var.h
new file mode 100644
index 00000000000..0d8a221126f
--- /dev/null
+++ b/sys/dev/ic/am79c930var.h
@@ -0,0 +1,79 @@
+/* $NetBSD: am79c930var.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: am79c930var.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#define AM79C930_BUS_PCMCIA 1
+#define AM79C930_BUS_ISAPNP 2 /* not implemented */
+
+struct am79c930_softc
+{
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+
+ struct am79c930_ops *sc_ops;
+
+ int sc_bustype;
+};
+
+struct am79c930_ops
+{
+ void (*write_1) __P((struct am79c930_softc *, u_int32_t, u_int8_t));
+ void (*write_2) __P((struct am79c930_softc *, u_int32_t, u_int16_t));
+ void (*write_4) __P((struct am79c930_softc *, u_int32_t, u_int32_t));
+ void (*write_bytes) __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+
+ u_int8_t (*read_1) __P((struct am79c930_softc *, u_int32_t));
+ u_int16_t (*read_2) __P((struct am79c930_softc *, u_int32_t));
+ u_int32_t (*read_4) __P((struct am79c930_softc *, u_int32_t));
+ void (*read_bytes) __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t));
+};
+
+void am79c930_chip_init __P((struct am79c930_softc *sc, int));
+
+void am79c930_gcr_setbits __P((struct am79c930_softc *sc, u_int8_t bits));
+void am79c930_gcr_clearbits __P((struct am79c930_softc *sc, u_int8_t bits));
+
+u_int8_t am79c930_gcr_read __P((struct am79c930_softc *sc));
+
+#define am79c930_hard_reset(sc) am79c930_gcr_setbits(sc, AM79C930_GCR_CORESET)
+#define am79c930_hard_reset_off(sc) am79c930_gcr_clearbits(sc, AM79C930_GCR_CORESET)
+
+
diff --git a/sys/dev/ic/awi.c b/sys/dev/ic/awi.c
new file mode 100644
index 00000000000..97f3b609a10
--- /dev/null
+++ b/sys/dev/ic/awi.c
@@ -0,0 +1,2622 @@
+/* $NetBSD: awi.c,v 1.8 1999/11/09 14:58:07 sommerfeld Exp $ */
+/* $OpenBSD: awi.c,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+/*
+ * Driver for AMD 802.11 firmware.
+ * Uses am79c930 chip driver to talk to firmware running on the am79c930.
+ *
+ * More-or-less a generic ethernet-like if driver, with 802.11 gorp added.
+ */
+
+/*
+ * todo:
+ * - flush tx queue on resynch.
+ * - clear oactive on "down".
+ * - rewrite copy-into-mbuf code
+ * - mgmt state machine gets stuck retransmitting assoc requests.
+ * - multicast filter.
+ * - fix device reset so it's more likely to work
+ * - show status goo through ifmedia.
+ *
+ * more todo:
+ * - deal with more 802.11 frames.
+ * - send reassoc request
+ * - deal with reassoc response
+ * - send/deal with disassociation
+ * - deal with "full" access points (no room for me).
+ * - power save mode
+ *
+ * later:
+ * - SSID preferences
+ * - need ioctls for poking at the MIBs
+ * - implement ad-hoc mode (including bss creation).
+ * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?)
+ * (focus on inf. mode since that will be needed for ietf)
+ * - deal with DH vs. FH versions of the card
+ * - deal with faster cards (2mb/s)
+ * - ?WEP goo (mmm, rc4) (it looks not particularly useful).
+ * - ifmedia revision.
+ * - common 802.11 mibish things.
+ * - common 802.11 media layer.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/device.h>
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.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
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+
+#ifndef ETHER_CRC_LEN
+#define ETHER_CRC_LEN 4
+#endif
+
+void awi_insane __P((struct awi_softc *sc));
+int awi_intlock __P((struct awi_softc *sc));
+void awi_intunlock __P((struct awi_softc *sc));
+void awi_intrinit __P((struct awi_softc *sc));
+u_int8_t awi_read_intst __P((struct awi_softc *sc));
+void awi_stop __P((struct awi_softc *sc));
+void awi_flush __P((struct awi_softc *sc));
+void awi_init __P((struct awi_softc *sc));
+void awi_set_mc __P((struct awi_softc *sc));
+void awi_rxint __P((struct awi_softc *));
+void awi_txint __P((struct awi_softc *));
+void awi_tx_packet __P((struct awi_softc *, int, struct mbuf *));
+
+void awi_rcv __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t));
+void awi_rcv_mgt __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t));
+void awi_rcv_data __P((struct awi_softc *, struct mbuf *));
+void awi_rcv_ctl __P((struct awi_softc *, struct mbuf *));
+
+int awi_enable __P((struct awi_softc *sc));
+void awi_disable __P((struct awi_softc *sc));
+
+void awi_zero __P((struct awi_softc *, u_int32_t, u_int32_t));
+
+void awi_cmd __P((struct awi_softc *, u_int8_t));
+void awi_cmd_test_if __P((struct awi_softc *));
+void awi_cmd_get_mib __P((struct awi_softc *sc, u_int8_t, u_int8_t, u_int8_t));
+void awi_cmd_txinit __P((struct awi_softc *sc));
+void awi_cmd_scan __P((struct awi_softc *sc));
+void awi_scan_next __P((struct awi_softc *sc));
+void awi_try_sync __P((struct awi_softc *sc));
+void awi_cmd_set_ss __P((struct awi_softc *sc));
+void awi_cmd_set_promisc __P((struct awi_softc *sc));
+void awi_cmd_set_allmulti __P((struct awi_softc *sc));
+void awi_cmd_set_infra __P((struct awi_softc *sc));
+void awi_cmd_set_notap __P((struct awi_softc *sc));
+void awi_cmd_get_myaddr __P((struct awi_softc *sc));
+
+
+void awi_cmd_scan_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_sync_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_set_ss_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_set_allmulti_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_set_promisc_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_set_infra_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_set_notap_done __P((struct awi_softc *sc, u_int8_t));
+void awi_cmd_get_myaddr_done __P((struct awi_softc *sc, u_int8_t));
+
+void awi_reset __P((struct awi_softc *));
+void awi_init_1 __P((struct awi_softc *));
+void awi_init_2 __P((struct awi_softc *, u_int8_t));
+void awi_mibdump __P((struct awi_softc *, u_int8_t));
+void awi_init_read_bufptrs_done __P((struct awi_softc *, u_int8_t));
+void awi_init_4 __P((struct awi_softc *, u_int8_t));
+void awi_init_5 __P((struct awi_softc *, u_int8_t));
+void awi_init_6 __P((struct awi_softc *, u_int8_t));
+void awi_running __P((struct awi_softc *));
+
+void awi_init_txdescr __P((struct awi_softc *));
+void awi_init_txd __P((struct awi_softc *, int, int, int, int));
+
+void awi_watchdog __P((struct ifnet *));
+void awi_start __P((struct ifnet *));
+int awi_ioctl __P((struct ifnet *, u_long, caddr_t));
+void awi_dump_rxchain __P((struct awi_softc *, char *, u_int32_t *));
+
+void awi_send_frame __P((struct awi_softc *, struct mbuf *));
+void awi_send_authreq __P((struct awi_softc *));
+void awi_send_assocreq __P((struct awi_softc *));
+void awi_parse_tlv __P((u_int8_t *base, u_int8_t *end, u_int8_t **vals, u_int8_t *lens, size_t nattr));
+
+u_int8_t *awi_add_rates __P((struct awi_softc *, struct mbuf *, u_int8_t *));
+u_int8_t *awi_add_ssid __P((struct awi_softc *, struct mbuf *, u_int8_t *));
+void * awi_init_hdr __P((struct awi_softc *, struct mbuf *, int, int));
+
+void awi_hexdump __P((char *tag, u_int8_t *data, int len));
+void awi_card_hexdump __P((struct awi_softc *, char *tag, u_int32_t offset, int len));
+
+int awi_drop_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *));
+void awi_drop_input __P((struct ifnet *, struct mbuf *));
+struct mbuf *awi_output_kludge __P((struct awi_softc *, struct mbuf *));
+void awi_set_timer __P((struct awi_softc *));
+void awi_restart_scan __P((struct awi_softc *));
+
+struct awi_rxd
+{
+ u_int32_t next;
+ u_int16_t len;
+ u_int8_t state, rate, rssi, index;
+ u_int32_t frame;
+ u_int32_t rxts;
+};
+
+void awi_copy_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *));
+u_int32_t awi_parse_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *));
+
+static const u_int8_t snap_magic[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
+
+int awi_scan_keepalive = 10;
+
+/*
+ * attach (called by bus-specific front end)
+ *
+ * look for banner message
+ * wait for selftests to complete (up to 2s??? eeee.)
+ * (do this with a timeout!!??!!)
+ * on timeout completion:
+ * issue test_interface command.
+ * get_mib command to locate TX buffer.
+ * set_mib command to set any non-default variables.
+ * init tx first.
+ * init rx second with enable receiver command
+ *
+ * mac mgmt portion executes sync command to start BSS
+ *
+ */
+
+/*
+ * device shutdown routine.
+ */
+
+/*
+ * device appears to be insane. rather than hanging, whap device upside
+ * the head on next timeout.
+ */
+
+void
+awi_insane(sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ printf("%s: device timeout\n", sc->sc_dev.dv_xname);
+
+ /* whap device on next timeout. */
+ sc->sc_state = AWI_ST_INSANE;
+ ifp->if_timer = 1;
+}
+
+void
+awi_set_timer (sc)
+ struct awi_softc *sc;
+{
+ if (sc->sc_tx_timer || sc->sc_scan_timer ||
+ sc->sc_mgt_timer || sc->sc_cmd_timer)
+ sc->sc_ifp->if_timer = 1;
+}
+
+
+/*
+ * Copy m0 into the given TX descriptor and give the descriptor to the
+ * device so it starts transmiting..
+ */
+
+void
+awi_tx_packet (sc, txd, m0)
+ struct awi_softc *sc;
+ int txd;
+ struct mbuf *m0;
+{
+ u_int32_t frame = sc->sc_txd[txd].frame;
+ u_int32_t len = sc->sc_txd[txd].len;
+ struct mbuf *m;
+
+ for (m = m0; m != NULL; m = m->m_next) {
+ u_int32_t nmove;
+ nmove = min(len, m->m_len);
+ awi_write_bytes (sc, frame, m->m_data, nmove);
+ if (nmove != m->m_len) {
+ printf("%s: large frame truncated\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ frame += nmove;
+ len -= nmove;
+ }
+
+ awi_init_txd (sc,
+ txd,
+ AWI_TXD_ST_OWN,
+ frame - sc->sc_txd[txd].frame,
+ AWI_RATE_1MBIT);
+
+#if 0
+ awi_card_hexdump (sc, "txd to go", sc->sc_txd[txd].descr,
+ AWI_TXD_SIZE);
+#endif
+
+}
+
+/*
+ * XXX KLUDGE XXX
+ *
+ * Convert ethernet-formatted frame into 802.11 data frame
+ * for infrastructure mode.
+ */
+
+struct mbuf *
+awi_output_kludge (sc, m0)
+ struct awi_softc *sc;
+ struct mbuf *m0;
+{
+ u_int8_t *framehdr;
+ u_int8_t *llchdr;
+ u_int8_t dstaddr[ETHER_ADDR_LEN];
+ struct awi_mac_header *amhdr;
+ u_int16_t etype;
+ struct ether_header *eh = mtod(m0, struct ether_header *);
+
+#if 0
+ awi_hexdump("etherframe", m0->m_data, m0->m_len);
+#endif
+
+ bcopy(eh->ether_dhost, dstaddr, sizeof(dstaddr));
+ etype = eh->ether_type;
+
+ m_adj(m0, sizeof(struct ether_header));
+
+ M_PREPEND(m0, sizeof(struct awi_mac_header) + 8, M_DONTWAIT);
+
+ if (m0 == NULL) {
+ printf("oops, prepend failed\n");
+ return NULL;
+ }
+
+ if (m0->m_len < 32) {
+ printf("oops, prepend only left %d bytes\n", m0->m_len);
+ m_freem(m0);
+ return NULL;
+ }
+ framehdr = mtod(m0, u_int8_t *);
+ amhdr = mtod(m0, struct awi_mac_header *);
+
+ amhdr->awi_fc = IEEEWL_FC_VERS |
+ IEEEWL_FC_TYPE_DATA<<IEEEWL_FC_TYPE_SHIFT;
+ amhdr->awi_f2 = IEEEWL_FC2_TODS;
+
+ bcopy(dstaddr, amhdr->awi_addr3, ETHER_ADDR_LEN); /* ether DST */
+ bcopy(sc->sc_active_bss.bss_id, amhdr->awi_addr1, ETHER_ADDR_LEN);
+ bcopy(sc->sc_my_addr, amhdr->awi_addr2, ETHER_ADDR_LEN);
+ amhdr->awi_duration = 0;
+ amhdr->awi_seqctl = 0;
+ llchdr = (u_int8_t *) (amhdr + 1);
+ bcopy(snap_magic, llchdr, 6);
+ bcopy(&etype, llchdr+6, 2);
+
+ return m0;
+}
+/*
+ * device start routine
+ *
+ * loop while there are free tx buffer descriptors and mbufs in the queue:
+ * -> copy mbufs to tx buffer and free mbufs.
+ * -> mark txd as good to go (OWN bit set, all others clear)
+ */
+
+void
+awi_start(ifp)
+ struct ifnet *ifp;
+{
+ struct awi_softc *sc = ifp->if_softc;
+ struct mbuf *m0;
+ int opending;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ printf("%s: start called while not running\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+
+ /*
+ * loop through send queue, setting up tx descriptors
+ * until we either run out of stuff to send, or descriptors
+ * to send them in.
+ */
+ opending = sc->sc_txpending;
+
+ while (sc->sc_txpending < sc->sc_ntxd) {
+ /*
+ * Grab a packet off the queue.
+ */
+ IF_DEQUEUE (&sc->sc_mgtq, m0);
+
+ if (m0 == NULL) {
+ /* XXX defer sending if not synched yet? */
+ IF_DEQUEUE (&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+#if NBPFILTER > 0
+ /*
+ * Pass packet to bpf if there is a listener.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif
+ /*
+ * We've got an ethernet-format frame.
+ * we need to mangle it into 802.11 form..
+ */
+ m0 = awi_output_kludge(sc, m0);
+ if (m0 == NULL)
+ continue;
+ }
+
+ awi_tx_packet(sc, sc->sc_txnext, m0);
+
+ sc->sc_txpending++;
+ sc->sc_txnext = (sc->sc_txnext + 1) % sc->sc_ntxd;
+
+ m_freem(m0);
+ }
+ if (sc->sc_txpending >= sc->sc_ntxd) {
+ /* no more slots available.. */
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+ if (sc->sc_txpending != opending) {
+ /* set watchdog timer in case unit flakes out */
+ if (sc->sc_tx_timer == 0)
+ sc->sc_tx_timer = 5;
+ awi_set_timer(sc);
+ }
+}
+
+int
+awi_enable(sc)
+ struct awi_softc *sc;
+{
+ if (sc->sc_enabled == 0) {
+ if ((sc->sc_enable != NULL) && ((*sc->sc_enable)(sc) != 0)) {
+ printf("%s: device enable failed\n",
+ sc->sc_dev.dv_xname);
+ return (EIO);
+ }
+ awi_init(sc);
+ }
+ sc->sc_enabled = 1;
+ return 0;
+}
+
+void
+awi_disable(sc)
+ struct awi_softc *sc;
+{
+ if (sc->sc_enabled != 0 && sc->sc_disable != NULL) {
+ (*sc->sc_disable)(sc);
+ sc->sc_enabled = 0;
+ }
+}
+
+
+
+int
+awi_intlock(sc)
+ struct awi_softc *sc;
+{
+ int i, j;
+ u_int8_t lockout;
+
+ DELAY(5);
+ for (j=0; j<10; j++) {
+ for (i=0; i<AWI_LOCKOUT_SPIN; i++) {
+ lockout = awi_read_1(sc, AWI_LOCKOUT_HOST);
+ if (!lockout)
+ break;
+ DELAY(5);
+ }
+ if (lockout)
+ break;
+ awi_write_1 (sc, AWI_LOCKOUT_MAC, 1);
+ lockout = awi_read_1(sc, AWI_LOCKOUT_HOST);
+
+ if (!lockout)
+ break;
+ /* oops, lost the race.. try again */
+ awi_write_1 (sc, AWI_LOCKOUT_MAC, 0);
+ }
+
+ if (lockout) {
+ awi_insane(sc);
+ return 0;
+ }
+ return 1;
+}
+
+void
+awi_intunlock(sc)
+ struct awi_softc *sc;
+{
+ awi_write_1 (sc, AWI_LOCKOUT_MAC, 0);
+}
+
+void
+awi_intrinit(sc)
+ struct awi_softc *sc;
+{
+ u_int8_t intmask;
+
+ am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT);
+
+ intmask = AWI_INT_GROGGY|AWI_INT_SCAN_CMPLT|
+ AWI_INT_TX|AWI_INT_RX|AWI_INT_CMD;
+
+ intmask = ~intmask;
+
+ if (!awi_intlock(sc))
+ return;
+
+ awi_write_1(sc, AWI_INTMASK, intmask);
+ awi_write_1(sc, AWI_INTMASK2, 0);
+
+ awi_intunlock(sc);
+}
+
+void awi_hexdump (char *tag, u_int8_t *data, int len)
+{
+ int i;
+
+ printf("%s:", tag);
+ for (i=0; i<len; i++) {
+ printf(" %02x", data[i]);
+ }
+ printf("\n");
+}
+
+void awi_card_hexdump (sc, tag, offset, len)
+ struct awi_softc *sc;
+ char *tag;
+ u_int32_t offset;
+ int len;
+{
+ int i;
+
+ printf("%s:", tag);
+ for (i=0; i<len; i++) {
+ printf(" %02x", awi_read_1(sc, offset+i));
+ }
+ printf("\n");
+}
+
+u_int8_t
+awi_read_intst(sc)
+ struct awi_softc *sc;
+{
+ u_int8_t state;
+
+ if (!awi_intlock(sc))
+ return 0;
+
+ /* we have int lock.. */
+
+ state = awi_read_1 (sc, AWI_INTSTAT);
+ awi_write_1(sc, AWI_INTSTAT, 0);
+
+ awi_intunlock(sc);
+
+ return state;
+}
+
+
+void
+awi_parse_tlv (u_int8_t *base, u_int8_t *end, u_int8_t **vals, u_int8_t *lens, size_t nattr)
+{
+ u_int8_t tag, len;
+
+ int i;
+
+ for (i=0; i<nattr; i++) {
+ vals[i] = NULL;
+ lens[i] = 0;
+ }
+
+ while (base < end) {
+ tag = base[0];
+ len = base[1];
+
+ base += 2;
+
+ if (tag < nattr) {
+ lens[tag] = len;
+ vals[tag] = base;
+ }
+ base += len;
+ }
+}
+
+void
+awi_send_frame (sc, m)
+ struct awi_softc *sc;
+ struct mbuf *m;
+{
+ IF_ENQUEUE(&sc->sc_mgtq, m);
+
+ awi_start(sc->sc_ifp);
+}
+
+void *
+awi_init_hdr (sc, m, f1, f2)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ int f1;
+ int f2;
+{
+ struct awi_mac_header *amhp;
+
+ /*
+ * initialize 802.11 mac header in mbuf, return pointer to next byte..
+ */
+
+ amhp = mtod(m, struct awi_mac_header *);
+
+ amhp->awi_fc = f1;
+ amhp->awi_f2 = f2;
+ amhp->awi_duration = 0;
+
+ bcopy(sc->sc_active_bss.bss_id, amhp->awi_addr1, ETHER_ADDR_LEN);
+ bcopy(sc->sc_my_addr, amhp->awi_addr2, ETHER_ADDR_LEN);
+ bcopy(sc->sc_active_bss.bss_id, amhp->awi_addr3, ETHER_ADDR_LEN);
+
+ amhp->awi_seqctl = 0;
+
+ return amhp+1;
+}
+
+
+
+u_int8_t *
+awi_add_rates (sc, m, ptr)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ u_int8_t *ptr;
+{
+ *ptr++ = 1; /* XXX */
+ *ptr++ = 1; /* XXX */
+ *ptr++ = 0x82; /* XXX */
+ return ptr;
+}
+
+u_int8_t *
+awi_add_ssid (sc, m, ptr)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ u_int8_t *ptr;
+{
+ int len = sc->sc_active_bss.sslen;
+ *ptr++ = 0; /* XXX */
+ *ptr++ = len;
+ bcopy(sc->sc_active_bss.ssid, ptr, len);
+ ptr += len;
+ return ptr;
+}
+
+
+
+void
+awi_send_authreq (sc)
+ struct awi_softc *sc;
+{
+ struct mbuf *m;
+ struct awi_auth_hdr *amahp;
+ u_int8_t *tlvptr;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ /*
+ * form an "association request" message.
+ */
+
+ /*
+ * auth alg number. 2 bytes. = 0
+ * auth txn seq number = 2 bytes = 1
+ * status code = 2 bytes = 0
+ * challenge text (not present)
+ */
+
+ if (m == 0)
+ return; /* we'll try again later.. */
+
+ amahp = awi_init_hdr (sc, m,
+ (IEEEWL_FC_VERS |
+ (IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT) |
+ (IEEEWL_SUBTYPE_AUTH << IEEEWL_FC_SUBTYPE_SHIFT)),
+ 0);
+
+ amahp->awi_algno[0] = 0;
+ amahp->awi_algno[1] = 0;
+ amahp->awi_seqno[0] = 1;
+ amahp->awi_seqno[1] = 0;
+ amahp->awi_status[0] = 0;
+ amahp->awi_status[1] = 0;
+
+ /*
+ * form an "authentication" message.
+ */
+
+ tlvptr = (u_int8_t *)(amahp+1);
+
+ tlvptr = awi_add_ssid(sc, m, tlvptr);
+ tlvptr = awi_add_rates(sc, m, tlvptr);
+
+ m->m_len = tlvptr - mtod(m, u_int8_t *);
+
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: sending auth request\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("frame", m->m_data, m->m_len);
+ }
+
+ awi_send_frame(sc, m);
+
+ sc->sc_mgt_timer = 2;
+ awi_set_timer(sc);
+}
+
+void
+awi_send_assocreq (sc)
+ struct awi_softc *sc;
+{
+ struct mbuf *m;
+ struct awi_assoc_hdr *amahp;
+ u_int8_t *tlvptr;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+
+ /*
+ * form an "association request" message.
+ */
+
+ if (m == 0)
+ return; /* we'll try again later.. */
+
+ /*
+ * cap info (2 bytes)
+ * listen interval (2 bytes)
+ * ssid (variable)
+ * supported rates (variable)
+ */
+
+ amahp = awi_init_hdr (sc, m,
+ IEEEWL_FC_TYPE_MGT, IEEEWL_SUBTYPE_ASSOCREQ);
+
+ amahp->awi_cap_info[0] = 4; /* XXX magic (CF-pollable) */
+ amahp->awi_cap_info[1] = 0;
+ amahp->awi_li[0] = 1;
+ amahp->awi_li[1] = 0;
+
+ tlvptr = (u_int8_t *)(amahp+1);
+
+ tlvptr = awi_add_ssid(sc, m, tlvptr);
+ tlvptr = awi_add_rates(sc, m, tlvptr);
+
+ m->m_len = tlvptr - mtod(m, u_int8_t *);
+
+
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: sending assoc request\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("frame", m->m_data, m->m_len);
+ }
+
+ awi_send_frame(sc, m);
+
+ sc->sc_mgt_timer = 2;
+ awi_set_timer(sc);
+}
+
+#if 0
+void
+awi_send_reassocreq (sc)
+{
+
+ /*
+ * form an "reassociation request" message.
+ */
+
+ /* 2 bytes frame control
+ 00100000 00000000
+ 2 bytes goo
+ 00000000 00000000
+ address 1: bssid
+ address 2: my address
+ address 3: bssid
+ 2 bytes seq/ctl
+ 00000000 00000000
+
+ cap info (2 bytes)
+ listen interval (2 bytes)
+ current ap address (6 bytes)
+ ssid (variable)
+ supported rates (va
+ */
+}
+
+#endif
+
+void
+awi_rcv_ctl (sc, m)
+ struct awi_softc *sc;
+ struct mbuf *m;
+{
+ printf("%s: ctl\n", sc->sc_dev.dv_xname);
+}
+
+void
+awi_rcv_data (sc, m)
+ struct awi_softc *sc;
+ struct mbuf *m;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int8_t *llc;
+ u_int8_t *to, *from;
+ struct awi_mac_header *amhp;
+
+ sc->sc_scan_timer = awi_scan_keepalive; /* user data is as good
+ as a beacon as a keepalive.. */
+
+ amhp = mtod(m, struct awi_mac_header *);
+
+ /*
+ * we have: 4 bytes useless goo.
+ * 3 x 6 bytes MAC addresses.
+ * 2 bytes goo.
+ * 802.x LLC header, SNAP header, and data.
+ *
+ * for now, we fake up a "normal" ethernet header and feed
+ * this to the appropriate input routine.
+ */
+
+ llc = (u_int8_t *)(amhp+1);
+
+ if (amhp->awi_f2 & IEEEWL_FC2_TODS) {
+ printf("drop packet to DS\n");
+ goto drop;
+ }
+
+ to = amhp->awi_addr1;
+ if (amhp->awi_f2 & IEEEWL_FC2_FROMDS)
+ from = amhp->awi_addr3;
+ else
+ from = amhp->awi_addr2;
+ if (memcmp (llc, snap_magic, 6) != 0)
+ goto drop;
+
+ /* XXX overwrite llc with "from" address */
+ /* XXX overwrite llc-6 with "to" address */
+ bcopy(from, llc, ETHER_ADDR_LEN);
+ bcopy(to, llc-6, ETHER_ADDR_LEN);
+
+ m_adj(m, sizeof(struct awi_mac_header) + sizeof(struct awi_llc_header)
+ - sizeof(struct ether_header));
+
+#if NBPFILTER > 0
+ /*
+ * Pass packet to bpf if there is a listener.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+#if __NetBSD_Version__ > 104010000
+ m->m_flags |= M_HASFCS;
+ (*ifp->if_input)(ifp, m);
+#else
+ {
+ struct ether_header *eh;
+ eh = mtod(m, struct ether_header *);
+ m_adj(m, sizeof(*eh));
+ m_adj(m, -ETHER_CRC_LEN);
+ ether_input(ifp, eh, m);
+ }
+#endif
+ return;
+ drop:
+ m_freem(m);
+}
+
+void
+awi_rcv_mgt (sc, m, rxts, rssi)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ u_int32_t rxts;
+ u_int8_t rssi;
+{
+ u_int8_t subtype;
+ u_int8_t *framehdr, *mgthdr, *end, *timestamp;
+ struct awi_auth_hdr *auhp;
+ struct ifnet *ifp = sc->sc_ifp;
+
+#define IEEEWL_MGT_NATTR 10 /* XXX */
+ u_int8_t *attr[IEEEWL_MGT_NATTR];
+ u_int8_t attrlen[IEEEWL_MGT_NATTR];
+ u_int8_t *addr1, *addr2, *addr3;
+ u_int8_t *sa, *da, *bss;
+
+ framehdr = mtod(m, u_int8_t *);
+
+ /*
+ * mgt frame:
+ * 2 bytes frame goo
+ * 2 bytes duration
+ * 6 bytes a1
+ * 6 bytes a2
+ * 6 bytes a3
+ * 2 bytes seq control.
+ * --
+ * 24 bytes goo.
+ */
+
+ subtype = (framehdr[IEEEWL_FC] & IEEEWL_FC_SUBTYPE_MASK)
+ >> IEEEWL_FC_SUBTYPE_SHIFT;
+
+ addr1 = framehdr + 4; /* XXX */
+ addr2 = addr1+ETHER_ADDR_LEN;
+ addr3 = addr2+ETHER_ADDR_LEN;
+
+ /* XXX look at to/from DS bits here!! */
+ da = addr1;
+ sa = addr3;
+ bss = addr2;
+
+ framehdr = mtod(m, u_int8_t *);
+ end = framehdr + m->m_len;
+ end -= 4; /* trim TLV */
+
+ mgthdr = framehdr + 24; /* XXX magic */
+
+ switch (subtype) {
+
+ case IEEEWL_SUBTYPE_ASSOCRESP:
+ /*
+ * this acknowledges that the AP will be forwarding traffic
+ * for us..
+ *
+ * contains:
+ * cap info
+ * status code
+ * AId
+ * supported rates.
+ */
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: got assoc resp\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("assocresp", m->m_data, m->m_len);
+ }
+ awi_drvstate (sc, AWI_DRV_INFASSOC);
+ sc->sc_state = AWI_ST_RUNNING;
+ sc->sc_mgt_timer = AWI_ASSOC_REFRESH;
+ awi_set_timer(sc);
+ if (sc->sc_new_bss) {
+ printf("%s: associated with %s, SSID: %s\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_active_bss.bss_id),
+ sc->sc_active_bss.ssid);
+ sc->sc_new_bss = 0;
+ }
+
+ /* XXX set media status to "i see carrier" */
+ break;
+
+ case IEEEWL_SUBTYPE_REASSOCRESP:
+ /*
+ * this indicates that we've moved from one AP to another
+ * within the same DS.
+ */
+ printf("reassoc_resp\n");
+
+ break;
+
+ case IEEEWL_SUBTYPE_PROBEREQ:
+ /* discard */
+ break;
+
+ case IEEEWL_SUBTYPE_PROBERESP:
+ /*
+ * 8 bytes timestamp.
+ * 2 bytes beacon intvl.
+ * 2 bytes cap info.
+ * then tlv data..
+ */
+ timestamp = mgthdr;
+
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: got probe resp\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("proberesp", m->m_data, m->m_len);
+ }
+ /* now, into the tlv goo.. */
+ mgthdr += 12; /* XXX magic */
+ awi_parse_tlv (mgthdr, end, attr, attrlen, IEEEWL_MGT_NATTR);
+
+ if (attr[IEEEWL_MGT_TLV_SSID] &&
+ attr[IEEEWL_MGT_TLV_FHPARMS] &&
+ attrlen[IEEEWL_MGT_TLV_SSID] < AWI_SSID_LEN) {
+ struct awi_bss_binding *bp = NULL;
+ int i;
+
+ for (i=0; i< sc->sc_nbindings; i++) {
+ struct awi_bss_binding *bp1 =
+ &sc->sc_bindings[i];
+ if (memcmp(bp1->bss_id, bss, ETHER_ADDR_LEN) == 0) {
+ bp = bp1;
+ break;
+ }
+ }
+
+ if (bp == NULL && sc->sc_nbindings < NBND) {
+ bp = &sc->sc_bindings[sc->sc_nbindings++];
+ }
+ if (bp != NULL) {
+ u_int8_t *fhparms =
+ attr[IEEEWL_MGT_TLV_FHPARMS];
+
+ bp->sslen = attrlen[IEEEWL_MGT_TLV_SSID];
+
+ bcopy(attr[IEEEWL_MGT_TLV_SSID], bp->ssid,
+ bp->sslen);
+ bp->ssid[bp->sslen] = 0;
+
+ bcopy(bss, bp->bss_id, ETHER_ADDR_LEN);
+
+ /* XXX more magic numbers.. */
+ bp->dwell_time = fhparms[0] | (fhparms[1]<<8);
+ bp->chanset = fhparms[2];
+ bp->pattern = fhparms[3];
+ bp->index = fhparms[4];
+ bp->rssi = rssi;
+ bp->rxtime = rxts;
+ bcopy(timestamp, bp->bss_timestamp, 8);
+ }
+ }
+
+ break;
+
+ case IEEEWL_SUBTYPE_BEACON:
+ if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) ==
+ (IFF_DEBUG|IFF_LINK2)) {
+ printf("%s: beacon from %s\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(addr2));
+ awi_hexdump("beacon", m->m_data, m->m_len);
+ }
+ /*
+ * Note that AP is still alive so we don't have to go looking
+ * for one for a while.
+ *
+ * XXX Beacons from other AP's should be recorded for
+ * potential use if we lose this AP.. (also, may want
+ * to notice if rssi of new AP is significantly
+ * stronger than old one and jump ship..)
+ */
+ if ((sc->sc_state >= AWI_ST_SYNCED) &&
+ (memcmp (addr2, sc->sc_active_bss.bss_id,
+ ETHER_ADDR_LEN) == 0)) {
+ sc->sc_scan_timer = awi_scan_keepalive;
+ awi_set_timer(sc);
+ }
+
+ break;
+
+ case IEEEWL_SUBTYPE_DISSOC:
+ printf("dissoc\n");
+
+ break;
+
+ case IEEEWL_SUBTYPE_AUTH:
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: got auth\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("auth", m->m_data, m->m_len);
+ }
+ /*
+ * woohoo! somebody likes us!
+ */
+
+ auhp = (struct awi_auth_hdr *)mgthdr;
+
+ if ((auhp->awi_status[0] == 0) && (auhp->awi_status[1] == 0))
+ {
+ awi_drvstate (sc, AWI_DRV_INFAUTH);
+ sc->sc_state = AWI_ST_AUTHED;
+ awi_send_assocreq (sc);
+ }
+ break;
+
+ case IEEEWL_SUBTYPE_DEAUTH:
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: got deauth\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump("deauth", m->m_data, m->m_len);
+ }
+ sc->sc_state = AWI_ST_SYNCED;
+ sc->sc_new_bss = 1;
+ awi_send_authreq(sc);
+ break;
+ default:
+ printf("unk mgt subtype %x\n", subtype);
+ break;
+ }
+ m_freem(m); /* done.. */
+}
+
+
+
+
+
+/*
+ * Do 802.11 receive processing. "m" contains a receive frame;
+ * rxts is the local receive timestamp
+ */
+
+void
+awi_rcv (sc, m, rxts, rssi)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ u_int32_t rxts;
+ u_int8_t rssi;
+{
+ u_int8_t *framehdr;
+ u_int8_t framectl;
+
+ framehdr = mtod(m, u_int8_t *);
+
+ /*
+ * peek at first byte of frame header.
+ * check version subfield (must be zero)
+ * check type subfield (00 = mgt, 01 = ctl, 10 = data)
+ * check subtype field (next four bits)
+ */
+
+ /*
+ * Not counting WDS mode, the IEEE 802.11 frame header format
+ * has *three* MAC addresses.
+ * (source, destination, and BSS).
+ *
+ * The BSS indicates which wireless "cable segment" we're part of;
+ * we discover this dynamically..
+ *
+ * Not content to put them in a fixed order, the exact
+ * ordering of these addresses depends on other attribute bits
+ * in the frame control word!
+ *
+ * an alternate presentation which is more self-consistent:
+ * address 1 is the "wireless destination" -- either the
+ * station address,
+ * for wireless->wireless traffic, or the BSS id of an AP.
+ *
+ * address 2 is the "wireless source" -- either the
+ * station address of a wireless node, or the BSS id of an AP.
+ *
+ * address 3 is the "other address" -- for STA->AP, the
+ * eventual destination; for AP->STA, the original source, and
+ * for ad-hoc mode, the BSS id..
+ */
+
+ framectl = framehdr[IEEEWL_FC];
+
+ if ((framectl & IEEEWL_FC_VERS_MASK) != IEEEWL_FC_VERS) {
+ printf("wrong vers. drop");
+ goto drop;
+ }
+
+ switch (framectl & IEEEWL_FC_TYPE_MASK) {
+ case IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT:
+ awi_rcv_mgt (sc, m, rxts, rssi);
+ m = 0;
+ break;
+
+ case IEEEWL_FC_TYPE_DATA << IEEEWL_FC_TYPE_SHIFT:
+ awi_rcv_data (sc, m);
+ m = 0;
+ break;
+
+ case IEEEWL_FC_TYPE_CTL << IEEEWL_FC_TYPE_SHIFT:
+ awi_rcv_ctl (sc, m);
+ default:
+ goto drop;
+ }
+
+ drop:
+ if (m) m_freem(m);
+}
+
+void
+awi_copy_rxd (sc, cur, rxd)
+ struct awi_softc *sc;
+ u_int32_t cur;
+ struct awi_rxd *rxd;
+{
+ if (sc->sc_ifp->if_flags & IFF_LINK0) {
+ printf("%x: ", cur);
+ awi_card_hexdump(sc, "rxd", cur, AWI_RXD_SIZE);
+ }
+
+ rxd->next = awi_read_4(sc, cur + AWI_RXD_NEXT);
+ rxd->state = awi_read_1(sc, cur + AWI_RXD_HOST_DESC_STATE);
+ rxd->len = awi_read_2 (sc, cur + AWI_RXD_LEN);
+ rxd->rate = awi_read_1 (sc, cur + AWI_RXD_RATE);
+ rxd->rssi = awi_read_1 (sc, cur + AWI_RXD_RSSI);
+ rxd->index = awi_read_1 (sc, cur + AWI_RXD_INDEX);
+ rxd->frame = awi_read_4 (sc, cur + AWI_RXD_START_FRAME);
+ rxd->rxts = awi_read_4 (sc, cur + AWI_RXD_LOCALTIME);
+
+ /*
+ * only the low order bits of "frame" and "next" are valid.
+ * (the documentation doesn't mention this).
+ */
+ rxd->frame &= 0xffff;
+ rxd->next &= (0xffff | AWI_RXD_NEXT_LAST);
+
+ /*
+ * XXX after masking, sanity check that rxd->frame and
+ * rxd->next lie within the receive area.
+ */
+ if (sc->sc_ifp->if_flags & IFF_LINK0) {
+ printf("nxt %x frame %x state %b len %d\n",
+ rxd->next, rxd->frame,
+ rxd->state, AWI_RXD_ST_BITS,
+ rxd->len);
+ }
+}
+
+
+u_int32_t
+awi_parse_rxd (sc, cur, rxd)
+ struct awi_softc *sc;
+ u_int32_t cur;
+ struct awi_rxd *rxd;
+{
+ struct mbuf *top;
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int32_t next;
+
+ if ((rxd->state & AWI_RXD_ST_CONSUMED) == 0) {
+ if (ifp->if_flags & IFF_LINK1) {
+ int xx = awi_read_1(sc, rxd->frame);
+ if (xx != (IEEEWL_FC_VERS |
+ (IEEEWL_FC_TYPE_MGT<<IEEEWL_FC_TYPE_SHIFT) |
+ (IEEEWL_SUBTYPE_BEACON << IEEEWL_FC_SUBTYPE_SHIFT))) {
+ char bitbuf[64];
+ printf("floosh: %d state ", sc->sc_flushpkt);
+ snprintf(bitbuf, sizeof bitbuf, "%b",
+ rxd->state, AWI_RXD_ST_BITS);
+ awi_card_hexdump(sc, bitbuf, rxd->frame,
+ rxd->len);
+ }
+
+ }
+ if ((sc->sc_flushpkt == 0) &&
+ (sc->sc_nextpkt == NULL)) {
+ MGETHDR(top, M_DONTWAIT, MT_DATA);
+
+ if (top == NULL) {
+ sc->sc_flushpkt = 1;
+ sc->sc_m = NULL;
+ sc->sc_mptr = NULL;
+ sc->sc_mleft = 0;
+ } else {
+ if (rxd->len >= MINCLSIZE)
+ MCLGET(top, M_DONTWAIT);
+
+ top->m_pkthdr.rcvif = ifp;
+ top->m_pkthdr.len = 0;
+ top->m_len = 0;
+
+ sc->sc_mleft = (top->m_flags & M_EXT) ?
+ MCLBYTES : MHLEN;
+ sc->sc_mptr = mtod(top, u_int8_t *);
+ sc->sc_m = top;
+ sc->sc_nextpkt = top;
+ }
+ }
+ if (sc->sc_flushpkt == 0) {
+ /* copy data into mbuf */
+
+ while (rxd->len > 0) {
+ int nmove = min (rxd->len, sc->sc_mleft);
+
+ awi_read_bytes (sc, rxd->frame, sc->sc_mptr,
+ nmove);
+
+ rxd->len -= nmove;
+ rxd->frame += nmove;
+ sc->sc_mleft -= nmove;
+ sc->sc_mptr += nmove;
+
+ sc->sc_nextpkt->m_pkthdr.len += nmove;
+ sc->sc_m->m_len += nmove;
+
+ if ((rxd->len > 0) && (sc->sc_mleft == 0)) {
+ struct mbuf *m1;
+
+ /* Get next mbuf.. */
+ MGET(m1, M_DONTWAIT, MT_DATA);
+ if (m1 == NULL) {
+ m_freem(sc->sc_nextpkt);
+ sc->sc_nextpkt = NULL;
+ sc->sc_flushpkt = 1;
+ sc->sc_m = NULL;
+ sc->sc_mptr = NULL;
+ sc->sc_mleft = 0;
+ break;
+ }
+ sc->sc_m->m_next = m1;
+ sc->sc_m = m1;
+ m1->m_len = 0;
+
+ sc->sc_mleft = MLEN;
+ sc->sc_mptr = mtod(m1, u_int8_t *);
+ }
+ }
+ }
+ if (rxd->state & AWI_RXD_ST_LF) {
+ if (sc->sc_flushpkt) {
+ sc->sc_flushpkt = 0;
+ }
+ else if (sc->sc_nextpkt != NULL) {
+ struct mbuf *m = sc->sc_nextpkt;
+ sc->sc_nextpkt = NULL;
+ sc->sc_flushpkt = 0;
+ sc->sc_m = NULL;
+ sc->sc_mptr = NULL;
+ sc->sc_mleft = 0;
+ awi_rcv(sc, m, rxd->rxts, rxd->rssi);
+ }
+ }
+ }
+ rxd->state |= AWI_RXD_ST_CONSUMED;
+ awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state);
+ next = cur;
+ if ((rxd->next & AWI_RXD_NEXT_LAST) == 0) {
+ rxd->state |= AWI_RXD_ST_OWN;
+ awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state);
+ next = rxd->next;
+ }
+ return next;
+}
+
+void
+awi_dump_rxchain (sc, what, descr)
+ struct awi_softc *sc;
+ char *what;
+ u_int32_t *descr;
+{
+ u_int32_t cur, next;
+ struct awi_rxd rxd;
+
+ cur = *descr;
+
+ if (cur & AWI_RXD_NEXT_LAST)
+ return;
+
+ do {
+ awi_copy_rxd(sc, cur, &rxd);
+
+ next = awi_parse_rxd(sc, cur, &rxd);
+ if ((rxd.state & AWI_RXD_ST_OWN) && (next == cur)) {
+ printf("%s: loop in rxd list?",
+ sc->sc_dev.dv_xname);
+ break;
+ }
+ cur = next;
+ } while (rxd.state & AWI_RXD_ST_OWN);
+
+ *descr = cur;
+}
+
+void
+awi_rxint (sc)
+ struct awi_softc *sc;
+{
+ awi_dump_rxchain (sc, "mgt", &sc->sc_rx_mgt_desc);
+ awi_dump_rxchain (sc, "data", &sc->sc_rx_data_desc);
+}
+
+void
+awi_init_txd (sc, tx, flag, len, rate)
+ struct awi_softc *sc;
+ int tx;
+ int flag;
+ int len;
+ int rate;
+{
+ u_int32_t txdbase = sc->sc_txd[tx].descr;
+ u_int32_t framebase = sc->sc_txd[tx].frame;
+ u_int32_t nextbase = sc->sc_txd[(tx+1)%sc->sc_ntxd].descr;
+
+ awi_write_4 (sc, txdbase + AWI_TXD_START, framebase);
+ awi_write_4 (sc, txdbase + AWI_TXD_NEXT, nextbase);
+ awi_write_4 (sc, txdbase + AWI_TXD_LENGTH, len);
+ awi_write_1 (sc, txdbase + AWI_TXD_RATE, rate);
+ /* zeroize tail end of txd */
+ awi_write_4 (sc, txdbase + AWI_TXD_NDA, 0);
+ awi_write_4 (sc, txdbase + AWI_TXD_NRA, 0);
+ /* Init state last; firmware keys off of this to know when to start tx */
+ awi_write_1 (sc, txdbase + AWI_TXD_STATE, flag);
+}
+
+void
+awi_init_txdescr (sc)
+ struct awi_softc *sc;
+{
+ int i;
+ u_int32_t offset = sc->sc_txbase;
+
+ sc->sc_txfirst = 0;
+ sc->sc_txnext = 0;
+
+ sc->sc_ntxd = sc->sc_txlen / (AWI_FRAME_SIZE + AWI_TXD_SIZE);
+ if (sc->sc_ntxd > NTXD) {
+ sc->sc_ntxd = NTXD;
+ printf("oops, no, only %d\n", sc->sc_ntxd);
+ }
+
+ /* Allocate TXD's */
+ for (i=0; i<sc->sc_ntxd; i++) {
+ sc->sc_txd[i].descr = offset;
+ offset += AWI_TXD_SIZE;
+ }
+ /* now, allocate buffer space to each txd.. */
+ for (i=0; i<sc->sc_ntxd; i++) {
+ sc->sc_txd[i].frame = offset;
+ sc->sc_txd[i].len = AWI_FRAME_SIZE;
+ offset += AWI_FRAME_SIZE;
+
+ }
+
+ /* now, initialize the TX descriptors into a circular linked list. */
+
+ for (i= 0; i<sc->sc_ntxd; i++) {
+ awi_init_txd(sc, i, 0, 0, 0);
+ }
+}
+
+void
+awi_txint (sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ int txfirst;
+
+ sc->sc_tx_timer = 0;
+
+ txfirst = sc->sc_txfirst;
+ while (sc->sc_txpending > 0) {
+ u_int8_t flags = awi_read_1 (sc, sc->sc_txd[txfirst].descr +
+ AWI_TXD_STATE);
+
+ if (flags & AWI_TXD_ST_OWN)
+ break;
+
+ if (flags & AWI_TXD_ST_ERROR) {
+ /* increment oerrs */;
+ }
+
+ txfirst = (txfirst + 1) % sc->sc_ntxd;
+ sc->sc_txpending--;
+ }
+
+ sc->sc_txfirst = txfirst;
+
+ if (sc->sc_txpending < sc->sc_ntxd)
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * see which descriptors are done..
+ */
+
+ awi_start(sc->sc_ifp);
+}
+
+
+
+
+/*
+ * device interrupt routine.
+ *
+ * lock out MAC
+ * loop:
+ * look at intr status, DTRT.
+ *
+ * on tx done, reclaim free buffers from tx, call start.
+ * on rx done, look at rx queue, copy to mbufs, mark as free,
+ * hand to ether media layer rx routine.
+ * on cmd done, call cmd cmpl continuation.
+ *
+ */
+
+int
+awi_intr(arg)
+ void *arg;
+{
+ struct awi_softc *sc = arg;
+ int handled = 0;
+
+ if (sc->sc_state == AWI_ST_OFF) {
+ u_int8_t intstate = awi_read_intst (sc);
+ return intstate != 0;
+ }
+
+ /* disable power down, (and implicitly ack interrupt) */
+ am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
+ awi_write_1(sc, AWI_DIS_PWRDN, 1);
+
+ for (;;) {
+ u_int8_t intstate = awi_read_intst (sc);
+
+ if (!intstate)
+ break;
+
+ handled = 1;
+
+ if (intstate & AWI_INT_RX)
+ awi_rxint(sc);
+
+ if (intstate & AWI_INT_TX)
+ awi_txint(sc);
+
+ if (intstate & AWI_INT_CMD) {
+ u_int8_t status;
+
+ if (!(sc->sc_flags & AWI_FL_CMD_INPROG))
+ printf("%s: no command in progress?\n",
+ sc->sc_dev.dv_xname);
+ status = awi_read_1(sc, AWI_CMD_STATUS);
+ awi_write_1 (sc, AWI_CMD, 0);
+ sc->sc_cmd_timer = 0;
+ sc->sc_flags &= ~AWI_FL_CMD_INPROG;
+
+ if (sc->sc_completion)
+ (*sc->sc_completion)(sc, status);
+ }
+ if (intstate & AWI_INT_SCAN_CMPLT) {
+ if (sc->sc_flags & AWI_FL_CMD_INPROG) {
+ panic("i can't take it any more");
+ }
+ /*
+ * scan completion heuristic..
+ */
+ if ((sc->sc_nbindings >= NBND)
+ || ((sc->sc_scan_timer == 0) &&
+ (sc->sc_nbindings > 0)))
+ awi_try_sync(sc);
+ else
+ awi_scan_next(sc);
+ }
+
+ }
+ /* reenable power down */
+ am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
+ awi_write_1(sc, AWI_DIS_PWRDN, 0);
+
+ return handled;
+}
+
+/*
+ * flush tx queues..
+ */
+
+void
+awi_flush(sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+
+ do {
+ IF_DEQUEUE (&sc->sc_mgtq, m);
+ m_freem(m);
+ } while (m != NULL);
+
+ do {
+ IF_DEQUEUE (&ifp->if_snd, m);
+ m_freem(m);
+ } while (m != NULL);
+}
+
+
+
+/*
+ * device stop routine
+ */
+
+void
+awi_stop(sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ awi_flush(sc);
+
+ /* Turn off timer.. */
+ ifp->if_timer = 0;
+ sc->sc_state = AWI_ST_OFF;
+ (void) awi_read_intst (sc);
+ /*
+ * XXX for pcmcia, there's no point in disabling the device,
+ * as it's about to be powered off..
+ * for non-PCMCIA attachments, we should, however, stop
+ * the receiver and transmitter here.
+ */
+}
+
+/*
+ * Watchdog routine, triggered by timer.
+ * This does periodic maintainance-type tasks on the interface.
+ */
+
+void
+awi_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct awi_softc *sc = ifp->if_softc;
+ u_int8_t test;
+ int i;
+
+ if (sc->sc_state == AWI_ST_OFF)
+ /* nothing to do */
+ return;
+ else if (sc->sc_state == AWI_ST_INSANE) {
+ awi_reset(sc);
+ return;
+ } else if (sc->sc_state == AWI_ST_SELFTEST) {
+ /* check for selftest completion.. */
+ test = awi_read_1(sc, AWI_SELFTEST);
+ if ((test & 0xf0) == 0xf0) { /* XXX magic numbers */
+ if (test == AWI_SELFTEST_PASSED) {
+ awi_init_1(sc);
+ } else {
+ printf("%s: selftest failed (code %x)\n",
+ sc->sc_dev.dv_xname, test);
+ awi_reset(sc);
+ }
+ }
+ sc->sc_selftest_tries++;
+ /* still running. try again on next tick */
+ if (sc->sc_selftest_tries < 5) {
+ ifp->if_timer = 1;
+ } else {
+ /*
+ * XXX should power down card, wait 1s, power it back
+ * up again..
+ */
+ printf("%s: device failed to complete selftest (code %x)\n",
+ sc->sc_dev.dv_xname, test);
+ ifp->if_timer = 0;
+ }
+ return;
+ }
+
+
+ /*
+ * command timer: if it goes to zero, device failed to respond.
+ * boot to the head.
+ */
+ if (sc->sc_cmd_timer) {
+ sc->sc_cmd_timer--;
+ if (sc->sc_cmd_timer == 0) {
+ sc->sc_flags &= ~AWI_FL_CMD_INPROG;
+
+ printf("%s: timeout waiting for command completion\n",
+ sc->sc_dev.dv_xname);
+ test = awi_read_1(sc, AWI_CMD_STATUS);
+ printf("%s: cmd status: %x\n", sc->sc_dev.dv_xname, test);
+ test = awi_read_1(sc, AWI_CMD);
+ printf("%s: cmd: %x\n", sc->sc_dev.dv_xname, test);
+ awi_card_hexdump(sc, "CSB", AWI_CSB, 16);
+ awi_reset(sc);
+ return;
+ }
+ }
+ /*
+ * Transmit timer. If it goes to zero, device failed to deliver a
+ * tx complete interrupt. boot to the head.
+ */
+ if (sc->sc_tx_timer) {
+ sc->sc_tx_timer--;
+ if ((sc->sc_tx_timer == 0) && (sc->sc_txpending)) {
+ awi_card_hexdump(sc, "CSB", AWI_CSB, 16);
+ printf("%s: transmit timeout\n", sc->sc_dev.dv_xname);
+ awi_card_hexdump(sc, "last_txd", AWI_LAST_TXD, 5*4);
+ for (i=0; i<sc->sc_ntxd; i++) {
+ awi_card_hexdump(sc, "txd",
+ sc->sc_txd[i].descr, AWI_TXD_SIZE);
+ }
+ awi_reset(sc);
+ return;
+ }
+ }
+ /*
+ * Scan timer.
+ * When synched, this is used to notice when we've stopped
+ * receiving beacons and should attempt to resynch.
+ *
+ * When unsynched, this is used to notice if we've received an
+ * interesting probe response and should synch up.
+ */
+
+ if (sc->sc_scan_timer) {
+ sc->sc_scan_timer--;
+ if (sc->sc_scan_timer == 0) {
+ if (sc->sc_state == AWI_ST_SCAN) {
+ /*
+ * XXX what if device fails to deliver
+ * a scan-completion interrupt?
+ */
+ } else {
+ printf("%s: no recent beacon from %s; rescanning\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_active_bss.bss_id));
+ awi_restart_scan(sc);
+ }
+ }
+ }
+
+ /*
+ * Management timer. Used to know when to send auth
+ * requests and associate requests.
+ */
+ if (sc->sc_mgt_timer) {
+ sc->sc_mgt_timer--;
+ if (sc->sc_mgt_timer == 0) {
+ switch (sc->sc_state)
+ {
+ case AWI_ST_SYNCED:
+ case AWI_ST_RUNNING:
+ sc->sc_state = AWI_ST_SYNCED;
+ awi_send_authreq(sc);
+ break;
+ case AWI_ST_AUTHED:
+ awi_send_assocreq(sc);
+ break;
+ default:
+ printf("weird state for mgt timeout!\n");
+ break;
+ }
+ }
+ }
+ awi_set_timer(sc);
+}
+
+void
+awi_set_mc (sc)
+ struct awi_softc *sc;
+{
+ /* XXX not implemented yet.. */
+}
+
+/*
+ * init routine
+ */
+
+/*
+ * ioctl routine
+ * SIOCSIFADDR sets IFF_UP
+ * SIOCIFMTU
+ * SIOCSIFFLAGS
+ * SIOCADDMULTI/SIOCDELMULTI
+ */
+
+int
+awi_ioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct awi_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ if ((error = awi_enable(sc)) != 0)
+ break;
+
+ ifp->if_flags |= IFF_UP;
+
+ /* XXX other AF support: inet6, NS, ... */
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ arp_ifinit(&sc->sc_ec, ifa);
+ break;
+#endif
+ default:
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (sc->sc_state != AWI_ST_OFF)) {
+ /*
+ * If interface is marked down and it is enabled, then
+ * stop it.
+ */
+ ifp->if_flags &= ~IFF_RUNNING;
+ awi_stop(sc);
+ awi_disable(sc);
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ if ((error = awi_enable(sc)) != 0)
+ break;
+ } else if ((ifp->if_flags & IFF_UP) != 0) {
+ /*
+ * Deal with other flags that change hardware
+ * state, i.e. IFF_PROMISC.
+ */
+ awi_set_mc(sc);
+ }
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ec) :
+ ether_delmulti(ifr, &sc->sc_ec);
+ if (error == ENETRESET) {
+ error = 0;
+ awi_set_mc(sc);
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+
+ }
+ splx(s);
+ return error;
+
+}
+
+int awi_activate (self, act)
+ struct device *self;
+ enum devact act;
+{
+ int s = splnet();
+ panic("awi_activate");
+
+#if 0
+ switch (act) {
+ case DVACT_ACTIVATE:
+ rv = EOPNOTSUPP;
+ break;
+
+ case DVACT_DEACTIVATE:
+#ifdef notyet
+ /* First, kill off the interface. */
+ if_detach(sc->sc_ethercom.ec_if);
+#endif
+
+ /* Now disable the interface. */
+ awidisable(sc);
+ break;
+ }
+#endif
+ splx(s);
+
+}
+
+int
+awi_drop_output (ifp, m0, dst, rt0)
+ struct ifnet *ifp;
+ struct mbuf *m0;
+ struct sockaddr *dst;
+ struct rtentry *rt0;
+{
+ m_freem(m0);
+ return 0;
+}
+
+void
+awi_drop_input (ifp, m0)
+ struct ifnet *ifp;
+ struct mbuf *m0;
+{
+ m_freem(m0);
+}
+
+int awi_attach (sc, macaddr)
+ struct awi_softc *sc;
+ u_int8_t *macaddr;
+{
+ struct ifnet *ifp = &sc->sc_ec.ac_if;
+ u_int8_t version[AWI_BANNER_LEN];
+
+ sc->sc_ifp = ifp;
+ sc->sc_nextpkt = NULL;
+ sc->sc_m = NULL;
+ sc->sc_mptr = NULL;
+ sc->sc_mleft = 0;
+ sc->sc_flushpkt = 0;
+
+ awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN);
+ printf("%s: firmware %s\n", sc->sc_dev.dv_xname, version);
+
+ bcopy(macaddr, sc->sc_my_addr, ETHER_ADDR_LEN);
+ printf("%s: 802.11 address %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_my_addr));
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_start = awi_start;
+ ifp->if_ioctl = awi_ioctl;
+ ifp->if_watchdog = awi_watchdog;
+ ifp->if_mtu = ETHERMTU;
+ /* XXX simplex may not be correct here.. */
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+
+ sc->sc_mgtq.ifq_maxlen = 5;
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ ifp->if_hdrlen = 32; /* 802.11 headers are bigger.. */
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 0;
+}
+
+void
+awi_zero (sc, from, to)
+ struct awi_softc *sc;
+ u_int32_t from, to;
+{
+ u_int32_t i;
+ for (i=from; i<to; i++)
+ awi_write_1(sc, i, 0);
+}
+
+void
+awi_init (sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ sc->sc_scan_duration = 100; /* scan for 100ms */
+
+ /*
+ * Maybe we should randomize these....
+ */
+ sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN;
+ sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN;
+
+ sc->sc_flags &= ~AWI_FL_CMD_INPROG;
+
+ ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
+ ifp->if_timer = 0;
+
+ sc->sc_cmd_timer = 0;
+ sc->sc_tx_timer = 0;
+ sc->sc_mgt_timer = 0;
+ sc->sc_scan_timer = 0;
+
+ sc->sc_nbindings = 0;
+
+ /*
+ * this reset sequence doesn't seem to always do the trick.
+ * hard-power-cycling the card may do it..
+ */
+
+ /*
+ * reset the hardware, just to be sure.
+ * (bring out the big hammer here..)
+ */
+ /* XXX insert delay here? */
+
+ am79c930_gcr_setbits (&sc->sc_chip, AM79C930_GCR_CORESET);
+ delay(10); /* XXX arbitrary value */
+
+ /*
+ * clear control memory regions (firmware should do this but...)
+ */
+ awi_zero(sc, AWI_LAST_TXD, AWI_BUFFERS);
+
+ awi_drvstate(sc, AWI_DRV_RESET);
+ sc->sc_selftest_tries = 0;
+
+ /*
+ * release reset
+ */
+ am79c930_gcr_clearbits (&sc->sc_chip, AM79C930_GCR_CORESET);
+ delay(10);
+
+ sc->sc_state = AWI_ST_SELFTEST;
+ ifp->if_timer = 1;
+
+}
+
+void
+awi_cmd (sc, opcode)
+ struct awi_softc *sc;
+ u_int8_t opcode;
+{
+ if (sc->sc_flags & AWI_FL_CMD_INPROG)
+ panic("%s: command reentered", sc->sc_dev.dv_xname);
+
+ sc->sc_flags |= AWI_FL_CMD_INPROG;
+
+ /* issue test-interface command */
+ awi_write_1(sc, AWI_CMD, opcode);
+
+ awi_write_1(sc, AWI_CMD_STATUS, 0);
+
+ sc->sc_cmd_timer = 2;
+ awi_set_timer(sc);
+}
+
+void
+awi_cmd_test_if (sc)
+ struct awi_softc *sc;
+{
+ awi_cmd (sc, AWI_CMD_NOP);
+}
+
+void
+awi_cmd_get_mib (sc, var, offset, len)
+ struct awi_softc *sc;
+ u_int8_t var;
+ u_int8_t offset;
+ u_int8_t len;
+{
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, var);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, len);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, offset);
+
+ awi_cmd (sc, AWI_CMD_GET_MIB);
+}
+
+void
+awi_cmd_txinit (sc)
+ struct awi_softc *sc;
+{
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_DATA, sc->sc_txbase);
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_MGT, 0);
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_BCAST, 0);
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_PS, 0);
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_CF, 0);
+
+ awi_cmd (sc, AWI_CMD_INIT_TX);
+}
+
+int awi_max_chan = -1;
+int awi_min_chan = 1000;
+int awi_max_pattern = -1;
+int awi_min_pattern = 1000;
+
+
+/*
+ * timeout-driven routine: complete device init once device has passed
+ * selftest.
+ */
+
+void awi_init_1 (sc)
+ struct awi_softc *sc;
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ awi_intrinit(sc);
+
+ sc->sc_state = AWI_ST_IFTEST;
+
+ if (ifp->if_flags & IFF_DEBUG) {
+ awi_card_hexdump(sc, "init_1 CSB", AWI_CSB, 16);
+ sc->sc_completion = awi_mibdump;
+ } else
+ sc->sc_completion = awi_init_2;
+
+ sc->sc_curmib = 0;
+
+ awi_cmd_test_if (sc);
+}
+
+void awi_mibdump (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ u_int8_t mibblk[256];
+
+ if (status != AWI_STAT_OK) {
+ printf("%s: pre-mibread failed (card unhappy?)\n",
+ sc->sc_dev.dv_xname);
+ awi_reset(sc);
+ return;
+ }
+
+ if (sc->sc_curmib != 0) {
+ awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA,
+ mibblk, 72);
+ awi_hexdump("mib", mibblk, 72);
+ }
+ if (sc->sc_curmib > AWI_MIB_LAST) {
+ awi_init_2 (sc, status);
+ } else {
+ sc->sc_completion = awi_mibdump;
+ printf("mib %d\n", sc->sc_curmib);
+ awi_cmd_get_mib (sc, sc->sc_curmib, 0, 30);
+ sc->sc_curmib++;
+ /* skip over reserved MIB's.. */
+ if ((sc->sc_curmib == 1) || (sc->sc_curmib == 6))
+ sc->sc_curmib++;
+ }
+}
+
+
+/*
+ * called on completion of test-interface command in first-stage init.
+ */
+
+void awi_init_2 (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ /* did it succeed? */
+ if (status != AWI_STAT_OK) {
+ printf("%s: nop failed (card unhappy?)\n",
+ sc->sc_dev.dv_xname);
+ awi_reset(sc);
+ }
+
+ sc->sc_state = AWI_ST_MIB_GET;
+ sc->sc_completion = awi_init_read_bufptrs_done;
+
+ awi_cmd_get_mib (sc, AWI_MIB_LOCAL, 0, AWI_MIB_LOCAL_SIZE);
+}
+
+void awi_init_read_bufptrs_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ if (status != AWI_STAT_OK) {
+ printf("%s: get_mib failed (card unhappy?)\n",
+ sc->sc_dev.dv_xname);
+ awi_reset(sc);
+ }
+
+ sc->sc_txbase = awi_read_4 (sc,
+ AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_OFFSET);
+ sc->sc_txlen = awi_read_4 (sc,
+ AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_SIZE);
+ sc->sc_rxbase = awi_read_4 (sc,
+ AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_OFFSET);
+ sc->sc_rxlen = awi_read_4 (sc,
+ AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_SIZE);
+ /*
+ * XXX consider repartitioning buffer space to allow for
+ * more efficient usage.
+ * 6144: 3 txds, 1476 waste (current partition)
+ * better splits:
+ * 4864: 3 txds, 196 waste
+ * 6400: 4 txds, 176 waste
+ * 7936: 5 txds, 156 waste
+ */
+
+#if 0
+ printf("tx offset: %x\n", sc->sc_txbase);
+ printf("tx size: %x\n", sc->sc_txlen);
+ printf("rx offset: %x\n", sc->sc_rxbase);
+ printf("rx size: %x\n", sc->sc_rxlen);
+#endif
+
+ sc->sc_state = AWI_ST_MIB_SET;
+ awi_cmd_set_notap(sc);
+}
+
+void awi_cmd_set_notap (sc)
+ struct awi_softc *sc;
+{
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX,
+ AWI_MIB_LOCAL_ACTING_AS_AP);
+
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0);
+ sc->sc_completion = awi_cmd_set_notap_done;
+ awi_cmd (sc, AWI_CMD_SET_MIB);
+}
+
+void awi_cmd_set_notap_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: set_infra failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+ awi_cmd_set_infra (sc);
+}
+
+void awi_cmd_set_infra (sc)
+ struct awi_softc *sc;
+{
+
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX,
+ AWI_MIB_LOCAL_INFRA_MODE);
+
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 1);
+ sc->sc_completion = awi_cmd_set_infra_done;
+ awi_cmd (sc, AWI_CMD_SET_MIB);
+}
+
+void awi_cmd_set_infra_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+#if 0
+ printf("set_infra done\n");
+#endif
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: set_infra failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+#if 0
+ printf("%s: set_infra done\n", sc->sc_dev.dv_xname);
+#endif
+ awi_cmd_set_allmulti (sc);
+}
+
+void awi_cmd_set_allmulti (sc)
+ struct awi_softc *sc;
+{
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX,
+ AWI_MIB_LOCAL_FILTMULTI);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0);
+ sc->sc_completion = awi_cmd_set_allmulti_done;
+ awi_cmd (sc, AWI_CMD_SET_MIB);
+}
+
+void awi_cmd_set_allmulti_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: set_almulti_done failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+ awi_cmd_set_promisc (sc);
+}
+
+void awi_cmd_set_promisc (sc)
+ struct awi_softc *sc;
+{
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX,
+ AWI_MIB_MAC_PROMISC);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); /* XXX */
+ sc->sc_completion = awi_cmd_set_promisc_done;
+ awi_cmd (sc, AWI_CMD_SET_MIB);
+}
+
+void awi_cmd_set_promisc_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+#if 0
+ printf("set promisc_done\n");
+#endif
+
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: set_promisc_done failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+#if 0
+ printf("%s: set_promisc done\n", sc->sc_dev.dv_xname);
+#endif
+
+ awi_init_txdescr(sc);
+
+ sc->sc_state = AWI_ST_TXINIT;
+ sc->sc_completion = awi_init_4;
+ awi_cmd_txinit(sc);
+}
+
+void
+awi_init_4 (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+#if 0
+ printf("%s: awi_init_4, st %x\n", sc->sc_dev.dv_xname, status);
+ awi_card_hexdump(sc, "init_4 CSB", AWI_CSB, 16);
+#endif
+
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: init_tx failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+
+ sc->sc_state = AWI_ST_RXINIT;
+ sc->sc_completion = awi_init_5;
+
+ awi_cmd (sc, AWI_CMD_INIT_RX);
+}
+
+void awi_init_5 (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+#if 0
+ struct ifnet *ifp = sc->sc_ifp;
+#endif
+
+#if 0
+ printf("%s: awi_init_5, st %x\n", sc->sc_dev.dv_xname, status);
+ awi_card_hexdump(sc, "init_5 CSB", AWI_CSB, 16);
+#endif
+
+ if (status != AWI_STAT_OK) {
+ printf("%s: init_rx failed (card unhappy?)\n",
+ sc->sc_dev.dv_xname);
+ awi_reset(sc);
+ return;
+ }
+
+ sc->sc_rx_data_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC);
+ sc->sc_rx_mgt_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC);
+
+#if 0
+ printf("%s: data desc %x, mgt desc %x\n", sc->sc_dev.dv_xname,
+ sc->sc_rx_data_desc, sc->sc_rx_mgt_desc);
+#endif
+ awi_restart_scan(sc);
+}
+
+void awi_restart_scan (sc)
+ struct awi_softc *sc;
+{
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: starting scan\n", sc->sc_dev.dv_xname);
+ }
+ sc->sc_scan_timer = 2;
+ sc->sc_mgt_timer = 0;
+ awi_set_timer(sc);
+
+ sc->sc_nbindings = 0;
+ sc->sc_state = AWI_ST_SCAN;
+ awi_drvstate (sc, AWI_DRV_INFSC);
+ awi_cmd_scan (sc);
+}
+
+void
+awi_cmd_scan (sc)
+ struct awi_softc *sc;
+{
+
+ awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION,
+ sc->sc_scan_duration);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
+ sc->sc_scan_chanset);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN,
+ sc->sc_scan_pattern);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0);
+
+ sc->sc_completion = awi_cmd_scan_done;
+ awi_cmd (sc, AWI_CMD_SCAN);
+}
+
+void
+awi_cmd_scan_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+#if 0
+ int erroffset;
+#endif
+ if (status == AWI_STAT_OK) {
+ if (sc->sc_scan_chanset > awi_max_chan)
+ awi_max_chan = sc->sc_scan_chanset;
+ if (sc->sc_scan_chanset < awi_min_chan)
+ awi_min_chan = sc->sc_scan_chanset;
+ if (sc->sc_scan_pattern > awi_max_pattern)
+ awi_max_pattern = sc->sc_scan_pattern;
+ if (sc->sc_scan_pattern < awi_min_pattern)
+ awi_min_pattern = sc->sc_scan_pattern;
+
+ return;
+ }
+#if 0
+ erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: scan failed; erroffset %d\n", sc->sc_dev.dv_xname,
+ erroffset);
+#endif
+ /* wait for response or scan timeout.. */
+}
+
+void
+awi_scan_next (sc)
+ struct awi_softc *sc;
+{
+ sc->sc_scan_pattern++;
+ if (sc->sc_scan_pattern > IEEEWL_FH_PATTERN_MAX) {
+ sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN;
+
+ sc->sc_scan_chanset++;
+ if (sc->sc_scan_chanset > IEEEWL_FH_CHANSET_MAX)
+ sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN;
+ }
+#if 0
+ printf("scan: pattern %x chanset %x\n", sc->sc_scan_pattern,
+ sc->sc_scan_chanset);
+#endif
+
+ awi_cmd_scan(sc);
+}
+
+void
+awi_try_sync (sc)
+ struct awi_softc *sc;
+{
+ int max_rssi = 0, best = 0;
+ int i;
+ struct awi_bss_binding *bp = NULL;
+
+ awi_flush(sc);
+
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: looking for best of %d\n",
+ sc->sc_dev.dv_xname, sc->sc_nbindings);
+ }
+ /* pick one with best rssi */
+ for (i=0; i<sc->sc_nbindings; i++) {
+ bp = &sc->sc_bindings[i];
+
+ if (bp->rssi > max_rssi) {
+ max_rssi = bp->rssi;
+ best = i;
+ }
+ }
+
+ if (bp == NULL) {
+ printf("%s: no beacons seen\n", sc->sc_dev.dv_xname);
+ awi_scan_next(sc);
+ return;
+ }
+
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: best %d\n", sc->sc_dev.dv_xname, best);
+ }
+ sc->sc_scan_timer = awi_scan_keepalive;
+
+ bp = &sc->sc_bindings[best];
+ bcopy(bp, &sc->sc_active_bss, sizeof(*bp));
+ sc->sc_new_bss = 1;
+
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index);
+ awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS, 0);
+
+ awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time);
+ awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0);
+
+ awi_write_bytes (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP,
+ bp->bss_timestamp, 8);
+ awi_write_4 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime);
+
+ sc->sc_completion = awi_cmd_sync_done;
+
+ awi_cmd (sc, AWI_CMD_SYNC);
+
+}
+
+void
+awi_cmd_sync_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: sync_done failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+
+ /*
+ * at this point, the card should be synchronized with the AP
+ * we heard from. tell the card what BSS and ESS it's running in..
+ */
+
+ awi_drvstate (sc, AWI_DRV_INFSY);
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: sync done, setting bss/iss parameters\n",
+ sc->sc_dev.dv_xname);
+ awi_hexdump ("bss", sc->sc_active_bss.bss_id, ETHER_ADDR_LEN);
+ printf("ssid: %s\n", sc->sc_active_bss.ssid);
+ }
+
+ awi_cmd_set_ss (sc);
+}
+
+
+void awi_cmd_set_ss (sc)
+ struct awi_softc *sc;
+{
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC_MGT);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE,
+ ETHER_ADDR_LEN + AWI_MIB_MGT_ESS_SIZE);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX,
+ AWI_MIB_MGT_BSS_ID);
+
+ awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA,
+ sc->sc_active_bss.bss_id, ETHER_ADDR_LEN);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN,
+ 0); /* XXX */
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN+1,
+ sc->sc_active_bss.sslen);
+ awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+8,
+ sc->sc_active_bss.ssid, AWI_MIB_MGT_ESS_SIZE-2);
+
+ sc->sc_completion = awi_cmd_set_ss_done;
+ awi_cmd (sc, AWI_CMD_SET_MIB);
+}
+
+void awi_cmd_set_ss_done (sc, status)
+ struct awi_softc *sc;
+ u_int8_t status;
+{
+ if (status != AWI_STAT_OK) {
+ int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET);
+ printf("%s: set_ss_done failed (card unhappy?); erroffset %d\n",
+ sc->sc_dev.dv_xname,
+ erroffset);
+ awi_reset(sc);
+ return;
+ }
+#if 0
+ printf("%s: set_ss done\n", sc->sc_dev.dv_xname);
+#endif
+
+ awi_running (sc);
+
+ /*
+ * now, we *should* be getting broadcast frames..
+ */
+ sc->sc_state = AWI_ST_SYNCED;
+ awi_send_authreq (sc);
+
+}
+
+void awi_running (sc)
+ struct awi_softc *sc;
+
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ /*
+ * Who knows what it is to be running?
+ * Only he who is running knows..
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ awi_start(ifp);
+}
+
+
+void awi_reset (sc)
+ struct awi_softc *sc;
+{
+ printf("%s: reset\n", sc->sc_dev.dv_xname);
+
+}
diff --git a/sys/dev/ic/awireg.h b/sys/dev/ic/awireg.h
new file mode 100644
index 00000000000..76c97ee5309
--- /dev/null
+++ b/sys/dev/ic/awireg.h
@@ -0,0 +1,510 @@
+/* $NetBSD: awireg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */
+/* $OpenBSD: awireg.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * The firmware typically loaded onto Am79C930-based 802.11 interfaces
+ * uses a 32k or larger shared memory buffer to communicate with the
+ * host.
+ *
+ * Depending on the exact configuration of the device, this buffer may
+ * either be mapped into PCMCIA memory space, or accessible a byte at
+ * a type through PCMCIA I/O space.
+ *
+ * This header defines offsets into this shared memory.
+ */
+
+
+/*
+ * LAST_TXD block. 5 32-bit words.
+ *
+ * There are five different output queues; this defines pointers to
+ * the last completed descriptor for each one.
+ */
+#define AWI_LAST_TXD 0x3ec /* last completed Tx Descr */
+
+#define AWI_LAST_BCAST_TXD AWI_LAST_TXD+0
+#define AWI_LAST_MGT_TXD AWI_LAST_TXD+4
+#define AWI_LAST_DATA_TXD AWI_LAST_TXD+8
+#define AWI_LAST_PS_POLL_TXD AWI_LAST_TXD+12
+#define AWI_LAST_CF_POLL_TXD AWI_LAST_TXD+16
+
+/*
+ * Banner block; null-terminated string.
+ *
+ * The doc says it contains
+ * "PCnetMobile:v2.00 mmddyy APIx.x\0"
+ */
+
+#define AWI_BANNER 0x480 /* Version string */
+#define AWI_BANNER_LEN 0x20
+
+/*
+ * Command block protocol:
+ * write command byte to a zero value.
+ * write command status to a zero value.
+ * write arguments to AWI_COMMAND_PARAMS
+ * write command byte to a non-zero value.
+ * wait for command status to be non-zero.
+ * write command byte to a zero value.
+ * write command status to a zero value.
+ */
+
+#define AWI_CMD 0x4a0 /* Command opcode byte */
+
+#define AWI_CMD_IDLE 0x0
+#define AWI_CMD_NOP 0x1
+
+#define AWI_CMD_SET_MIB 0x2
+#define AWI_CMD_GET_MIB 0x9
+
+#define AWI_CA_MIB_TYPE 0x0
+#define AWI_CA_MIB_SIZE 0x1
+#define AWI_CA_MIB_INDEX 0x2
+#define AWI_CA_MIB_DATA 0x4
+
+#define AWI_MIB_LOCAL 0x0
+#define AWI_MIB_MAC_ADDR 0x2
+#define AWI_MIB_MAC 0x3
+#define AWI_MIB_MAC_STAT 0x4
+#define AWI_MIB_MAC_MGT 0x5
+#define AWI_MIB_DRVR_MAC 0x6
+#define AWI_MIB_PHY 0x7
+
+#define AWI_MIB_LAST AWI_MIB_PHY
+
+
+#define AWI_CMD_INIT_TX 0x3
+
+#define AWI_CA_TX_LEN 0x14
+#define AWI_CA_TX_DATA 0x0
+#define AWI_CA_TX_MGT 0x4
+#define AWI_CA_TX_BCAST 0x8
+#define AWI_CA_TX_PS 0xc
+#define AWI_CA_TX_CF 0x10
+
+#define AWI_CMD_FLUSH_TX 0x4
+
+#define AWI_CA_FTX_LEN 0x5
+#define AWI_CA_FTX_DATA 0x0
+#define AWI_CA_FTX_MGT 0x1
+#define AWI_CA_FTX_BCAST 0x2
+#define AWI_CA_FTX_PS 0x3
+#define AWI_CA_FTX_CF 0x4
+
+#define AWI_CMD_INIT_RX 0x5
+#define AWI_CA_IRX_LEN 0x8
+#define AWI_CA_IRX_DATA_DESC 0x0 /* return */
+#define AWI_CA_IRX_PS_DESC 0x4 /* return */
+
+#define AWI_CMD_KILL_RX 0x6
+
+#define AWI_CMD_SLEEP 0x7
+#define AWI_CA_SLEEP_LEN 0x8
+#define AWI_CA_WAKEUP 0x0 /* uint64 */
+
+#define AWI_CMD_WAKE 0x8
+
+#define AWI_CMD_SCAN 0xa
+#define AWI_CA_SCAN_LEN 0x6
+#define AWI_CA_SCAN_DURATION 0x0
+#define AWI_CA_SCAN_SET 0x2
+#define AWI_CA_SCAN_PATTERN 0x3
+#define AWI_CA_SCAN_IDX 0x4
+#define AWI_CA_SCAN_SUSP 0x5
+
+#define AWI_CMD_SYNC 0xb
+#define AWI_CA_SYNC_LEN 0x14
+#define AWI_CA_SYNC_SET 0x0
+#define AWI_CA_SYNC_PATTERN 0x1
+#define AWI_CA_SYNC_IDX 0x2
+#define AWI_CA_SYNC_STARTBSS 0x3
+#define AWI_CA_SYNC_DWELL 0x4
+#define AWI_CA_SYNC_MBZ 0x6
+#define AWI_CA_SYNC_TIMESTAMP 0x8
+#define AWI_CA_SYNC_REFTIME 0x10
+
+#define AWI_CMD_RESUME 0xc
+
+#define AWI_CMD_STATUS 0x4a1 /* Command status */
+
+#define AWI_STAT_IDLE 0x0
+#define AWI_STAT_OK 0x1
+#define AWI_STAT_BADCMD 0x2
+#define AWI_STAT_BADPARM 0x3
+#define AWI_STAT_NOTIMP 0x4
+#define AWI_STAT_BADRES 0x5
+#define AWI_STAT_BADMODE 0x6
+
+#define AWI_ERROR_OFFSET 0x4a2 /* Offset to erroneous parameter */
+#define AWI_CMD_PARAMS 0x4a4 /* Command parameters */
+
+#define AWI_CSB 0x4f0 /* Control/Status block */
+
+#define AWI_SELFTEST 0x4f0
+
+#define AWI_SELFTEST_INIT 0x00 /* initial */
+#define AWI_SELFTEST_FIRMCKSUM 0x01 /* firmware cksum running */
+#define AWI_SELFTEST_HARDWARE 0x02 /* hardware tests running */
+#define AWI_SELFTEST_MIB 0x03 /* mib initializing */
+
+#define AWI_SELFTEST_MIB_FAIL 0xfa
+#define AWI_SELFTEST_RADIO_FAIL 0xfb
+#define AWI_SELFTEST_MAC_FAIL 0xfc
+#define AWI_SELFTEST_FLASH_FAIL 0xfd
+#define AWI_SELFTEST_RAM_FAIL 0xfe
+#define AWI_SELFTEST_PASSED 0xff
+
+#define AWI_STA_STATE 0x4f1
+
+#define AWI_STA_AP 0x20 /* acting as AP */
+#define AWI_STA_NOPSP 0x10 /* Power Saving disabled */
+#define AWI_STA_DOZE 0x08 /* about to go to sleep */
+#define AWI_STA_PSP 0x04 /* enable PSP */
+#define AWI_STA_RXEN 0x02 /* enable RX */
+#define AWI_STA_TXEN 0x01 /* enable TX */
+
+#define AWI_INTSTAT 0x4f3
+#define AWI_INTMASK 0x4f4
+
+/* Bits in AWI_INTSTAT/AWI_INTMASK */
+
+#define AWI_INT_GROGGY 0x80 /* about to wake up */
+#define AWI_INT_CFP_ENDING 0x40 /* cont. free period ending */
+#define AWI_INT_DTIM 0x20 /* beacon outgoing */
+#define AWI_INT_CFP_START 0x10 /* cont. free period starting */
+#define AWI_INT_SCAN_CMPLT 0x08 /* scan complete */
+#define AWI_INT_TX 0x04 /* tx done */
+#define AWI_INT_RX 0x02 /* rx done */
+#define AWI_INT_CMD 0x01 /* cmd done */
+
+#define AWI_INT_BITS "\20\1CMD\2RX\3TX\4SCAN\5CFPST\6DTIM\7CFPE\10GROGGY"
+
+/*
+ * The following are used to implement a locking protocol between host
+ * and MAC to protect the interrupt status and mask fields.
+ *
+ * driver: read lockout_host byte; if zero, set lockout_mac to non-zero,
+ * then reread lockout_host byte; if still zero, host has lock.
+ * if non-zero, clear lockout_mac, loop.
+ */
+
+#define AWI_LOCKOUT_MAC 0x4f5
+#define AWI_LOCKOUT_HOST 0x4f6
+
+
+#define AWI_INTSTAT2 0x4f7
+#define AWI_INTMASK2 0x4fd
+
+/* Bits in AWI_INTSTAT2/INTMASK2 */
+#define AWI_INT2_RXMGT 0x80 /* mgt/ps recieved */
+#define AWI_INT2_RXDATA 0x40 /* data received */
+#define AWI_INT2_TXMGT 0x10 /* mgt tx done */
+#define AWI_INT2_TXCF 0x08f /* CF tx done */
+#define AWI_INT2_TXPS 0x04 /* PS tx done */
+#define AWI_INT2_TXBCAST 0x02 /* Broadcast tx done */
+#define AWI_INT2_TXDATA 0x01 /* data tx done */
+
+#define AWI_DIS_PWRDN 0x4fc /* disable powerdown if set */
+
+#define AWI_DRIVERSTATE 0x4fe /* driver state */
+
+#define AWI_DRV_STATEMASK 0x0f
+
+#define AWI_DRV_RESET 0x0
+#define AWI_DRV_INFSY 0x1 /* inf synced */
+#define AWI_DRV_ADHSC 0x2 /* adhoc scan */
+#define AWI_DRV_ADHSY 0x3 /* adhoc synced */
+#define AWI_DRV_INFSC 0x4 /* inf scanning */
+#define AWI_DRV_INFAUTH 0x5 /* inf authed */
+#define AWI_DRV_INFASSOC 0x6 /* inf associated */
+#define AWI_DRV_INFTOSS 0x7 /* inf handoff */
+#define AWI_DRV_APNONE 0x8 /* AP activity: no assoc */
+#define AWI_DRV_APQUIET 0xc /* AP: >=one assoc, no traffic */
+#define AWI_DRV_APLO 0xd /* AP: >=one assoc, light tfc */
+#define AWI_DRV_APMED 0xe /* AP: >=one assoc, mod tfc */
+#define AWI_DRV_APHIGH 0xf /* AP: >=one assoc, heavy tfc */
+
+#define AWI_DRV_AUTORXLED 0x10
+#define AWI_DRV_AUTOTXLED 0x20
+#define AWI_DRV_RXLED 0x40
+#define AWI_DRV_TXLED 0x80
+
+#define AWI_VBM 0x500 /* Virtual Bit Map */
+
+#define AWI_BUFFERS 0x600 /* Buffers */
+
+/*
+ * Receive descriptors; there are a linked list of these chained
+ * through the "NEXT" fields, starting from XXX
+ */
+
+#define AWI_RXD_SIZE 0x18
+
+#define AWI_RXD_NEXT 0x4
+#define AWI_RXD_NEXT_LAST 0x80000000
+
+
+#define AWI_RXD_HOST_DESC_STATE 0x9
+
+#define AWI_RXD_ST_OWN 0x80 /* host owns this */
+#define AWI_RXD_ST_CONSUMED 0x40 /* host is done */
+#define AWI_RXD_ST_LF 0x20 /* last frag */
+#define AWI_RXD_ST_CRC 0x08 /* CRC error */
+#define AWI_RXD_ST_OFLO 0x02 /* possible buffer overrun */
+#define AWI_RXD_ST_RXERROR 0x01 /* this frame is borked; discard me */
+
+#define AWI_RXD_ST_BITS "\20\1ERROR\2OVERRUN\4CRC\6LF\7CONSUMED\10OWN"
+
+#define AWI_RXD_RSSI 0xa /* 1 byte: radio strength indicator */
+#define AWI_RXD_INDEX 0xb /* 1 byte: FH hop index or DS channel */
+#define AWI_RXD_LOCALTIME 0xc /* 4 bytes: local time of RX */
+#define AWI_RXD_START_FRAME 0x10 /* 4 bytes: ptr to first received byte */
+#define AWI_RXD_LEN 0x14 /* 2 bytes: rx len in bytes */
+#define AWI_RXD_RATE 0x16 /* 1 byte: rx rate in 1e5 bps */
+
+/*
+ * Transmit descriptors.
+ */
+
+#define AWI_TXD_SIZE 0x18
+
+#define AWI_TXD_START 0x00 /* pointer to start of frame */
+#define AWI_TXD_NEXT 0x04 /* pointer to next TXD */
+#define AWI_TXD_LENGTH 0x08 /* length of frame */
+#define AWI_TXD_STATE 0x0a /* state */
+
+#define AWI_TXD_ST_OWN 0x80 /* MAC owns this */
+#define AWI_TXD_ST_DONE 0x40 /* MAC is done */
+#define AWI_TXD_ST_REJ 0x20 /* MAC doesn't like */
+#define AWI_TXD_ST_MSDU 0x10 /* MSDU timeout */
+#define AWI_TXD_ST_ABRT 0x08 /* TX aborted */
+#define AWI_TXD_ST_RETURNED 0x04 /* TX returned */
+#define AWI_TXD_ST_RETRY 0x02 /* TX retries exceeded */
+#define AWI_TXD_ST_ERROR 0x01 /* TX error */
+
+#define AWI_TXD_RATE 0x0b /* rate */
+
+#define AWI_RATE_1MBIT 10
+#define AWI_RATE_2MBIT 20
+
+#define AWI_TXD_NDA 0x0c /* num DIFS attempts */
+#define AWI_TXD_NDF 0x0d /* num DIFS failures */
+#define AWI_TXD_NSA 0x0e /* num SIFS attempts */
+#define AWI_TXD_NSF 0x0f /* num SIFS failures */
+
+#define AWI_TXD_NRA 0x14 /* num RTS attempts */
+#define AWI_TXD_NDTA 0x15 /* num data attempts */
+#define AWI_TXD_CTL 0x16 /* control */
+
+#define AWI_TXD_CTL_PSN 0x80 /* preserve sequence in MAC frame */
+#define AWI_TXD_CTL_BURST 0x02 /* host is doing 802.11 fragmt. */
+#define AWI_TXD_CTL_FRAGS 0x01 /* override normal fragmentation */
+
+/*
+ * MIB structures.
+ */
+
+/*
+ * MIB 0: Local MIB
+ */
+
+#define AWI_MIB_LOCAL_NOFRAG 0
+#define AWI_MIB_LOCAL_NOPLCP 1
+#define AWI_MIB_LOCAL_MACPRES 2
+#define AWI_MIB_LOCAL_RXMGTQ 3
+#define AWI_MIB_LOCAL_NOREASM 4
+#define AWI_MIB_LOCAL_NOSTRIPPLCP 5
+#define AWI_MIB_LOCAL_NORXERROR 6
+#define AWI_MIB_LOCAL_NOPWRSAVE 7
+
+#define AWI_MIB_LOCAL_FILTMULTI 8
+#define AWI_MIB_LOCAL_NOSEQCHECK 9
+#define AWI_MIB_LOCAL_CFPENDFLUSHCFPQ 10
+#define AWI_MIB_LOCAL_INFRA_MODE 11
+#define AWI_MIB_LOCAL_PWD_LEVEL 12
+#define AWI_MIB_LOCAL_CFPMODE 13
+
+#define AWI_MIB_LOCAL_TXB_OFFSET 14
+#define AWI_MIB_LOCAL_TXB_SIZE 18
+#define AWI_MIB_LOCAL_RXB_OFFSET 22
+#define AWI_MIB_LOCAL_RXB_SIZE 26
+
+#define AWI_MIB_LOCAL_ACTING_AS_AP 30
+#define AWI_MIB_LOCAL_FILL_CFP 31
+#define AWI_MIB_LOCAL_SIZE 32
+
+/*
+ * MAC mib
+ */
+
+#define AWI_MIB_MAC_RTS_THRESH 4 /* 2 bytes */
+#define AWI_MIB_MAC_CW_MAX 6
+#define AWI_MIB_MAC_CW_MIN 8
+#define AWI_MIB_MAC_PROMISC 10
+#define AWI_MIB_MAC_SHORT_RETRY 16
+#define AWI_MIB_MAC_LONG_RETRY 17
+#define AWI_MIB_MAC_MAX_FRAME 18
+#define AWI_MIB_MAC_MAX_FRAG 20
+#define AWI_MIB_MAC_PROBE_DELAY 22
+#define AWI_MIB_MAC_PROBE_RESP_MIN 24
+#define AWI_MIB_MAC_PROBE_RESP_MAX 26
+#define AWI_MIB_MAC_MAX_TX_MSDU_LIFE 28
+#define AWI_MIB_MAC_MAX_RX_MSDU_LIFE 32
+#define AWI_MIB_MAC_STATION_BASE_RATE 36
+#define AWI_MIB_MAC_DES_ESSID 38 /* 34 bytes */
+
+/*
+ * MGT mib.
+ */
+
+#define AWI_MIB_MGT_POWER_MODE 0
+#define AWI_MIB_MGT_SCAN_MODE 1
+#define AWI_MIB_MGT_SCAN_STATE 2
+#define AWI_MIB_MGT_DTIM_PERIOD 3
+#define AWI_MIB_MGT_ATIM_WINDOW 4
+#define AWI_MIB_MGT_WEPREQ 6
+#define AWI_MIB_MGT_BEACON_PD 8
+#define AWI_MIB_MGT_PASSIVE_SCAN 10
+#define AWI_MIB_MGT_LISTEN_INT 12
+#define AWI_MIB_MGT_MEDIUP_OCC 14
+#define AWI_MIB_MGT_MAX_MPDU_TIME 16
+#define AWI_MIB_MGT_CFP_MAX_DUR 18
+#define AWI_MIB_MGT_CFP_RATE 20
+#define AWI_MIB_MGT_NO_DTMS 21
+#define AWI_MIB_MGT_STATION_ID 22
+#define AWI_MIB_MGT_BSS_ID 24
+#define AWI_MIB_MGT_ESS_ID 30 /* 34 bytes */
+#define AWI_MIB_MGT_ESS_SIZE 34
+
+
+/*
+ * MAC address group.
+ */
+
+#define AWI_MIB_MAC_ADDR_MINE 0
+#define AWI_MIB_MAC_ADDR_MULTI0 6
+#define AWI_MIB_MAC_ADDR_MULTI1 12
+#define AWI_MIB_MAC_ADDR_MULTI2 18
+#define AWI_MIB_MAC_ADDR_MULTI3 24
+
+#define AWI_MIB_MAC_ADDR_TXEN 30
+
+/*
+ * 802.11 media layer goo.
+ * Should be split out into separate module independant of this driver.
+ */
+
+#define IEEEWL_FC 0 /* frame control */
+
+#define IEEEWL_FC_VERS 0
+#define IEEEWL_FC_VERS_MASK 0x03
+
+#define IEEEWL_FC_TYPE_MGT 0
+#define IEEEWL_FC_TYPE_CTL 1
+#define IEEEWL_FC_TYPE_DATA 2
+
+#define IEEEWL_FC_TYPE_MASK 0x0c
+#define IEEEWL_FC_TYPE_SHIFT 2
+
+#define IEEEWL_FC_SUBTYPE_MASK 0xf0
+#define IEEEWL_FC_SUBTYPE_SHIFT 4
+
+#define IEEEWL_SUBTYPE_ASSOCREQ 0x00
+#define IEEEWL_SUBTYPE_ASSOCRESP 0x01
+#define IEEEWL_SUBTYPE_REASSOCREQ 0x02
+#define IEEEWL_SUBTYPE_REASSOCRESP 0x03
+#define IEEEWL_SUBTYPE_PROBEREQ 0x04
+#define IEEEWL_SUBTYPE_PROBERESP 0x05
+
+#define IEEEWL_SUBTYPE_BEACON 0x08
+#define IEEEWL_SUBTYPE_DISSOC 0x0a
+#define IEEEWL_SUBTYPE_AUTH 0x0b
+#define IEEEWL_SUBTYPE_DEAUTH 0x0c
+
+#define IEEEWL_FC2 1 /* second byte of fc */
+
+/*
+ * TLV tags for things we care about..
+ */
+#define IEEEWL_MGT_TLV_SSID 0
+#define IEEEWL_MGT_TLV_FHPARMS 2
+
+/*
+ * misc frame control bits in second byte of frame control word.
+ * there are others, but we don't ever want to set them..
+ */
+
+#define IEEEWL_FC2_DSMASK 0x03
+
+#define IEEEWL_FC2_TODS 0x01
+#define IEEEWL_FC2_FROMDS 0x02
+
+#define IEEEWL_FH_CHANSET_MIN 1
+#define IEEEWL_FH_CHANSET_MAX 3
+#define IEEEWL_FH_PATTERN_MIN 0
+#define IEEEWL_FH_PATTERN_MAX 77
+
+struct awi_mac_header
+{
+ u_int8_t awi_fc;
+ u_int8_t awi_f2;
+ u_int16_t awi_duration;
+ u_int8_t awi_addr1[6];
+ u_int8_t awi_addr2[6];
+ u_int8_t awi_addr3[6];
+ u_int16_t awi_seqctl;
+};
+
+struct awi_llc_header
+{
+ u_int8_t awi_llc_goo[8];
+};
+
+struct awi_assoc_hdr
+{
+ u_int8_t awi_cap_info[2];
+ u_int8_t awi_li[2];
+};
+
+struct awi_auth_hdr
+{
+ u_int8_t awi_algno[2];
+ u_int8_t awi_seqno[2];
+ u_int8_t awi_status[2];
+};
diff --git a/sys/dev/ic/awivar.h b/sys/dev/ic/awivar.h
new file mode 100644
index 00000000000..d50fa7c9b66
--- /dev/null
+++ b/sys/dev/ic/awivar.h
@@ -0,0 +1,183 @@
+/* $NetBSD: awivar.h,v 1.4 1999/11/09 14:58:07 sommerfeld Exp $ */
+/* $OpenBSD: awivar.h,v 1.1 1999/12/16 02:56:56 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+
+enum awi_state {
+ AWI_ST_OFF, /* powered off */
+ AWI_ST_SELFTEST, /* waiting for selftest to complete*/
+ AWI_ST_IFTEST, /* waiting for interface to respond */
+ AWI_ST_MIB_GET, /* fetching MIB variables */
+ AWI_ST_MIB_SET, /* stuffing MIB variables */
+ AWI_ST_TXINIT, /* initializing TX side */
+ AWI_ST_RXINIT, /* initializing RX side */
+ AWI_ST_SCAN, /* hunting for a BSS */
+ AWI_ST_SYNCED, /* synced? trying to auth.. */
+ /* there are probably some missing 802.11 states here.. */
+ AWI_ST_AUTHED, /* authenticated */
+ AWI_ST_RUNNING, /* ready to send user data.. */
+ AWI_ST_INSANE, /* failed to respond.. */
+};
+
+#define AWI_FL_CMD_INPROG 0x0001
+
+#define AWI_SSID_LEN 33
+
+struct awi_bss_binding
+{
+ u_int8_t chanset; /* channel set to use */
+ u_int8_t pattern; /* hop pattern to use */
+ u_int8_t index; /* index to use */
+ u_int8_t rssi; /* strenght of this beacon */
+ u_int16_t dwell_time; /* dwell time */
+ u_int8_t bss_timestamp[8]; /* timestamp of this bss */
+ u_int8_t bss_id[6];
+ u_int32_t rxtime; /* unit's local time */
+ u_int8_t sslen;
+ u_int8_t ssid[AWI_SSID_LEN];
+};
+
+#define NBND 4
+#define NTXD 4
+
+struct awi_txbd
+{
+ u_int32_t descr; /* offset to descriptor */
+ u_int32_t frame; /* offset to frame */
+ u_int32_t len; /* frame length */
+};
+
+struct awi_softc
+{
+ struct device sc_dev;
+ struct am79c930_softc sc_chip;
+ struct arpcom sc_ec;
+ int sc_enabled;
+ enum awi_state sc_state;
+ int sc_flags;
+ void *sc_ih; /* interrupt handler */
+ struct ifnet *sc_ifp; /* XXX */
+ int (*sc_enable) __P((struct awi_softc *));
+ void (*sc_disable) __P((struct awi_softc *));
+ void (*sc_completion) __P((struct awi_softc *,
+ u_int8_t));
+
+ struct ifqueue sc_mgtq;
+
+ u_int32_t sc_txbase;
+ u_int32_t sc_txlen;
+ u_int32_t sc_rxbase;
+ u_int32_t sc_rxlen;
+
+ u_int32_t sc_rx_data_desc;
+ u_int32_t sc_rx_mgt_desc;
+
+ u_int16_t sc_scan_duration;
+ u_int8_t sc_scan_chanset;
+ u_int8_t sc_scan_pattern;
+
+ int sc_nbindings;
+
+ u_int8_t sc_my_addr[6];
+
+ int sc_new_bss;
+ struct awi_bss_binding sc_active_bss;
+ /*
+ * BSS's found during a scan.. XXX doesn't need to be in-line
+ */
+ struct awi_bss_binding sc_bindings[NBND];
+
+ int sc_txpending;
+ int sc_ntxd;
+ int sc_txnext; /* next txd to be given to driver */
+ int sc_txfirst; /* first unsent txd dev has */
+ struct awi_txbd sc_txd[NTXD];
+ u_int8_t sc_curmib;
+
+ int sc_scan_timer;
+ int sc_tx_timer;
+ int sc_mgt_timer;
+ int sc_cmd_timer;
+ int sc_selftest_tries;
+
+ /*
+ * packet parsing state.
+ */
+
+ struct mbuf *sc_nextpkt;
+ struct mbuf *sc_m;
+ u_int8_t *sc_mptr;
+ u_int32_t sc_mleft;
+ int sc_flushpkt;
+};
+
+extern int awi_activate __P((struct device *, enum devact));
+extern int awi_attach __P((struct awi_softc *, u_int8_t *macaddr));
+extern void awi_init __P((struct awi_softc *));
+extern void awi_stop __P((struct awi_softc *));
+
+#define awi_read_1(sc, off) ((sc)->sc_chip.sc_ops->read_1)(&sc->sc_chip, off)
+#define awi_read_2(sc, off) ((sc)->sc_chip.sc_ops->read_2)(&sc->sc_chip, off)
+#define awi_read_4(sc, off) ((sc)->sc_chip.sc_ops->read_4)(&sc->sc_chip, off)
+#define awi_read_bytes(sc, off, ptr, len) ((sc)->sc_chip.sc_ops->read_bytes)(&sc->sc_chip, off, ptr, len)
+
+#define awi_write_1(sc, off, val) \
+ ((sc)->sc_chip.sc_ops->write_1)(&sc->sc_chip, off, val)
+#define awi_write_2(sc, off, val) \
+ ((sc)->sc_chip.sc_ops->write_2)(&sc->sc_chip, off, val)
+#define awi_write_4(sc, off, val) \
+ ((sc)->sc_chip.sc_ops->write_4)(&sc->sc_chip, off, val)
+#define awi_write_bytes(sc, off, ptr, len) \
+ ((sc)->sc_chip.sc_ops->write_bytes)(&sc->sc_chip, off, ptr, len)
+
+#define awi_drvstate(sc, state) \
+ awi_write_1(sc, AWI_DRIVERSTATE, \
+ ((state) | AWI_DRV_AUTORXLED|AWI_DRV_AUTOTXLED));
+
+/* Number of trips around the loop waiting for the device.. */
+
+#define AWI_LOCKOUT_SPIN 10000 /* 10ms */
+
+/* 24-byte mac header + 8 byte SNAP header + 1500-byte ether MTU */
+#define AWI_FRAME_SIZE 1532
+
+/* refresh associations every 300s */
+
+#define AWI_ASSOC_REFRESH 300
+
+extern int awi_intr __P((void *));
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index 4a2797c8dc4..32e338c45d5 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pcmcia,v 1.24 1999/08/13 20:34:17 fgsch Exp $
+# $OpenBSD: files.pcmcia,v 1.25 1999/12/16 02:56:56 deraadt Exp $
# $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $
#
# Config.new file and device description for machine-independent PCMCIA code.
@@ -69,3 +69,11 @@ file dev/pcmcia/if_cnw.c cnw
device wi: ether, ifnet
attach wi at pcmcia
file dev/pcmcia/if_wi.c wi
+
+# AMD 79c930-based 802.11 cards (including BayStack 650 FH card).
+device awi: ether, ifnet
+attach awi at pcmcia with awi_pcmcia
+
+file dev/pcmcia/if_awi_pcmcia.c awi_pcmcia
+file dev/ic/awi.c awi
+file dev/ic/am79c930.c awi
diff --git a/sys/dev/pcmcia/if_awi_pcmcia.c b/sys/dev/pcmcia/if_awi_pcmcia.c
new file mode 100644
index 00000000000..b9f17b74630
--- /dev/null
+++ b/sys/dev/pcmcia/if_awi_pcmcia.c
@@ -0,0 +1,412 @@
+/* $NetBSD: if_awi_pcmcia.c,v 1.5 1999/11/06 16:43:54 sommerfeld Exp $ */
+/* $OpenBSD: if_awi_pcmcia.c,v 1.1 1999/12/16 02:56:57 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Bill Sommerfeld
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+/*
+ * PCMCIA attachment for BayStack 650 802.11FH PCMCIA card,
+ * based on the AMD 79c930 802.11 controller chip.
+ *
+ * This attachment can probably be trivally adapted for other FH and
+ * DS cards based on the same chipset.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/select.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <netinet/if_ether.h>
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+
+#include <dev/pcmcia/pcmciareg.h>
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciadevs.h>
+
+int awi_pcmcia_match __P((struct device *, void *, void *));
+void awi_pcmcia_attach __P((struct device *, struct device *, void *));
+int awi_pcmcia_detach __P((struct device *, int));
+
+int awi_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *));
+int awi_pcmcia_enable __P((struct awi_softc *));
+void awi_pcmcia_disable __P((struct awi_softc *));
+
+struct awi_pcmcia_softc {
+ struct awi_softc sc_awi; /* real "awi" softc */
+
+ /* PCMCIA-specific goo */
+ struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
+ int sc_io_window; /* our i/o window */
+ struct pcmcia_function *sc_pf; /* our PCMCIA function */
+};
+
+int awi_pcmcia_find __P((struct awi_pcmcia_softc *,
+ struct pcmcia_attach_args *, struct pcmcia_config_entry *));
+
+/* Autoconfig definition of driver back-end */
+struct cfdriver awi_cd = {
+ NULL, "awi", DV_IFNET
+};
+
+struct cfattach awi_pcmcia_ca = {
+ sizeof(struct awi_pcmcia_softc), awi_pcmcia_match, awi_pcmcia_attach,
+ awi_pcmcia_detach, /* awi_activate */ 0
+};
+
+/*
+ * XXX following is common to most PCMCIA NIC's and belongs
+ * in common code
+ */
+
+struct awi_pcmcia_get_enaddr_args {
+ int got_enaddr;
+ u_int8_t enaddr[ETHER_ADDR_LEN];
+};
+
+int awi_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *));
+
+int
+awi_pcmcia_enable(sc)
+ struct awi_softc *sc;
+{
+ struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc;
+ struct pcmcia_function *pf = psc->sc_pf;
+
+ /* establish the interrupt. */
+ sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, awi_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt\n",
+ sc->sc_dev.dv_xname);
+ return (1);
+ }
+ return (pcmcia_function_enable(pf));
+}
+
+void
+awi_pcmcia_disable(sc)
+ struct awi_softc *sc;
+{
+ struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc;
+ struct pcmcia_function *pf = psc->sc_pf;
+
+ pcmcia_function_disable (pf);
+ pcmcia_intr_disestablish (pf, sc->sc_ih);
+}
+
+int
+awi_pcmcia_match(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct pcmcia_attach_args *pa = aux;
+
+ if (pa->manufacturer != PCMCIA_VENDOR_BAY)
+ return (0);
+
+ if (pa->product == PCMCIA_PRODUCT_BAY_STACK_650)
+ return (1);
+
+ return (0);
+}
+
+int
+awi_pcmcia_find (psc, pa, cfe)
+ struct awi_pcmcia_softc *psc;
+ struct pcmcia_attach_args *pa;
+ struct pcmcia_config_entry *cfe;
+{
+ struct awi_softc *sc = &psc->sc_awi;
+ int fail = 0;
+ u_int8_t version[AWI_BANNER_LEN];
+
+ /*
+ * see if we can read the firmware version sanely
+ * through the i/o ports.
+ * if not, try a different CIS string..
+ */
+ if (pcmcia_io_alloc(psc->sc_pf, cfe->iospace[0].start,
+ cfe->iospace[0].length, 0, &psc->sc_pcioh) != 0)
+ goto fail;
+
+ if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0, psc->sc_pcioh.size,
+ &psc->sc_pcioh, &psc->sc_io_window))
+ goto fail_io_free;
+
+ /* Enable the card. */
+ pcmcia_function_init(psc->sc_pf, cfe);
+ if (pcmcia_function_enable(psc->sc_pf))
+ goto fail_io_unmap;
+
+ sc->sc_chip.sc_iot = psc->sc_pcioh.iot;
+ sc->sc_chip.sc_ioh = psc->sc_pcioh.ioh;
+ am79c930_chip_init(&sc->sc_chip, 0);
+
+ DELAY(100);
+
+ awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN);
+
+ if (memcmp(version, "PCnetMobile:", 12) == 0)
+ return 0;
+
+ fail++;
+ pcmcia_function_disable (psc->sc_pf);
+
+ fail_io_unmap:
+ fail++;
+ pcmcia_io_unmap (psc->sc_pf, psc->sc_io_window);
+
+ fail_io_free:
+ fail++;
+ pcmcia_io_free (psc->sc_pf, &psc->sc_pcioh);
+ fail:
+ fail++;
+ return fail;
+}
+
+
+
+void
+awi_pcmcia_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct awi_pcmcia_softc *psc = (void *) self;
+ struct awi_softc *sc = &psc->sc_awi;
+ struct pcmcia_attach_args *pa = aux;
+ struct pcmcia_config_entry *cfe;
+ struct pcmcia_mem_handle memh;
+ struct awi_pcmcia_get_enaddr_args pgea;
+ bus_addr_t memoff;
+ int memwin;
+
+#if 1
+ int i, j;
+
+ for (cfe = pa->pf->cfe_head.sqh_first, i=0;
+ cfe != NULL;
+ cfe = cfe->cfe_list.sqe_next, i++) {
+ printf("%d: %d memspaces, %d iospaces\n",
+ i, cfe->num_memspace, cfe->num_iospace);
+ printf("%d: number %d flags %x iftype %d iomask %lx irqmask %x maxtwins %x\n",
+ i, cfe->number, cfe->flags, cfe->iftype, cfe->iomask,
+ cfe->irqmask, cfe->maxtwins);
+ for (j=0; j<cfe->num_memspace; j++) {
+ printf("%d: mem %d: len %lx card %lx host %lx\n",
+ i, j,
+ cfe->memspace[j].length,
+ cfe->memspace[j].cardaddr,
+ cfe->memspace[j].hostaddr);
+ }
+ for (j=0; j<cfe->num_iospace; j++) {
+ printf("%d: io %d: len %lx start %lx\n",
+ i, j,
+ cfe->iospace[j].length,
+ cfe->iospace[j].start);
+ }
+ }
+#endif
+
+ psc->sc_pf = pa->pf;
+
+ for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
+ cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
+ if (cfe->iftype != PCMCIA_IFTYPE_IO)
+ continue;
+ if (cfe->num_iospace < 1)
+ continue;
+ if (cfe->iospace[0].length < AM79C930_IO_SIZE)
+ continue;
+
+ if (awi_pcmcia_find(psc, pa, cfe) == 0)
+ break;
+ }
+ if (cfe == NULL) {
+ printf(": no suitable CIS info found\n");
+ return;
+ }
+
+ sc->sc_enabled = 1;
+ sc->sc_state = AWI_ST_SELFTEST;
+ printf(": BayStack 650 Wireless (802.11)\n");
+
+ if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE, &memh) != 0) {
+ printf("%s: unable to allocate memory space; using i/o only\n",
+ sc->sc_dev.dv_xname);
+ } else if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_COMMON,
+ AM79C930_MEM_BASE, AM79C930_MEM_SIZE,
+ &memh, &memoff, &memwin)) {
+ printf("%s: unable to map memory space; using i/o only\n",
+ sc->sc_dev.dv_xname);
+ pcmcia_mem_free(psc->sc_pf, &memh);
+ } else {
+ sc->sc_chip.sc_memt = memh.memt;
+ sc->sc_chip.sc_memh = memh.memh;
+ am79c930_chip_init(&sc->sc_chip, 1);
+ }
+
+ sc->sc_chip.sc_bustype = AM79C930_BUS_PCMCIA;
+
+ sc->sc_enable = awi_pcmcia_enable;
+ sc->sc_disable = awi_pcmcia_disable;
+
+ /* Read station address. */
+ pgea.got_enaddr = 0;
+ if (pcmcia_scan_cis(parent, awi_pcmcia_get_enaddr, &pgea) == -1) {
+ printf("%s: Couldn't read CIS to get ethernet address\n",
+ sc->sc_dev.dv_xname);
+ return;
+ } else if (!pgea.got_enaddr) {
+ printf("%s: Couldn't get ethernet address from CIS\n",
+ sc->sc_dev.dv_xname);
+ return;
+ } else
+#ifdef DIAGNOSTIC
+ printf("%s: Ethernet address from CIS: %s\n",
+ sc->sc_dev.dv_xname, ether_sprintf(pgea.enaddr))
+#endif
+ ;
+
+ awi_attach(sc, pgea.enaddr);
+
+#ifndef NETBSD_ORIGINAL
+ awi_init(sc);
+ awi_stop(sc);
+#endif
+
+#ifdef notyet /* NETBSD_ORIGINAL */
+ sc->sc_state = AWI_ST_OFF;
+
+ sc->sc_enabled = 0;
+ /*
+ * XXX This should be done once the framework has enable/disable hooks.
+ */
+ pcmcia_function_disable(psc->sc_pf);
+#endif /* notyet */
+}
+
+
+int
+awi_pcmcia_detach(self, flags)
+ struct device *self;
+ int flags;
+{
+ struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)self;
+
+ /* Unmap our i/o window. */
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
+
+ /* Free our i/o space. */
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
+
+#ifdef notyet
+ /*
+ * Our softc is about to go away, so drop our reference
+ * to the ifnet.
+ */
+ if_delref(psc->sc_awi.sc_ethercom.ec_if);
+ return (0);
+#else
+ return (EBUSY);
+#endif
+}
+
+/*
+ * XXX copied verbatim from if_mbe_pcmcia.c.
+ * this function should be in common pcmcia code..
+ */
+
+int
+awi_pcmcia_get_enaddr(tuple, arg)
+ struct pcmcia_tuple *tuple;
+ void *arg;
+{
+ struct awi_pcmcia_get_enaddr_args *p = arg;
+ int i;
+
+ if (tuple->code == PCMCIA_CISTPL_FUNCE) {
+ if (tuple->length < 2) /* sub code and ether addr length */
+ return (0);
+
+ if ((pcmcia_tuple_read_1(tuple, 0) !=
+ PCMCIA_TPLFE_TYPE_LAN_NID) ||
+ (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN))
+ return (0);
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ p->enaddr[i] = pcmcia_tuple_read_1(tuple, i + 2);
+ p->got_enaddr = 1;
+ return (1);
+ }
+ return (0);
+}