📄 if_wlp.c
字号:
/* * Copyright (c) 1997 Carnegie Mellon University. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted (including for commercial or for-profit * use), provided that both the copyright notice and this permission notice * appear in all copies of the software, derivative works, or modified * versions, and any portions thereof, and that both notices appear in * supporting documentation, and that credit is given to Carnegie Mellon * University in all publications reporting on direct or indirect use of this * code or its derivatives. * * THIS IMPLEMENTATION IS EXPERIMENTAL AND MAY HAVE BUGS, SOME OF WHICH MAY HAVE * SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS SOFTWARE IN ITS "AS * IS" CONDITION, 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 CARNEGIE MELLON * UNIVERSITY 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. * * Carnegie Mellon encourages (but does not require) users of this software to * return any improvements or extensions that they make, and to grant * Carnegie Mellon the rights to redistribute these changes without * encumbrance. * * */#include "card.h"#include "wlp.h"#include "bpfilter.h" /* /sys/compile/<___>/bpfilter.h */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/errno.h>#include <sys/ioctl.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/syslog.h>#include <sys/time.h>#include <net/if.h>#include <net/if_dl.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#ifdef INET6#include <netinet/if_ether6.h>#include <netinet/if_ndp6.h>#endif#ifdef MONARCH_ADHOC#include <dsr/dsr_ifqueue.h>#endif#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#include <machine/clock.h>#include <i386/isa/isa_device.h>struct wlp_softc wlp_softc[NWLP];#include <i386/isa/ic/i82593.h> /* Intel 82593 Definitions */#include <i386/isa/if_wlp_ir.h> /* IBM Infrared Definitions */#include <i386/isa/if_wlp_wavelan.h> /* Lucent WaveLAN Definitions */#include <i386/isa/if_wlp.h> /* Shared code */#ifdef WAVELAN_ROAMING#include <i386/isa/if_wlp_wavelan_roam.h>#endif/* * ====================================================================== * Common Routines * ====================================================================== */int wlp_isa_probe(struct isa_device *);int wlp_isa_attach(struct isa_device *);int wlpattach(struct isa_device *);static void wlpstart(struct ifnet *);int wlpioctl(struct ifnet * ifp, int cmd, caddr_t data);static void wlpread(struct wlp_softc *, u_int32_t, u_int32_t, u_int32_t);static void wlpstop(struct wlp_softc *);void wlpwatchdog(struct ifnet *);#if 0static void wlpdump(struct wlp_softc *);#endifstatic void get_ifstats(struct wlp_softc *, struct ifreq *);static void dump_bytes(caddr_t, u_int32_t);struct isa_driver wlpdriver = {wlp_isa_probe, wlp_isa_attach, "wlp", 0};/* * ====================================================================== * Intel 82593 Specific Routines * ====================================================================== */static voidi82593_default_config(struct i82593_conf *cfg);static voidi82593_default_config(struct i82593_conf *cfg){ cfg->byte_count_low = sizeof(cfg->data.cfgblock); cfg->byte_count_high = 0; cfg->data.bytes[0] = 0x2A; cfg->data.bytes[1] = 0x00; cfg->data.bytes[2] = 0x26; cfg->data.bytes[3] = 0x00; cfg->data.bytes[4] = 0x60; cfg->data.bytes[5] = 0x00; cfg->data.bytes[6] = 0xF2; cfg->data.bytes[7] = 0x00; cfg->data.bytes[8] = 0x00; cfg->data.bytes[9] = 0x40; cfg->data.bytes[10] = 0xFF; cfg->data.bytes[11] = 0x00; cfg->data.bytes[12] = 0x3F; cfg->data.bytes[13] = 0x07; cfg->data.bytes[14] = 0x00; cfg->data.bytes[15] = 0x00;}intProbeIntel82593(struct isa_device * is, int iftype){ struct wlp_softc *sc = &wlp_softc[is->id_unit]; struct i82593_conf cfg; u_int8_t status;#ifdef WLP_DEBUG printf("ProbeIntel82593() resetting chip...\n");#endif /* * Reset the 82593. */ IOWrite1(0x00, P0_RESET); DELAY(1000);#if 0 status = IORead1(0x00); if (status != 0x10) { printf("wlp%d: could not reset the 82593 (status = %x)\n", is->id_unit, status); goto bad; }#endif /* * Configure the 82593 with default values */ i82593_default_config(&cfg); if (iftype == IFTYPE_REDWING) { RW_ResetTXDMA(); MEMWrite((caddr_t) &cfg, RW_RXWINDOW, sizeof(cfg)); } else if (iftype == IFTYPE_WAVELAN) { WLP_ResetTXDMA(); WLP_PointTXBUF(WLP_TXBASE); IOWrite(0x04, (caddr_t) &cfg, sizeof(cfg)); }#ifdef WLP_DEBUG printf("ProbeIntel82593() configuring chip...\n");#endif IOWrite1(0x00, P0_CONFIGURE); status = I82593_wait(sc, P0_CONFIGURE); if (status != (P0_CONFIGURE | P0_S0_INT | P0_S0_EXEC)) { printf("wlp%d: Configure of the Intel 82593 failed (status = %x)\n", is->id_unit, status); goto bad; }#ifdef WLP_DEBUG else { IOWrite1(0x00, P0_NOP | P0_STATUS1); printf("wlp%d: Intel 82593 configured successfully, Chip Signature: %x\n", is->id_unit, IORead1(0x00)); }#endif /* * Perform self-diagnostics on the 82593 */#ifdef WLP_DEBUG printf("ProbeIntel82593() performing diagnostics...\n");#endif IOWrite1(0x00, P0_DIAGNOSE); DELAY(10000); status = I82593_wait(sc, DIAGNOSE_PASSED); if (status != (DIAGNOSE_PASSED | P0_S0_INT | P0_S0_EXEC)) { printf("wlp%d: self diagnostics failed (status = %x)\n", is->id_unit, status); goto bad; }#ifdef WLP_DEBUG else { printf("wlp%d: self diagnostics passed\n", is->id_unit); }#endif return 0;bad: return ENODEV;}u_int8_tI82593_wait(sc, cmd) struct wlp_softc *sc; u_int8_t cmd;{ u_int32_t count = 0; u_int8_t status = cmd | P0_S0_INT | P0_S0_EXEC; u_int8_t val = 0;#ifdef WLP_DEBUG printf("I82593_wait() ENTRY\n");#endif DELAY(200); while ((val != status) && (count++ < 100)) { IOWrite1(0x00, P0_NOP); /* resets register pointer */ DELAY(100); val = IORead1(0x00); if (val & P0_S0_INT) {#ifdef WLP_DEBUG printf("%s(): got %x from the Intel 82593\n", __FUNCTION__, val);#endif IOWrite1(0x00, P0_INT_ACK); } DELAY(1000); }#ifdef WLP_DEBUG printf("I82593_wait() EXIT\n");#endif return val;}/* * ====================================================================== * PCMCIA SPECIFIC CODE * ====================================================================== */#if NCARD > 0/* * PC-Card (PCMCIA) specific code. */static int card_intr(struct pccard_devinfo *); /* Interrupt handler */static void wlpunload(struct pccard_devinfo *); /* Disable driver */static int wlpcrdinit(struct pccard_devinfo *); /* init device */struct pccard_device wlppccdrv = { "wlp", wlpcrdinit, /* Initialization */ wlpunload, /* Disable */ card_intr, /* Interrupt Handler */ 0, /* Attributes - presently unused */ &net_imask /* Interrupt mask for device */};DATA_SET(pccarddrv_set, wlppccdrv);static intcard_intr(struct pccard_devinfo * dp){#ifdef WLP_DEBUG printf("wlp%d: ENTRY card_intr()\n", dp->isahd.id_unit);#endif wlpintr(dp->isahd.id_unit);#ifdef WLP_DEBUG printf("wlp%d: EXIT card_intr()\n", dp->isahd.id_unit);#endif return 1;}static voidwlpunload(struct pccard_devinfo * dp){ struct isa_device *is = &dp->isahd; struct wlp_softc *sc = &wlp_softc[is->id_unit]; struct ifnet *ifp = &sc->sc_ac.ac_if; if (sc->sc_gone) { printf("wlp%d: already unloaded\n", is->id_unit); return; } ifp->if_flags &= ~IFF_RUNNING; if_down(ifp); sc->sc_gone = 1;#ifdef WAVELAN_ROAMING if (sc->sc_iftype == IFTYPE_WAVELAN) { RoamOnOff(sc, ROAM_OFF); }#endif printf("wlp%d: unload\n", is->id_unit);}/* ====================================================================== The "pccard_devinfo" structure contains the following fields: struct pccard_device *drv; struct isa_device isahd; int running; u_char misc[128]; struct slot *slt; struct pccard_devinfo *next;====================================================================== */#ifdef WLP_DEBUGstatic void dump_pccard_devinfo(struct pccard_devinfo*);static void dump_isa_device(struct isa_device*);static void dump_slot(struct slot*);static voiddump_pccard_devinfo(dp) struct pccard_devinfo *dp;{ printf("PCCARD_DEVINFO dp: %08x\n", dp); printf("\tdrv: %08x\n", dp->drv); printf("\trunning: %8x\n", dp->running); dump_isa_device(&dp->isahd); dump_slot(dp->slt); printf("--------------------------------------------------\n");}static voiddump_isa_device(is) struct isa_device *is;{ printf("ISA_DEVICE is: %08x\n", is); printf("\tid_id: %8x\n", is->id_id); printf("\tid_driver: %08x\n", is->id_driver); printf("\tid_iobase: %8x\n", is->id_iobase); printf("\tid_irq: %8x\n", is->id_irq); printf("\tid_drq: %8x\n", is->id_drq); printf("\tid_maddr: %08x\n", is->id_maddr); printf("\tid_msize: %8x\n", is->id_msize); printf("\tid_intr: %08x\n", is->id_intr); printf("\tid_unit: %8x\n", is->id_unit); printf("\tid_flags: %8x\n", is->id_flags); printf("\tid_scsiid: %8x\n", is->id_scsiid); printf("\tid_alive: %8x\n", is->id_alive); printf("\tid_ri_flags: %8x\n", is->id_ri_flags); printf("\tid_reconfig: %8x\n", is->id_reconfig); printf("\tid_enabled: %8x\n", is->id_enabled); printf("\tid_conflicts: %8x\n", is->id_conflicts); printf("\tid_next: %08x\n", is->id_next);}static voiddump_slot(slt) struct slot *slt;{ printf("SLOT slt: %08x\n", slt); printf("\tslotnum: %8x\n", slt->slotnum); printf("\tflags: %8x\n", slt->flags); printf("\trwmem: %8x\n", slt->rwmem); printf("\tirq: %8x\n", slt->irq); printf("\tirqref: %8x\n", slt->irqref); printf("\tdevices: %08x\n", slt->devices); printf("\tinsert_seq: %8x\n", slt->insert_seq); // state // laststate // selp // mem // io // pwr printf("\tctrl: %08x\n", slt->ctrl); printf("\tcdata: %08x\n", slt->cdata); printf("\tpwr_off_pending: %8x\n", slt->pwr_off_pending); // printf("\tdevfs_token: %08x\n", slt->devfs_token); printf("\tnext: %08x\n", slt->next);}#endif /* WLP_DEBUG *//* ====================================================================== */static intwlpcrdinit(struct pccard_devinfo * dp){ struct isa_device *is = &dp->isahd; struct wlp_softc *sc = &wlp_softc[is->id_unit];#ifdef WLP_DEBUG printf("wlp%d: ENTRY wlpcrdinit()\n", is->id_unit); printf("\tirq: 0x%04x\n", is->id_irq); printf("\tiobase: 0x%04x\n", is->id_iobase);#endif /* * Make sure that PCCARD gives us a valid IO Address */ if(is->id_iobase == 0x00) { printf("wlp%d: invalid IO address\n", is->id_unit); return ENODEV; } /* * Check to make sure that "unit" is within range. */ if ((is->id_unit < 0) || (is->id_unit > NWLP - 1)) { printf("wlp%d: board out of range [0..%d]\n", is->id_unit, NWLP); return ENODEV; } sc->sc_irq = is->id_irq; sc->sc_iobase = is->id_iobase; sc->sc_maddr = is->id_maddr; sc->sc_msize = is->id_msize; sc->sc_unit = is->id_unit; sc->sc_gone = 0; if (rwprobe(is) == RW_IOSIZE) { sc->sc_iftype = IFTYPE_REDWING; sc->sc_ifconfig = rwconfig;#ifdef WLP_DEBUG printf("wlp%d: found a IBM Infrared card\n", is->id_unit);#endif } else if (wlpprobe(is, dp) == WLP_IOSIZE) { sc->sc_iftype = IFTYPE_WAVELAN; sc->sc_ifconfig = wlpconfig;#ifdef WLP_DEBUG printf("wlp%d: found a WaveLAN card\n", is->id_unit);#endif } else { printf("wlp%d: probe failed\n", is->id_unit); return ENXIO; } if (wlpattach(is) == 0) { printf("wlp%d: attach failed\n", is->id_unit); return ENXIO; } sc->sc_ac.ac_if.if_snd.ifq_maxlen = ifqmaxlen;#ifdef WLP_DEBUG printf("wlp%d: EXIT wlpcrdinit()\n", is->id_unit);#endif return 0;}#endif /* NCARD > 0 *//* * ====================================================================== * DEVICE INITIALIZATION ROUTINES * ====================================================================== */intwlp_isa_probe(is) struct isa_device *is;{ struct wlp_softc *sc = &wlp_softc[is->id_unit]; /* * Check to make sure that "unit" is within range. */ if ((is->id_unit < 0) || (is->id_unit > NWLP - 1)) { printf("wlp%d: board out of range [0..%d]\n", is->id_unit, NWLP); return 0; } bzero(sc, sizeof(*sc));#if NCARD > 0 return 0;#endif sc->sc_irq = is->id_irq; sc->sc_iobase = is->id_iobase; sc->sc_maddr = is->id_maddr; sc->sc_msize = is->id_msize; sc->sc_unit = is->id_unit; sc->sc_gone = 0; if (rwprobe(is) == RW_IOSIZE) { u_int8_t status; sc->sc_iftype = IFTYPE_REDWING; sc->sc_ifconfig = rwconfig; /* * Verify that the IRQ setting specified in kernel, matches * the dip switch on the card. */ status = IORead1(0x0C); if ((status & P12_ISA_IRQ) && (sc->sc_irq != 0x8000)) { printf("wlp%d: Dip switch 4 is incorrectly set to IRQ 15\n", is->id_unit); goto bad; } else if (!(status & P12_ISA_IRQ) && (sc->sc_irq != 0x0400)) { printf("wlp%d: Dip switch 4 is incorrectly set to IRQ 10\n", is->id_unit); goto bad; } return RW_IOSIZE; } /* Don't support ISA WaveLAN Cards */bad: return 0;}intwlp_isa_attach(struct isa_device * is){ return wlpattach(is);}intwlpattach(struct isa_device * is){ struct wlp_softc *sc = &wlp_softc[is->id_unit]; struct ifnet *ifp; /* * Configure the Card */ if (sc->sc_ifconfig(sc)) { printf("wlp%d: failed to configure the card.\n", sc->sc_unit); return 0; /* ERROR */ } ifp = &sc->sc_ac.ac_if; if (ifp->if_name == 0) { ifp->if_name = "wlp"; ifp->if_unit = sc->sc_unit; ifp->if_ioctl = wlpioctl; ifp->if_output = ether_output; ifp->if_start = wlpstart; ifp->if_watchdog = wlpwatchdog; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; if_attach(ifp); ether_ifattach(ifp);#if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));#endif } if (sc->sc_iftype == IFTYPE_REDWING) { printf("wlp%d: address %02x:%02x:%02x:%02x:%02x:%02x\n", sc->sc_unit, ETHER_ADDR_FORMAT(sc->sc_ac.ac_enaddr)); } else if (sc->sc_iftype == IFTYPE_WAVELAN) { printf("wlp%d: nwid: %x:%x, address %02x:%02x:%02x:%02x:%02x:%02x\n", sc->sc_unit, sc->sc_nwid[0], sc->sc_nwid[1], ETHER_ADDR_FORMAT(sc->sc_ac.ac_enaddr)); } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -