summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>1999-11-25 20:45:49 +0000
committerwpaul <wpaul@FreeBSD.org>1999-11-25 20:45:49 +0000
commitd0da4e010d8ed65bf5f7db99a1b113baee7bf5fa (patch)
treed01702dbf8687a701f67068bb061e5aaf01cb2c1
parent7f96711685a7ad2d836d4782c997fa98f82cf736 (diff)
downloadFreeBSD-src-d0da4e010d8ed65bf5f7db99a1b113baee7bf5fa.zip
FreeBSD-src-d0da4e010d8ed65bf5f7db99a1b113baee7bf5fa.tar.gz
Update the WaveLAN/IEEE driver:
- Convert to new bus attachment scheme. Thanks to Blaz Zupan for doing the initial work here. One thing I changed was to have the attach and detach routines work like the PCI drivers, which means that in theory you should be able to load and unload the driver like the PCI NIC drivers, however the pccard support for this hasn't settled down yet so it doesn't quite work. Once the pccard work is done, I'll have to revisit this. - Add device wi0 to PCCARD. If we're lucky, people should be able to install via their WaveLAN cards now. - Add support for signal strength caching. The wicontrol utility has also been updated to allow zeroing and displaying the signal strength cache. - Add a /sys/modules/wi directory and fix a Makefile to builf if_wi.ko. Currently this module is only built for the i386 platform, though once the pccard stuff is done it should be able to work on the alpha too. (Theoretically you should be able to plug one of the WaveLAN/IEEE ISA cards into an alpha with an ISA slot, but we'll see how that turns out. - Update LINT to use only device wi0. There is no true ISA version of the WaveLAN/IEEE so we'll never use an ISA attachment. - Update files.i386 so that if_wi is dependent on card.
-rw-r--r--sys/conf/NOTES2
-rw-r--r--sys/conf/files.i3862
-rw-r--r--sys/dev/wi/if_wavelan_ieee.h25
-rw-r--r--sys/dev/wi/if_wi.c548
-rw-r--r--sys/dev/wi/if_wireg.h14
-rw-r--r--sys/i386/conf/LINT2
-rw-r--r--sys/i386/conf/NOTES2
-rw-r--r--sys/i386/conf/PCCARD4
-rw-r--r--sys/i386/conf/files.i3862
-rw-r--r--sys/i386/include/if_wavelan_ieee.h25
-rw-r--r--sys/i386/isa/if_wi.c548
-rw-r--r--sys/i386/isa/if_wireg.h14
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/wi/Makefile16
-rw-r--r--usr.sbin/wicontrol/Makefile2
-rw-r--r--usr.sbin/wicontrol/wicontrol.817
-rw-r--r--usr.sbin/wicontrol/wicontrol.c88
17 files changed, 981 insertions, 332 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 44cf11d..00ee4f4 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -1282,7 +1282,7 @@ device le0 at isa? port 0x300 irq 5 iomem 0xd0000
device lnc0 at isa? port 0x280 irq 10 drq 0
device rdp0 at isa? port 0x378 irq 7 flags 2
device sr0 at isa? port 0x300 irq 5 iomem 0xd0000
-device wi0 at isa? port? irq?
+device wi0
options WLCACHE # enables the signal-strength cache
options WLDEBUG # enables verbose debugging output
device wl0 at isa? port 0x300 irq ?
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index b5fb112..b0ad19a 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -211,7 +211,7 @@ i386/isa/if_le.c optional le
i386/isa/if_lnc.c optional lnc
i386/isa/if_rdp.c optional rdp
i386/isa/if_sr.c optional sr
-i386/isa/if_wi.c optional wi
+i386/isa/if_wi.c optional wi card
i386/isa/if_wl.c optional wl
i386/isa/if_wlp.c optional wlp
i386/isa/if_ze.c optional ze
diff --git a/sys/dev/wi/if_wavelan_ieee.h b/sys/dev/wi/if_wavelan_ieee.h
index ef5f5ae..8ce57f9 100644
--- a/sys/dev/wi/if_wavelan_ieee.h
+++ b/sys/dev/wi/if_wavelan_ieee.h
@@ -72,6 +72,10 @@ struct wi_req {
*/
#define WI_RID_IFACE_STATS 0x0100
#define WI_RID_MGMT_XMIT 0x0200
+#ifdef WICACHE
+#define WI_RID_ZERO_CACHE 0x0300
+#define WI_RID_READ_CACHE 0x0400
+#endif
struct wi_80211_hdr {
u_int16_t frame_ctl;
@@ -120,6 +124,27 @@ struct wi_mgmt_hdr {
u_int16_t seq_ctl;
};
+/*
+ * Lucent/wavelan IEEE signal strength cache
+ *
+ * driver keeps cache of last
+ * MAXWICACHE packets to arrive including signal strength info.
+ * daemons may read this via ioctl
+ *
+ * Each entry in the wi_sigcache has a unique macsrc.
+ */
+#ifdef WICACHE
+#define MAXWICACHE 10
+
+struct wi_sigcache {
+ char macsrc[6]; /* unique MAC address for entry */
+ int ipsrc; /* ip address associated with packet */
+ int signal; /* signal strength of the packet */
+ int noise; /* noise value */
+ int quality; /* quality of the packet */
+};
+#endif
+
#ifndef KERNEL
struct wi_counters {
u_int32_t wi_tx_unicast_frames;
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index 53437a1..e5e8a01 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -66,20 +66,26 @@
#define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
#define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
-
-#include "card.h"
-#undef NCARD
-#define NCARD 0
-#include "wi.h"
+#define WICACHE /* turn on signal strength cache code */
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/eventhandler.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/clock.h>
+#include <machine/md_var.h>
+#include <machine/bus_pio.h>
+#include <sys/rman.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -88,53 +94,33 @@
#include <net/if_media.h>
#include <net/if_types.h>
-#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
-#endif
#include <net/bpf.h>
-#include <machine/clock.h>
-#include <machine/md_var.h>
-#include <machine/bus_pio.h>
-#include <machine/bus.h>
-
-#include <i386/isa/isa_device.h>
-#include <i386/isa/icu.h>
-#include <i386/isa/if_wireg.h>
#include <machine/if_wavelan_ieee.h>
-
-#if NCARD > 0
-#include <sys/select.h>
-#include <pccard/cardinfo.h>
-#include <pccard/slot.h>
-#endif
+#include <i386/isa/if_wireg.h>
#if !defined(lint)
static const char rcsid[] =
"$FreeBSD$";
#endif
-static struct wi_softc wi_softc[NWI];
-
#ifdef foo
static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
#endif
-static int wi_probe __P((struct isa_device *));
-static int wi_attach __P((struct isa_device *));
-ointhand2_t wi_intr;
+static void wi_intr __P((void *));
static void wi_reset __P((struct wi_softc *));
static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
static void wi_init __P((void *));
static void wi_start __P((struct ifnet *));
static void wi_stop __P((struct wi_softc *));
static void wi_watchdog __P((struct ifnet *));
-static void wi_shutdown __P((void *, int));
static void wi_rxeof __P((struct wi_softc *));
static void wi_txeof __P((struct wi_softc *, int));
static void wi_update_stats __P((struct wi_softc *));
@@ -153,136 +139,118 @@ static void wi_inquire __P((void *));
static void wi_setdef __P((struct wi_softc *, struct wi_req *));
static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int));
-struct isa_driver widriver = {
- wi_probe,
- wi_attach,
- "wi",
- 1
-};
+#ifdef WICACHE
+static
+void wi_cache_store __P((struct wi_softc *, struct ether_header *,
+ struct mbuf *, unsigned short));
+#endif
+
+static int wi_pccard_probe __P((device_t));
+static int wi_pccard_attach __P((device_t));
+static int wi_pccard_detach __P((device_t));
+static void wi_shutdown __P((device_t));
+
+static int wi_alloc __P((device_t));
+static void wi_free __P((device_t));
-#if NCARD > 0
-static int wi_pccard_init __P((struct pccard_devinfo *));
-static void wi_pccard_unload __P((struct pccard_devinfo *));
-static int wi_pccard_intr __P((struct pccard_devinfo *));
+static device_method_t wi_pccard_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, wi_pccard_probe),
+ DEVMETHOD(device_attach, wi_pccard_attach),
+ DEVMETHOD(device_detach, wi_pccard_detach),
+ DEVMETHOD(device_shutdown, wi_shutdown),
+
+ { 0, 0 }
+};
-#ifdef PCCARD_MODULE
-PCCARD_MODULE(wi, wi_pccard_init, wi_pccard_unload,
- wi_pccard_intr, 0, net_imask);
-#else
-static struct pccard_device wi_info = {
+static driver_t wi_pccard_driver = {
"wi",
- wi_pccard_init,
- wi_pccard_unload,
- wi_pccard_intr,
- 0, /* Attributes - presently unused */
- &net_imask /* Interrupt mask for device */
- /* XXX - Should this also include net_imask? */
+ wi_pccard_methods,
+ sizeof(struct wi_softc)
};
-DATA_SET(pccarddrv_set, wi_info);
-#endif
+static devclass_t wi_pccard_devclass;
-/* Initialize the PCCARD. */
-static int wi_pccard_init(sc_p)
- struct pccard_devinfo *sc_p;
-{
- struct wi_softc *sc;
- int i;
- u_int32_t irq;
+DRIVER_MODULE(if_wi, pccard, wi_pccard_driver, wi_pccard_devclass, 0, 0);
- if (sc_p->isahd.id_unit >= NWI)
- return(ENODEV);
+static int wi_pccard_probe(dev)
+ device_t dev;
+{
+ struct wi_softc *sc;
+ int error;
- sc = &wi_softc[sc_p->isahd.id_unit];
+ sc = device_get_softc(dev);
sc->wi_gone = 0;
- sc->wi_unit = sc_p->isahd.id_unit;
- sc->wi_bhandle = sc_p->isahd.id_iobase;
- sc->wi_btag = I386_BUS_SPACE_IO;
+
+ error = wi_alloc(dev);
+ if (error)
+ return (error);
+
+ device_set_desc(dev, "WaveLAN/IEEE 802.11");
+ wi_free(dev);
/* Make sure interrupts are disabled. */
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
- /* Grr. IRQ is encoded as a bitmask. */
- irq = sc_p->isahd.id_irq;
- for (i = 0; i < 32; i++) {
- if (irq & 0x1)
- break;
- irq >>= 1;
- }
-
- /*
- * Print a nice probe message to let the operator
- * know something interesting is happening.
- */
- printf("wi%d: <WaveLAN/IEEE 802.11> at 0x%x-0x%x irq %d on isa\n",
- sc_p->isahd.id_unit, sc_p->isahd.id_iobase,
- sc_p->isahd.id_iobase + WI_IOSIZ - 1, i);
-
- if (wi_attach(&sc_p->isahd))
- return(ENXIO);
-
- return(0);
+ return (0);
}
-static void wi_pccard_unload(sc_p)
- struct pccard_devinfo *sc_p;
+static int wi_pccard_detach(dev)
+ device_t dev;
{
struct wi_softc *sc;
struct ifnet *ifp;
+ int s;
+
+ s = splimp();
- sc = &wi_softc[sc_p->isahd.id_unit];
+ sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
if (sc->wi_gone) {
- printf("wi%d: already unloaded\n", sc_p->isahd.id_unit);
- return;
+ device_printf(dev, "already unloaded\n");
+ return(ENODEV);
}
- ifp->if_flags &= ~IFF_RUNNING;
- if_down(ifp);
+ wi_stop(sc);
+ if_detach(ifp);
+ bus_teardown_intr(dev, sc->irq, &sc->wi_intrhand);
+ wi_free(dev);
sc->wi_gone = 1;
- printf("wi%d: unloaded\n", sc_p->isahd.id_unit);
- return;
-}
-
-static int wi_pccard_intr(sc_p)
- struct pccard_devinfo *sc_p;
-{
- wi_intr(sc_p->isahd.id_unit);
- return(1);
-}
-#endif
+ splx(s);
+ device_printf(dev, "unload\n");
-static int wi_probe(isa_dev)
- struct isa_device *isa_dev;
-{
- /*
- * The ISA WaveLAN/IEEE card is actually not an ISA card:
- * it's a PCMCIA card plugged into a PCMCIA bridge adapter
- * that fits into an ISA slot. Consequently, we will always
- * be using the pccard support to probe and attach these
- * devices, so we can never actually probe one from here.
- */
return(0);
}
-static int wi_attach(isa_dev)
- struct isa_device *isa_dev;
+static int wi_pccard_attach(device_t dev)
{
struct wi_softc *sc;
struct wi_ltv_macaddr mac;
struct wi_ltv_gen gen;
struct ifnet *ifp;
- char ifname[IFNAMSIZ];
+ int error;
-#ifdef PCCARD_MODULE
- isa_dev->id_ointr = wi_intr;
-#endif
- sc = &wi_softc[isa_dev->id_unit];
+ sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
+ error = wi_alloc(dev);
+ if (error) {
+ device_printf(dev, "wi_alloc() failed! (%d)\n", error);
+ return (error);
+ }
+
+ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
+ wi_intr, sc, &sc->wi_intrhand);
+
+ if (error) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ wi_free(dev);
+ return (error);
+ }
+
/* Reset the NIC. */
wi_reset(sc);
@@ -293,7 +261,7 @@ static int wi_attach(isa_dev)
bcopy((char *)&mac.wi_mac_addr,
(char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
- printf("wi%d: Ethernet address: %6D\n", sc->wi_unit,
+ device_printf(dev, "Ethernet address: %6D\n",
sc->arpcom.ac_enaddr, ":");
ifp->if_softc = sc;
@@ -348,24 +316,12 @@ static int wi_attach(isa_dev)
wi_stop(sc);
/*
- * If this logical interface has already been attached,
- * don't attach it again or chaos will ensue.
+ * Call MI attach routines.
*/
- sprintf(ifname, "wi%d", sc->wi_unit);
-
- if (ifunit(ifname) == NULL) {
- callout_handle_init(&sc->wi_stat_ch);
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
- EVENTHANDLER_REGISTER(shutdown_post_sync, wi_shutdown, sc,
- SHUTDOWN_PRI_DEFAULT);
- }
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ callout_handle_init(&sc->wi_stat_ch);
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
return(0);
}
@@ -413,8 +369,8 @@ static void wi_rxeof(sc)
rx_frame.wi_status == WI_STAT_TUNNEL ||
rx_frame.wi_status == WI_STAT_WMP_MSG) {
if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
- printf("wi%d: oversized packet received "
- "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
+ device_printf(sc->dev, "oversized packet received "
+ "(wi_dat_len=%d, wi_status=0x%x)\n",
rx_frame.wi_dat_len, rx_frame.wi_status);
m_freem(m);
ifp->if_ierrors++;
@@ -440,8 +396,8 @@ static void wi_rxeof(sc)
} else {
if((rx_frame.wi_dat_len +
sizeof(struct ether_header)) > MCLBYTES) {
- printf("wi%d: oversized packet received "
- "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
+ device_printf(sc->dev, "oversized packet received "
+ "(wi_dat_len=%d, wi_status=0x%x)\n",
rx_frame.wi_dat_len, rx_frame.wi_status);
m_freem(m);
ifp->if_ierrors++;
@@ -473,6 +429,9 @@ static void wi_rxeof(sc)
/* Receive packet. */
m_adj(m, sizeof(struct ether_header));
+#ifdef WICACHE
+ wi_cache_store(sc, eh, m, rx_frame.wi_q_info);
+#endif
ether_input(ifp, eh, m);
return;
@@ -555,14 +514,13 @@ void wi_update_stats(sc)
return;
}
-void wi_intr(unit)
- int unit;
+static void wi_intr(xsc)
+ void *xsc;
{
- struct wi_softc *sc;
+ struct wi_softc *sc = xsc;
struct ifnet *ifp;
u_int16_t status;
- sc = &wi_softc[unit];
ifp = &sc->arpcom.ac_if;
if (!(ifp->if_flags & IFF_UP)) {
@@ -657,14 +615,19 @@ static int wi_cmd(sc, cmd, val)
static void wi_reset(sc)
struct wi_softc *sc;
{
+ wi_cmd(sc, WI_CMD_INI, 0);
+ DELAY(100000);
+ wi_cmd(sc, WI_CMD_INI, 0);
+ DELAY(100000);
+#ifdef foo
if (wi_cmd(sc, WI_CMD_INI, 0))
- printf("wi%d: init failed\n", sc->wi_unit);
+ device_printf(sc->dev, "init failed\n");
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
/* Calibrate timer. */
WI_SETVAL(WI_RID_TICK_TIME, 8);
-
+#endif
return;
}
@@ -752,7 +715,7 @@ static int wi_seek(sc, id, off, chan)
offreg = WI_OFF1;
break;
default:
- printf("wi%d: invalid data path: %x\n", sc->wi_unit, chan);
+ device_printf(sc->dev, "invalid data path: %x\n", chan);
return(EIO);
}
@@ -848,8 +811,7 @@ static int wi_alloc_nicmem(sc, len, id)
int i;
if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) {
- printf("wi%d: failed to allocate %d bytes on NIC\n",
- sc->wi_unit, len);
+ device_printf(sc->dev, "failed to allocate %d bytes on NIC\n", len);
return(ENOMEM);
}
@@ -1037,7 +999,23 @@ static int wi_ioctl(ifp, command, data)
bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
sizeof(sc->wi_stats));
wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
- } else {
+ }
+#ifdef WICACHE
+ else if (wreq.wi_type == WI_RID_ZERO_CACHE) {
+ sc->wi_sigitems = sc->wi_nextitem = 0;
+ } else if (wreq.wi_type == WI_RID_READ_CACHE) {
+ char *pt = (char *)&wreq.wi_val;
+ bcopy((char *)&sc->wi_sigitems,
+ (char *)pt, sizeof(int));
+ pt += (sizeof (int));
+ wreq.wi_len = sizeof(int) / 2;
+ bcopy((char *)&sc->wi_sigcache, (char *)pt,
+ sizeof(struct wi_sigcache) * sc->wi_sigitems);
+ wreq.wi_len += ((sizeof(struct wi_sigcache) *
+ sc->wi_sigitems) / 2) + 1;
+ }
+#endif
+ else {
if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) {
error = EINVAL;
break;
@@ -1147,11 +1125,11 @@ static void wi_init(xsc)
wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
- printf("wi%d: tx buffer allocation failed\n", sc->wi_unit);
+ device_printf(sc->dev, "tx buffer allocation failed\n");
sc->wi_tx_data_id = id;
if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
- printf("wi%d: mgmt. buffer allocation failed\n", sc->wi_unit);
+ device_printf(sc->dev, "mgmt. buffer allocation failed\n");
sc->wi_tx_mgmt_id = id;
/* enable interrupts */
@@ -1244,7 +1222,7 @@ static void wi_start(ifp)
m_freem(m0);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
- printf("wi%d: xmit failed\n", sc->wi_unit);
+ device_printf(sc->dev, "xmit failed\n");
ifp->if_flags |= IFF_OACTIVE;
@@ -1286,7 +1264,7 @@ static int wi_mgmt_xmit(sc, data, len)
(len - sizeof(struct wi_80211_hdr)) + 2);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
- printf("wi%d: xmit failed\n", sc->wi_unit);
+ device_printf(sc->dev, "xmit failed\n");
return(EIO);
}
@@ -1320,7 +1298,7 @@ static void wi_watchdog(ifp)
sc = ifp->if_softc;
- printf("wi%d: device timeout\n", sc->wi_unit);
+ device_printf(sc->dev,"device timeout\n");
wi_init(sc);
@@ -1329,14 +1307,264 @@ static void wi_watchdog(ifp)
return;
}
-static void wi_shutdown(arg, howto)
- void *arg;
- int howto;
+static int wi_alloc(dev)
+ device_t dev;
+{
+ struct wi_softc *sc = device_get_softc(dev);
+ int rid;
+
+ rid = 0;
+ sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->iobase) {
+ device_printf(dev, "No I/O space?!\n");
+ return (ENXIO);
+ }
+
+ rid = 0;
+ sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->irq) {
+ device_printf(dev, "No irq?!\n");
+ return (ENXIO);
+ }
+
+ sc->dev = dev;
+ sc->wi_unit = device_get_unit(dev);
+ sc->wi_io_addr = rman_get_start(sc->iobase);
+ sc->wi_btag = rman_get_bustag(sc->iobase);
+ sc->wi_bhandle = rman_get_bushandle(sc->iobase);
+
+ return (0);
+}
+
+static void wi_free(dev)
+ device_t dev;
+{
+ struct wi_softc *sc = device_get_softc(dev);
+
+ if (sc->iobase != NULL)
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
+ if (sc->irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+
+ return;
+}
+
+static void wi_shutdown(dev)
+ device_t dev;
{
struct wi_softc *sc;
- sc = arg;
+ sc = device_get_softc(dev);
wi_stop(sc);
return;
}
+
+#ifdef WICACHE
+/* wavelan signal strength cache code.
+ * store signal/noise/quality on per MAC src basis in
+ * a small fixed cache. The cache wraps if > MAX slots
+ * used. The cache may be zeroed out to start over.
+ * Two simple filters exist to reduce computation:
+ * 1. ip only (literally 0x800) which may be used
+ * to ignore some packets. It defaults to ip only.
+ * it could be used to focus on broadcast, non-IP 802.11 beacons.
+ * 2. multicast/broadcast only. This may be used to
+ * ignore unicast packets and only cache signal strength
+ * for multicast/broadcast packets (beacons); e.g., Mobile-IP
+ * beacons and not unicast traffic.
+ *
+ * The cache stores (MAC src(index), IP src (major clue), signal,
+ * quality, noise)
+ *
+ * No apologies for storing IP src here. It's easy and saves much
+ * trouble elsewhere. The cache is assumed to be INET dependent,
+ * although it need not be.
+ */
+
+#ifdef documentation
+
+int wi_sigitems; /* number of cached entries */
+struct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */
+int wi_nextitem; /* index/# of entries */
+
+
+#endif
+
+/* control variables for cache filtering. Basic idea is
+ * to reduce cost (e.g., to only Mobile-IP agent beacons
+ * which are broadcast or multicast). Still you might
+ * want to measure signal strength with unicast ping packets
+ * on a pt. to pt. ant. setup.
+ */
+/* set true if you want to limit cache items to broadcast/mcast
+ * only packets (not unicast). Useful for mobile-ip beacons which
+ * are broadcast/multicast at network layer. Default is all packets
+ * so ping/unicast will work say with pt. to pt. antennae setup.
+ */
+static int wi_cache_mcastonly = 0;
+SYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW,
+ &wi_cache_mcastonly, 0, "");
+
+/* set true if you want to limit cache items to IP packets only
+*/
+static int wi_cache_iponly = 1;
+SYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW,
+ &wi_cache_iponly, 0, "");
+
+/*
+ * Original comments:
+ * -----------------
+ * wi_cache_store, per rx packet store signal
+ * strength in MAC (src) indexed cache.
+ *
+ * follows linux driver in how signal strength is computed.
+ * In ad hoc mode, we use the rx_quality field.
+ * signal and noise are trimmed to fit in the range from 47..138.
+ * rx_quality field MSB is signal strength.
+ * rx_quality field LSB is noise.
+ * "quality" is (signal - noise) as is log value.
+ * note: quality CAN be negative.
+ *
+ * In BSS mode, we use the RID for communication quality.
+ * TBD: BSS mode is currently untested.
+ *
+ * Bill's comments:
+ * ---------------
+ * Actually, we use the rx_quality field all the time for both "ad-hoc"
+ * and BSS modes. Why? Because reading an RID is really, really expensive:
+ * there's a bunch of PIO operations that have to be done to read a record
+ * from the NIC, and reading the comms quality RID each time a packet is
+ * received can really hurt performance. We don't have to do this anyway:
+ * the comms quality field only reflects the values in the rx_quality field
+ * anyway. The comms quality RID is only meaningful in infrastructure mode,
+ * but the values it contains are updated based on the rx_quality from
+ * frames received from the access point.
+ *
+ * Also, according to Lucent, the signal strength and noise level values
+ * can be converted to dBms by subtracting 149, so I've modified the code
+ * to do that instead of the scaling it did originally.
+ */
+static
+void wi_cache_store (struct wi_softc *sc, struct ether_header *eh,
+ struct mbuf *m, unsigned short rx_quality)
+{
+ struct ip *ip = 0;
+ int i;
+ static int cache_slot = 0; /* use this cache entry */
+ static int wrapindex = 0; /* next "free" cache entry */
+ int sig, noise;
+ int sawip=0;
+
+ /* filters:
+ * 1. ip only
+ * 2. configurable filter to throw out unicast packets,
+ * keep multicast only.
+ */
+
+ if ((ntohs(eh->ether_type) == 0x800)) {
+ sawip = 1;
+ }
+
+ /* filter for ip packets only
+ */
+ if (wi_cache_iponly && !sawip) {
+ return;
+ }
+
+ /* filter for broadcast/multicast only
+ */
+ if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
+ return;
+ }
+
+#ifdef SIGDEBUG
+ printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit,
+ rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
+#endif
+
+ /* find the ip header. we want to store the ip_src
+ * address.
+ */
+ if (sawip) {
+ ip = mtod(m, struct ip *);
+ }
+
+ /* do a linear search for a matching MAC address
+ * in the cache table
+ * . MAC address is 6 bytes,
+ * . var w_nextitem holds total number of entries already cached
+ */
+ for(i = 0; i < sc->wi_nextitem; i++) {
+ if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) {
+ /* Match!,
+ * so we already have this entry,
+ * update the data
+ */
+ break;
+ }
+ }
+
+ /* did we find a matching mac address?
+ * if yes, then overwrite a previously existing cache entry
+ */
+ if (i < sc->wi_nextitem ) {
+ cache_slot = i;
+ }
+ /* else, have a new address entry,so
+ * add this new entry,
+ * if table full, then we need to replace LRU entry
+ */
+ else {
+
+ /* check for space in cache table
+ * note: wi_nextitem also holds number of entries
+ * added in the cache table
+ */
+ if ( sc->wi_nextitem < MAXWICACHE ) {
+ cache_slot = sc->wi_nextitem;
+ sc->wi_nextitem++;
+ sc->wi_sigitems = sc->wi_nextitem;
+ }
+ /* no space found, so simply wrap with wrap index
+ * and "zap" the next entry
+ */
+ else {
+ if (wrapindex == MAXWICACHE) {
+ wrapindex = 0;
+ }
+ cache_slot = wrapindex++;
+ }
+ }
+
+ /* invariant: cache_slot now points at some slot
+ * in cache.
+ */
+ if (cache_slot < 0 || cache_slot >= MAXWICACHE) {
+ log(LOG_ERR, "wi_cache_store, bad index: %d of "
+ "[0..%d], gross cache error\n",
+ cache_slot, MAXWICACHE);
+ return;
+ }
+
+ /* store items in cache
+ * .ip source address
+ * .mac src
+ * .signal, etc.
+ */
+ if (sawip) {
+ sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
+ }
+ bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6);
+
+ sig = (rx_quality >> 8) & 0xFF;
+ noise = rx_quality & 0xFF;
+ sc->wi_sigcache[cache_slot].signal = sig - 149;
+ sc->wi_sigcache[cache_slot].noise = noise - 149;
+ sc->wi_sigcache[cache_slot].quality = sig - noise;
+
+ return;
+}
+#endif
diff --git a/sys/dev/wi/if_wireg.h b/sys/dev/wi/if_wireg.h
index d417327..65cba4d 100644
--- a/sys/dev/wi/if_wireg.h
+++ b/sys/dev/wi/if_wireg.h
@@ -59,9 +59,14 @@ struct wi_counters {
struct wi_softc {
struct arpcom arpcom;
struct ifmedia ifmedia;
+ device_t dev;
int wi_unit;
+ struct resource * iobase;
+ struct resource * irq;
bus_space_handle_t wi_bhandle;
bus_space_tag_t wi_btag;
+ void * wi_intrhand;
+ int wi_io_addr;
int wi_tx_data_id;
int wi_tx_mgmt_id;
int wi_gone;
@@ -81,6 +86,11 @@ struct wi_softc {
char wi_ibss_name[32];
u_int8_t wi_txbuf[1536];
struct wi_counters wi_stats;
+#ifdef WICACHE
+ int wi_sigitems;
+ struct wi_sigcache wi_sigcache[MAXWICACHE];
+ int wi_nextitem;
+#endif
struct callout_handle wi_stat_ch;
};
@@ -99,8 +109,8 @@ struct wi_softc {
/* Default TX rate: 2Mbps, auto fallback */
#define WI_DEFAULT_TX_RATE 3
-/* Default network name: ANY */
-#define WI_DEFAULT_NETNAME "ANY"
+/* Default network name: empty string implies any */
+#define WI_DEFAULT_NETNAME ""
#define WI_DEFAULT_AP_DENSITY 1
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index 44cf11d..00ee4f4 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -1282,7 +1282,7 @@ device le0 at isa? port 0x300 irq 5 iomem 0xd0000
device lnc0 at isa? port 0x280 irq 10 drq 0
device rdp0 at isa? port 0x378 irq 7 flags 2
device sr0 at isa? port 0x300 irq 5 iomem 0xd0000
-device wi0 at isa? port? irq?
+device wi0
options WLCACHE # enables the signal-strength cache
options WLDEBUG # enables verbose debugging output
device wl0 at isa? port 0x300 irq ?
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 44cf11d..00ee4f4 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -1282,7 +1282,7 @@ device le0 at isa? port 0x300 irq 5 iomem 0xd0000
device lnc0 at isa? port 0x280 irq 10 drq 0
device rdp0 at isa? port 0x378 irq 7 flags 2
device sr0 at isa? port 0x300 irq 5 iomem 0xd0000
-device wi0 at isa? port? irq?
+device wi0
options WLCACHE # enables the signal-strength cache
options WLDEBUG # enables verbose debugging output
device wl0 at isa? port 0x300 irq ?
diff --git a/sys/i386/conf/PCCARD b/sys/i386/conf/PCCARD
index 3e416e6..52b5947 100644
--- a/sys/i386/conf/PCCARD
+++ b/sys/i386/conf/PCCARD
@@ -186,6 +186,10 @@ device ex0 at isa? port? irq?
# NOTE: This removes the isa attachment so that the pccard unit numbers
# come out right.
device ep0
+# WaveLAN/IEEE 802.1 wireless NICs. Note: the WaveLAN/IEEE really
+# exists only as a PCMCIA device, so there is no ISA attatement needed
+# and resources will always be dynamically assigned by the pccard code.
+device wi0
# The probe order of these is presently determined by i386/isa/isa_compat.c.
device ie0 at isa? port 0x300 irq 10 iomem 0xd0000
device fe0 at isa? port 0x300 irq ?
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
index b5fb112..b0ad19a 100644
--- a/sys/i386/conf/files.i386
+++ b/sys/i386/conf/files.i386
@@ -211,7 +211,7 @@ i386/isa/if_le.c optional le
i386/isa/if_lnc.c optional lnc
i386/isa/if_rdp.c optional rdp
i386/isa/if_sr.c optional sr
-i386/isa/if_wi.c optional wi
+i386/isa/if_wi.c optional wi card
i386/isa/if_wl.c optional wl
i386/isa/if_wlp.c optional wlp
i386/isa/if_ze.c optional ze
diff --git a/sys/i386/include/if_wavelan_ieee.h b/sys/i386/include/if_wavelan_ieee.h
index ef5f5ae..8ce57f9 100644
--- a/sys/i386/include/if_wavelan_ieee.h
+++ b/sys/i386/include/if_wavelan_ieee.h
@@ -72,6 +72,10 @@ struct wi_req {
*/
#define WI_RID_IFACE_STATS 0x0100
#define WI_RID_MGMT_XMIT 0x0200
+#ifdef WICACHE
+#define WI_RID_ZERO_CACHE 0x0300
+#define WI_RID_READ_CACHE 0x0400
+#endif
struct wi_80211_hdr {
u_int16_t frame_ctl;
@@ -120,6 +124,27 @@ struct wi_mgmt_hdr {
u_int16_t seq_ctl;
};
+/*
+ * Lucent/wavelan IEEE signal strength cache
+ *
+ * driver keeps cache of last
+ * MAXWICACHE packets to arrive including signal strength info.
+ * daemons may read this via ioctl
+ *
+ * Each entry in the wi_sigcache has a unique macsrc.
+ */
+#ifdef WICACHE
+#define MAXWICACHE 10
+
+struct wi_sigcache {
+ char macsrc[6]; /* unique MAC address for entry */
+ int ipsrc; /* ip address associated with packet */
+ int signal; /* signal strength of the packet */
+ int noise; /* noise value */
+ int quality; /* quality of the packet */
+};
+#endif
+
#ifndef KERNEL
struct wi_counters {
u_int32_t wi_tx_unicast_frames;
diff --git a/sys/i386/isa/if_wi.c b/sys/i386/isa/if_wi.c
index 53437a1..e5e8a01 100644
--- a/sys/i386/isa/if_wi.c
+++ b/sys/i386/isa/if_wi.c
@@ -66,20 +66,26 @@
#define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
#define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
-
-#include "card.h"
-#undef NCARD
-#define NCARD 0
-#include "wi.h"
+#define WICACHE /* turn on signal strength cache code */
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/eventhandler.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/clock.h>
+#include <machine/md_var.h>
+#include <machine/bus_pio.h>
+#include <sys/rman.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -88,53 +94,33 @@
#include <net/if_media.h>
#include <net/if_types.h>
-#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
-#endif
#include <net/bpf.h>
-#include <machine/clock.h>
-#include <machine/md_var.h>
-#include <machine/bus_pio.h>
-#include <machine/bus.h>
-
-#include <i386/isa/isa_device.h>
-#include <i386/isa/icu.h>
-#include <i386/isa/if_wireg.h>
#include <machine/if_wavelan_ieee.h>
-
-#if NCARD > 0
-#include <sys/select.h>
-#include <pccard/cardinfo.h>
-#include <pccard/slot.h>
-#endif
+#include <i386/isa/if_wireg.h>
#if !defined(lint)
static const char rcsid[] =
"$FreeBSD$";
#endif
-static struct wi_softc wi_softc[NWI];
-
#ifdef foo
static u_int8_t wi_mcast_addr[6] = { 0x01, 0x60, 0x1D, 0x00, 0x01, 0x00 };
#endif
-static int wi_probe __P((struct isa_device *));
-static int wi_attach __P((struct isa_device *));
-ointhand2_t wi_intr;
+static void wi_intr __P((void *));
static void wi_reset __P((struct wi_softc *));
static int wi_ioctl __P((struct ifnet *, u_long, caddr_t));
static void wi_init __P((void *));
static void wi_start __P((struct ifnet *));
static void wi_stop __P((struct wi_softc *));
static void wi_watchdog __P((struct ifnet *));
-static void wi_shutdown __P((void *, int));
static void wi_rxeof __P((struct wi_softc *));
static void wi_txeof __P((struct wi_softc *, int));
static void wi_update_stats __P((struct wi_softc *));
@@ -153,136 +139,118 @@ static void wi_inquire __P((void *));
static void wi_setdef __P((struct wi_softc *, struct wi_req *));
static int wi_mgmt_xmit __P((struct wi_softc *, caddr_t, int));
-struct isa_driver widriver = {
- wi_probe,
- wi_attach,
- "wi",
- 1
-};
+#ifdef WICACHE
+static
+void wi_cache_store __P((struct wi_softc *, struct ether_header *,
+ struct mbuf *, unsigned short));
+#endif
+
+static int wi_pccard_probe __P((device_t));
+static int wi_pccard_attach __P((device_t));
+static int wi_pccard_detach __P((device_t));
+static void wi_shutdown __P((device_t));
+
+static int wi_alloc __P((device_t));
+static void wi_free __P((device_t));
-#if NCARD > 0
-static int wi_pccard_init __P((struct pccard_devinfo *));
-static void wi_pccard_unload __P((struct pccard_devinfo *));
-static int wi_pccard_intr __P((struct pccard_devinfo *));
+static device_method_t wi_pccard_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, wi_pccard_probe),
+ DEVMETHOD(device_attach, wi_pccard_attach),
+ DEVMETHOD(device_detach, wi_pccard_detach),
+ DEVMETHOD(device_shutdown, wi_shutdown),
+
+ { 0, 0 }
+};
-#ifdef PCCARD_MODULE
-PCCARD_MODULE(wi, wi_pccard_init, wi_pccard_unload,
- wi_pccard_intr, 0, net_imask);
-#else
-static struct pccard_device wi_info = {
+static driver_t wi_pccard_driver = {
"wi",
- wi_pccard_init,
- wi_pccard_unload,
- wi_pccard_intr,
- 0, /* Attributes - presently unused */
- &net_imask /* Interrupt mask for device */
- /* XXX - Should this also include net_imask? */
+ wi_pccard_methods,
+ sizeof(struct wi_softc)
};
-DATA_SET(pccarddrv_set, wi_info);
-#endif
+static devclass_t wi_pccard_devclass;
-/* Initialize the PCCARD. */
-static int wi_pccard_init(sc_p)
- struct pccard_devinfo *sc_p;
-{
- struct wi_softc *sc;
- int i;
- u_int32_t irq;
+DRIVER_MODULE(if_wi, pccard, wi_pccard_driver, wi_pccard_devclass, 0, 0);
- if (sc_p->isahd.id_unit >= NWI)
- return(ENODEV);
+static int wi_pccard_probe(dev)
+ device_t dev;
+{
+ struct wi_softc *sc;
+ int error;
- sc = &wi_softc[sc_p->isahd.id_unit];
+ sc = device_get_softc(dev);
sc->wi_gone = 0;
- sc->wi_unit = sc_p->isahd.id_unit;
- sc->wi_bhandle = sc_p->isahd.id_iobase;
- sc->wi_btag = I386_BUS_SPACE_IO;
+
+ error = wi_alloc(dev);
+ if (error)
+ return (error);
+
+ device_set_desc(dev, "WaveLAN/IEEE 802.11");
+ wi_free(dev);
/* Make sure interrupts are disabled. */
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
- /* Grr. IRQ is encoded as a bitmask. */
- irq = sc_p->isahd.id_irq;
- for (i = 0; i < 32; i++) {
- if (irq & 0x1)
- break;
- irq >>= 1;
- }
-
- /*
- * Print a nice probe message to let the operator
- * know something interesting is happening.
- */
- printf("wi%d: <WaveLAN/IEEE 802.11> at 0x%x-0x%x irq %d on isa\n",
- sc_p->isahd.id_unit, sc_p->isahd.id_iobase,
- sc_p->isahd.id_iobase + WI_IOSIZ - 1, i);
-
- if (wi_attach(&sc_p->isahd))
- return(ENXIO);
-
- return(0);
+ return (0);
}
-static void wi_pccard_unload(sc_p)
- struct pccard_devinfo *sc_p;
+static int wi_pccard_detach(dev)
+ device_t dev;
{
struct wi_softc *sc;
struct ifnet *ifp;
+ int s;
+
+ s = splimp();
- sc = &wi_softc[sc_p->isahd.id_unit];
+ sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
if (sc->wi_gone) {
- printf("wi%d: already unloaded\n", sc_p->isahd.id_unit);
- return;
+ device_printf(dev, "already unloaded\n");
+ return(ENODEV);
}
- ifp->if_flags &= ~IFF_RUNNING;
- if_down(ifp);
+ wi_stop(sc);
+ if_detach(ifp);
+ bus_teardown_intr(dev, sc->irq, &sc->wi_intrhand);
+ wi_free(dev);
sc->wi_gone = 1;
- printf("wi%d: unloaded\n", sc_p->isahd.id_unit);
- return;
-}
-
-static int wi_pccard_intr(sc_p)
- struct pccard_devinfo *sc_p;
-{
- wi_intr(sc_p->isahd.id_unit);
- return(1);
-}
-#endif
+ splx(s);
+ device_printf(dev, "unload\n");
-static int wi_probe(isa_dev)
- struct isa_device *isa_dev;
-{
- /*
- * The ISA WaveLAN/IEEE card is actually not an ISA card:
- * it's a PCMCIA card plugged into a PCMCIA bridge adapter
- * that fits into an ISA slot. Consequently, we will always
- * be using the pccard support to probe and attach these
- * devices, so we can never actually probe one from here.
- */
return(0);
}
-static int wi_attach(isa_dev)
- struct isa_device *isa_dev;
+static int wi_pccard_attach(device_t dev)
{
struct wi_softc *sc;
struct wi_ltv_macaddr mac;
struct wi_ltv_gen gen;
struct ifnet *ifp;
- char ifname[IFNAMSIZ];
+ int error;
-#ifdef PCCARD_MODULE
- isa_dev->id_ointr = wi_intr;
-#endif
- sc = &wi_softc[isa_dev->id_unit];
+ sc = device_get_softc(dev);
ifp = &sc->arpcom.ac_if;
+ error = wi_alloc(dev);
+ if (error) {
+ device_printf(dev, "wi_alloc() failed! (%d)\n", error);
+ return (error);
+ }
+
+ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
+ wi_intr, sc, &sc->wi_intrhand);
+
+ if (error) {
+ device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
+ wi_free(dev);
+ return (error);
+ }
+
/* Reset the NIC. */
wi_reset(sc);
@@ -293,7 +261,7 @@ static int wi_attach(isa_dev)
bcopy((char *)&mac.wi_mac_addr,
(char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
- printf("wi%d: Ethernet address: %6D\n", sc->wi_unit,
+ device_printf(dev, "Ethernet address: %6D\n",
sc->arpcom.ac_enaddr, ":");
ifp->if_softc = sc;
@@ -348,24 +316,12 @@ static int wi_attach(isa_dev)
wi_stop(sc);
/*
- * If this logical interface has already been attached,
- * don't attach it again or chaos will ensue.
+ * Call MI attach routines.
*/
- sprintf(ifname, "wi%d", sc->wi_unit);
-
- if (ifunit(ifname) == NULL) {
- callout_handle_init(&sc->wi_stat_ch);
- /*
- * Call MI attach routines.
- */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
-
- EVENTHANDLER_REGISTER(shutdown_post_sync, wi_shutdown, sc,
- SHUTDOWN_PRI_DEFAULT);
- }
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ callout_handle_init(&sc->wi_stat_ch);
+ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
return(0);
}
@@ -413,8 +369,8 @@ static void wi_rxeof(sc)
rx_frame.wi_status == WI_STAT_TUNNEL ||
rx_frame.wi_status == WI_STAT_WMP_MSG) {
if((rx_frame.wi_dat_len + WI_SNAPHDR_LEN) > MCLBYTES) {
- printf("wi%d: oversized packet received "
- "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
+ device_printf(sc->dev, "oversized packet received "
+ "(wi_dat_len=%d, wi_status=0x%x)\n",
rx_frame.wi_dat_len, rx_frame.wi_status);
m_freem(m);
ifp->if_ierrors++;
@@ -440,8 +396,8 @@ static void wi_rxeof(sc)
} else {
if((rx_frame.wi_dat_len +
sizeof(struct ether_header)) > MCLBYTES) {
- printf("wi%d: oversized packet received "
- "(wi_dat_len=%d, wi_status=0x%x)\n", sc->wi_unit,
+ device_printf(sc->dev, "oversized packet received "
+ "(wi_dat_len=%d, wi_status=0x%x)\n",
rx_frame.wi_dat_len, rx_frame.wi_status);
m_freem(m);
ifp->if_ierrors++;
@@ -473,6 +429,9 @@ static void wi_rxeof(sc)
/* Receive packet. */
m_adj(m, sizeof(struct ether_header));
+#ifdef WICACHE
+ wi_cache_store(sc, eh, m, rx_frame.wi_q_info);
+#endif
ether_input(ifp, eh, m);
return;
@@ -555,14 +514,13 @@ void wi_update_stats(sc)
return;
}
-void wi_intr(unit)
- int unit;
+static void wi_intr(xsc)
+ void *xsc;
{
- struct wi_softc *sc;
+ struct wi_softc *sc = xsc;
struct ifnet *ifp;
u_int16_t status;
- sc = &wi_softc[unit];
ifp = &sc->arpcom.ac_if;
if (!(ifp->if_flags & IFF_UP)) {
@@ -657,14 +615,19 @@ static int wi_cmd(sc, cmd, val)
static void wi_reset(sc)
struct wi_softc *sc;
{
+ wi_cmd(sc, WI_CMD_INI, 0);
+ DELAY(100000);
+ wi_cmd(sc, WI_CMD_INI, 0);
+ DELAY(100000);
+#ifdef foo
if (wi_cmd(sc, WI_CMD_INI, 0))
- printf("wi%d: init failed\n", sc->wi_unit);
+ device_printf(sc->dev, "init failed\n");
CSR_WRITE_2(sc, WI_INT_EN, 0);
CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
/* Calibrate timer. */
WI_SETVAL(WI_RID_TICK_TIME, 8);
-
+#endif
return;
}
@@ -752,7 +715,7 @@ static int wi_seek(sc, id, off, chan)
offreg = WI_OFF1;
break;
default:
- printf("wi%d: invalid data path: %x\n", sc->wi_unit, chan);
+ device_printf(sc->dev, "invalid data path: %x\n", chan);
return(EIO);
}
@@ -848,8 +811,7 @@ static int wi_alloc_nicmem(sc, len, id)
int i;
if (wi_cmd(sc, WI_CMD_ALLOC_MEM, len)) {
- printf("wi%d: failed to allocate %d bytes on NIC\n",
- sc->wi_unit, len);
+ device_printf(sc->dev, "failed to allocate %d bytes on NIC\n", len);
return(ENOMEM);
}
@@ -1037,7 +999,23 @@ static int wi_ioctl(ifp, command, data)
bcopy((char *)&sc->wi_stats, (char *)&wreq.wi_val,
sizeof(sc->wi_stats));
wreq.wi_len = (sizeof(sc->wi_stats) / 2) + 1;
- } else {
+ }
+#ifdef WICACHE
+ else if (wreq.wi_type == WI_RID_ZERO_CACHE) {
+ sc->wi_sigitems = sc->wi_nextitem = 0;
+ } else if (wreq.wi_type == WI_RID_READ_CACHE) {
+ char *pt = (char *)&wreq.wi_val;
+ bcopy((char *)&sc->wi_sigitems,
+ (char *)pt, sizeof(int));
+ pt += (sizeof (int));
+ wreq.wi_len = sizeof(int) / 2;
+ bcopy((char *)&sc->wi_sigcache, (char *)pt,
+ sizeof(struct wi_sigcache) * sc->wi_sigitems);
+ wreq.wi_len += ((sizeof(struct wi_sigcache) *
+ sc->wi_sigitems) / 2) + 1;
+ }
+#endif
+ else {
if (wi_read_record(sc, (struct wi_ltv_gen *)&wreq)) {
error = EINVAL;
break;
@@ -1147,11 +1125,11 @@ static void wi_init(xsc)
wi_cmd(sc, WI_CMD_ENABLE|sc->wi_portnum, 0);
if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
- printf("wi%d: tx buffer allocation failed\n", sc->wi_unit);
+ device_printf(sc->dev, "tx buffer allocation failed\n");
sc->wi_tx_data_id = id;
if (wi_alloc_nicmem(sc, 1518 + sizeof(struct wi_frame) + 8, &id))
- printf("wi%d: mgmt. buffer allocation failed\n", sc->wi_unit);
+ device_printf(sc->dev, "mgmt. buffer allocation failed\n");
sc->wi_tx_mgmt_id = id;
/* enable interrupts */
@@ -1244,7 +1222,7 @@ static void wi_start(ifp)
m_freem(m0);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id))
- printf("wi%d: xmit failed\n", sc->wi_unit);
+ device_printf(sc->dev, "xmit failed\n");
ifp->if_flags |= IFF_OACTIVE;
@@ -1286,7 +1264,7 @@ static int wi_mgmt_xmit(sc, data, len)
(len - sizeof(struct wi_80211_hdr)) + 2);
if (wi_cmd(sc, WI_CMD_TX|WI_RECLAIM, id)) {
- printf("wi%d: xmit failed\n", sc->wi_unit);
+ device_printf(sc->dev, "xmit failed\n");
return(EIO);
}
@@ -1320,7 +1298,7 @@ static void wi_watchdog(ifp)
sc = ifp->if_softc;
- printf("wi%d: device timeout\n", sc->wi_unit);
+ device_printf(sc->dev,"device timeout\n");
wi_init(sc);
@@ -1329,14 +1307,264 @@ static void wi_watchdog(ifp)
return;
}
-static void wi_shutdown(arg, howto)
- void *arg;
- int howto;
+static int wi_alloc(dev)
+ device_t dev;
+{
+ struct wi_softc *sc = device_get_softc(dev);
+ int rid;
+
+ rid = 0;
+ sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->iobase) {
+ device_printf(dev, "No I/O space?!\n");
+ return (ENXIO);
+ }
+
+ rid = 0;
+ sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->irq) {
+ device_printf(dev, "No irq?!\n");
+ return (ENXIO);
+ }
+
+ sc->dev = dev;
+ sc->wi_unit = device_get_unit(dev);
+ sc->wi_io_addr = rman_get_start(sc->iobase);
+ sc->wi_btag = rman_get_bustag(sc->iobase);
+ sc->wi_bhandle = rman_get_bushandle(sc->iobase);
+
+ return (0);
+}
+
+static void wi_free(dev)
+ device_t dev;
+{
+ struct wi_softc *sc = device_get_softc(dev);
+
+ if (sc->iobase != NULL)
+ bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
+ if (sc->irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
+
+ return;
+}
+
+static void wi_shutdown(dev)
+ device_t dev;
{
struct wi_softc *sc;
- sc = arg;
+ sc = device_get_softc(dev);
wi_stop(sc);
return;
}
+
+#ifdef WICACHE
+/* wavelan signal strength cache code.
+ * store signal/noise/quality on per MAC src basis in
+ * a small fixed cache. The cache wraps if > MAX slots
+ * used. The cache may be zeroed out to start over.
+ * Two simple filters exist to reduce computation:
+ * 1. ip only (literally 0x800) which may be used
+ * to ignore some packets. It defaults to ip only.
+ * it could be used to focus on broadcast, non-IP 802.11 beacons.
+ * 2. multicast/broadcast only. This may be used to
+ * ignore unicast packets and only cache signal strength
+ * for multicast/broadcast packets (beacons); e.g., Mobile-IP
+ * beacons and not unicast traffic.
+ *
+ * The cache stores (MAC src(index), IP src (major clue), signal,
+ * quality, noise)
+ *
+ * No apologies for storing IP src here. It's easy and saves much
+ * trouble elsewhere. The cache is assumed to be INET dependent,
+ * although it need not be.
+ */
+
+#ifdef documentation
+
+int wi_sigitems; /* number of cached entries */
+struct wi_sigcache wi_sigcache[MAXWICACHE]; /* array of cache entries */
+int wi_nextitem; /* index/# of entries */
+
+
+#endif
+
+/* control variables for cache filtering. Basic idea is
+ * to reduce cost (e.g., to only Mobile-IP agent beacons
+ * which are broadcast or multicast). Still you might
+ * want to measure signal strength with unicast ping packets
+ * on a pt. to pt. ant. setup.
+ */
+/* set true if you want to limit cache items to broadcast/mcast
+ * only packets (not unicast). Useful for mobile-ip beacons which
+ * are broadcast/multicast at network layer. Default is all packets
+ * so ping/unicast will work say with pt. to pt. antennae setup.
+ */
+static int wi_cache_mcastonly = 0;
+SYSCTL_INT(_machdep, OID_AUTO, wi_cache_mcastonly, CTLFLAG_RW,
+ &wi_cache_mcastonly, 0, "");
+
+/* set true if you want to limit cache items to IP packets only
+*/
+static int wi_cache_iponly = 1;
+SYSCTL_INT(_machdep, OID_AUTO, wi_cache_iponly, CTLFLAG_RW,
+ &wi_cache_iponly, 0, "");
+
+/*
+ * Original comments:
+ * -----------------
+ * wi_cache_store, per rx packet store signal
+ * strength in MAC (src) indexed cache.
+ *
+ * follows linux driver in how signal strength is computed.
+ * In ad hoc mode, we use the rx_quality field.
+ * signal and noise are trimmed to fit in the range from 47..138.
+ * rx_quality field MSB is signal strength.
+ * rx_quality field LSB is noise.
+ * "quality" is (signal - noise) as is log value.
+ * note: quality CAN be negative.
+ *
+ * In BSS mode, we use the RID for communication quality.
+ * TBD: BSS mode is currently untested.
+ *
+ * Bill's comments:
+ * ---------------
+ * Actually, we use the rx_quality field all the time for both "ad-hoc"
+ * and BSS modes. Why? Because reading an RID is really, really expensive:
+ * there's a bunch of PIO operations that have to be done to read a record
+ * from the NIC, and reading the comms quality RID each time a packet is
+ * received can really hurt performance. We don't have to do this anyway:
+ * the comms quality field only reflects the values in the rx_quality field
+ * anyway. The comms quality RID is only meaningful in infrastructure mode,
+ * but the values it contains are updated based on the rx_quality from
+ * frames received from the access point.
+ *
+ * Also, according to Lucent, the signal strength and noise level values
+ * can be converted to dBms by subtracting 149, so I've modified the code
+ * to do that instead of the scaling it did originally.
+ */
+static
+void wi_cache_store (struct wi_softc *sc, struct ether_header *eh,
+ struct mbuf *m, unsigned short rx_quality)
+{
+ struct ip *ip = 0;
+ int i;
+ static int cache_slot = 0; /* use this cache entry */
+ static int wrapindex = 0; /* next "free" cache entry */
+ int sig, noise;
+ int sawip=0;
+
+ /* filters:
+ * 1. ip only
+ * 2. configurable filter to throw out unicast packets,
+ * keep multicast only.
+ */
+
+ if ((ntohs(eh->ether_type) == 0x800)) {
+ sawip = 1;
+ }
+
+ /* filter for ip packets only
+ */
+ if (wi_cache_iponly && !sawip) {
+ return;
+ }
+
+ /* filter for broadcast/multicast only
+ */
+ if (wi_cache_mcastonly && ((eh->ether_dhost[0] & 1) == 0)) {
+ return;
+ }
+
+#ifdef SIGDEBUG
+ printf("wi%d: q value %x (MSB=0x%x, LSB=0x%x) \n", sc->wi_unit,
+ rx_quality & 0xffff, rx_quality >> 8, rx_quality & 0xff);
+#endif
+
+ /* find the ip header. we want to store the ip_src
+ * address.
+ */
+ if (sawip) {
+ ip = mtod(m, struct ip *);
+ }
+
+ /* do a linear search for a matching MAC address
+ * in the cache table
+ * . MAC address is 6 bytes,
+ * . var w_nextitem holds total number of entries already cached
+ */
+ for(i = 0; i < sc->wi_nextitem; i++) {
+ if (! bcmp(eh->ether_shost , sc->wi_sigcache[i].macsrc, 6 )) {
+ /* Match!,
+ * so we already have this entry,
+ * update the data
+ */
+ break;
+ }
+ }
+
+ /* did we find a matching mac address?
+ * if yes, then overwrite a previously existing cache entry
+ */
+ if (i < sc->wi_nextitem ) {
+ cache_slot = i;
+ }
+ /* else, have a new address entry,so
+ * add this new entry,
+ * if table full, then we need to replace LRU entry
+ */
+ else {
+
+ /* check for space in cache table
+ * note: wi_nextitem also holds number of entries
+ * added in the cache table
+ */
+ if ( sc->wi_nextitem < MAXWICACHE ) {
+ cache_slot = sc->wi_nextitem;
+ sc->wi_nextitem++;
+ sc->wi_sigitems = sc->wi_nextitem;
+ }
+ /* no space found, so simply wrap with wrap index
+ * and "zap" the next entry
+ */
+ else {
+ if (wrapindex == MAXWICACHE) {
+ wrapindex = 0;
+ }
+ cache_slot = wrapindex++;
+ }
+ }
+
+ /* invariant: cache_slot now points at some slot
+ * in cache.
+ */
+ if (cache_slot < 0 || cache_slot >= MAXWICACHE) {
+ log(LOG_ERR, "wi_cache_store, bad index: %d of "
+ "[0..%d], gross cache error\n",
+ cache_slot, MAXWICACHE);
+ return;
+ }
+
+ /* store items in cache
+ * .ip source address
+ * .mac src
+ * .signal, etc.
+ */
+ if (sawip) {
+ sc->wi_sigcache[cache_slot].ipsrc = ip->ip_src.s_addr;
+ }
+ bcopy( eh->ether_shost, sc->wi_sigcache[cache_slot].macsrc, 6);
+
+ sig = (rx_quality >> 8) & 0xFF;
+ noise = rx_quality & 0xFF;
+ sc->wi_sigcache[cache_slot].signal = sig - 149;
+ sc->wi_sigcache[cache_slot].noise = noise - 149;
+ sc->wi_sigcache[cache_slot].quality = sig - noise;
+
+ return;
+}
+#endif
diff --git a/sys/i386/isa/if_wireg.h b/sys/i386/isa/if_wireg.h
index d417327..65cba4d 100644
--- a/sys/i386/isa/if_wireg.h
+++ b/sys/i386/isa/if_wireg.h
@@ -59,9 +59,14 @@ struct wi_counters {
struct wi_softc {
struct arpcom arpcom;
struct ifmedia ifmedia;
+ device_t dev;
int wi_unit;
+ struct resource * iobase;
+ struct resource * irq;
bus_space_handle_t wi_bhandle;
bus_space_tag_t wi_btag;
+ void * wi_intrhand;
+ int wi_io_addr;
int wi_tx_data_id;
int wi_tx_mgmt_id;
int wi_gone;
@@ -81,6 +86,11 @@ struct wi_softc {
char wi_ibss_name[32];
u_int8_t wi_txbuf[1536];
struct wi_counters wi_stats;
+#ifdef WICACHE
+ int wi_sigitems;
+ struct wi_sigcache wi_sigcache[MAXWICACHE];
+ int wi_nextitem;
+#endif
struct callout_handle wi_stat_ch;
};
@@ -99,8 +109,8 @@ struct wi_softc {
/* Default TX rate: 2Mbps, auto fallback */
#define WI_DEFAULT_TX_RATE 3
-/* Default network name: ANY */
-#define WI_DEFAULT_NETNAME "ANY"
+/* Default network name: empty string implies any */
+#define WI_DEFAULT_NETNAME ""
#define WI_DEFAULT_AP_DENSITY 1
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 2f14760..bc97db6 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -11,7 +11,7 @@ SUBDIR+=usb ugen uhid ukbd ulpt ums umodem umass
# XXX some of these can move to the general case when de-i386'ed
.if ${MACHINE_ARCH} == "i386"
SUBDIR+=amr bktr coff fpu gnufpu ibcs2 linux mlx ncp nwfs splash streams \
- svr4 syscons vesa vinum
+ svr4 syscons vesa vinum wi
.endif
.include <bsd.subdir.mk>
diff --git a/sys/modules/wi/Makefile b/sys/modules/wi/Makefile
new file mode 100644
index 0000000..dc7b3cb
--- /dev/null
+++ b/sys/modules/wi/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+S = ${.CURDIR}/../..
+.PATH: $S/i386/isa
+KMOD = if_wi
+SRCS = if_wi.c device_if.h bus_if.h
+CLEANFILES += device_if.h bus_if.h
+CFLAGS += ${DEBUG_FLAGS}
+
+device_if.h: $S/kern/makedevops.pl $S/kern/device_if.m
+ perl $S/kern/makedevops.pl -h $S/kern/device_if.m
+
+bus_if.h: $S/kern/makedevops.pl $S/kern/bus_if.m
+ perl $S/kern/makedevops.pl -h $S/kern/bus_if.m
+
+.include <bsd.kmod.mk>
diff --git a/usr.sbin/wicontrol/Makefile b/usr.sbin/wicontrol/Makefile
index 47ea6f8..f68ae34 100644
--- a/usr.sbin/wicontrol/Makefile
+++ b/usr.sbin/wicontrol/Makefile
@@ -2,7 +2,7 @@
PROG= wicontrol
SRCS= wicontrol.c
-CFLAGS+= -Wall
+CFLAGS+= -Wall -DWICACHE
MAN8= wicontrol.8
diff --git a/usr.sbin/wicontrol/wicontrol.8 b/usr.sbin/wicontrol/wicontrol.8
index ad7d03c..c0b363e 100644
--- a/usr.sbin/wicontrol/wicontrol.8
+++ b/usr.sbin/wicontrol/wicontrol.8
@@ -65,6 +65,10 @@
.Fl i Ar iface Fl P Ar 0|1
.Nm wicontrol
.Fl i Ar iface Fl S Ar max_sleep_duration
+.Nm wicontrol
+.Fl i Ar iface Fl Z (zero signal cache)
+.Nm wicontrol
+.Fl i Ar iface Fl C (display signal cache)
.Sh DESCRIPTION
The
.Nm
@@ -238,6 +242,19 @@ Specify the sleep interval to use when power management is enabled.
The
.Are max sleep interval
is specified in milliseconds. The default is 100.
+.It Fl i Ar iface Fl Z
+Clear the signal strength cache maintained internally by the
+.Nm wi
+driver.
+.It Fl i Ar iface Fl C
+Display the cached signal strength information maintained by the
+.Nm wi
+driver. The driver retains information about signal strength and
+noise level for packets received from different hosts. The signal
+strength and noise level values are displayed in units of dBms.
+The signal quality values is produced by subtracting the noise level
+from the signal strength (i.e. less noise and better signal yields
+better signal quality).
.El
.Sh SEE ALSO
.Xr wi 4 ,
diff --git a/usr.sbin/wicontrol/wicontrol.c b/usr.sbin/wicontrol/wicontrol.c
index bdb9e20..ef62368 100644
--- a/usr.sbin/wicontrol/wicontrol.c
+++ b/usr.sbin/wicontrol/wicontrol.c
@@ -431,10 +431,77 @@ static void usage(p)
fprintf(stderr, "\t%s -i iface -f frequency\n", p);
fprintf(stderr, "\t%s -i iface -P 0|1t\n", p);
fprintf(stderr, "\t%s -i iface -S max sleep duration\n", p);
+#ifdef WICACHE
+ fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
+ fprintf(stderr, "\t%s -i iface -C print signal cache\n", p);
+#endif
exit(1);
}
+#ifdef WICACHE
+static void wi_zerocache(iface)
+ char *iface;
+{
+ struct wi_req wreq;
+
+ if (iface == NULL)
+ errx(1, "must specify interface name");
+
+ bzero((char *)&wreq, sizeof(wreq));
+ wreq.wi_len = 0;
+ wreq.wi_type = WI_RID_ZERO_CACHE;
+
+ wi_getval(iface, &wreq);
+}
+
+static void wi_readcache(iface)
+ char *iface;
+{
+ struct wi_req wreq;
+ int *wi_sigitems;
+ struct wi_sigcache *sc;
+ char * pt;
+ int i;
+
+ if (iface == NULL)
+ errx(1, "must specify interface name");
+
+ bzero((char *)&wreq, sizeof(wreq));
+ wreq.wi_len = WI_MAX_DATALEN;
+ wreq.wi_type = WI_RID_READ_CACHE;
+
+ wi_getval(iface, &wreq);
+
+ wi_sigitems = (int *) &wreq.wi_val;
+ pt = ((char *) &wreq.wi_val);
+ pt += sizeof(int);
+ sc = (struct wi_sigcache *) pt;
+
+ for (i = 0; i < *wi_sigitems; i++) {
+ printf("[%d/%d]:", i+1, *wi_sigitems);
+ printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
+ sc->macsrc[0]&0xff,
+ sc->macsrc[1]&0xff,
+ sc->macsrc[2]&0xff,
+ sc->macsrc[3]&0xff,
+ sc->macsrc[4]&0xff,
+ sc->macsrc[5]&0xff);
+ printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
+ ((sc->ipsrc >> 8) & 0xff),
+ ((sc->ipsrc >> 16) & 0xff),
+ ((sc->ipsrc >> 24) & 0xff));
+ printf(" sig: %d, noise: %d, qual: %d\n",
+ sc->signal,
+ sc->noise,
+ sc->quality);
+ sc++;
+ }
+
+ return;
+}
+#endif
+
int main(argc, argv)
int argc;
char *argv[];
@@ -444,8 +511,24 @@ int main(argc, argv)
char *p = argv[0];
while((ch = getopt(argc, argv,
- "hoc:d:f:i:p:r:q:t:n:s:m:P:S:")) != -1) {
+ "hoc:d:f:i:p:r:q:t:n:s:m:P:S:ZC")) != -1) {
switch(ch) {
+ case 'Z':
+#ifdef WICACHE
+ wi_zerocache(iface);
+ exit(0);
+#else
+ printf("WICACHE not available\n");
+#endif
+ break;
+ case 'C':
+#ifdef WICACHE
+ wi_readcache(iface);
+#else
+ printf("WICACHE not available\n");
+#endif
+ exit(0);
+ break;
case 'o':
wi_dumpstats(iface);
exit(0);
@@ -515,3 +598,6 @@ int main(argc, argv)
exit(0);
}
+
+
+
OpenPOWER on IntegriCloud