summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2000-08-17 16:16:32 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2000-08-17 16:16:32 +0000
commit9372b87e9b3753b4321c4fd1e64a830b6f7d6cfa (patch)
tree56a20bc794fdf2d7200ab90ebee5a81a03ad80fd /sys/dev
parenta5bdafd3e77273d8bbb56ae6eabd33da49eac255 (diff)
replace if_awi w/ semi-current netbsd driver; still has problems
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/am79c930.c181
-rw-r--r--sys/dev/ic/am79c930reg.h254
-rw-r--r--sys/dev/ic/am79c930var.h3
-rw-r--r--sys/dev/ic/awi.c4550
-rw-r--r--sys/dev/ic/awi_wep.c535
-rw-r--r--sys/dev/ic/awireg.h443
-rw-r--r--sys/dev/ic/awivar.h278
-rw-r--r--sys/dev/pcmcia/files.pcmcia11
-rw-r--r--sys/dev/pcmcia/if_awi_pcmcia.c361
9 files changed, 3611 insertions, 3005 deletions
diff --git a/sys/dev/ic/am79c930.c b/sys/dev/ic/am79c930.c
index 4e8a524c08c..739d0d48078 100644
--- a/sys/dev/ic/am79c930.c
+++ b/sys/dev/ic/am79c930.c
@@ -1,5 +1,4 @@
-/* $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 $ */
+/* $NetBSD: am79c930.c,v 1.5 2000/03/23 13:57:58 onoe Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -63,17 +62,30 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
+#ifndef __FreeBSD__
#include <sys/device.h>
+#endif
#include <machine/cpu.h>
+#ifdef __FreeBSD__
+#include <machine/bus_pio.h>
+#include <machine/bus_memio.h>
+#endif
#include <machine/bus.h>
+#ifdef __NetBSD__
#include <machine/intr.h>
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <dev/ic/am79c930reg.h>
#include <dev/ic/am79c930var.h>
+#endif
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+#endif
-#define AM930_DELAY(x) /*nothing*/;
+#define AM930_DELAY(x) /*nothing*/
void am79c930_regdump __P((struct am79c930_softc *sc));
@@ -124,7 +136,6 @@ static void io_write_1 (sc, off, val)
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));
@@ -140,8 +151,16 @@ static void io_write_2 (sc, off, val)
u_int32_t off;
u_int16_t val;
{
- io_write_1(sc, off, val & 0xff);
- io_write_1(sc, off+1, (val >> 8) & 0xff);
+ 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 & 0xff);
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA, (val>>8)&0xff);
+ AM930_DELAY(1);
}
static void io_write_4 (sc, off, val)
@@ -149,11 +168,20 @@ static void io_write_4 (sc, off, val)
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);
+ 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 & 0xff);
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>8)&0xff);
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>16)&0xff);
+ AM930_DELAY(1);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>24)&0xff);
+ AM930_DELAY(1);
}
static void io_write_bytes (sc, off, ptr, len)
@@ -163,10 +191,15 @@ static void io_write_bytes (sc, off, ptr, len)
size_t len;
{
int i;
- /* XXX higher offset values needed for 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);
for (i=0; i<len; i++)
- io_write_1 (sc, off+i, ptr[i]);
+ bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,ptr[i]);
}
static u_int8_t io_read_1 (sc, off)
@@ -189,19 +222,40 @@ 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);
+ u_int16_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);
+ val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8;
+ AM930_DELAY(1);
+ return val;
}
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);
+ u_int32_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);
+ val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8;
+ AM930_DELAY(1);
+ val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 16;
+ AM930_DELAY(1);
+ val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 24;
+ AM930_DELAY(1);
+ return val;
}
static void io_read_bytes (sc, off, ptr, len)
@@ -212,18 +266,21 @@ static void io_read_bytes (sc, off, ptr, len)
{
int i;
+ 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);
for (i=0; i<len; i++)
- ptr[i] = io_read_1(sc, off+i);
+ ptr[i] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
+ AM79C930_IODPA);
}
-
-
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);
}
@@ -232,9 +289,16 @@ static void mem_write_2 (sc, off, val)
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);
+ bus_space_tag_t t = sc->sc_memt;
+ bus_space_handle_t h = sc->sc_memh;
+
+ /* could be unaligned */
+ if ((off & 0x1) == 0)
+ bus_space_write_2(t, h, off, val);
+ else {
+ bus_space_write_1(t, h, off, val & 0xff);
+ bus_space_write_1(t, h, off+1, (val >> 8) & 0xff);
+ }
}
static void mem_write_4 (sc, off, val)
@@ -242,11 +306,18 @@ static void mem_write_4 (sc, off, val)
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);
+ bus_space_tag_t t = sc->sc_memt;
+ bus_space_handle_t h = sc->sc_memh;
+
+ /* could be unaligned */
+ if ((off & 0x3) == 0)
+ bus_space_write_4(t, h, off, val);
+ else {
+ bus_space_write_1(t, h, off, val & 0xff);
+ bus_space_write_1(t, h, off+1, (val >> 8) & 0xff);
+ bus_space_write_1(t, h, off+2, (val >> 16) & 0xff);
+ bus_space_write_1(t, h, off+3, (val >> 24) & 0xff);
+ }
}
static void mem_write_bytes (sc, off, ptr, len)
@@ -255,11 +326,7 @@ static void mem_write_bytes (sc, off, ptr, len)
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]);
+ bus_space_write_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len);
}
@@ -267,7 +334,6 @@ 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);
}
@@ -275,22 +341,28 @@ 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);
+ /* could be unaligned */
+ if ((off & 0x1) == 0)
+ return bus_space_read_2(sc->sc_memt, sc->sc_memh, off);
+ else
+ 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);
+ /* could be unaligned */
+ if ((off & 0x3) == 0)
+ return bus_space_read_4(sc->sc_memt, sc->sc_memh, off);
+ else
+ 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);
}
@@ -301,12 +373,7 @@ static void mem_read_bytes (sc, off, ptr, len)
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);
+ bus_space_read_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len);
}
@@ -378,3 +445,5 @@ void am79c930_chip_init (sc, how)
else
sc->sc_ops = &iospace_ops;
}
+
+
diff --git a/sys/dev/ic/am79c930reg.h b/sys/dev/ic/am79c930reg.h
index 9dfcd537086..8441f0f9961 100644
--- a/sys/dev/ic/am79c930reg.h
+++ b/sys/dev/ic/am79c930reg.h
@@ -1,255 +1,4 @@
-/* $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 $ */
+/* $NetBSD$ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -317,6 +66,7 @@
#define AM79C930_IO_BASE 0
#define AM79C930_IO_SIZE 16
#define AM79C930_IO_SIZE_BIG 40
+#define AM79C930_IO_ALIGN 0x40 /* am79c930 decodes lower 6bits */
#define AM79C930_GCR 0 /* General Config Register */
diff --git a/sys/dev/ic/am79c930var.h b/sys/dev/ic/am79c930var.h
index 0d8a221126f..26b4777b0f7 100644
--- a/sys/dev/ic/am79c930var.h
+++ b/sys/dev/ic/am79c930var.h
@@ -1,5 +1,4 @@
-/* $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 $ */
+/* $NetBSD$ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
diff --git a/sys/dev/ic/awi.c b/sys/dev/ic/awi.c
index 97f3b609a10..eeab4b80036 100644
--- a/sys/dev/ic/awi.c
+++ b/sys/dev/ic/awi.c
@@ -1,5 +1,4 @@
-/* $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 $ */
+/* $NetBSD: awi.c,v 1.26 2000/07/21 04:48:55 onoe Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -75,39 +74,70 @@
* - common 802.11 media layer.
*/
+/*
+ * Driver for AMD 802.11 PCnetMobile firmware.
+ * Uses am79c930 chip driver to talk to firmware running on the am79c930.
+ *
+ * The initial version of the driver was written by
+ * Bill Sommerfeld <sommerfeld@netbsd.org>.
+ * Then the driver module completely rewritten to support cards with DS phy
+ * and to support adhoc mode by Atsushi Onoe <onoe@netbsd.org>
+ */
+
+#ifndef __OpenBSD__
+#include "opt_inet.h"
+#endif
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+#define NBPFILTER 1
+#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include "bpf.h"
+#define NBPFILTER NBPF
+#else
#include "bpfilter.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
#include <sys/socket.h>
-#include <sys/ioctl.h>
+#include <sys/sockio.h>
#include <sys/errno.h>
#include <sys/syslog.h>
-#include <sys/select.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+#include <sys/bus.h>
+#else
#include <sys/device.h>
-#if NRND > 0
-#include <sys/rnd.h>
#endif
#include <net/if.h>
#include <net/if_dl.h>
+#ifndef __OpenBSD__
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#else
+#include <net/if_ether.h>
+#endif
+#endif
#include <net/if_media.h>
+#include <net/if_llc.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
+#ifdef __NetBSD__
+#include <netinet/if_inarp.h>
+#else
#include <netinet/if_ether.h>
#endif
-
-#ifdef NS
-#include <netns/ns.h>
-#include <netns/ns_if.h>
#endif
+#include <net/if_ieee80211.h>
+
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
@@ -115,2508 +145,2712 @@
#include <machine/cpu.h>
#include <machine/bus.h>
+#ifdef __NetBSD__
#include <machine/intr.h>
+#endif
+#ifdef __FreeBSD__
+#include <machine/clock.h>
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#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
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+#include <dev/awi/awireg.h>
+#include <dev/awi/awivar.h>
#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 int awi_ioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+#ifdef IFM_IEEE80211
+static int awi_media_rate2opt __P((struct awi_softc *sc, int rate));
+static int awi_media_opt2rate __P((struct awi_softc *sc, int opt));
+static int awi_media_change __P((struct ifnet *ifp));
+static void awi_media_status __P((struct ifnet *ifp, struct ifmediareq *imr));
+#endif
+static void awi_watchdog __P((struct ifnet *ifp));
+static void awi_start __P((struct ifnet *ifp));
+static void awi_txint __P((struct awi_softc *sc));
+static struct mbuf * awi_fix_txhdr __P((struct awi_softc *sc, struct mbuf *m0));
+static struct mbuf * awi_fix_rxhdr __P((struct awi_softc *sc, struct mbuf *m0));
+static void awi_input __P((struct awi_softc *sc, struct mbuf *m, u_int32_t rxts, u_int8_t rssi));
+static void awi_rxint __P((struct awi_softc *sc));
+static struct mbuf * awi_devget __P((struct awi_softc *sc, u_int32_t off, u_int16_t len));
+static int awi_init_hw __P((struct awi_softc *sc));
+static int awi_init_mibs __P((struct awi_softc *sc));
+static int awi_init_txrx __P((struct awi_softc *sc));
+static void awi_stop_txrx __P((struct awi_softc *sc));
+static int awi_start_scan __P((struct awi_softc *sc));
+static int awi_next_scan __P((struct awi_softc *sc));
+static void awi_stop_scan __P((struct awi_softc *sc));
+static void awi_recv_beacon __P((struct awi_softc *sc, struct mbuf *m0, u_int32_t rxts, u_int8_t rssi));
+static int awi_set_ss __P((struct awi_softc *sc));
+static void awi_try_sync __P((struct awi_softc *sc));
+static void awi_sync_done __P((struct awi_softc *sc));
+static void awi_send_deauth __P((struct awi_softc *sc));
+static void awi_send_auth __P((struct awi_softc *sc, int seq));
+static void awi_recv_auth __P((struct awi_softc *sc, struct mbuf *m0));
+static void awi_send_asreq __P((struct awi_softc *sc, int reassoc));
+static void awi_recv_asresp __P((struct awi_softc *sc, struct mbuf *m0));
+static int awi_mib __P((struct awi_softc *sc, u_int8_t cmd, u_int8_t mib));
+static int awi_cmd_scan __P((struct awi_softc *sc));
+static int awi_cmd __P((struct awi_softc *sc, u_int8_t cmd));
+static void awi_cmd_done __P((struct awi_softc *sc));
+static int awi_next_txd __P((struct awi_softc *sc, int len, u_int32_t *framep, u_int32_t*ntxdp));
+static int awi_lock __P((struct awi_softc *sc));
+static void awi_unlock __P((struct awi_softc *sc));
+static int awi_intr_lock __P((struct awi_softc *sc));
+static void awi_intr_unlock __P((struct awi_softc *sc));
+static int awi_cmd_wait __P((struct awi_softc *sc));
+static void awi_print_essid __P((u_int8_t *essid));
+
+#ifdef AWI_DEBUG
+static void awi_dump_pkt __P((struct awi_softc *sc, struct mbuf *m, int rssi));
+int awi_verbose = 0;
+int awi_dump = 0;
+#define AWI_DUMP_MASK(fc0) (1 << (((fc0) & IEEE80211_FC0_SUBTYPE_MASK) >> 4))
+int awi_dump_mask = AWI_DUMP_MASK(IEEE80211_FC0_SUBTYPE_BEACON);
+int awi_dump_hdr = 0;
+int awi_dump_len = 28;
+#endif
-static const u_int8_t snap_magic[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
+#if NBPFILTER > 0
+#define AWI_BPF_NORM 0
+#define AWI_BPF_RAW 1
+#ifdef __FreeBSD__
+#define AWI_BPF_MTAP(sc, m, raw) do { \
+ if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \
+ bpf_mtap((sc)->sc_ifp, (m)); \
+} while (0);
+#else
+#define AWI_BPF_MTAP(sc, m, raw) do { \
+ if ((sc)->sc_ifp->if_bpf && (sc)->sc_rawbpf == (raw)) \
+ bpf_mtap((sc)->sc_ifp->if_bpf, (m)); \
+} while (0);
+#endif
+#else
+#define AWI_BPF_MTAP(sc, m, raw)
+#endif
-int awi_scan_keepalive = 10;
+#ifndef llc_snap
+#define llc_snap llc_un.type_snap
+#endif
-/*
- * 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
- *
- */
+#ifdef __OpenBSD__
+struct cfdriver awi_cd = {
+ NULL, "awi", DV_IFNET
+};
+#endif
-/*
- * device shutdown routine.
- */
+#ifdef __FreeBSD__
+#if __FreeBSD__ >= 4
+devclass_t awi_devclass;
+#endif
-/*
- * device appears to be insane. rather than hanging, whap device upside
- * the head on next timeout.
- */
+/* NetBSD compatible functions */
+static char * ether_sprintf __P((u_int8_t *));
-void
-awi_insane(sc)
- struct awi_softc *sc;
+static char *
+ether_sprintf(enaddr)
+ u_int8_t *enaddr;
{
- 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;
-}
+ static char strbuf[18];
-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;
+ sprintf(strbuf, "%6D", enaddr, ":");
+ return strbuf;
}
-
-
-/*
- * 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)
+int
+awi_attach(sc)
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);
+ struct ifnet *ifp = sc->sc_ifp;
+ int s;
+ int error;
+#ifdef IFM_IEEE80211
+ int i;
+ u_int8_t *phy_rates;
+ int mword;
+ struct ifmediareq imr;
#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;
+ s = splnet();
+ /*
+ * Even if we can sleep in initialization state,
+ * all other processes (e.g. ifconfig) have to wait for
+ * completion of attaching interface.
+ */
+ sc->sc_busy = 1;
+ sc->sc_status = AWI_ST_INIT;
+ TAILQ_INIT(&sc->sc_scan);
+ error = awi_init_hw(sc);
+ if (error) {
+ sc->sc_invalid = 1;
+ splx(s);
+ return error;
}
-
- if (m0->m_len < 32) {
- printf("oops, prepend only left %d bytes\n", m0->m_len);
- m_freem(m0);
- return NULL;
+ error = awi_init_mibs(sc);
+ splx(s);
+ if (error) {
+ sc->sc_invalid = 1;
+ return error;
}
- 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);
+ ifp->if_softc = sc;
+ ifp->if_start = awi_start;
+ ifp->if_ioctl = awi_ioctl;
+ ifp->if_watchdog = awi_watchdog;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_hdrlen = sizeof(struct ieee80211_frame) +
+ sizeof(struct ether_header);
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+#ifdef IFF_NOTRAILERS
+ ifp->if_flags |= IFF_NOTRAILERS;
+#endif
+#ifdef __NetBSD__
+ memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
+#endif
+#ifdef __FreeBSD__
+ ifp->if_output = ether_output;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ memcpy(sc->sc_ec.ac_enaddr, sc->sc_mib_addr.aMAC_Address,
+ ETHER_ADDR_LEN);
+#endif
- if (m0 == NULL) {
- /* XXX defer sending if not synched yet? */
- IF_DEQUEUE (&ifp->if_snd, m0);
- if (m0 == NULL)
- break;
+ printf("%s: IEEE802.11 %s %dMbps (firmware %s)\n",
+ sc->sc_dev.dv_xname,
+ sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH ? "FH" : "DS",
+ sc->sc_tx_rate / 10, sc->sc_banner);
+ printf("%s: address %s\n",
+ sc->sc_dev.dv_xname, ether_sprintf(sc->sc_mib_addr.aMAC_Address));
+ if_attach(ifp);
+#ifdef __OpenBSD__
+ ether_ifattach(ifp);
#if NBPFILTER > 0
- /*
- * Pass packet to bpf if there is a listener.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m0);
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+#elif defined(__FreeBSD__)
+ ether_ifattach(ifp);
+#if NBPFILTER > 0
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+#elif defined(__NetBSD__)
+ ether_ifattach(ifp, sc->sc_mib_addr.aMAC_Address);
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
#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;
+#ifdef IFM_IEEE80211
+ ifmedia_init(&sc->sc_media, 0, awi_media_change, awi_media_status);
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ for (i = 0; i < phy_rates[1]; i++) {
+ mword = awi_media_rate2opt(sc, AWI_80211_RATE(phy_rates[2 + i]));
+ if (mword == 0)
+ continue;
+ mword |= IFM_IEEE80211;
+ ifmedia_add(&sc->sc_media, mword, 0, NULL);
+ ifmedia_add(&sc->sc_media,
+ mword | IFM_IEEE80211_ADHOC, 0, NULL);
+ if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
+ ifmedia_add(&sc->sc_media,
+ mword | IFM_IEEE80211_ADHOC | IFM_FLAG0, 0, NULL);
}
- 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);
- }
-}
+ awi_media_status(ifp, &imr);
+ ifmedia_set(&sc->sc_media, imr.ifm_active);
+#endif
-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;
-}
+ /* ready to accept ioctl */
+ awi_unlock(sc);
-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;
- }
+ /* Attach is successful. */
+ sc->sc_attached = 1;
+ return 0;
}
-
-
+#ifndef __FreeBSD__
int
-awi_intlock(sc)
+awi_detach(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;
+ struct ifnet *ifp = sc->sc_ifp;
+ int s;
- if (!awi_intlock(sc))
- return;
-
- awi_write_1(sc, AWI_INTMASK, intmask);
- awi_write_1(sc, AWI_INTMASK2, 0);
+ /* Succeed if there is no work to do. */
+ if (!sc->sc_attached)
+ return (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]);
+ s = splnet();
+ sc->sc_invalid = 1;
+ awi_stop(sc);
+ while (sc->sc_sleep_cnt > 0) {
+ wakeup(sc);
+ (void)tsleep(sc, PWAIT, "awidet", 1);
}
- 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));
+ if (sc->sc_wep_ctx != NULL)
+ free(sc->sc_wep_ctx, M_DEVBUF);
+#if NBPFILTER > 0
+ bpfdetach(ifp);
+#endif
+#ifdef IFM_IEEE80211
+ ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
+#endif
+ ether_ifdetach(ifp);
+ if_detach(ifp);
+ if (sc->sc_enabled) {
+ if (sc->sc_disable)
+ (*sc->sc_disable)(sc);
+ sc->sc_enabled = 0;
}
- printf("\n");
+ splx(s);
+ return 0;
}
-u_int8_t
-awi_read_intst(sc)
- struct awi_softc *sc;
+int
+awi_activate(self, act)
+ struct device *self;
+ enum devact act;
{
- 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;
-}
+ struct awi_softc *sc = (struct awi_softc *)self;
+ int s, error = 0;
-
-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;
+ s = splnet();
+ switch (act) {
+ case DVACT_ACTIVATE:
+ error = EOPNOTSUPP;
+ break;
- 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;
+ case DVACT_DEACTIVATE:
+ sc->sc_invalid = 1;
+#ifdef __NetBSD__
+ if (sc->sc_ifp)
+ if_deactivate(sc->sc_ifp);
+#endif
+ break;
}
-}
-
-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;
-}
+ splx(s);
-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;
+ return error;
}
-
-
void
-awi_send_authreq (sc)
+awi_power(sc, why)
struct awi_softc *sc;
+ int why;
{
- 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.
- */
+ int s;
+ int ocansleep;
- 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_enabled)
+ return;
- 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);
+ s = splnet();
+ ocansleep = sc->sc_cansleep;
+ sc->sc_cansleep = 0;
+#ifdef needtobefixed /*ONOE*/
+ if (why == PWR_RESUME) {
+ sc->sc_enabled = 0;
+ awi_init(sc);
+ (void)awi_intr(sc);
+ } else {
+ awi_stop(sc);
+ if (sc->sc_disable)
+ (*sc->sc_disable)(sc);
}
-
- awi_send_frame(sc, m);
-
- sc->sc_mgt_timer = 2;
- awi_set_timer(sc);
+#endif
+ sc->sc_cansleep = ocansleep;
+ splx(s);
}
+#endif /* __NetBSD__ */
-void
-awi_send_assocreq (sc)
- struct awi_softc *sc;
+static int
+awi_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
{
- 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 *);
+ struct awi_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error;
+ struct ieee80211_nwid nwid;
+ u_int8_t *p;
+ s = splnet();
- 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);
+#ifdef __OpenBSD__
+ if ((error = ether_ioctl(ifp, &sc->sc_ec, cmd, data)) > 0) {
+ splx(s);
+ return (error);
}
-
- 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);
+ /* serialize ioctl */
+ error = awi_lock(sc);
+ if (error)
+ goto cantlock;
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ arp_ifinit((void *)ifp, ifa);
+ break;
#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);
+ /* FALLTHROUGH */
+ case SIOCSIFFLAGS:
+ sc->sc_format_llc = !(ifp->if_flags & IFF_LINK0);
+ if (!(ifp->if_flags & IFF_UP)) {
+ if (sc->sc_enabled) {
+ awi_stop(sc);
+ if (sc->sc_disable)
+ (*sc->sc_disable)(sc);
+ sc->sc_enabled = 0;
}
+ break;
}
-
+ error = awi_init(sc);
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);
- }
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#ifdef __FreeBSD__
+ error = ENETRESET; /*XXX*/
+#else
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ec) :
+ ether_delmulti(ifr, &sc->sc_ec);
+#endif
/*
- * 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..)
+ * Do not rescan BSS. Rather, just reset multicast filter.
*/
- 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);
+ if (error == ENETRESET) {
+ if (sc->sc_enabled)
+ error = awi_init(sc);
+ else
+ error = 0;
}
-
break;
-
- case IEEEWL_SUBTYPE_DISSOC:
- printf("dissoc\n");
-
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > ETHERMTU)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
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);
+ case SIOCS80211NWID:
+ error = copyin(ifr->ifr_data, &nwid, sizeof(nwid));
+ if (error)
+ break;
+ if (nwid.i_len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
+ break;
}
- /*
- * 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);
+ if (sc->sc_mib_mac.aDesired_ESS_ID[1] == nwid.i_len &&
+ memcmp(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
+ nwid.i_len) == 0)
+ break;
+ memset(sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
+ sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_mib_mac.aDesired_ESS_ID[1] = nwid.i_len;
+ memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], nwid.i_nwid,
+ nwid.i_len);
+ if (sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(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);
+ case SIOCG80211NWID:
+ if (ifp->if_flags & IFF_RUNNING)
+ p = sc->sc_bss.essid;
+ else
+ p = sc->sc_mib_mac.aDesired_ESS_ID;
+ error = copyout(p + 1, ifr->ifr_data, 1 + IEEE80211_NWID_LEN);
+ break;
+ case SIOCS80211NWKEY:
+ error = awi_wep_setnwkey(sc, (struct ieee80211_nwkey *)data);
+ break;
+ case SIOCG80211NWKEY:
+ error = awi_wep_getnwkey(sc, (struct ieee80211_nwkey *)data);
break;
+#ifdef IFM_IEEE80211
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ break;
+#endif
default:
- printf("unk mgt subtype %x\n", subtype);
+#ifdef notyet
+ error = awi_wicfg(ifp, cmd, data);
+#else
+ error = EINVAL;
+#endif
break;
}
- m_freem(m); /* done.. */
+ awi_unlock(sc);
+ cantlock:
+ splx(s);
+ return error;
}
-
-
-
-
-/*
- * Do 802.11 receive processing. "m" contains a receive frame;
- * rxts is the local receive timestamp
- */
-
-void
-awi_rcv (sc, m, rxts, rssi)
+#ifdef IFM_IEEE80211
+static int
+awi_media_rate2opt(sc, rate)
struct awi_softc *sc;
- struct mbuf *m;
- u_int32_t rxts;
- u_int8_t rssi;
+ int rate;
{
- 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..
- */
+ int mword;
- 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;
+ mword = 0;
+ switch (rate) {
+ case 10:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ mword = IFM_IEEE80211_FH1;
+ else
+ mword = IFM_IEEE80211_DS1;
break;
-
- case IEEEWL_FC_TYPE_DATA << IEEEWL_FC_TYPE_SHIFT:
- awi_rcv_data (sc, m);
- m = 0;
+ case 20:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ mword = IFM_IEEE80211_FH2;
+ else
+ mword = IFM_IEEE80211_DS2;
+ break;
+ case 55:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
+ mword = IFM_IEEE80211_DS5;
+ break;
+ case 110:
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_DS)
+ mword = IFM_IEEE80211_DS11;
break;
-
- case IEEEWL_FC_TYPE_CTL << IEEEWL_FC_TYPE_SHIFT:
- awi_rcv_ctl (sc, m);
- default:
- goto drop;
}
-
- drop:
- if (m) m_freem(m);
+ return mword;
}
-void
-awi_copy_rxd (sc, cur, rxd)
+static int
+awi_media_opt2rate(sc, opt)
struct awi_softc *sc;
- u_int32_t cur;
- struct awi_rxd *rxd;
+ int opt;
{
- 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);
+ int rate;
- /*
- * 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);
+ rate = 0;
+ switch (IFM_SUBTYPE(opt)) {
+ case IFM_IEEE80211_FH1:
+ case IFM_IEEE80211_FH2:
+ if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_FH)
+ return 0;
+ break;
+ case IFM_IEEE80211_DS1:
+ case IFM_IEEE80211_DS2:
+ case IFM_IEEE80211_DS5:
+ case IFM_IEEE80211_DS11:
+ if (sc->sc_mib_phy.IEEE_PHY_Type != AWI_PHY_TYPE_DS)
+ return 0;
+ break;
}
-}
-
-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;
+ switch (IFM_SUBTYPE(opt)) {
+ case IFM_IEEE80211_FH1:
+ case IFM_IEEE80211_DS1:
+ rate = 10;
+ break;
+ case IFM_IEEE80211_FH2:
+ case IFM_IEEE80211_DS2:
+ rate = 20;
+ break;
+ case IFM_IEEE80211_DS5:
+ rate = 55;
+ break;
+ case IFM_IEEE80211_DS11:
+ rate = 110;
+ break;
}
- return next;
+ return rate;
}
-void
-awi_dump_rxchain (sc, what, descr)
- struct awi_softc *sc;
- char *what;
- u_int32_t *descr;
+/*
+ * Called from ifmedia_ioctl via awi_ioctl with lock obtained.
+ */
+static int
+awi_media_change(ifp)
+ struct ifnet *ifp;
{
- 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;
+ struct awi_softc *sc = ifp->if_softc;
+ struct ifmedia_entry *ime;
+ u_int8_t *phy_rates;
+ int i, rate, error;
+
+ error = 0;
+ ime = sc->sc_media.ifm_cur;
+ rate = awi_media_opt2rate(sc, ime->ifm_media);
+ if (rate == 0)
+ return EINVAL;
+ if (rate != sc->sc_tx_rate) {
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ for (i = 0; i < phy_rates[1]; i++) {
+ if (rate == AWI_80211_RATE(phy_rates[2 + i]))
+ 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);
+ if (i == phy_rates[1])
+ return EINVAL;
}
-
- /* 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;
-
+ if (ime->ifm_media & IFM_IEEE80211_ADHOC) {
+ sc->sc_mib_local.Network_Mode = 0;
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ sc->sc_no_bssid = 0;
+ else
+ sc->sc_no_bssid = (ime->ifm_media & IFM_FLAG0) ? 1 : 0;
+ } else {
+ sc->sc_mib_local.Network_Mode = 1;
}
-
- /* 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);
+ if (sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
}
+ return error;
}
-void
-awi_txint (sc)
- struct awi_softc *sc;
+static void
+awi_media_status(ifp, imr)
+ struct ifnet *ifp;
+ struct ifmediareq *imr;
{
- 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 */;
- }
+ struct awi_softc *sc = ifp->if_softc;
- txfirst = (txfirst + 1) % sc->sc_ntxd;
- sc->sc_txpending--;
+ imr->ifm_status = IFM_AVALID;
+ if (ifp->if_flags & IFF_RUNNING)
+ imr->ifm_status |= IFM_ACTIVE;
+ imr->ifm_active = IFM_IEEE80211;
+ imr->ifm_active |= awi_media_rate2opt(sc, sc->sc_tx_rate);
+ if (sc->sc_mib_local.Network_Mode == 0) {
+ imr->ifm_active |= IFM_IEEE80211_ADHOC;
+ if (sc->sc_no_bssid)
+ imr->ifm_active |= IFM_FLAG0;
}
-
- 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.
- *
- */
+#endif /* IFM_IEEE80211 */
int
awi_intr(arg)
void *arg;
{
struct awi_softc *sc = arg;
- int handled = 0;
+ u_int16_t status;
+ int error, handled = 0, ocansleep;
- if (sc->sc_state == AWI_ST_OFF) {
- u_int8_t intstate = awi_read_intst (sc);
- return intstate != 0;
- }
+ if (!sc->sc_enabled || !sc->sc_enab_intr || sc->sc_invalid)
+ return 0;
- /* disable power down, (and implicitly ack interrupt) */
- am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
+ am79c930_gcr_setbits(&sc->sc_chip,
+ AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT);
awi_write_1(sc, AWI_DIS_PWRDN, 1);
-
- for (;;) {
- u_int8_t intstate = awi_read_intst (sc);
+ ocansleep = sc->sc_cansleep;
+ sc->sc_cansleep = 0;
- if (!intstate)
+ for (;;) {
+ error = awi_intr_lock(sc);
+ if (error)
+ break;
+ status = awi_read_1(sc, AWI_INTSTAT);
+ awi_write_1(sc, AWI_INTSTAT, 0);
+ awi_write_1(sc, AWI_INTSTAT, 0);
+ status |= awi_read_1(sc, AWI_INTSTAT2) << 8;
+ awi_write_1(sc, AWI_INTSTAT2, 0);
+ DELAY(10);
+ awi_intr_unlock(sc);
+ if (!sc->sc_cmd_inprog)
+ status &= ~AWI_INT_CMD; /* make sure */
+ if (status == 0)
break;
-
handled = 1;
-
- if (intstate & AWI_INT_RX)
+ if (status & AWI_INT_RX)
awi_rxint(sc);
-
- if (intstate & AWI_INT_TX)
+ if (status & 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);
+ if (status & AWI_INT_CMD)
+ awi_cmd_done(sc);
+ if (status & AWI_INT_SCAN_CMPLT) {
+ if (sc->sc_status == AWI_ST_SCAN &&
+ sc->sc_mgt_timer > 0)
+ (void)awi_next_scan(sc);
}
-
}
- /* reenable power down */
+ sc->sc_cansleep = ocansleep;
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)
+int
+awi_init(sc)
struct awi_softc *sc;
{
+ int error, ostatus;
+ int n;
struct ifnet *ifp = sc->sc_ifp;
- struct mbuf *m;
+#ifdef __FreeBSD__
+ struct ifmultiaddr *ifma;
+#else
+ struct ether_multi *enm;
+ struct ether_multistep step;
+#endif
- 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);
+ /* reinitialize muticast filter */
+ n = 0;
+ ifp->if_flags |= IFF_ALLMULTI;
+ sc->sc_mib_local.Accept_All_Multicast_Dis = 0;
+ if (ifp->if_flags & IFF_PROMISC) {
+ sc->sc_mib_mac.aPromiscuous_Enable = 1;
+ goto set_mib;
+ }
+ sc->sc_mib_mac.aPromiscuous_Enable = 0;
+#ifdef __FreeBSD__
+ if (ifp->if_amcount != 0)
+ goto set_mib;
+ for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
+ ifma = LIST_NEXT(ifma, ifma_link)) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ if (n == AWI_GROUP_ADDR_SIZE)
+ goto set_mib;
+ memcpy(sc->sc_mib_addr.aGroup_Addresses[n],
+ LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+ ETHER_ADDR_LEN);
+ n++;
+ }
+#else
+ ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+ while (enm != NULL) {
+ if (n == AWI_GROUP_ADDR_SIZE ||
+ memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)
+ != 0)
+ goto set_mib;
+ memcpy(sc->sc_mib_addr.aGroup_Addresses[n], enm->enm_addrlo,
+ ETHER_ADDR_LEN);
+ n++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+#endif
+ for (; n < AWI_GROUP_ADDR_SIZE; n++)
+ memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, ETHER_ADDR_LEN);
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
+
+ set_mib:
+#ifdef notdef /* allow non-encrypted frame for receiving. */
+ sc->sc_mib_mgt.Wep_Required = sc->sc_wep_algo != NULL ? 1 : 0;
+#endif
+ if (!sc->sc_enabled) {
+ sc->sc_enabled = 1;
+ if (sc->sc_enable)
+ (*sc->sc_enable)(sc);
+ sc->sc_status = AWI_ST_INIT;
+ error = awi_init_hw(sc);
+ if (error)
+ return error;
+ }
+ ostatus = sc->sc_status;
+ sc->sc_status = AWI_ST_INIT;
+ if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY)) != 0) {
+ awi_stop(sc);
+ return error;
+ }
+ if (ifp->if_flags & IFF_RUNNING)
+ sc->sc_status = AWI_ST_RUNNING;
+ else {
+ if (ostatus == AWI_ST_INIT) {
+ error = awi_init_txrx(sc);
+ if (error)
+ return error;
+ }
+ error = awi_start_scan(sc);
+ }
+ return error;
}
-
-
-/*
- * device stop routine
- */
-
void
awi_stop(sc)
struct awi_softc *sc;
{
struct ifnet *ifp = sc->sc_ifp;
-
- awi_flush(sc);
+ struct awi_bss *bp;
+ struct mbuf *m;
- /* Turn off timer.. */
+ sc->sc_status = AWI_ST_INIT;
+ if (!sc->sc_invalid) {
+ (void)awi_cmd_wait(sc);
+ if (sc->sc_mib_local.Network_Mode &&
+ sc->sc_status > AWI_ST_AUTH)
+ awi_send_deauth(sc);
+ awi_stop_txrx(sc);
+ }
+ ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
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.
- */
+ sc->sc_tx_timer = sc->sc_rx_timer = sc->sc_mgt_timer = 0;
+ for (;;) {
+ IF_DEQUEUE(&sc->sc_mgtq, m);
+ if (m == NULL)
+ break;
+ m_freem(m);
+ }
+ for (;;) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+ m_freem(m);
+ }
+ while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
+ TAILQ_REMOVE(&sc->sc_scan, bp, list);
+ free(bp, M_DEVBUF);
+ }
}
-/*
- * Watchdog routine, triggered by timer.
- * This does periodic maintainance-type tasks on the interface.
- */
-
-void
+static void
awi_watchdog(ifp)
struct ifnet *ifp;
{
struct awi_softc *sc = ifp->if_softc;
- u_int8_t test;
- int i;
+ int ocansleep;
- 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;
- }
+ if (sc->sc_invalid) {
+ 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;
+ ocansleep = sc->sc_cansleep;
+ sc->sc_cansleep = 0;
+ if (sc->sc_tx_timer && --sc->sc_tx_timer == 0) {
+ printf("%s: transmit timeout\n", sc->sc_dev.dv_xname);
+ awi_txint(sc);
+ }
+ if (sc->sc_rx_timer && --sc->sc_rx_timer == 0) {
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: no recent beacons from %s; rescanning\n",
+ sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_bss.bssid));
}
+ ifp->if_flags &= ~IFF_RUNNING;
+ awi_start_scan(sc);
}
- /*
- * 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;
+ if (sc->sc_mgt_timer && --sc->sc_mgt_timer == 0) {
+ switch (sc->sc_status) {
+ case AWI_ST_SCAN:
+ awi_stop_scan(sc);
+ break;
+ case AWI_ST_AUTH:
+ case AWI_ST_ASSOC:
+ /* restart scan */
+ awi_start_scan(sc);
+ break;
+ default:
+ break;
}
}
- /*
- * 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);
+ if (sc->sc_tx_timer == 0 && sc->sc_rx_timer == 0 &&
+ sc->sc_mgt_timer == 0)
+ ifp->if_timer = 0;
+ else
+ ifp->if_timer = 1;
+ sc->sc_cansleep = ocansleep;
+}
+
+static void
+awi_start(ifp)
+ struct ifnet *ifp;
+{
+ struct awi_softc *sc = ifp->if_softc;
+ struct mbuf *m0, *m;
+ u_int32_t txd, frame, ntxd;
+ u_int8_t rate;
+ int len, sent = 0;
+
+ for (;;) {
+ txd = sc->sc_txnext;
+ IF_DEQUEUE(&sc->sc_mgtq, m0);
+ if (m0 != NULL) {
+ if (awi_next_txd(sc, m0->m_pkthdr.len, &frame, &ntxd)) {
+ IF_PREPEND(&sc->sc_mgtq, m0);
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
}
- }
- }
-
- /*
- * 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);
+ } else {
+ if (!(ifp->if_flags & IFF_RUNNING))
break;
- case AWI_ST_AUTHED:
- awi_send_assocreq(sc);
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
break;
- default:
- printf("weird state for mgt timeout!\n");
+ len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame);
+ if (sc->sc_format_llc)
+ len += sizeof(struct llc) -
+ sizeof(struct ether_header);
+ if (sc->sc_wep_algo != NULL)
+ len += IEEE80211_WEP_IVLEN +
+ IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
+ if (awi_next_txd(sc, len, &frame, &ntxd)) {
+ IF_PREPEND(&ifp->if_snd, m0);
+ ifp->if_flags |= IFF_OACTIVE;
break;
}
+ AWI_BPF_MTAP(sc, m0, AWI_BPF_NORM);
+ m0 = awi_fix_txhdr(sc, m0);
+ if (sc->sc_wep_algo != NULL && m0 != NULL)
+ m0 = awi_wep_encrypt(sc, m0, 1);
+ if (m0 == NULL) {
+ ifp->if_oerrors++;
+ continue;
+ }
+ ifp->if_opackets++;
+ }
+#ifdef AWI_DEBUG
+ if (awi_dump)
+ awi_dump_pkt(sc, m0, -1);
+#endif
+ AWI_BPF_MTAP(sc, m0, AWI_BPF_RAW);
+ len = 0;
+ for (m = m0; m != NULL; m = m->m_next) {
+ awi_write_bytes(sc, frame + len, mtod(m, u_int8_t *),
+ m->m_len);
+ len += m->m_len;
}
+ m_freem(m0);
+ rate = sc->sc_tx_rate; /*XXX*/
+ awi_write_1(sc, ntxd + AWI_TXD_STATE, 0);
+ awi_write_4(sc, txd + AWI_TXD_START, frame);
+ awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd);
+ awi_write_4(sc, txd + AWI_TXD_LENGTH, len);
+ awi_write_1(sc, txd + AWI_TXD_RATE, rate);
+ awi_write_4(sc, txd + AWI_TXD_NDA, 0);
+ awi_write_4(sc, txd + AWI_TXD_NRA, 0);
+ awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN);
+ sc->sc_txnext = ntxd;
+ sent++;
+ }
+ if (sent) {
+ if (sc->sc_tx_timer == 0)
+ sc->sc_tx_timer = 5;
+ ifp->if_timer = 1;
+#ifdef AWI_DEBUG
+ if (awi_verbose)
+ printf("awi_start: sent %d txdone %d txnext %d txbase %d txend %d\n", sent, sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
+#endif
}
- awi_set_timer(sc);
}
-void
-awi_set_mc (sc)
- struct awi_softc *sc;
+static void
+awi_txint(sc)
+ struct awi_softc *sc;
{
- /* XXX not implemented yet.. */
-}
+ struct ifnet *ifp = sc->sc_ifp;
+ u_int8_t flags;
-/*
- * init routine
- */
+ while (sc->sc_txdone != sc->sc_txnext) {
+ flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE);
+ if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE))
+ break;
+ if (flags & AWI_TXD_ST_ERROR)
+ ifp->if_oerrors++;
+ sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) &
+ 0x7fff;
+ }
+ sc->sc_tx_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+#ifdef AWI_DEBUG
+ if (awi_verbose)
+ printf("awi_txint: txdone %d txnext %d txbase %d txend %d\n",
+ sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend);
+#endif
+ awi_start(ifp);
+}
-/*
- * 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;
+static struct mbuf *
+awi_fix_txhdr(sc, m0)
+ struct awi_softc *sc;
+ struct mbuf *m0;
{
- 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();
+ struct ether_header eh;
+ struct ieee80211_frame *wh;
+ struct llc *llc;
- switch (cmd) {
- case SIOCSIFADDR:
- if ((error = awi_enable(sc)) != 0)
- break;
+ if (m0->m_len < sizeof(eh)) {
+ m0 = m_pullup(m0, sizeof(eh));
+ if (m0 == NULL)
+ return NULL;
+ }
+ memcpy(&eh, mtod(m0, caddr_t), sizeof(eh));
+ if (sc->sc_format_llc) {
+ m_adj(m0, sizeof(struct ether_header) - sizeof(struct llc));
+ llc = mtod(m0, struct llc *);
+ llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
+ llc->llc_control = LLC_UI;
+ llc->llc_snap.org_code[0] = llc->llc_snap.org_code[1] =
+ llc->llc_snap.org_code[2] = 0;
+ llc->llc_snap.ether_type = eh.ether_type;
+ }
+ M_PREPEND(m0, sizeof(struct ieee80211_frame), M_DONTWAIT);
+ if (m0 == NULL)
+ return NULL;
+ wh = mtod(m0, struct ieee80211_frame *);
+
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
+ LE_WRITE_2(wh->i_dur, 0);
+ LE_WRITE_2(wh->i_seq, 0);
+ if (sc->sc_mib_local.Network_Mode) {
+ wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
+ memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr3, eh.ether_dhost, ETHER_ADDR_LEN);
+ } else {
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ memcpy(wh->i_addr1, eh.ether_dhost, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr2, eh.ether_shost, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ }
+ return m0;
+}
- ifp->if_flags |= IFF_UP;
+static struct mbuf *
+awi_fix_rxhdr(sc, m0)
+ struct awi_softc *sc;
+ struct mbuf *m0;
+{
+ struct ieee80211_frame wh;
+ struct ether_header *eh;
+ struct llc *llc;
- /* XXX other AF support: inet6, NS, ... */
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- arp_ifinit(&sc->sc_ec, ifa);
+ if (m0->m_len < sizeof(wh)) {
+ m_freem(m0);
+ return NULL;
+ }
+ llc = (struct llc *)(mtod(m0, caddr_t) + sizeof(wh));
+ if (llc->llc_dsap == LLC_SNAP_LSAP &&
+ llc->llc_ssap == LLC_SNAP_LSAP &&
+ llc->llc_control == LLC_UI &&
+ llc->llc_snap.org_code[0] == 0 &&
+ llc->llc_snap.org_code[1] == 0 &&
+ llc->llc_snap.org_code[2] == 0) {
+ memcpy(&wh, mtod(m0, caddr_t), sizeof(wh));
+ m_adj(m0, sizeof(wh) + sizeof(*llc) - sizeof(*eh));
+ eh = mtod(m0, struct ether_header *);
+ switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
+ case IEEE80211_FC1_DIR_NODS:
+ memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
+ memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
break;
-#endif
- default:
+ case IEEE80211_FC1_DIR_TODS:
+ memcpy(eh->ether_dhost, wh.i_addr3, ETHER_ADDR_LEN);
+ memcpy(eh->ether_shost, wh.i_addr2, ETHER_ADDR_LEN);
break;
+ case IEEE80211_FC1_DIR_FROMDS:
+ memcpy(eh->ether_dhost, wh.i_addr1, ETHER_ADDR_LEN);
+ memcpy(eh->ether_shost, wh.i_addr3, ETHER_ADDR_LEN);
+ break;
+ case IEEE80211_FC1_DIR_DSTODS:
+ m_freem(m0);
+ return NULL;
}
- 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);
+ } else {
+ /* assuming ethernet encapsulation, just strip 802.11 header */
+ m_adj(m0, sizeof(wh));
+ }
+ if (ALIGN(mtod(m0, caddr_t) + sizeof(struct ether_header)) !=
+ (u_int)(mtod(m0, caddr_t) + sizeof(struct ether_header))) {
+ /* XXX: we loose to estimate the type of encapsulation */
+ struct mbuf *n, *n0, **np;
+ caddr_t newdata;
+ int off;
+
+ n0 = NULL;
+ np = &n0;
+ off = 0;
+ while (m0->m_pkthdr.len > off) {
+ if (n0 == NULL) {
+ MGETHDR(n, M_DONTWAIT, MT_DATA);
+ if (n == NULL) {
+ m_freem(m0);
+ return NULL;
+ }
+ M_COPY_PKTHDR(n, m0);
+ n->m_len = MHLEN;
+ } else {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n == NULL) {
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+ }
+ n->m_len = MLEN;
+ }
+ if (m0->m_pkthdr.len - off >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ if (n0 == NULL) {
+ newdata = (caddr_t)
+ ALIGN(n->m_data
+ + sizeof(struct ether_header))
+ - sizeof(struct ether_header);
+ n->m_len -= newdata - n->m_data;
+ n->m_data = newdata;
+ }
+ if (n->m_len > m0->m_pkthdr.len - off)
+ n->m_len = m0->m_pkthdr.len - off;
+ m_copydata(m0, off, n->m_len, mtod(n, caddr_t));
+ off += n->m_len;
+ *np = n;
+ np = &n->m_next;
}
- break;
-
- default:
- error = EINVAL;
- break;
-
+ m_freem(m0);
+ m0 = n0;
}
- splx(s);
- return error;
-
+ return m0;
}
-int awi_activate (self, act)
- struct device *self;
- enum devact act;
+static void
+awi_input(sc, m, rxts, rssi)
+ struct awi_softc *sc;
+ struct mbuf *m;
+ u_int32_t rxts;
+ u_int8_t rssi;
{
- int s = splnet();
- panic("awi_activate");
-
-#if 0
- switch (act) {
- case DVACT_ACTIVATE:
- rv = EOPNOTSUPP;
- break;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211_frame *wh;
+#ifndef __NetBSD__
+ struct ether_header *eh;
+#endif
- case DVACT_DEACTIVATE:
-#ifdef notyet
- /* First, kill off the interface. */
- if_detach(sc->sc_ethercom.ec_if);
+ /* trim CRC here for WEP can find its own CRC at the end of packet. */
+ m_adj(m, -ETHER_CRC_LEN);
+ AWI_BPF_MTAP(sc, m, AWI_BPF_RAW);
+ wh = mtod(m, struct ieee80211_frame *);
+ if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
+ IEEE80211_FC0_VERSION_0) {
+ printf("%s; receive packet with wrong version: %x\n",
+ sc->sc_dev.dv_xname, wh->i_fc[0]);
+ m_freem(m);
+ ifp->if_ierrors++;
+ return;
+ }
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ m = awi_wep_encrypt(sc, m, 0);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+ wh = mtod(m, struct ieee80211_frame *);
+ }
+#ifdef AWI_DEBUG
+ if (awi_dump)
+ awi_dump_pkt(sc, m, rssi);
#endif
- /* Now disable the interface. */
- awidisable(sc);
- break;
+ if ((sc->sc_mib_local.Network_Mode || !sc->sc_no_bssid) &&
+ sc->sc_status == AWI_ST_RUNNING) {
+ if (memcmp(wh->i_addr2, sc->sc_bss.bssid, ETHER_ADDR_LEN) == 0) {
+ sc->sc_rx_timer = 10;
+ sc->sc_bss.rssi = rssi;
+ }
}
+ switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+ case IEEE80211_FC0_TYPE_DATA:
+ if (sc->sc_mib_local.Network_Mode) {
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
+ IEEE80211_FC1_DIR_FROMDS) {
+ m_freem(m);
+ return;
+ }
+ } else {
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
+ IEEE80211_FC1_DIR_NODS) {
+ m_freem(m);
+ return;
+ }
+ }
+ m = awi_fix_rxhdr(sc, m);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ break;
+ }
+ ifp->if_ipackets++;
+#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)
+ AWI_BPF_MTAP(sc, m, AWI_BPF_NORM);
#endif
- splx(s);
-
+#ifdef __NetBSD__
+ (*ifp->if_input)(ifp, m);
+#else
+ eh = mtod(m, struct ether_header *);
+ m_adj(m, sizeof(*eh));
+ ether_input(ifp, eh, m);
+#endif
+ break;
+ case IEEE80211_FC0_TYPE_MGT:
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
+ IEEE80211_FC1_DIR_NODS) {
+ m_freem(m);
+ return;
+ }
+ switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ awi_recv_beacon(sc, m, rxts, rssi);
+ break;
+ case IEEE80211_FC0_SUBTYPE_AUTH:
+ awi_recv_auth(sc, m);
+ break;
+ case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
+ case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
+ awi_recv_asresp(sc, m);
+ break;
+ case IEEE80211_FC0_SUBTYPE_DEAUTH:
+ if (sc->sc_mib_local.Network_Mode)
+ awi_send_auth(sc, 1);
+ break;
+ case IEEE80211_FC0_SUBTYPE_DISASSOC:
+ if (sc->sc_mib_local.Network_Mode)
+ awi_send_asreq(sc, 1);
+ break;
+ }
+ m_freem(m);
+ break;
+ case IEEE80211_FC0_TYPE_CTL:
+ default:
+ /* should not come here */
+ m_freem(m);
+ break;
+ }
}
-int
-awi_drop_output (ifp, m0, dst, rt0)
- struct ifnet *ifp;
- struct mbuf *m0;
- struct sockaddr *dst;
- struct rtentry *rt0;
+static void
+awi_rxint(sc)
+ struct awi_softc *sc;
{
- m_freem(m0);
- return 0;
-}
+ u_int8_t state, rate, rssi;
+ u_int16_t len;
+ u_int32_t frame, next, rxts, rxoff;
+ struct mbuf *m;
-void
-awi_drop_input (ifp, m0)
- struct ifnet *ifp;
- struct mbuf *m0;
-{
- m_freem(m0);
+ rxoff = sc->sc_rxdoff;
+ for (;;) {
+ state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE);
+ if (state & AWI_RXD_ST_OWN)
+ break;
+ if (!(state & AWI_RXD_ST_CONSUMED)) {
+ if (state & AWI_RXD_ST_RXERROR)
+ sc->sc_ifp->if_ierrors++;
+ else {
+ len = awi_read_2(sc, rxoff + AWI_RXD_LEN);
+ rate = awi_read_1(sc, rxoff + AWI_RXD_RATE);
+ rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI);
+ frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & 0x7fff;
+ rxts = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME);
+ m = awi_devget(sc, frame, len);
+ if (state & AWI_RXD_ST_LF)
+ awi_input(sc, m, rxts, rssi);
+ else
+ sc->sc_rxpend = m;
+ }
+ state |= AWI_RXD_ST_CONSUMED;
+ awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
+ }
+ next = awi_read_4(sc, rxoff + AWI_RXD_NEXT);
+ if (next & AWI_RXD_NEXT_LAST)
+ break;
+ /* make sure the next pointer is correct */
+ if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT))
+ break;
+ state |= AWI_RXD_ST_OWN;
+ awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state);
+ rxoff = next & 0x7fff;
+ }
+ sc->sc_rxdoff = rxoff;
}
-int awi_attach (sc, macaddr)
+static struct mbuf *
+awi_devget(sc, off, len)
struct awi_softc *sc;
- u_int8_t *macaddr;
+ u_int32_t off;
+ u_int16_t len;
{
- 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.. */
+ struct mbuf *m;
+ struct mbuf *top, **mp;
+ u_int tlen;
+
+ top = sc->sc_rxpend;
+ mp = &top;
+ if (top != NULL) {
+ sc->sc_rxpend = NULL;
+ top->m_pkthdr.len += len;
+ m = top;
+ while (*mp != NULL) {
+ m = *mp;
+ mp = &m->m_next;
+ }
+ if (m->m_flags & M_EXT)
+ tlen = m->m_ext.ext_size;
+ else if (m->m_flags & M_PKTHDR)
+ tlen = MHLEN;
+ else
+ tlen = MLEN;
+ tlen -= m->m_len;
+ if (tlen > len)
+ tlen = len;
+ awi_read_bytes(sc, off, mtod(m, u_int8_t *) + m->m_len, tlen);
+ off += tlen;
+ len -= tlen;
+ }
-#if NBPFILTER > 0
- bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
-#endif
- return 0;
+ while (len > 0) {
+ if (top == NULL) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return NULL;
+ m->m_pkthdr.rcvif = sc->sc_ifp;
+ m->m_pkthdr.len = len;
+ m->m_len = MHLEN;
+ } else {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(top);
+ return NULL;
+ }
+ m->m_len = MLEN;
+ }
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = m->m_ext.ext_size;
+ }
+ if (top == NULL) {
+ int hdrlen = sizeof(struct ieee80211_frame) +
+ (sc->sc_format_llc ? sizeof(struct llc) :
+ sizeof(struct ether_header));
+ caddr_t newdata = (caddr_t)
+ ALIGN(m->m_data + hdrlen) - hdrlen;
+ m->m_len -= newdata - m->m_data;
+ m->m_data = newdata;
+ }
+ if (m->m_len > len)
+ m->m_len = len;
+ awi_read_bytes(sc, off, mtod(m, u_int8_t *), m->m_len);
+ off += m->m_len;
+ len -= m->m_len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+ return top;
}
-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);
-}
+/*
+ * Initialize hardware and start firmware to accept commands.
+ * Called everytime after power on firmware.
+ */
-void
-awi_init (sc)
+static int
+awi_init_hw(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);
+ u_int8_t status;
+ u_int16_t intmask;
+ int i, error;
+ sc->sc_enab_intr = 0;
+ sc->sc_invalid = 0; /* XXX: really? */
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;
+ /* reset firmware */
+ am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET);
+ DELAY(100);
+ awi_write_1(sc, AWI_SELFTEST, 0);
+ awi_write_1(sc, AWI_CMD, 0);
+ awi_write_1(sc, AWI_BANNER, 0);
+ am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET);
+ DELAY(100);
+
+ /* wait for selftest completion */
+ for (i = 0; ; i++) {
+ if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) {
+ printf("%s: failed to complete selftest (timeout)\n",
+ sc->sc_dev.dv_xname);
+ return ENXIO;
+ }
+ status = awi_read_1(sc, AWI_SELFTEST);
+ if ((status & 0xf0) == 0xf0)
+ break;
+ if (sc->sc_cansleep) {
+ sc->sc_sleep_cnt++;
+ (void)tsleep(sc, PWAIT, "awitst", 1);
+ sc->sc_sleep_cnt--;
+ } else {
+ DELAY(1000*1000/hz);
+ }
+ }
+ if (status != AWI_SELFTEST_PASSED) {
+ printf("%s: failed to complete selftest (code %x)\n",
+ sc->sc_dev.dv_xname, status);
+ return ENXIO;
+ }
-}
+ /* check banner to confirm firmware write it */
+ awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN);
+ if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) {
+ printf("%s: failed to complete selftest (bad banner)\n",
+ sc->sc_dev.dv_xname);
+ for (i = 0; i < AWI_BANNER_LEN; i++)
+ printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]);
+ printf("\n");
+ return ENXIO;
+ }
-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);
-}
+ /* initializing interrupt */
+ sc->sc_enab_intr = 1;
+ error = awi_intr_lock(sc);
+ if (error)
+ return error;
+ intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT |
+ AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD;
+ awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff);
+ awi_write_1(sc, AWI_INTMASK2, 0);
+ awi_write_1(sc, AWI_INTSTAT, 0);
+ awi_write_1(sc, AWI_INTSTAT2, 0);
+ awi_intr_unlock(sc);
+ am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT);
-void
-awi_cmd_test_if (sc)
- struct awi_softc *sc;
-{
- awi_cmd (sc, AWI_CMD_NOP);
+ /* issueing interface test command */
+ error = awi_cmd(sc, AWI_CMD_NOP);
+ if (error) {
+ printf("%s: failed to complete selftest", sc->sc_dev.dv_xname);
+ if (error == ENXIO)
+ printf(" (no hardware)\n");
+ else if (error != EWOULDBLOCK)
+ printf(" (error %d)\n", error);
+ else if (sc->sc_cansleep)
+ printf(" (lost interrupt)\n");
+ else
+ printf(" (command timeout)\n");
+ }
+ return error;
}
-void
-awi_cmd_get_mib (sc, var, offset, len)
+/*
+ * Extract the factory default MIB value from firmware and assign the driver
+ * default value.
+ * Called once at attaching the interface.
+ */
+
+static int
+awi_init_mibs(sc)
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);
+ int i, error;
+ u_int8_t *rate;
+
+ if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT)) != 0 ||
+ (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY)) != 0) {
+ printf("%s: failed to get default mib value (error %d)\n",
+ sc->sc_dev.dv_xname, error);
+ return error;
+ }
- awi_cmd (sc, AWI_CMD_GET_MIB);
+ rate = sc->sc_mib_phy.aSuprt_Data_Rates;
+ sc->sc_tx_rate = AWI_RATE_1MBIT;
+ for (i = 0; i < rate[1]; i++) {
+ if (AWI_80211_RATE(rate[2 + i]) > sc->sc_tx_rate)
+ sc->sc_tx_rate = AWI_80211_RATE(rate[2 + i]);
+ }
+ awi_init_region(sc);
+ memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
+ sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
+ sc->sc_mib_local.Fragmentation_Dis = 1;
+ sc->sc_mib_local.Accept_All_Multicast_Dis = 1;
+ sc->sc_mib_local.Power_Saving_Mode_Dis = 1;
+
+ /* allocate buffers */
+ sc->sc_txbase = AWI_BUFFERS;
+ sc->sc_txend = sc->sc_txbase +
+ (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) +
+ sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS;
+ LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase);
+ LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size,
+ sc->sc_txend - sc->sc_txbase);
+ LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend);
+ LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size,
+ AWI_BUFFERS_END - sc->sc_txend);
+ sc->sc_mib_local.Network_Mode = 1;
+ sc->sc_mib_local.Acting_as_AP = 0;
+ return 0;
}
-void
-awi_cmd_txinit (sc)
+/*
+ * Start transmitter and receiver of firmware
+ * Called after awi_init_hw() to start operation.
+ */
+
+static int
+awi_init_txrx(sc)
struct awi_softc *sc;
{
+ int error;
+
+ /* start transmitter */
+ sc->sc_txdone = sc->sc_txnext = sc->sc_txbase;
+ awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0);
+ awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0);
+ awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0);
+ awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0);
+ awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0);
+ awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0);
+ awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0);
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);
+ error = awi_cmd(sc, AWI_CMD_INIT_TX);
+ if (error)
+ return error;
+
+ /* start receiver */
+ if (sc->sc_rxpend) {
+ m_freem(sc->sc_rxpend);
+ sc->sc_rxpend = NULL;
+ }
+ error = awi_cmd(sc, AWI_CMD_INIT_RX);
+ if (error)
+ return error;
+ sc->sc_rxdoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC);
+ sc->sc_rxmoff = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC);
+ return 0;
}
-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)
+static void
+awi_stop_txrx(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);
+ if (sc->sc_cmd_inprog)
+ (void)awi_cmd_wait(sc);
+ (void)awi_cmd(sc, AWI_CMD_KILL_RX);
+ (void)awi_cmd_wait(sc);
+ sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX;
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_DATA, 1);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_MGT, 0);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_BCAST, 0);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_PS, 0);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_FTX_CF, 0);
+ (void)awi_cmd(sc, AWI_CMD_FLUSH_TX);
+ (void)awi_cmd_wait(sc);
}
-void awi_mibdump (sc, status)
+int
+awi_init_region(sc)
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);
+
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
+ case AWI_REG_DOMAIN_US:
+ case AWI_REG_DOMAIN_CA:
+ case AWI_REG_DOMAIN_EU:
+ sc->sc_scan_min = 0;
+ sc->sc_scan_max = 77;
+ break;
+ case AWI_REG_DOMAIN_ES:
+ sc->sc_scan_min = 0;
+ sc->sc_scan_max = 26;
+ break;
+ case AWI_REG_DOMAIN_FR:
+ sc->sc_scan_min = 0;
+ sc->sc_scan_max = 32;
+ break;
+ case AWI_REG_DOMAIN_JP:
+ sc->sc_scan_min = 6;
+ sc->sc_scan_max = 17;
+ break;
+ default:
+ return EINVAL;
+ }
+ sc->sc_scan_set = sc->sc_scan_cur % 3 + 1;
} 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++;
+ switch (sc->sc_mib_phy.aCurrent_Reg_Domain) {
+ case AWI_REG_DOMAIN_US:
+ case AWI_REG_DOMAIN_CA:
+ sc->sc_scan_min = 1;
+ sc->sc_scan_max = 11;
+ sc->sc_scan_cur = 3;
+ break;
+ case AWI_REG_DOMAIN_EU:
+ sc->sc_scan_min = 1;
+ sc->sc_scan_max = 13;
+ sc->sc_scan_cur = 3;
+ break;
+ case AWI_REG_DOMAIN_ES:
+ sc->sc_scan_min = 10;
+ sc->sc_scan_max = 11;
+ sc->sc_scan_cur = 10;
+ break;
+ case AWI_REG_DOMAIN_FR:
+ sc->sc_scan_min = 10;
+ sc->sc_scan_max = 13;
+ sc->sc_scan_cur = 10;
+ break;
+ case AWI_REG_DOMAIN_JP:
+ sc->sc_scan_min = 14;
+ sc->sc_scan_max = 14;
+ sc->sc_scan_cur = 14;
+ break;
+ default:
+ return EINVAL;
+ }
}
+ sc->sc_ownch = sc->sc_scan_cur;
+ return 0;
}
-
-/*
- * called on completion of test-interface command in first-stage init.
- */
-
-void awi_init_2 (sc, status)
+static int
+awi_start_scan(sc)
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;
+ int error = 0;
+ struct awi_bss *bp;
- awi_cmd_get_mib (sc, AWI_MIB_LOCAL, 0, AWI_MIB_LOCAL_SIZE);
+ while ((bp = TAILQ_FIRST(&sc->sc_scan)) != NULL) {
+ TAILQ_REMOVE(&sc->sc_scan, bp, list);
+ free(bp, M_DEVBUF);
+ }
+ if (!sc->sc_mib_local.Network_Mode && sc->sc_no_bssid) {
+ memset(&sc->sc_bss, 0, sizeof(sc->sc_bss));
+ sc->sc_bss.essid[0] = IEEE80211_ELEMID_SSID;
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ sc->sc_bss.chanset = sc->sc_ownch % 3 + 1;
+ sc->sc_bss.pattern = sc->sc_ownch;
+ sc->sc_bss.index = 1;
+ sc->sc_bss.dwell_time = 200; /*XXX*/
+ } else
+ sc->sc_bss.chanset = sc->sc_ownch;
+ sc->sc_status = AWI_ST_SETSS;
+ error = awi_set_ss(sc);
+ } else {
+ if (sc->sc_mib_local.Network_Mode)
+ awi_drvstate(sc, AWI_DRV_INFSC);
+ else
+ awi_drvstate(sc, AWI_DRV_ADHSC);
+ sc->sc_start_bss = 0;
+ sc->sc_active_scan = 1;
+ sc->sc_mgt_timer = AWI_ASCAN_WAIT / 1000;
+ sc->sc_ifp->if_timer = 1;
+ sc->sc_status = AWI_ST_SCAN;
+ error = awi_cmd_scan(sc);
+ }
+ return error;
}
-void awi_init_read_bufptrs_done (sc, status)
+static int
+awi_next_scan(sc)
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
- */
+ int error;
-#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);
+ for (;;) {
+ /*
+ * The pattern parameter for FH phy should be incremented
+ * by 3. But BayStack 650 Access Points apparently always
+ * assign hop pattern set parameter to 1 for any pattern.
+ * So we try all combinations of pattern/set parameters.
+ * Since this causes no error, it may be a bug of
+ * PCnetMobile firmware.
+ */
+ sc->sc_scan_cur++;
+ if (sc->sc_scan_cur > sc->sc_scan_max) {
+ sc->sc_scan_cur = sc->sc_scan_min;
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ sc->sc_scan_set = sc->sc_scan_set % 3 + 1;
+ }
+ error = awi_cmd_scan(sc);
+ if (error != EINVAL)
+ break;
+ }
+ return error;
}
-void awi_cmd_set_notap (sc)
+static void
+awi_stop_scan(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);
-}
+ struct ifnet *ifp = sc->sc_ifp;
+ struct awi_bss *bp, *sbp;
+ int fail;
-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);
+ bp = TAILQ_FIRST(&sc->sc_scan);
+ if (bp == NULL) {
+ notfound:
+ if (sc->sc_active_scan) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: entering passive scan mode\n",
+ sc->sc_dev.dv_xname);
+ sc->sc_active_scan = 0;
+ }
+ sc->sc_mgt_timer = AWI_PSCAN_WAIT / 1000;
+ ifp->if_timer = 1;
+ (void)awi_next_scan(sc);
return;
}
- awi_cmd_set_infra (sc);
+ sbp = NULL;
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s:\tmacaddr ch/pat sig flag wep essid\n",
+ sc->sc_dev.dv_xname);
+ for (; bp != NULL; bp = TAILQ_NEXT(bp, list)) {
+ if (bp->fails) {
+ /*
+ * The configuration of the access points may change
+ * during my scan. So we retries to associate with
+ * it unless there are any suitable AP.
+ */
+ if (bp->fails++ < 3)
+ continue;
+ bp->fails = 0;
+ }
+ fail = 0;
+ /*
+ * Since the firmware apparently scans not only the specified
+ * channel of SCAN command but all available channel within
+ * the region, we should filter out unnecessary responses here.
+ */
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ if (bp->pattern < sc->sc_scan_min ||
+ bp->pattern > sc->sc_scan_max)
+ fail |= 0x01;
+ } else {
+ if (bp->chanset < sc->sc_scan_min ||
+ bp->chanset > sc->sc_scan_max)
+ fail |= 0x01;
+ }
+ if (sc->sc_mib_local.Network_Mode) {
+ if (!(bp->capinfo & IEEE80211_CAPINFO_ESS) ||
+ (bp->capinfo & IEEE80211_CAPINFO_IBSS))
+ fail |= 0x02;
+ } else {
+ if ((bp->capinfo & IEEE80211_CAPINFO_ESS) ||
+ !(bp->capinfo & IEEE80211_CAPINFO_IBSS))
+ fail |= 0x02;
+ }
+ if (sc->sc_wep_algo == NULL) {
+ if (bp->capinfo & IEEE80211_CAPINFO_PRIVACY)
+ fail |= 0x04;
+ } else {
+ if (!(bp->capinfo & IEEE80211_CAPINFO_PRIVACY))
+ fail |= 0x04;
+ }
+ if (sc->sc_mib_mac.aDesired_ESS_ID[1] != 0 &&
+ memcmp(&sc->sc_mib_mac.aDesired_ESS_ID, bp->essid,
+ sizeof(bp->essid)) != 0)
+ fail |= 0x08;
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf(" %c %s", fail ? '-' : '+',
+ ether_sprintf(bp->esrc));
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" %2d/%d%c", bp->pattern, bp->chanset,
+ fail & 0x01 ? '!' : ' ');
+ else
+ printf(" %4d%c", bp->chanset,
+ fail & 0x01 ? '!' : ' ');
+ printf(" %+4d", bp->rssi);
+ printf(" %4s%c",
+ (bp->capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
+ (bp->capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
+ "????",
+ fail & 0x02 ? '!' : ' ');
+ printf(" %3s%c ",
+ (bp->capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" :
+ "no",
+ fail & 0x04 ? '!' : ' ');
+ awi_print_essid(bp->essid);
+ printf("%s\n", fail & 0x08 ? "!" : "");
+ }
+ if (!fail) {
+ if (sbp == NULL || bp->rssi > sbp->rssi)
+ sbp = bp;
+ }
+ }
+ if (sbp == NULL)
+ goto notfound;
+ sc->sc_bss = *sbp;
+ (void)awi_set_ss(sc);
}
-void awi_cmd_set_infra (sc)
+static void
+awi_recv_beacon(sc, m0, rxts, rssi)
struct awi_softc *sc;
+ struct mbuf *m0;
+ u_int32_t rxts;
+ u_int8_t rssi;
{
+ struct ieee80211_frame *wh;
+ struct awi_bss *bp;
+ u_int8_t *frame, *eframe;
+ u_int8_t *tstamp, *bintval, *capinfo, *ssid, *rates, *parms;
- 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);
-}
+ if (sc->sc_status != AWI_ST_SCAN)
+ return;
+ wh = mtod(m0, struct ieee80211_frame *);
-void awi_cmd_set_infra_done (sc, status)
- struct awi_softc *sc;
- u_int8_t status;
-{
-#if 0
- printf("set_infra done\n");
+ frame = (u_int8_t *)&wh[1];
+ eframe = mtod(m0, u_int8_t *) + m0->m_len;
+ /*
+ * XXX:
+ * timestamp [8]
+ * beacon interval [2]
+ * capability information [2]
+ * ssid [tlv]
+ * supported rates [tlv]
+ * parameter set [tlv]
+ * ...
+ */
+ if (frame + 12 > eframe) {
+#ifdef AWI_DEBUG
+ if (awi_verbose)
+ printf("awi_recv_beacon: frame too short \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);
+ tstamp = frame;
+ frame += 8;
+ bintval = frame;
+ frame += 2;
+ capinfo = frame;
+ frame += 2;
+
+ ssid = rates = parms = NULL;
+ while (frame < eframe) {
+ switch (*frame) {
+ case IEEE80211_ELEMID_SSID:
+ ssid = frame;
+ break;
+ case IEEE80211_ELEMID_RATES:
+ rates = frame;
+ break;
+ case IEEE80211_ELEMID_FHPARMS:
+ case IEEE80211_ELEMID_DSPARMS:
+ parms = frame;
+ break;
+ }
+ frame += frame[1] + 2;
+ }
+ if (ssid == NULL || rates == NULL || parms == NULL) {
+#ifdef AWI_DEBUG
+ if (awi_verbose)
+ printf("awi_recv_beacon: ssid=%p, rates=%p, parms=%p\n",
+ ssid, rates, parms);
#endif
- awi_cmd_set_allmulti (sc);
-}
+ return;
+ }
+ if (ssid[1] > IEEE80211_NWID_LEN) {
+#ifdef AWI_DEBUG
+ if (awi_verbose)
+ printf("awi_recv_beacon: bad ssid len: %d from %s\n",
+ ssid[1], ether_sprintf(wh->i_addr2));
+#endif
+ return;
+ }
-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);
+ for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
+ bp = TAILQ_NEXT(bp, list)) {
+ if (memcmp(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN) == 0 &&
+ memcmp(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN) == 0)
+ break;
+ }
+ if (bp == NULL) {
+ bp = malloc(sizeof(struct awi_bss), M_DEVBUF, M_NOWAIT);
+ if (bp == NULL)
+ return;
+ TAILQ_INSERT_TAIL(&sc->sc_scan, bp, list);
+ memcpy(bp->esrc, wh->i_addr2, ETHER_ADDR_LEN);
+ memcpy(bp->bssid, wh->i_addr3, ETHER_ADDR_LEN);
+ memset(bp->essid, 0, sizeof(bp->essid));
+ memcpy(bp->essid, ssid, 2 + ssid[1]);
+ }
+ bp->rssi = rssi;
+ bp->rxtime = rxts;
+ memcpy(bp->timestamp, tstamp, sizeof(bp->timestamp));
+ bp->interval = LE_READ_2(bintval);
+ bp->capinfo = LE_READ_2(capinfo);
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ bp->chanset = parms[4];
+ bp->pattern = parms[5];
+ bp->index = parms[6];
+ bp->dwell_time = LE_READ_2(parms + 2);
+ } else {
+ bp->chanset = parms[2];
+ bp->pattern = 0;
+ bp->index = 0;
+ bp->dwell_time = 0;
+ }
+ if (sc->sc_mgt_timer == 0)
+ awi_stop_scan(sc);
}
-void awi_cmd_set_allmulti_done (sc, status)
+static int
+awi_set_ss(sc)
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;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct awi_bss *bp;
+ int error;
+
+ sc->sc_status = AWI_ST_SETSS;
+ bp = &sc->sc_bss;
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: ch %d pat %d id %d dw %d iv %d bss %s ssid ",
+ sc->sc_dev.dv_xname, bp->chanset,
+ bp->pattern, bp->index, bp->dwell_time, bp->interval,
+ ether_sprintf(bp->bssid));
+ awi_print_essid(bp->essid);
+ printf("\n");
}
- awi_cmd_set_promisc (sc);
+ memcpy(&sc->sc_mib_mgt.aCurrent_BSS_ID, bp->bssid, ETHER_ADDR_LEN);
+ memcpy(&sc->sc_mib_mgt.aCurrent_ESS_ID, bp->essid,
+ AWI_ESS_ID_SIZE);
+ LE_WRITE_2(&sc->sc_mib_mgt.aBeacon_Period, bp->interval);
+ error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
+ return error;
}
-void awi_cmd_set_promisc (sc)
+static void
+awi_try_sync(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);
-}
+ struct awi_bss *bp;
-void awi_cmd_set_promisc_done (sc, status)
+ sc->sc_status = AWI_ST_SYNC;
+ bp = &sc->sc_bss;
+
+ if (sc->sc_cmd_inprog) {
+ if (awi_cmd_wait(sc))
+ return;
+ }
+ sc->sc_cmd_inprog = AWI_CMD_SYNC;
+ 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,
+ sc->sc_start_bss ? 1 : 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->timestamp, 8);
+ awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime);
+ (void)awi_cmd(sc, AWI_CMD_SYNC);
+}
+
+static void
+awi_sync_done(sc)
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);
+ struct ifnet *ifp = sc->sc_ifp;
- sc->sc_state = AWI_ST_TXINIT;
- sc->sc_completion = awi_init_4;
- awi_cmd_txinit(sc);
+ if (sc->sc_mib_local.Network_Mode) {
+ awi_drvstate(sc, AWI_DRV_INFSY);
+ awi_send_auth(sc, 1);
+ } else {
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf("%s: synced with", sc->sc_dev.dv_xname);
+ if (sc->sc_no_bssid)
+ printf(" no-bssid");
+ else {
+ printf(" %s ssid ",
+ ether_sprintf(sc->sc_bss.bssid));
+ awi_print_essid(sc->sc_bss.essid);
+ }
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" at chanset %d pattern %d\n",
+ sc->sc_bss.chanset, sc->sc_bss.pattern);
+ else
+ printf(" at channel %d\n", sc->sc_bss.chanset);
+ }
+ awi_drvstate(sc, AWI_DRV_ADHSY);
+ sc->sc_status = AWI_ST_RUNNING;
+ ifp->if_flags |= IFF_RUNNING;
+ awi_start(ifp);
+ }
}
-void
-awi_init_4 (sc, status)
+static void
+awi_send_deauth(sc)
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
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ struct ieee80211_frame *wh;
+ u_int8_t *deauth;
- 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);
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
return;
- }
-
- sc->sc_state = AWI_ST_RXINIT;
- sc->sc_completion = awi_init_5;
-
- awi_cmd (sc, AWI_CMD_INIT_RX);
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: sending deauth to %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_bss.bssid));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+ IEEE80211_FC0_SUBTYPE_AUTH;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ LE_WRITE_2(wh->i_dur, 0);
+ LE_WRITE_2(wh->i_seq, 0);
+ memcpy(wh->i_addr1, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+
+ deauth = (u_int8_t *)&wh[1];
+ LE_WRITE_2(deauth, IEEE80211_REASON_AUTH_LEAVE);
+ deauth += 2;
+
+ m->m_pkthdr.len = m->m_len = deauth - mtod(m, u_int8_t *);
+ IF_ENQUEUE(&sc->sc_mgtq, m);
+ awi_start(ifp);
+ awi_drvstate(sc, AWI_DRV_INFTOSS);
}
-void awi_init_5 (sc, status)
+static void
+awi_send_auth(sc, seq)
struct awi_softc *sc;
- u_int8_t status;
+ int seq;
{
-#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
+ struct mbuf *m;
+ struct ieee80211_frame *wh;
+ u_int8_t *auth;
- if (status != AWI_STAT_OK) {
- printf("%s: init_rx failed (card unhappy?)\n",
- sc->sc_dev.dv_xname);
- awi_reset(sc);
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
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);
+ sc->sc_status = AWI_ST_AUTH;
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: sending auth to %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_bss.bssid));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
+ IEEE80211_FC0_SUBTYPE_AUTH;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ LE_WRITE_2(wh->i_dur, 0);
+ LE_WRITE_2(wh->i_seq, 0);
+ memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+
+ auth = (u_int8_t *)&wh[1];
+ /* algorithm number */
+ LE_WRITE_2(auth, IEEE80211_AUTH_ALG_OPEN);
+ auth += 2;
+ /* sequence number */
+ LE_WRITE_2(auth, seq);
+ auth += 2;
+ /* status */
+ LE_WRITE_2(auth, 0);
+ auth += 2;
+
+ m->m_pkthdr.len = m->m_len = auth - mtod(m, u_int8_t *);
+ IF_ENQUEUE(&sc->sc_mgtq, m);
+ awi_start(ifp);
-#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);
+ sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
+ ifp->if_timer = 1;
}
-void awi_restart_scan (sc)
+static void
+awi_recv_auth(sc, m0)
struct awi_softc *sc;
+ struct mbuf *m0;
{
- if (sc->sc_ifp->if_flags & IFF_DEBUG) {
- printf("%s: starting scan\n", sc->sc_dev.dv_xname);
+ struct ieee80211_frame *wh;
+ u_int8_t *auth, *eframe;
+ struct awi_bss *bp;
+ u_int16_t status;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ auth = (u_int8_t *)&wh[1];
+ eframe = mtod(m0, u_int8_t *) + m0->m_len;
+ if (sc->sc_ifp->if_flags & IFF_DEBUG)
+ printf("%s: receive auth from %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(wh->i_addr2));
+
+ /* algorithm number */
+ if (LE_READ_2(auth) != IEEE80211_AUTH_ALG_OPEN)
+ return;
+ auth += 2;
+ if (!sc->sc_mib_local.Network_Mode) {
+ if (sc->sc_status != AWI_ST_RUNNING)
+ return;
+ if (LE_READ_2(auth) == 1)
+ awi_send_auth(sc, 2);
+ return;
+ }
+ if (sc->sc_status != AWI_ST_AUTH)
+ return;
+ /* sequence number */
+ if (LE_READ_2(auth) != 2)
+ return;
+ auth += 2;
+ /* status */
+ status = LE_READ_2(auth);
+ if (status != 0) {
+ printf("%s: authentication failed (reason %d)\n",
+ sc->sc_dev.dv_xname, status);
+ for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
+ bp = TAILQ_NEXT(bp, list)) {
+ if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
+ == 0) {
+ bp->fails++;
+ break;
+ }
+ }
+ return;
}
- 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);
+ awi_drvstate(sc, AWI_DRV_INFAUTH);
+ awi_send_asreq(sc, 0);
}
-void
-awi_cmd_scan (sc)
+static void
+awi_send_asreq(sc, reassoc)
struct awi_softc *sc;
+ int reassoc;
{
-
- 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);
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ struct ieee80211_frame *wh;
+ u_int16_t lintval;
+ u_int8_t *asreq;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return;
+ sc->sc_status = AWI_ST_ASSOC;
+ if (ifp->if_flags & IFF_DEBUG)
+ printf("%s: sending %sassoc req to %s\n", sc->sc_dev.dv_xname,
+ reassoc ? "re" : "",
+ ether_sprintf(sc->sc_bss.bssid));
+
+ wh = mtod(m, struct ieee80211_frame *);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT;
+ if (reassoc)
+ wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
+ else
+ wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
+ wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
+ LE_WRITE_2(wh->i_dur, 0);
+ LE_WRITE_2(wh->i_seq, 0);
+ memcpy(wh->i_addr1, sc->sc_bss.esrc, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr2, sc->sc_mib_addr.aMAC_Address, ETHER_ADDR_LEN);
+ memcpy(wh->i_addr3, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+
+ asreq = (u_int8_t *)&wh[1];
+
+ /* capability info */
+ if (sc->sc_wep_algo == NULL)
+ LE_WRITE_2(asreq, IEEE80211_CAPINFO_CF_POLLABLE);
+ else
+ LE_WRITE_2(asreq,
+ IEEE80211_CAPINFO_CF_POLLABLE | IEEE80211_CAPINFO_PRIVACY);
+ asreq += 2;
+ /* listen interval */
+ lintval = LE_READ_2(&sc->sc_mib_mgt.aListen_Interval);
+ LE_WRITE_2(asreq, lintval);
+ asreq += 2;
+ if (reassoc) {
+ /* current AP address */
+ memcpy(asreq, sc->sc_bss.bssid, ETHER_ADDR_LEN);
+ asreq += ETHER_ADDR_LEN;
+ }
+ /* ssid */
+ memcpy(asreq, sc->sc_bss.essid, 2 + sc->sc_bss.essid[1]);
+ asreq += 2 + asreq[1];
+ /* supported rates */
+ memcpy(asreq, &sc->sc_mib_phy.aSuprt_Data_Rates, 4);
+ asreq += 2 + asreq[1];
+
+ m->m_pkthdr.len = m->m_len = asreq - mtod(m, u_int8_t *);
+ IF_ENQUEUE(&sc->sc_mgtq, m);
+ awi_start(ifp);
+
+ sc->sc_mgt_timer = AWI_TRANS_TIMEOUT / 1000;
+ ifp->if_timer = 1;
}
-void
-awi_cmd_scan_done (sc, status)
+static void
+awi_recv_asresp(sc, m0)
struct awi_softc *sc;
- u_int8_t status;
+ struct mbuf *m0;
{
-#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;
-
+ struct ieee80211_frame *wh;
+ u_int8_t *asresp, *eframe;
+ u_int16_t status;
+ u_int8_t rate, *phy_rates;
+ struct awi_bss *bp;
+ int i, j;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ asresp = (u_int8_t *)&wh[1];
+ eframe = mtod(m0, u_int8_t *) + m0->m_len;
+ if (sc->sc_ifp->if_flags & IFF_DEBUG)
+ printf("%s: receive assoc resp from %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(wh->i_addr2));
+
+ if (!sc->sc_mib_local.Network_Mode)
+ return;
+
+ if (sc->sc_status != AWI_ST_ASSOC)
+ return;
+ /* capability info */
+ asresp += 2;
+ /* status */
+ status = LE_READ_2(asresp);
+ if (status != 0) {
+ printf("%s: association failed (reason %d)\n",
+ sc->sc_dev.dv_xname, status);
+ for (bp = TAILQ_FIRST(&sc->sc_scan); bp != NULL;
+ bp = TAILQ_NEXT(bp, list)) {
+ if (memcmp(bp->esrc, sc->sc_bss.esrc, ETHER_ADDR_LEN)
+ == 0) {
+ bp->fails++;
+ break;
+ }
+ }
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.. */
+ asresp += 2;
+ /* association id */
+ asresp += 2;
+ /* supported rates */
+ rate = AWI_RATE_1MBIT;
+ for (i = 0; i < asresp[1]; i++) {
+ if (AWI_80211_RATE(asresp[2 + i]) <= rate)
+ continue;
+ phy_rates = sc->sc_mib_phy.aSuprt_Data_Rates;
+ for (j = 0; j < phy_rates[1]; j++) {
+ if (AWI_80211_RATE(asresp[2 + i]) ==
+ AWI_80211_RATE(phy_rates[2 + j]))
+ rate = AWI_80211_RATE(asresp[2 + i]);
+ }
+ }
+ if (sc->sc_ifp->if_flags & IFF_DEBUG) {
+ printf("%s: associated with %s ssid ",
+ sc->sc_dev.dv_xname, ether_sprintf(sc->sc_bss.bssid));
+ awi_print_essid(sc->sc_bss.essid);
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH)
+ printf(" chanset %d pattern %d\n",
+ sc->sc_bss.chanset, sc->sc_bss.pattern);
+ else
+ printf(" channel %d\n", sc->sc_bss.chanset);
+ }
+ sc->sc_tx_rate = rate;
+ sc->sc_mgt_timer = 0;
+ sc->sc_rx_timer = 10;
+ sc->sc_ifp->if_timer = 1;
+ sc->sc_status = AWI_ST_RUNNING;
+ sc->sc_ifp->if_flags |= IFF_RUNNING;
+ awi_drvstate(sc, AWI_DRV_INFASSOC);
+ awi_start(sc->sc_ifp);
}
-void
-awi_scan_next (sc)
+static int
+awi_mib(sc, cmd, mib)
struct awi_softc *sc;
+ u_int8_t cmd;
+ u_int8_t mib;
{
- sc->sc_scan_pattern++;
- if (sc->sc_scan_pattern > IEEEWL_FH_PATTERN_MAX) {
- sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN;
+ int error;
+ u_int8_t size, *ptr;
- sc->sc_scan_chanset++;
- if (sc->sc_scan_chanset > IEEEWL_FH_CHANSET_MAX)
- sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN;
+ switch (mib) {
+ case AWI_MIB_LOCAL:
+ ptr = (u_int8_t *)&sc->sc_mib_local;
+ size = sizeof(sc->sc_mib_local);
+ break;
+ case AWI_MIB_ADDR:
+ ptr = (u_int8_t *)&sc->sc_mib_addr;
+ size = sizeof(sc->sc_mib_addr);
+ break;
+ case AWI_MIB_MAC:
+ ptr = (u_int8_t *)&sc->sc_mib_mac;
+ size = sizeof(sc->sc_mib_mac);
+ break;
+ case AWI_MIB_STAT:
+ ptr = (u_int8_t *)&sc->sc_mib_stat;
+ size = sizeof(sc->sc_mib_stat);
+ break;
+ case AWI_MIB_MGT:
+ ptr = (u_int8_t *)&sc->sc_mib_mgt;
+ size = sizeof(sc->sc_mib_mgt);
+ break;
+ case AWI_MIB_PHY:
+ ptr = (u_int8_t *)&sc->sc_mib_phy;
+ size = sizeof(sc->sc_mib_phy);
+ break;
+ default:
+ return EINVAL;
}
-#if 0
- printf("scan: pattern %x chanset %x\n", sc->sc_scan_pattern,
- sc->sc_scan_chanset);
+ if (sc->sc_cmd_inprog) {
+ error = awi_cmd_wait(sc);
+ if (error) {
+ if (error == EWOULDBLOCK)
+ printf("awi_mib: cmd %d inprog",
+ sc->sc_cmd_inprog);
+ return error;
+ }
+ }
+ sc->sc_cmd_inprog = cmd;
+ if (cmd == AWI_CMD_SET_MIB)
+ awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, mib);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, size);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, 0);
+ error = awi_cmd(sc, cmd);
+ if (error)
+ return error;
+ if (cmd == AWI_CMD_GET_MIB) {
+ awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, ptr, size);
+#ifdef AWI_DEBUG
+ if (awi_verbose) {
+ int i;
+
+ printf("awi_mib: #%d:", mib);
+ for (i = 0; i < size; i++)
+ printf(" %02x", ptr[i]);
+ printf("\n");
+ }
#endif
-
- awi_cmd_scan(sc);
+ }
+ return 0;
}
-void
-awi_try_sync (sc)
+static int
+awi_cmd_scan(sc)
struct awi_softc *sc;
{
- int max_rssi = 0, best = 0;
- int i;
- struct awi_bss_binding *bp = NULL;
-
- awi_flush(sc);
+ int error;
+ u_int8_t scan_mode;
- if (sc->sc_ifp->if_flags & IFF_DEBUG) {
- printf("%s: looking for best of %d\n",
- sc->sc_dev.dv_xname, sc->sc_nbindings);
+ if (sc->sc_active_scan)
+ scan_mode = AWI_SCAN_ACTIVE;
+ else
+ scan_mode = AWI_SCAN_PASSIVE;
+ if (sc->sc_mib_mgt.aScan_Mode != scan_mode) {
+ sc->sc_mib_mgt.aScan_Mode = scan_mode;
+ error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT);
+ return error;
}
- /* 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 (sc->sc_cmd_inprog) {
+ error = awi_cmd_wait(sc);
+ if (error)
+ return error;
}
-
- if (bp == NULL) {
- printf("%s: no beacons seen\n", sc->sc_dev.dv_xname);
- awi_scan_next(sc);
- return;
+ sc->sc_cmd_inprog = AWI_CMD_SCAN;
+ awi_write_2(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION,
+ sc->sc_active_scan ? AWI_ASCAN_DURATION : AWI_PSCAN_DURATION);
+ if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) {
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
+ sc->sc_scan_set);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN,
+ sc->sc_scan_cur);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1);
+ } else {
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET,
+ sc->sc_scan_cur);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, 0);
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 0);
}
+ awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0);
+ return awi_cmd(sc, AWI_CMD_SCAN);
+}
- 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);
+static int
+awi_cmd(sc, cmd)
+ struct awi_softc *sc;
+ u_int8_t cmd;
+{
+ u_int8_t status;
+ int error = 0;
+ sc->sc_cmd_inprog = cmd;
+ awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE);
+ awi_write_1(sc, AWI_CMD, cmd);
+ if (sc->sc_status != AWI_ST_INIT)
+ return 0;
+ error = awi_cmd_wait(sc);
+ if (error)
+ return error;
+ status = awi_read_1(sc, AWI_CMD_STATUS);
+ awi_write_1(sc, AWI_CMD, 0);
+ switch (status) {
+ case AWI_STAT_OK:
+ break;
+ case AWI_STAT_BADPARM:
+ return EINVAL;
+ default:
+ printf("%s: command %d failed %x\n",
+ sc->sc_dev.dv_xname, cmd, status);
+ return ENXIO;
+ }
+ return 0;
}
-void
-awi_cmd_sync_done (sc, status)
+static void
+awi_cmd_done(sc)
struct awi_softc *sc;
- u_int8_t status;
{
+ u_int8_t cmd, status;
+
+ status = awi_read_1(sc, AWI_CMD_STATUS);
+ if (status == AWI_STAT_IDLE)
+ return; /* stray interrupt */
+
+ cmd = sc->sc_cmd_inprog;
+ sc->sc_cmd_inprog = 0;
+ if (sc->sc_status == AWI_ST_INIT) {
+ wakeup(sc);
+ return;
+ }
+ awi_write_1(sc, AWI_CMD, 0);
+
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);
+ printf("%s: command %d failed %x\n",
+ sc->sc_dev.dv_xname, cmd, status);
return;
}
+ switch (sc->sc_status) {
+ case AWI_ST_SCAN:
+ if (cmd == AWI_CMD_SET_MIB)
+ awi_cmd_scan(sc); /* retry */
+ break;
+ case AWI_ST_SETSS:
+ awi_try_sync(sc);
+ break;
+ case AWI_ST_SYNC:
+ awi_sync_done(sc);
+ break;
+ default:
+ break;
+ }
+}
+static int
+awi_next_txd(sc, len, framep, ntxdp)
+ struct awi_softc *sc;
+ int len;
+ u_int32_t *framep, *ntxdp;
+{
+ u_int32_t txd, ntxd, frame;
+
+ txd = sc->sc_txnext;
+ frame = txd + AWI_TXD_SIZE;
+ if (frame + len > sc->sc_txend)
+ frame = sc->sc_txbase;
+ ntxd = frame + len;
+ if (ntxd + AWI_TXD_SIZE > sc->sc_txend)
+ ntxd = sc->sc_txbase;
+ *framep = frame;
+ *ntxdp = ntxd;
/*
- * 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..
+ * Determine if there are any room in ring buffer.
+ * --- send wait, === new data, +++ conflict (ENOBUFS)
+ * base........................end
+ * done----txd=====ntxd OK
+ * --txd=====done++++ntxd-- full
+ * --txd=====ntxd done-- OK
+ * ==ntxd done----txd=== OK
+ * ==done++++ntxd----txd=== full
+ * ++ntxd txd=====done++ full
*/
-
- 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);
+ if (txd < ntxd) {
+ if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone)
+ return ENOBUFS;
+ } else {
+ if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone)
+ return ENOBUFS;
}
-
- awi_cmd_set_ss (sc);
+ return 0;
}
+static int
+awi_lock(sc)
+ struct awi_softc *sc;
+{
+ int error = 0;
+
+ if (curproc == NULL) {
+ /*
+ * XXX
+ * Though driver ioctl should be called with context,
+ * KAME ipv6 stack calls ioctl in interrupt for now.
+ * We simply abort the request if there are other
+ * ioctl requests in progress.
+ */
+ if (sc->sc_busy) {
+ return EWOULDBLOCK;
+ if (sc->sc_invalid)
+ return ENXIO;
+ }
+ sc->sc_busy = 1;
+ sc->sc_cansleep = 0;
+ return 0;
+ }
+ while (sc->sc_busy) {
+ if (sc->sc_invalid)
+ return ENXIO;
+ sc->sc_sleep_cnt++;
+ error = tsleep(sc, PWAIT | PCATCH, "awilck", 0);
+ sc->sc_sleep_cnt--;
+ if (error)
+ return error;
+ }
+ sc->sc_busy = 1;
+ sc->sc_cansleep = 1;
+ return 0;
+}
-void awi_cmd_set_ss (sc)
+static void
+awi_unlock(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);
+ sc->sc_busy = 0;
+ sc->sc_cansleep = 0;
+ if (sc->sc_sleep_cnt)
+ wakeup(sc);
}
-void awi_cmd_set_ss_done (sc, status)
+static int
+awi_intr_lock(sc)
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;
+ u_int8_t status;
+ int i, retry;
+
+ status = 1;
+ for (retry = 0; retry < 10; retry++) {
+ for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) {
+ status = awi_read_1(sc, AWI_LOCKOUT_HOST);
+ if (status == 0)
+ break;
+ DELAY(5);
+ }
+ if (status != 0)
+ break;
+ awi_write_1(sc, AWI_LOCKOUT_MAC, 1);
+ status = awi_read_1(sc, AWI_LOCKOUT_HOST);
+ if (status == 0)
+ break;
+ awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
}
-#if 0
- printf("%s: set_ss done\n", sc->sc_dev.dv_xname);
-#endif
+ if (status != 0) {
+ printf("%s: failed to lock interrupt\n",
+ sc->sc_dev.dv_xname);
+ return ENXIO;
+ }
+ return 0;
+}
- awi_running (sc);
-
- /*
- * now, we *should* be getting broadcast frames..
- */
- sc->sc_state = AWI_ST_SYNCED;
- awi_send_authreq (sc);
-
+static void
+awi_intr_unlock(sc)
+ struct awi_softc *sc;
+{
+
+ awi_write_1(sc, AWI_LOCKOUT_MAC, 0);
}
-void awi_running (sc)
+static int
+awi_cmd_wait(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);
+ int i, error = 0;
+
+ i = 0;
+ while (sc->sc_cmd_inprog) {
+ if (sc->sc_invalid)
+ return ENXIO;
+ if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) {
+ printf("%s: failed to access hardware\n",
+ sc->sc_dev.dv_xname);
+ sc->sc_invalid = 1;
+ return ENXIO;
+ }
+ if (sc->sc_cansleep) {
+ sc->sc_sleep_cnt++;
+ error = tsleep(sc, PWAIT, "awicmd",
+ AWI_CMD_TIMEOUT*hz/1000);
+ sc->sc_sleep_cnt--;
+ } else {
+ if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) {
+ awi_cmd_done(sc);
+ break;
+ }
+ if (i++ >= AWI_CMD_TIMEOUT*1000/10)
+ error = EWOULDBLOCK;
+ else
+ DELAY(10);
+ }
+ if (error)
+ break;
+ }
+ return error;
}
+static void
+awi_print_essid(essid)
+ u_int8_t *essid;
+{
+ int i, len;
+ u_int8_t *p;
-void awi_reset (sc)
+ len = essid[1];
+ if (len > IEEE80211_NWID_LEN)
+ len = IEEE80211_NWID_LEN; /*XXX*/
+ /* determine printable or not */
+ for (i = 0, p = essid + 2; i < len; i++, p++) {
+ if (*p < ' ' || *p > 0x7e)
+ break;
+ }
+ if (i == len) {
+ printf("\"");
+ for (i = 0, p = essid + 2; i < len; i++, p++)
+ printf("%c", *p);
+ printf("\"");
+ } else {
+ printf("0x");
+ for (i = 0, p = essid + 2; i < len; i++, p++)
+ printf("%02x", *p);
+ }
+}
+
+#ifdef AWI_DEBUG
+static void
+awi_dump_pkt(sc, m, rssi)
struct awi_softc *sc;
+ struct mbuf *m;
+ int rssi;
{
- printf("%s: reset\n", sc->sc_dev.dv_xname);
+ struct ieee80211_frame *wh;
+ int i, l;
+
+ wh = mtod(m, struct ieee80211_frame *);
+
+ if (awi_dump_mask != 0 &&
+ ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK)==IEEE80211_FC1_DIR_NODS) &&
+ ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_MGT)) {
+ if ((AWI_DUMP_MASK(wh->i_fc[0]) & awi_dump_mask) != 0)
+ return;
+ }
+ if (awi_dump_mask < 0 &&
+ (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)==IEEE80211_FC0_TYPE_DATA)
+ return;
+ if (rssi < 0)
+ printf("tx: ");
+ else
+ printf("rx: ");
+ switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
+ case IEEE80211_FC1_DIR_NODS:
+ printf("NODS %s", ether_sprintf(wh->i_addr2));
+ printf("->%s", ether_sprintf(wh->i_addr1));
+ printf("(%s)", ether_sprintf(wh->i_addr3));
+ break;
+ case IEEE80211_FC1_DIR_TODS:
+ printf("TODS %s", ether_sprintf(wh->i_addr2));
+ printf("->%s", ether_sprintf(wh->i_addr3));
+ printf("(%s)", ether_sprintf(wh->i_addr1));
+ break;
+ case IEEE80211_FC1_DIR_FROMDS:
+ printf("FRDS %s", ether_sprintf(wh->i_addr3));
+ printf("->%s", ether_sprintf(wh->i_addr1));
+ printf("(%s)", ether_sprintf(wh->i_addr2));
+ break;
+ case IEEE80211_FC1_DIR_DSTODS:
+ printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1]));
+ printf("->%s", ether_sprintf(wh->i_addr3));
+ printf("(%s", ether_sprintf(wh->i_addr2));
+ printf("->%s)", ether_sprintf(wh->i_addr1));
+ break;
+ }
+ switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
+ case IEEE80211_FC0_TYPE_DATA:
+ printf(" data");
+ break;
+ case IEEE80211_FC0_TYPE_MGT:
+ switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
+ case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
+ printf(" probe_req");
+ break;
+ case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
+ printf(" probe_resp");
+ break;
+ case IEEE80211_FC0_SUBTYPE_BEACON:
+ printf(" beacon");
+ break;
+ case IEEE80211_FC0_SUBTYPE_AUTH:
+ printf(" auth");
+ break;
+ case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
+ printf(" assoc_req");
+ break;
+ case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
+ printf(" assoc_resp");
+ break;
+ case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
+ printf(" reassoc_req");
+ break;
+ case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
+ printf(" reassoc_resp");
+ break;
+ case IEEE80211_FC0_SUBTYPE_DEAUTH:
+ printf(" deauth");
+ break;
+ case IEEE80211_FC0_SUBTYPE_DISASSOC:
+ printf(" disassoc");
+ break;
+ default:
+ printf(" mgt#%d",
+ wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ default:
+ printf(" type#%d",
+ wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
+ break;
+ }
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+ printf(" WEP");
+ if (rssi >= 0)
+ printf(" +%d", rssi);
+ printf("\n");
+ if (awi_dump_len > 0) {
+ l = m->m_len;
+ if (l > awi_dump_len + sizeof(*wh))
+ l = awi_dump_len + sizeof(*wh);
+ i = sizeof(*wh);
+ if (awi_dump_hdr)
+ i = 0;
+ for (; i < l; i++) {
+ if ((i & 1) == 0)
+ printf(" ");
+ printf("%02x", mtod(m, u_int8_t *)[i]);
+ }
+ printf("\n");
+ }
}
+#endif
diff --git a/sys/dev/ic/awi_wep.c b/sys/dev/ic/awi_wep.c
new file mode 100644
index 00000000000..87f968130f2
--- /dev/null
+++ b/sys/dev/ic/awi_wep.c
@@ -0,0 +1,535 @@
+/* $NetBSD: awi_wep.c,v 1.2 2000/07/04 14:47:58 onoe Exp $ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Atsushi Onoe.
+ *
+ * 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.
+ */
+
+/*
+ * WEP support framework for the awi driver.
+ *
+ * No actual encryption capability is provided here, but any can be added
+ * to awi_wep_algo table below.
+ *
+ * Note that IEEE802.11 specification states WEP uses RC4 with 40bit key,
+ * which is a proprietary encryption algorithm available under license
+ * from RSA Data Security Inc. Using another algorithm, includes null
+ * encryption provided here, the awi driver cannot be able to communicate
+ * with other stations.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/sockio.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+#include <sys/bus.h>
+#else
+#include <sys/device.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#include <net/if_arp.h>
+#elif defined(__OpenBSD__)
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#else
+#include <net/if_ether.h>
+#endif
+#include <net/if_media.h>
+#include <net/if_ieee80211.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+#ifdef __FreeBSD__
+#include <machine/clock.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+#include <dev/ic/am79c930reg.h>
+#include <dev/ic/am79c930var.h>
+#include <dev/ic/awireg.h>
+#include <dev/ic/awivar.h>
+#endif
+
+#ifdef __NetBSD__
+#include <crypto/arc4/arc4.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <dev/awi/am79c930reg.h>
+#include <dev/awi/am79c930var.h>
+#include <dev/awi/awireg.h>
+#include <dev/awi/awivar.h>
+
+#include <crypto/rc4/rc4.h>
+static __inline int
+arc4_ctxlen(void)
+{
+ return sizeof(struct rc4_state);
+}
+
+static __inline void
+arc4_setkey(void *ctx, u_int8_t *key, int keylen)
+{
+ rc4_init(ctx, key, keylen);
+}
+
+static __inline void
+arc4_encrypt(void *ctx, u_int8_t *dst, u_int8_t *src, int len)
+{
+ rc4_crypt(ctx, dst, src, len);
+}
+#endif
+
+static void awi_crc_init __P((void));
+static u_int32_t awi_crc_update __P((u_int32_t crc, u_int8_t *buf, int len));
+
+static int awi_null_ctxlen __P((void));
+static void awi_null_setkey __P((void *ctx, u_int8_t *key, int keylen));
+static void awi_null_copy __P((void *ctx, u_int8_t *dst, u_int8_t *src, int len));
+
+/* XXX: the order should be known to wiconfig/user */
+
+static struct awi_wep_algo awi_wep_algo[] = {
+/* 0: no wep */
+ { "no" }, /* dummy for no wep */
+
+#if 0
+/* 1: normal wep (arc4) */
+ { "arc4", arc4_ctxlen, arc4_setkey,
+ arc4_encrypt, arc4_encrypt },
+#endif
+/* 2: debug wep (null) */
+ { "null", awi_null_ctxlen, awi_null_setkey,
+ awi_null_copy, awi_null_copy },
+ /* dummy for wep without encryption */
+};
+
+int
+awi_wep_setnwkey(sc, nwkey)
+ struct awi_softc *sc;
+ struct ieee80211_nwkey *nwkey;
+{
+ int i, len, error;
+ u_int8_t keybuf[AWI_MAX_KEYLEN];
+
+ if (nwkey->i_defkid <= 0 ||
+ nwkey->i_defkid > IEEE80211_WEP_NKID)
+ return EINVAL;
+ error = 0;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keydat == NULL)
+ continue;
+ len = nwkey->i_key[i].i_keylen;
+ if (len > sizeof(keybuf)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(nwkey->i_key[i].i_keydat, keybuf, len);
+ if (error)
+ break;
+ error = awi_wep_setkey(sc, i, keybuf, len);
+ if (error)
+ break;
+ }
+ if (error == 0) {
+ sc->sc_wep_defkid = nwkey->i_defkid - 1;
+ error = awi_wep_setalgo(sc, nwkey->i_wepon);
+ if (error == 0 && sc->sc_enabled) {
+ awi_stop(sc);
+ error = awi_init(sc);
+ }
+ }
+ return error;
+}
+
+int
+awi_wep_getnwkey(sc, nwkey)
+ struct awi_softc *sc;
+ struct ieee80211_nwkey *nwkey;
+{
+ int i, len, error, suerr;
+ u_int8_t keybuf[AWI_MAX_KEYLEN];
+
+ nwkey->i_wepon = awi_wep_getalgo(sc);
+ nwkey->i_defkid = sc->sc_wep_defkid + 1;
+ /* do not show any keys to non-root user */
+#ifdef __FreeBSD__
+ suerr = suser(curproc);
+#else
+ suerr = suser(curproc->p_ucred, &curproc->p_acflag);
+#endif
+ error = 0;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ if (nwkey->i_key[i].i_keydat == NULL)
+ continue;
+ if (suerr) {
+ error = suerr;
+ break;
+ }
+ len = sizeof(keybuf);
+ error = awi_wep_getkey(sc, i, keybuf, &len);
+ if (error)
+ break;
+ if (nwkey->i_key[i].i_keylen < len) {
+ error = ENOSPC;
+ break;
+ }
+ nwkey->i_key[i].i_keylen = len;
+ error = copyout(keybuf, nwkey->i_key[i].i_keydat, len);
+ if (error)
+ break;
+ }
+ return error;
+}
+
+int
+awi_wep_getalgo(sc)
+ struct awi_softc *sc;
+{
+
+ if (sc->sc_wep_algo == NULL)
+ return 0;
+ return sc->sc_wep_algo - awi_wep_algo;
+}
+
+int
+awi_wep_setalgo(sc, algo)
+ struct awi_softc *sc;
+ int algo;
+{
+ struct awi_wep_algo *awa;
+ int ctxlen;
+
+ awi_crc_init(); /* XXX: not belongs here */
+ if (algo < 0 || algo > sizeof(awi_wep_algo)/sizeof(awi_wep_algo[0]))
+ return EINVAL;
+ awa = &awi_wep_algo[algo];
+ if (awa->awa_name == NULL)
+ return EINVAL;
+ if (awa->awa_ctxlen == NULL) {
+ awa = NULL;
+ ctxlen = 0;
+ } else
+ ctxlen = awa->awa_ctxlen();
+ if (sc->sc_wep_ctx != NULL) {
+ free(sc->sc_wep_ctx, M_DEVBUF);
+ sc->sc_wep_ctx = NULL;
+ }
+ if (ctxlen) {
+ sc->sc_wep_ctx = malloc(ctxlen, M_DEVBUF, M_NOWAIT);
+ if (sc->sc_wep_ctx == NULL)
+ return ENOMEM;
+ }
+ sc->sc_wep_algo = awa;
+ return 0;
+}
+
+int
+awi_wep_setkey(sc, kid, key, keylen)
+ struct awi_softc *sc;
+ int kid;
+ unsigned char *key;
+ int keylen;
+{
+
+ if (kid < 0 || kid >= IEEE80211_WEP_NKID)
+ return EINVAL;
+ if (keylen < 0 || keylen + IEEE80211_WEP_IVLEN > AWI_MAX_KEYLEN)
+ return EINVAL;
+ sc->sc_wep_keylen[kid] = keylen;
+ if (keylen > 0)
+ memcpy(sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, key, keylen);
+ return 0;
+}
+
+int
+awi_wep_getkey(sc, kid, key, keylen)
+ struct awi_softc *sc;
+ int kid;
+ unsigned char *key;
+ int *keylen;
+{
+
+ if (kid < 0 || kid >= IEEE80211_WEP_NKID)
+ return EINVAL;
+ if (*keylen < sc->sc_wep_keylen[kid])
+ return ENOSPC;
+ *keylen = sc->sc_wep_keylen[kid];
+ if (*keylen > 0)
+ memcpy(key, sc->sc_wep_key[kid] + IEEE80211_WEP_IVLEN, *keylen);
+ return 0;
+}
+
+struct mbuf *
+awi_wep_encrypt(sc, m0, txflag)
+ struct awi_softc *sc;
+ struct mbuf *m0;
+ int txflag;
+{
+ struct mbuf *m, *n, *n0;
+ struct ieee80211_frame *wh;
+ struct awi_wep_algo *awa;
+ int left, len, moff, noff, keylen, kid;
+ u_int32_t iv, crc;
+ u_int8_t *key, *ivp;
+ void *ctx;
+ u_int8_t crcbuf[IEEE80211_WEP_CRCLEN];
+
+ n0 = NULL;
+ awa = sc->sc_wep_algo;
+ if (awa == NULL)
+ goto fail;
+ ctx = sc->sc_wep_ctx;
+ m = m0;
+ left = m->m_pkthdr.len;
+ MGET(n, M_DONTWAIT, m->m_type);
+ n0 = n;
+ if (n == NULL)
+ goto fail;
+ M_COPY_PKTHDR(n, m);
+ len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN;
+ if (txflag) {
+ n->m_pkthdr.len += len;
+ } else {
+ wh = mtod(n, struct ieee80211_frame *);
+ n->m_pkthdr.len -= len;
+ left -= len;
+ }
+ n->m_len = MHLEN;
+ if (n->m_pkthdr.len >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ len = sizeof(struct ieee80211_frame);
+ memcpy(mtod(n, caddr_t), mtod(m, caddr_t), len);
+ left -= len;
+ moff = len;
+ noff = len;
+ if (txflag) {
+ kid = sc->sc_wep_defkid;
+ wh = mtod(n, struct ieee80211_frame *);
+ wh->i_fc[1] |= IEEE80211_FC1_WEP;
+ iv = random();
+ /*
+ * store IV, byte order is not the matter since it's random.
+ * assuming IEEE80211_WEP_IVLEN is 3
+ */
+ ivp = mtod(n, u_int8_t *) + noff;
+ ivp[0] = (iv >> 16) & 0xff;
+ ivp[1] = (iv >> 8) & 0xff;
+ ivp[2] = iv & 0xff;
+ ivp[3] = kid & 0x03; /* clear pad and keyid */
+ noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
+ } else {
+ ivp = mtod(m, u_int8_t *) + moff;
+ moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
+ kid = ivp[IEEE80211_WEP_IVLEN] & 0x03;
+ }
+ key = sc->sc_wep_key[kid];
+ keylen = sc->sc_wep_keylen[kid];
+ /* assuming IEEE80211_WEP_IVLEN is 3 */
+ key[0] = ivp[0];
+ key[1] = ivp[1];
+ key[2] = ivp[2];
+ awa->awa_setkey(ctx, key, IEEE80211_WEP_IVLEN + keylen);
+
+ /* encrypt with calculating CRC */
+ crc = ~0;
+ while (left > 0) {
+ len = m->m_len - moff;
+ if (len == 0) {
+ m = m->m_next;
+ moff = 0;
+ continue;
+ }
+ if (len > n->m_len - noff) {
+ len = n->m_len - noff;
+ if (len == 0) {
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto fail;
+ n = n->m_next;
+ n->m_len = MLEN;
+ if (left >= MINCLSIZE) {
+ MCLGET(n, M_DONTWAIT);
+ if (n->m_flags & M_EXT)
+ n->m_len = n->m_ext.ext_size;
+ }
+ noff = 0;
+ continue;
+ }
+ }
+ if (len > left)
+ len = left;
+ if (txflag) {
+ awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff,
+ mtod(m, caddr_t) + moff, len);
+ crc = awi_crc_update(crc, mtod(m, caddr_t) + moff, len);
+ } else {
+ awa->awa_decrypt(ctx, mtod(n, caddr_t) + noff,
+ mtod(m, caddr_t) + moff, len);
+ crc = awi_crc_update(crc, mtod(n, caddr_t) + noff, len);
+ }
+ left -= len;
+ moff += len;
+ noff += len;
+ }
+ crc = ~crc;
+ if (txflag) {
+ LE_WRITE_4(crcbuf, crc);
+ if (n->m_len >= noff + sizeof(crcbuf))
+ n->m_len = noff + sizeof(crcbuf);
+ else {
+ n->m_len = noff;
+ MGET(n->m_next, M_DONTWAIT, n->m_type);
+ if (n->m_next == NULL)
+ goto fail;
+ n = n->m_next;
+ n->m_len = sizeof(crcbuf);
+ noff = 0;
+ }
+ awa->awa_encrypt(ctx, mtod(n, caddr_t) + noff, crcbuf,
+ sizeof(crcbuf));
+ } else {
+ n->m_len = noff;
+ noff = 0;
+ for (; noff < sizeof(crcbuf); noff += len, m = m->m_next) {
+ if (m->m_len < moff + len)
+ len = m->m_len - moff;
+ if (len == 0)
+ continue;
+ awa->awa_decrypt(ctx, crcbuf + noff,
+ mtod(m, caddr_t) + moff, len);
+ }
+ if (crc != LE_READ_4(crcbuf))
+ goto fail;
+ }
+ m_freem(m0);
+ return n0;
+
+ fail:
+ m_freem(m0);
+ m_freem(n0);
+ return NULL;
+}
+
+/*
+ * CRC 32 -- routine from RFC 2083
+ */
+
+/* Table of CRCs of all 8-bit messages */
+static u_int32_t awi_crc_table[256];
+static int awi_crc_table_computed = 0;
+
+/* Make the table for a fast CRC. */
+static void
+awi_crc_init()
+{
+ u_int32_t c;
+ int n, k;
+
+ if (awi_crc_table_computed)
+ return;
+ for (n = 0; n < 256; n++) {
+ c = (u_int32_t)n;
+ for (k = 0; k < 8; k++) {
+ if (c & 1)
+ c = 0xedb88320UL ^ (c >> 1);
+ else
+ c = c >> 1;
+ }
+ awi_crc_table[n] = c;
+ }
+ awi_crc_table_computed = 1;
+}
+
+/*
+ * Update a running CRC with the bytes buf[0..len-1]--the CRC
+ * should be initialized to all 1's, and the transmitted value
+ * is the 1's complement of the final running CRC
+ */
+
+static u_int32_t
+awi_crc_update(crc, buf, len)
+ u_int32_t crc;
+ u_int8_t *buf;
+ int len;
+{
+ u_int8_t *endbuf;
+
+ for (endbuf = buf + len; buf < endbuf; buf++)
+ crc = awi_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return crc;
+}
+
+/*
+ * Null -- do nothing but copy.
+ */
+
+static int
+awi_null_ctxlen()
+{
+
+ return 0;
+}
+
+static void
+awi_null_setkey(ctx, key, keylen)
+ void *ctx;
+ u_char *key;
+ int keylen;
+{
+}
+
+static void
+awi_null_copy(ctx, dst, src, len)
+ void *ctx;
+ u_char *dst;
+ u_char *src;
+ int len;
+{
+
+ memcpy(dst, src, len);
+}
diff --git a/sys/dev/ic/awireg.h b/sys/dev/ic/awireg.h
index 76c97ee5309..9866c561e3c 100644
--- a/sys/dev/ic/awireg.h
+++ b/sys/dev/ic/awireg.h
@@ -1,5 +1,4 @@
-/* $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 $ */
+/* $NetBSD: awireg.h,v 1.3 2000/03/22 11:22:22 onoe Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -58,11 +57,11 @@
*/
#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
+#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.
@@ -72,7 +71,7 @@
*/
#define AWI_BANNER 0x480 /* Version string */
-#define AWI_BANNER_LEN 0x20
+#define AWI_BANNER_LEN 0x20
/*
* Command block protocol:
@@ -85,96 +84,94 @@
* write command status to a zero value.
*/
-#define AWI_CMD 0x4a0 /* Command opcode byte */
+#define AWI_CMD 0x4a0 /* Command opcode byte */
-#define AWI_CMD_IDLE 0x0
-#define AWI_CMD_NOP 0x1
+#define AWI_CMD_IDLE 0x0
+#define AWI_CMD_NOP 0x1
-#define AWI_CMD_SET_MIB 0x2
-#define AWI_CMD_GET_MIB 0x9
+#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_TYPE 0x0
+#define AWI_CA_MIB_SIZE 0x1
#define AWI_CA_MIB_INDEX 0x2
-#define AWI_CA_MIB_DATA 0x4
+#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_LOCAL 0x0
+#define AWI_MIB_ADDR 0x2
+#define AWI_MIB_MAC 0x3
+#define AWI_MIB_STAT 0x4
+#define AWI_MIB_MGT 0x5
+#define AWI_MIB_DRVR 0x6
+#define AWI_MIB_PHY 0x7
-#define AWI_MIB_LAST AWI_MIB_PHY
-
-#define AWI_CMD_INIT_TX 0x3
+#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_BCAST 0x8
#define AWI_CA_TX_PS 0xc
#define AWI_CA_TX_CF 0x10
-#define AWI_CMD_FLUSH_TX 0x4
+#define AWI_CMD_FLUSH_TX 0x4
#define AWI_CA_FTX_LEN 0x5
-#define AWI_CA_FTX_DATA 0x0
+#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_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_KILL_RX 0x6
-#define AWI_CMD_SLEEP 0x7
+#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_WAKE 0x8
-#define AWI_CMD_SCAN 0xa
-#define AWI_CA_SCAN_LEN 0x6
+#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_SET 0x2
#define AWI_CA_SCAN_PATTERN 0x3
-#define AWI_CA_SCAN_IDX 0x4
+#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_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_IDX 0x2
#define AWI_CA_SYNC_STARTBSS 0x3
#define AWI_CA_SYNC_DWELL 0x4
-#define AWI_CA_SYNC_MBZ 0x6
+#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_RESUME 0xc
-#define AWI_CMD_STATUS 0x4a1 /* Command status */
+#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_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_CSB 0x4f0 /* Control/Status block */
#define AWI_SELFTEST 0x4f0
@@ -184,9 +181,9 @@
#define AWI_SELFTEST_MIB 0x03 /* mib initializing */
#define AWI_SELFTEST_MIB_FAIL 0xfa
-#define AWI_SELFTEST_RADIO_FAIL 0xfb
+#define AWI_SELFTEST_RADIO_FAIL 0xfb
#define AWI_SELFTEST_MAC_FAIL 0xfc
-#define AWI_SELFTEST_FLASH_FAIL 0xfd
+#define AWI_SELFTEST_FLASH_FAIL 0xfd
#define AWI_SELFTEST_RAM_FAIL 0xfe
#define AWI_SELFTEST_PASSED 0xff
@@ -213,8 +210,6 @@
#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.
@@ -224,7 +219,7 @@
* if non-zero, clear lockout_mac, loop.
*/
-#define AWI_LOCKOUT_MAC 0x4f5
+#define AWI_LOCKOUT_MAC 0x4f5
#define AWI_LOCKOUT_HOST 0x4f6
@@ -232,17 +227,17 @@
#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_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 0x08 /* 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_DRIVERSTATE 0x4fe /* driver state */
#define AWI_DRV_STATEMASK 0x0f
@@ -251,46 +246,45 @@
#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_INFAUTH 0x5 /* inf authed */
#define AWI_DRV_INFASSOC 0x6 /* inf associated */
-#define AWI_DRV_INFTOSS 0x7 /* inf handoff */
+#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_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_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_VBM 0x500 /* Virtual Bit Map */
#define AWI_BUFFERS 0x600 /* Buffers */
+#define AWI_BUFFERS_END 0x6000
/*
* 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_SIZE 0x18
-#define AWI_RXD_NEXT 0x4
-#define AWI_RXD_NEXT_LAST 0x80000000
+#define AWI_RXD_NEXT 0x4
+#define AWI_RXD_NEXT_LAST 0x80000000
-#define AWI_RXD_HOST_DESC_STATE 0x9
+#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_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 */
@@ -309,19 +303,19 @@
#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_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_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_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_RATE_1MBIT 10
+#define AWI_RATE_2MBIT 20
#define AWI_TXD_NDA 0x0c /* num DIFS attempts */
#define AWI_TXD_NDF 0x0d /* num DIFS failures */
@@ -332,7 +326,7 @@
#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_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 */
@@ -340,171 +334,126 @@
* 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
+#define AWI_ESS_ID_SIZE (IEEE80211_NWID_LEN+2)
+struct awi_mib_local {
+ u_int8_t Fragmentation_Dis;
+ u_int8_t Add_PLCP_Dis;
+ u_int8_t MAC_Hdr_Prsv;
+ u_int8_t Rx_Mgmt_Que_En;
+ u_int8_t Re_Assembly_Dis;
+ u_int8_t Strip_PLCP_Dis;
+ u_int8_t Rx_Error_Dis;
+ u_int8_t Power_Saving_Mode_Dis;
+ u_int8_t Accept_All_Multicast_Dis;
+ u_int8_t Check_Seq_Cntl_Dis;
+ u_int8_t Flush_CFP_Queue_On_CF_End;
+ u_int8_t Network_Mode;
+ u_int8_t PWD_Lvl;
+ u_int8_t CFP_Mode;
+ u_int8_t Tx_Buffer_Offset[4];
+ u_int8_t Tx_Buffer_Size[4];
+ u_int8_t Rx_Buffer_Offset[4];
+ u_int8_t Rx_Buffer_Size[4];
+ u_int8_t Acting_as_AP;
+ u_int8_t Fill_CFP;
+};
-/*
- * misc frame control bits in second byte of frame control word.
- * there are others, but we don't ever want to set them..
- */
+struct awi_mib_mac {
+ u_int8_t _Reserved1[2];
+ u_int8_t _Reserved2[2];
+ u_int8_t aRTS_Threshold[2];
+ u_int8_t aCW_max[2];
+ u_int8_t aCW_min[2];
+ u_int8_t aPromiscuous_Enable;
+ u_int8_t _Reserved3;
+ u_int8_t _Reserved4[4];
+ u_int8_t aShort_Retry_Limit;
+ u_int8_t aLong_Retry_Limit;
+ u_int8_t aMax_Frame_Length[2];
+ u_int8_t aFragmentation_Threshold[2];
+ u_int8_t aProbe_Delay[2];
+ u_int8_t aMin_Probe_Response_Time[2];
+ u_int8_t aMax_Probe_Response_Time[2];
+ u_int8_t aMax_Transmit_MSDU_Lifetime[4];
+ u_int8_t aMax_Receive_MSDU_Lifetime[4];
+ u_int8_t aStation_Basic_Rate[2];
+ u_int8_t aDesired_ESS_ID[AWI_ESS_ID_SIZE];
+};
-#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_mib_stat {
+ u_int8_t aTransmitted_MPDU_Count[4];
+ u_int8_t aTransmitted_MSDU_Count[4];
+ u_int8_t aOctets_Transmitted_Cnt[4];
+ u_int8_t aMulticast_Transmitted_Frame_Count[2];
+ u_int8_t aBroadcast_Transmitted_Frame_Count[2];
+ u_int8_t aFailed_Count[4];
+ u_int8_t aRetry_Count[4];
+ u_int8_t aMultiple_Retry_Count[4];
+ u_int8_t aFrame_Duplicate_Count[4];
+ u_int8_t aRTS_Success_Count[4];
+ u_int8_t aRTS_Failure_Count[4];
+ u_int8_t aACK_Failure_Count[4];
+ u_int8_t aReceived_Frame_Count [4];
+ u_int8_t aOctets_Received_Count[4];
+ u_int8_t aMulticast_Received_Count[2];
+ u_int8_t aBroadcast_Received_Count[2];
+ u_int8_t aFCS_Error_Count[4];
+ u_int8_t aError_Count[4];
+ u_int8_t aWEP_Undecryptable_Count[4];
};
-struct awi_llc_header
-{
- u_int8_t awi_llc_goo[8];
+struct awi_mib_mgt {
+ u_int8_t aPower_Mgt_Mode;
+ u_int8_t aScan_Mode;
+#define AWI_SCAN_PASSIVE 0x00
+#define AWI_SCAN_ACTIVE 0x01
+#define AWI_SCAN_BACKGROUND 0x02
+ u_int8_t aScan_State;
+ u_int8_t aDTIM_Period;
+ u_int8_t aATIM_Window[2];
+ u_int8_t Wep_Required;
+ u_int8_t _Reserved1;
+ u_int8_t aBeacon_Period[2];
+ u_int8_t aPassive_Scan_Duration[2];
+ u_int8_t aListen_Interval[2];
+ u_int8_t aMedium_Occupancy_Limit[2];
+ u_int8_t aMax_MPDU_Time[2];
+ u_int8_t aCFP_Max_Duration[2];
+ u_int8_t aCFP_Rate;
+ u_int8_t Do_Not_Receive_DTIMs;
+ u_int8_t aStation_ID[2];
+ u_int8_t aCurrent_BSS_ID[ETHER_ADDR_LEN];
+ u_int8_t aCurrent_ESS_ID[AWI_ESS_ID_SIZE];
};
-struct awi_assoc_hdr
-{
- u_int8_t awi_cap_info[2];
- u_int8_t awi_li[2];
+#define AWI_GROUP_ADDR_SIZE 4
+struct awi_mib_addr {
+ u_int8_t aMAC_Address[ETHER_ADDR_LEN];
+ u_int8_t aGroup_Addresses[AWI_GROUP_ADDR_SIZE][ETHER_ADDR_LEN];
+ u_int8_t aTransmit_Enable_Status;
+ u_int8_t _Reserved1;
};
-struct awi_auth_hdr
-{
- u_int8_t awi_algno[2];
- u_int8_t awi_seqno[2];
- u_int8_t awi_status[2];
+#define AWI_PWR_LEVEL_SIZE 4
+struct awi_mib_phy {
+ u_int8_t aSlot_Time[2];
+ u_int8_t aSIFS[2];
+ u_int8_t aMPDU_Maximum[2];
+ u_int8_t aHop_Time[2];
+ u_int8_t aSuprt_Data_Rates[4];
+ u_int8_t aCurrent_Reg_Domain;
+#define AWI_REG_DOMAIN_US 0x10
+#define AWI_REG_DOMAIN_CA 0x20
+#define AWI_REG_DOMAIN_EU 0x30
+#define AWI_REG_DOMAIN_ES 0x31
+#define AWI_REG_DOMAIN_FR 0x32
+#define AWI_REG_DOMAIN_JP 0x40
+ u_int8_t aPreamble_Lngth;
+ u_int8_t aPLCP_Hdr_Lngth;
+ u_int8_t Pwr_Up_Time[AWI_PWR_LEVEL_SIZE][2];
+ u_int8_t IEEE_PHY_Type;
+#define AWI_PHY_TYPE_FH 1
+#define AWI_PHY_TYPE_DS 2
+#define AWI_PHY_TYPE_IR 3
+ u_int8_t RCR_33A_Bits[8];
};
diff --git a/sys/dev/ic/awivar.h b/sys/dev/ic/awivar.h
index d50fa7c9b66..a2ce7ef5de4 100644
--- a/sys/dev/ic/awivar.h
+++ b/sys/dev/ic/awivar.h
@@ -1,5 +1,4 @@
-/* $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 $ */
+/* $NetBSD: awivar.h,v 1.12 2000/07/21 04:48:56 onoe Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -37,120 +36,137 @@
* 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.. */
+/* timer values in msec */
+#define AWI_SELFTEST_TIMEOUT 5000
+#define AWI_CMD_TIMEOUT 2000
+#define AWI_LOCKOUT_TIMEOUT 50
+#define AWI_ASCAN_DURATION 100
+#define AWI_ASCAN_WAIT 3000
+#define AWI_PSCAN_DURATION 200
+#define AWI_PSCAN_WAIT 5000
+#define AWI_TRANS_TIMEOUT 2000
+
+#define AWI_NTXBUFS 4
+#define AWI_MAX_KEYLEN 16
+
+enum awi_status {
+ AWI_ST_INIT,
+ AWI_ST_SCAN,
+ AWI_ST_SETSS,
+ AWI_ST_SYNC,
+ AWI_ST_AUTH,
+ AWI_ST_ASSOC,
+ AWI_ST_RUNNING
};
-#define AWI_FL_CMD_INPROG 0x0001
-
-#define AWI_SSID_LEN 33
-
-struct awi_bss_binding
+struct awi_bss
{
- 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];
+ TAILQ_ENTRY(awi_bss) list;
+ u_int8_t esrc[ETHER_ADDR_LEN];
+ 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; /* strength of this beacon */
+ u_int16_t dwell_time; /* dwell time */
+ u_int8_t timestamp[8]; /* timestamp of this bss */
+ u_int8_t bssid[ETHER_ADDR_LEN];
+ u_int16_t capinfo;
+ u_int32_t rxtime; /* unit's local time */
+ u_int16_t interval; /* beacon interval */
+ u_int8_t txrate;
+ u_int8_t fails;
+ u_int8_t essid[IEEE80211_NWID_LEN + 2];
};
-#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_wep_algo {
+ char *awa_name;
+ int (*awa_ctxlen) __P((void));
+ void (*awa_setkey) __P((void *, u_char *, int));
+ void (*awa_encrypt) __P((void *, u_char *, u_char *, int));
+ void (*awa_decrypt) __P((void *, u_char *, u_char *, int));
};
struct awi_softc
{
+#ifdef __NetBSD__
+ struct device sc_dev;
+ struct ethercom sc_ec;
+ void *sc_ih; /* interrupt handler */
+#endif
+#ifdef __FreeBSD__
+#if __FreeBSD__ >= 4
+ struct {
+ char dv_xname[64]; /*XXX*/
+ } sc_dev;
+#else
+ struct device sc_dev;
+#endif
+#endif
+#ifdef __OpenBSD__
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 */
+#endif
+ struct am79c930_softc sc_chip;
+ struct ifnet *sc_ifp;
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 ifmedia sc_media;
+ enum awi_status sc_status;
+ unsigned int sc_enabled:1,
+ sc_busy:1,
+ sc_cansleep:1,
+ sc_invalid:1,
+ sc_enab_intr:1,
+ sc_format_llc:1,
+ sc_start_bss:1,
+ sc_rawbpf:1,
+ sc_no_bssid:1,
+ sc_active_scan:1,
+ sc_attached:1; /* attach has succeeded */
+ u_int8_t sc_cmd_inprog;
+ int sc_sleep_cnt;
+
+ int sc_mgt_timer;
+
+ TAILQ_HEAD(, awi_bss) sc_scan;
+ u_int8_t sc_scan_cur;
+ u_int8_t sc_scan_min;
+ u_int8_t sc_scan_max;
+ u_int8_t sc_scan_set;
+ struct awi_bss sc_bss;
+ u_int8_t sc_ownssid[IEEE80211_NWID_LEN + 2];
+ u_int8_t sc_ownch;
+
+ int sc_rx_timer;
+ u_int32_t sc_rxdoff;
+ u_int32_t sc_rxmoff;
+ struct mbuf *sc_rxpend;
+
+ int sc_tx_timer;
+ u_int8_t sc_tx_rate;
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;
+ u_int32_t sc_txend;
+ u_int32_t sc_txnext;
+ u_int32_t sc_txdone;
+
+ int sc_wep_keylen[IEEE80211_WEP_NKID]; /* keylen */
+ u_int8_t sc_wep_key[IEEE80211_WEP_NKID][AWI_MAX_KEYLEN];
+ int sc_wep_defkid;
+ void *sc_wep_ctx; /* work area */
+ struct awi_wep_algo *sc_wep_algo;
+
+ u_char sc_banner[AWI_BANNER_LEN];
+ struct awi_mib_local sc_mib_local;
+ struct awi_mib_addr sc_mib_addr;
+ struct awi_mib_mac sc_mib_mac;
+ struct awi_mib_stat sc_mib_stat;
+ struct awi_mib_mgt sc_mib_mgt;
+ struct awi_mib_phy sc_mib_phy;
};
-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)
@@ -167,17 +183,59 @@ extern void awi_stop __P((struct awi_softc *));
#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
+ ((state) | AWI_DRV_AUTORXLED|AWI_DRV_AUTOTXLED))
+
+/* unalligned little endian access */
+#define LE_READ_2(p) \
+ (((u_int8_t *)(p))[0] | (((u_int8_t *)(p))[1] << 8))
+#define LE_READ_4(p) \
+ (((u_int8_t *)(p))[0] | (((u_int8_t *)(p))[1] << 8) | \
+ (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))
+#define LE_WRITE_2(p, v) \
+ ((((u_int8_t *)(p))[0] = ((u_int32_t)(v) & 0xff)), \
+ (((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff)))
+#define LE_WRITE_4(p, v) \
+ ((((u_int8_t *)(p))[0] = ((u_int32_t)(v) & 0xff)), \
+ (((u_int8_t *)(p))[1] = (((u_int32_t)(v) >> 8) & 0xff)), \
+ (((u_int8_t *)(p))[2] = (((u_int32_t)(v) >> 16) & 0xff)), \
+ (((u_int8_t *)(p))[3] = (((u_int32_t)(v) >> 24) & 0xff)))
+
+#define AWI_80211_RATE(rate) (((rate) & 0x7f) * 5)
+
+int awi_attach __P((struct awi_softc *));
+int awi_intr __P((void *));
+void awi_reset __P((struct awi_softc *));
+#ifndef __FreeBSD__
+int awi_activate __P((struct device *, enum devact));
+int awi_detach __P((struct awi_softc *));
+void awi_power __P((struct awi_softc *, int));
+#endif
+
+void awi_stop __P((struct awi_softc *sc));
+int awi_init __P((struct awi_softc *sc));
+int awi_init_region __P((struct awi_softc *));
+int awi_wicfg __P((struct ifnet *, u_long, caddr_t));
+
+int awi_wep_setnwkey __P((struct awi_softc *, struct ieee80211_nwkey *));
+int awi_wep_getnwkey __P((struct awi_softc *, struct ieee80211_nwkey *));
+int awi_wep_getalgo __P((struct awi_softc *));
+int awi_wep_setalgo __P((struct awi_softc *, int));
+int awi_wep_setkey __P((struct awi_softc *, int, unsigned char *, int));
+int awi_wep_getkey __P((struct awi_softc *, int, unsigned char *, int *));
+struct mbuf *awi_wep_encrypt __P((struct awi_softc *, struct mbuf *, int));
+
+#ifdef __FreeBSD__
+/* Provide mem* for compat with NetBSD to fix LINT */
+static __inline int
+memcmp(const void *b1, const void *b2, size_t len)
+{
+ return (bcmp(b1, b2, len));
+}
-extern int awi_intr __P((void *));
+static __inline void *
+memset(void *b, int c, size_t len)
+{
+ bzero(b, len);
+ return (b);
+}
+#endif
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index 1c07957361b..cea7d0a1b67 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pcmcia,v 1.32 2000/06/19 08:58:54 fgsch Exp $
+# $OpenBSD: files.pcmcia,v 1.33 2000/08/17 16:16:31 mickey 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.
@@ -77,10 +77,11 @@ 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
+file dev/pcmcia/if_awi_pcmcia.c awi_pcmcia
+file dev/ic/awi.c awi
+file dev/ic/awi_wep.c awi
+#file dev/ic/awi_wicfg.c awi
+file dev/ic/am79c930.c awi
# Raytheon(Raylink)/WebGear IEEE 802.11 FH WLAN
device ray: ether, ifnet, ifmedia
diff --git a/sys/dev/pcmcia/if_awi_pcmcia.c b/sys/dev/pcmcia/if_awi_pcmcia.c
index 0119dced22e..7c9fb4b388d 100644
--- a/sys/dev/pcmcia/if_awi_pcmcia.c
+++ b/sys/dev/pcmcia/if_awi_pcmcia.c
@@ -1,5 +1,5 @@
-/* $NetBSD: if_awi_pcmcia.c,v 1.5 1999/11/06 16:43:54 sommerfeld Exp $ */
-/* $OpenBSD: if_awi_pcmcia.c,v 1.3 2000/04/24 19:43:35 niklas Exp $ */
+/* $NetBSD: if_awi_pcmcia.c,v 1.13 2000/03/22 11:22:20 onoe Exp $ */
+/* $OpenBSD: if_awi_pcmcia.c,v 1.4 2000/08/17 16:16:31 mickey Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -61,23 +61,13 @@
#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
+#include <net/if_ieee80211.h>
#if NBPFILTER > 0
#include <net/bpf.h>
-#include <net/bpfdesc.h>
#endif
#include <machine/cpu.h>
@@ -93,53 +83,102 @@
#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 */
+ struct awi_softc sc_awi; /* real "awi" softc */
/* PCMCIA-specific goo */
struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
+ struct pcmcia_mem_handle sc_memh; /* PCMCIA memory space info */
int sc_io_window; /* our i/o window */
+ int sc_mem_window; /* our memory window */
struct pcmcia_function *sc_pf; /* our PCMCIA function */
+ void *sc_powerhook; /* power hook descriptor */
};
-int awi_pcmcia_find __P((struct awi_pcmcia_softc *,
- struct pcmcia_attach_args *, struct pcmcia_config_entry *));
+static int awi_pcmcia_match __P((struct device *, void *, void *));
+static void awi_pcmcia_attach __P((struct device *, struct device *, void *));
+static int awi_pcmcia_detach __P((struct device *, int));
+static int awi_pcmcia_enable __P((struct awi_softc *));
+static void awi_pcmcia_disable __P((struct awi_softc *));
+static void awi_pcmcia_powerhook __P((int, void *));
-/* Autoconfig definition of driver back-end */
-struct cfdriver awi_cd = {
- NULL, "awi", DV_IFNET
-};
+static int awi_pcmcia_find __P((struct awi_pcmcia_softc *,
+ struct pcmcia_attach_args *, struct pcmcia_config_entry *));
struct cfattach awi_pcmcia_ca = {
sizeof(struct awi_pcmcia_softc), awi_pcmcia_match, awi_pcmcia_attach,
- awi_pcmcia_detach, /* awi_activate */ 0
+ awi_pcmcia_detach, awi_activate
};
-/*
- * XXX following is common to most PCMCIA NIC's and belongs
- * in common code
- */
+static struct awi_pcmcia_product {
+ u_int32_t app_vendor; /* vendor ID */
+ u_int32_t app_product; /* product ID */
+ const char *app_cisinfo[4]; /* CIS information */
+ const char *app_name; /* product name */
+} awi_pcmcia_products[] = {
+ { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_STACK_650,
+ PCMCIA_CIS_BAY_STACK_650, "BayStack 650" },
+
+ { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_STACK_660,
+ PCMCIA_CIS_BAY_STACK_660, "BayStack 660" },
-struct awi_pcmcia_get_enaddr_args {
- int got_enaddr;
- u_int8_t enaddr[ETHER_ADDR_LEN];
+ { PCMCIA_VENDOR_BAY, PCMCIA_PRODUCT_BAY_SURFER_PRO,
+ PCMCIA_CIS_BAY_SURFER_PRO, "AirSurfer Pro" },
+
+ { PCMCIA_VENDOR_AMD, PCMCIA_PRODUCT_AMD_AM79C930,
+ PCMCIA_CIS_AMD_AM79C930, "AMD AM79C930" },
+
+ { PCMCIA_VENDOR_ICOM, PCMCIA_PRODUCT_ICOM_SL200,
+ PCMCIA_CIS_ICOM_SL200, "Icom SL-200" },
+
+ { PCMCIA_VENDOR_NOKIA, PCMCIA_PRODUCT_NOKIA_C020_WLAN,
+ PCMCIA_CIS_NOKIA_C020_WLAN, "Nokia C020" },
+
+ { PCMCIA_VENDOR_FARALLON, PCMCIA_PRODUCT_FARALLON_SKYLINE,
+ PCMCIA_CIS_FARALLON_SKYLINE, "SkyLINE Wireless" },
+
+/* { PCMCIA_VENDOR_BREEZECOM, PCMCIA_PRODUCT_BREEZECOM_BREEZENET,
+ PCMCIA_CIS_BREEZECOM_BREEZENET, "BreezeNet SC-PX" },
+*/
+ { 0, 0,
+ { NULL, NULL, NULL, NULL }, NULL },
};
-int awi_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *));
+static struct awi_pcmcia_product *
+ awi_pcmcia_lookup __P((struct pcmcia_attach_args *));
+
+static struct awi_pcmcia_product *
+awi_pcmcia_lookup(pa)
+ struct pcmcia_attach_args *pa;
+{
+ struct awi_pcmcia_product *app;
+
+ for (app = awi_pcmcia_products; app->app_name != NULL; app++) {
+ /* match by vendor/product id */
+ if (pa->manufacturer != PCMCIA_VENDOR_INVALID &&
+ pa->manufacturer == app->app_vendor &&
+ pa->product != PCMCIA_PRODUCT_INVALID &&
+ pa->product == app->app_product)
+ return (app);
+
+ /* match by CIS information */
+ if (pa->card->cis1_info[0] != NULL &&
+ app->app_cisinfo[0] != NULL &&
+ strcmp(pa->card->cis1_info[0], app->app_cisinfo[0]) == 0 &&
+ pa->card->cis1_info[1] != NULL &&
+ app->app_cisinfo[1] != NULL &&
+ strcmp(pa->card->cis1_info[1], app->app_cisinfo[1]) == 0)
+ return (app);
+ }
+
+ return (NULL);
+}
-int
+static int
awi_pcmcia_enable(sc)
struct awi_softc *sc;
{
- struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc;
+ struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc;
struct pcmcia_function *pf = psc->sc_pf;
/* establish the interrupt. */
@@ -149,21 +188,28 @@ awi_pcmcia_enable(sc)
sc->sc_dev.dv_xname);
return (1);
}
- return (pcmcia_function_enable(pf));
+
+ if (pcmcia_function_enable(pf)) {
+ pcmcia_intr_disestablish(pf, sc->sc_ih);
+ return (1);
+ }
+ DELAY(1000);
+
+ return (0);
}
-void
+static void
awi_pcmcia_disable(sc)
struct awi_softc *sc;
{
- struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *) sc;
+ struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc;
struct pcmcia_function *pf = psc->sc_pf;
pcmcia_intr_disestablish (pf, sc->sc_ih);
pcmcia_function_disable (pf);
}
-int
+static int
awi_pcmcia_match(parent, match, aux)
struct device *parent;
void *match;
@@ -171,17 +217,14 @@ awi_pcmcia_match(parent, match, aux)
{
struct pcmcia_attach_args *pa = aux;
- if (pa->manufacturer != PCMCIA_VENDOR_BAY)
- return (0);
-
- if (pa->product == PCMCIA_PRODUCT_BAY_STACK_650)
+ if (awi_pcmcia_lookup(pa) != NULL)
return (1);
return (0);
}
-int
-awi_pcmcia_find (psc, pa, cfe)
+static int
+awi_pcmcia_find(psc, pa, cfe)
struct awi_pcmcia_softc *psc;
struct pcmcia_attach_args *pa;
struct pcmcia_config_entry *cfe;
@@ -189,95 +232,69 @@ awi_pcmcia_find (psc, pa, 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)
+ cfe->iospace[0].length, AM79C930_IO_ALIGN,
+ &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))
+ if (pcmcia_function_enable(psc->sc_pf))
goto fail_io_unmap;
-
+
+ sc->sc_chip.sc_bustype = AM79C930_BUS_PCMCIA;
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(1000);
- awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN);
+ awi_read_bytes(sc, AWI_BANNER, version, AWI_BANNER_LEN);
if (memcmp(version, "PCnetMobile:", 12) == 0)
- return 0;
-
+ return (0);
+
fail++;
- pcmcia_function_disable (psc->sc_pf);
-
+ pcmcia_function_disable(psc->sc_pf);
+
fail_io_unmap:
fail++;
- pcmcia_io_unmap (psc->sc_pf, psc->sc_io_window);
-
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
+
fail_io_free:
fail++;
- pcmcia_io_free (psc->sc_pf, &psc->sc_pcioh);
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
fail:
fail++;
- return fail;
+ psc->sc_io_window = -1;
+ return (fail);
}
-
-
-void
+static void
awi_pcmcia_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
- struct awi_pcmcia_softc *psc = (void *) self;
+ struct awi_pcmcia_softc *psc = (void *)self;
struct awi_softc *sc = &psc->sc_awi;
+ struct awi_pcmcia_product *app;
struct pcmcia_attach_args *pa = aux;
struct pcmcia_config_entry *cfe;
- struct awi_pcmcia_get_enaddr_args pgea;
-#if 0
- struct pcmcia_mem_handle memh;
bus_addr_t memoff;
- int memwin;
-#endif
-#if 0
- 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
+ app = awi_pcmcia_lookup(pa);
+ if (app == NULL)
+ panic("awi_pcmcia_attach: impossible");
psc->sc_pf = pa->pf;
@@ -295,122 +312,116 @@ awi_pcmcia_attach(parent, self, aux)
}
if (cfe == NULL) {
printf(": no suitable CIS info found\n");
- return;
+ goto no_config_entry;
}
sc->sc_enabled = 1;
- sc->sc_state = AWI_ST_SELFTEST;
- printf(": BayStack 650 Wireless (802.11)\n");
+ printf(": %s\n", app->app_name);
-#if 0
- if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE, &memh) != 0) {
+ psc->sc_mem_window = -1;
+ if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE,
+ &psc->sc_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)) {
+ } else if (pcmcia_mem_map(psc->sc_pf,
+ PCMCIA_MEM_COMMON, AM79C930_MEM_BASE,
+ AM79C930_MEM_SIZE, &psc->sc_memh, &memoff, &psc->sc_mem_window)) {
printf("%s: unable to map memory space; using i/o only\n",
sc->sc_dev.dv_xname);
- pcmcia_mem_free(psc->sc_pf, &memh);
+ pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
} else {
- sc->sc_chip.sc_memt = memh.memt;
- sc->sc_chip.sc_memh = memh.memh;
+ sc->sc_chip.sc_memt = psc->sc_memh.memt;
+ sc->sc_chip.sc_memh = psc->sc_memh.memh;
am79c930_chip_init(&sc->sc_chip, 1);
}
-#endif
- 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",
+ /* establish the interrupt. */
+ sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, awi_intr, sc);
+ if (sc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt\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
- ;
+ goto no_interrupt;
+ }
+ sc->sc_ifp = &sc->sc_ec.ac_if;
+ sc->sc_cansleep = 1;
- awi_attach(sc, pgea.enaddr);
+ if (awi_attach(sc) != 0) {
+ printf("%s: failed to attach controller\n",
+ sc->sc_dev.dv_xname);
+ goto attach_failed;
+ }
+ psc->sc_powerhook = powerhook_establish(awi_pcmcia_powerhook, psc);
-#ifndef NETBSD_ORIGINAL
- awi_init(sc);
- awi_stop(sc);
-#endif
+ sc->sc_enabled = 0;
+ /* disable device and disestablish the interrupt */
+ awi_pcmcia_disable(sc);
+ return;
+
+ attach_failed:
+ pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
+
+ no_interrupt:
+ /* Unmap our memory window and space */
+ if (psc->sc_mem_window != -1) {
+ pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window);
+ pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
+ }
-#ifdef notyet /* NETBSD_ORIGINAL */
- sc->sc_state = AWI_ST_OFF;
+ /* Unmap our i/o window and space */
+ pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
+ pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
- sc->sc_enabled = 0;
- /*
- * XXX This should be done once the framework has enable/disable hooks.
- */
+ /* Disable the function */
pcmcia_function_disable(psc->sc_pf);
-#endif /* notyet */
+
+ no_config_entry:
+ psc->sc_io_window = -1;
}
-int
+static int
awi_pcmcia_detach(self, flags)
struct device *self;
int flags;
{
struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)self;
+ int error;
+
+ if (psc->sc_io_window == -1)
+ /* Nothing to detach. */
+ return (0);
+
+ if (psc->sc_powerhook != NULL)
+ powerhook_disestablish(psc->sc_powerhook);
+
+ error = awi_detach(&psc->sc_awi);
+ if (error != 0)
+ return (error);
+
+ /* Unmap our memory window and free memory space */
+ if (psc->sc_mem_window != -1) {
+ pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window);
+ pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
+ }
/* 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;
+static void
+awi_pcmcia_powerhook(why, arg)
+ int why;
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);
+ struct awi_pcmcia_softc *psc = arg;
+ struct awi_softc *sc = &psc->sc_awi;
- 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);
+ awi_power(sc, why);
}