diff options
author | nyan <nyan@FreeBSD.org> | 2000-09-14 12:02:07 +0000 |
---|---|---|
committer | nyan <nyan@FreeBSD.org> | 2000-09-14 12:02:07 +0000 |
commit | 06ebe902eacf8fbbbd8fc4b5586d73ac25d6d9d6 (patch) | |
tree | 06baac96d005c9fec13e5881e69b75eecda82b61 /sys/dev/fe | |
parent | b4f34dbe5f1f3df9123b79bb6b3263563bdde972 (diff) | |
download | FreeBSD-src-06ebe902eacf8fbbbd8fc4b5586d73ac25d6d9d6.zip FreeBSD-src-06ebe902eacf8fbbbd8fc4b5586d73ac25d6d9d6.tar.gz |
- Newbus'ify and bus_space'ify.
- Separate bus dependent part and independent part.
- Moved source files to sys/dev/fe (repo copied).
- Fixed some comments by chi@bd.mbn.or.jp (Chiharu Shibata)
Tested by: bsd-nomads@clave.gr.jp and
FreeBSD98-testers@jp.freebsd.org
Diffstat (limited to 'sys/dev/fe')
-rw-r--r-- | sys/dev/fe/if_fe.c | 2886 | ||||
-rw-r--r-- | sys/dev/fe/if_fe_cbus.c | 1018 | ||||
-rw-r--r-- | sys/dev/fe/if_fe_isa.c | 1063 | ||||
-rw-r--r-- | sys/dev/fe/if_fe_pccard.c | 277 | ||||
-rw-r--r-- | sys/dev/fe/if_fereg.h | 48 | ||||
-rw-r--r-- | sys/dev/fe/if_fevar.h | 182 |
6 files changed, 3041 insertions, 2433 deletions
diff --git a/sys/dev/fe/if_fe.c b/sys/dev/fe/if_fe.c index 79883cc..7b16e6d 100644 --- a/sys/dev/fe/if_fe.c +++ b/sys/dev/fe/if_fe.c @@ -24,7 +24,6 @@ * $FreeBSD$ * * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards. - * To be used with FreeBSD 3.x * Contributed by M. Sekiguchi. <seki@sysrap.cs.fujitsu.co.jp> * * This version is intended to be a generic template for various @@ -60,15 +59,15 @@ /* * TODO: * o To support ISA PnP auto configuration for FMV-183/184. + * o To support REX-9886/87(PC-98 only). * o To reconsider mbuf usage. * o To reconsider transmission buffer usage, including * transmission buffer size (currently 4KB x 2) and pros-and- * cons of multiple frame transmission. * o To test IPX codes. - * o To test FreeBSD3.0-current. + * o To test new-bus frontend. */ -#include "fe.h" #include "opt_fe.h" #include "opt_inet.h" #include "opt_ipx.h" @@ -76,10 +75,16 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/socket.h> #include <sys/sockio.h> #include <sys/mbuf.h> -#include <sys/socket.h> +#include <sys/module.h> +#include <machine/clock.h> + #include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> #include <net/ethernet.h> #include <net/if.h> @@ -93,35 +98,9 @@ #include <net/bpf.h> -#include <machine/clock.h> - -#include <i386/isa/isa_device.h> -#include <i386/isa/icu.h> - -#ifndef COMPAT_OLDISA -#error "The fe device requires the old isa compatibility shims" -#endif - -/* PCCARD suport */ -/* XXX FIXME! doesn't work with new pccard code, must be converted! */ -#ifdef notdef -#include "card.h" -#endif -#if NCARD > 0 -#include <sys/kernel.h> -#include <sys/select.h> -#include <sys/module.h> -#include <pccard/cardinfo.h> -#include <pccard/slot.h> -#endif - #include <i386/isa/ic/mb86960.h> -#include <i386/isa/if_fereg.h> - -/* - * Default settings for fe driver specific options. - * They can be set in config file by "options" statements. - */ +#include <dev/fe/if_fereg.h> +#include <dev/fe/if_fevar.h> /* * Transmit just one packet per a "send" command to 86960. @@ -155,14 +134,8 @@ /* Force DLCR6 override. */ #define FE_FLAGS_OVERRIDE_DLCR6 0x0080 -/* Shouldn't these be defined somewhere else such as isa_device.h? */ -#define NO_IOADDR (-1) -#define NO_IRQ 0 -/* - * Data type for a multicast address filter on 8696x. - */ -struct fe_filter { u_char data [ FE_FILTER_LEN ]; }; +devclass_t fe_devclass; /* * Special filter values. @@ -170,92 +143,17 @@ struct fe_filter { u_char data [ FE_FILTER_LEN ]; }; static struct fe_filter const fe_filter_nothing = { FE_FILTER_NOTHING }; static struct fe_filter const fe_filter_all = { FE_FILTER_ALL }; -/* How many registers does an fe-supported adapter have at maximum? */ -#define MAXREGISTERS 32 - -/* - * fe_softc: per line info and status - */ -static struct fe_softc { - - /* Used by "common" codes. */ - struct arpcom arpcom; /* Ethernet common */ - - /* Used by config codes. */ - - /* Set by probe() and not modified in later phases. */ - char const * typestr; /* printable name of the interface. */ - u_short iobase; /* base I/O address of the adapter. */ - u_short ioaddr [ MAXREGISTERS ]; /* I/O addresses of registers. */ - u_short txb_size; /* size of TX buffer, in bytes */ - u_char proto_dlcr4; /* DLCR4 prototype. */ - u_char proto_dlcr5; /* DLCR5 prototype. */ - u_char proto_dlcr6; /* DLCR6 prototype. */ - u_char proto_dlcr7; /* DLCR7 prototype. */ - u_char proto_bmpr13; /* BMPR13 prototype. */ - u_char stability; /* How stable is this? */ - u_short priv_info; /* info specific to a vendor/model. */ - - /* Vendor/model specific hooks. */ - void (*init)(struct fe_softc *); /* Just before fe_init(). */ - void (*stop)(struct fe_softc *); /* Just after fe_stop(). */ - - /* Transmission buffer management. */ - u_short txb_free; /* free bytes in TX buffer */ - u_char txb_count; /* number of packets in TX buffer */ - u_char txb_sched; /* number of scheduled packets */ - - /* Excessive collision counter (see fe_tint() for details.) */ - u_char tx_excolls; /* # of excessive collisions. */ - - /* Multicast address filter management. */ - u_char filter_change; /* MARs must be changed ASAP. */ - struct fe_filter filter;/* new filter value. */ - - /* Network management. */ - struct ifmib_iso_8802_3 mibdata; - - /* Media information. */ - struct ifmedia media; /* used by if_media. */ - u_short mbitmap; /* bitmap for supported media; see bit2media */ - int defmedia; /* default media */ - void (* msel)(struct fe_softc *); /* media selector. */ - -} fe_softc[NFE]; - -#define sc_if arpcom.ac_if -#define sc_unit arpcom.ac_if.if_unit -#define sc_enaddr arpcom.ac_enaddr - /* Standard driver entry points. These can be static. */ -static int fe_probe ( struct isa_device * ); -static int fe_attach ( struct isa_device * ); -static void fe_init ( void * ); -static ointhand2_t feintr; -static int fe_ioctl ( struct ifnet *, u_long, caddr_t ); -static void fe_start ( struct ifnet * ); -static void fe_watchdog ( struct ifnet * ); -static int fe_medchange ( struct ifnet * ); -static void fe_medstat ( struct ifnet *, struct ifmediareq * ); +static void fe_init (void *); +static inthand2_t fe_intr; +static int fe_ioctl (struct ifnet *, u_long, caddr_t); +static void fe_start (struct ifnet *); +static void fe_watchdog (struct ifnet *); +static int fe_medchange (struct ifnet *); +static void fe_medstat (struct ifnet *, struct ifmediareq *); /* Local functions. Order of declaration is confused. FIXME. */ -static int fe_probe_ssi ( struct isa_device *, struct fe_softc * ); -static int fe_probe_jli ( struct isa_device *, struct fe_softc * ); -static int fe_probe_fmv ( struct isa_device *, struct fe_softc * ); -static int fe_probe_lnx ( struct isa_device *, struct fe_softc * ); -static int fe_probe_gwy ( struct isa_device *, struct fe_softc * ); -static int fe_probe_ubn ( struct isa_device *, struct fe_softc * ); -#ifdef PC98 -static int fe_probe_re1000 ( struct isa_device *, struct fe_softc * ); -static int fe_probe_cnet9ne( struct isa_device *, struct fe_softc * ); -static int fe_probe_rex ( struct isa_device *, struct fe_softc * ); -#endif -#if NCARD > 0 -static int fe_probe_mbh ( struct isa_device *, struct fe_softc * ); -static int fe_probe_tdk ( struct isa_device *, struct fe_softc * ); -#endif static int fe_get_packet ( struct fe_softc *, u_short ); -static void fe_stop ( struct fe_softc * ); static void fe_tint ( struct fe_softc *, u_char ); static void fe_rint ( struct fe_softc *, u_char ); static void fe_xmit ( struct fe_softc * ); @@ -267,17 +165,6 @@ static void fe_loadmar ( struct fe_softc * ); static void fe_emptybuffer ( struct fe_softc * ); #endif -/* Driver struct used in the config code. This must be public (external.) */ -struct isa_driver fedriver = -{ - INTR_TYPE_NET, - fe_probe, - fe_attach, - "fe", - 1 /* It's safe to mark as "sensitive" */ -}; -COMPAT_ISA_DRIVER(fe, fedriver); - /* * Fe driver specific constants which relate to 86960/86965. */ @@ -302,11 +189,6 @@ COMPAT_ISA_DRIVER(fe, fedriver); * Miscellaneous definitions not directly related to hardware. */ -/* Flags for stability. */ -#define UNSTABLE_IRQ 0x01 /* IRQ setting may be incorrect. */ -#define UNSTABLE_MAC 0x02 /* Probed MAC address may be incorrect. */ -#define UNSTABLE_TYPE 0x04 /* Probed vendor/model may be incorrect. */ - /* The following line must be delete when "net/if_media.h" support it. */ #ifndef IFM_10_FL #define IFM_10_FL /* 13 */ IFM_10_5 @@ -315,19 +197,12 @@ COMPAT_ISA_DRIVER(fe, fedriver); #if 0 /* Mapping between media bitmap (in fe_softc.mbitmap) and ifm_media. */ static int const bit2media [] = { -#define MB_HA 0x0001 IFM_HDX | IFM_ETHER | IFM_AUTO, -#define MB_HM 0x0002 IFM_HDX | IFM_ETHER | IFM_MANUAL, -#define MB_HT 0x0004 IFM_HDX | IFM_ETHER | IFM_10_T, -#define MB_H2 0x0008 IFM_HDX | IFM_ETHER | IFM_10_2, -#define MB_H5 0x0010 IFM_HDX | IFM_ETHER | IFM_10_5, -#define MB_HF 0x0020 IFM_HDX | IFM_ETHER | IFM_10_FL, -#define MB_FT 0x0040 IFM_FDX | IFM_ETHER | IFM_10_T, /* More can be come here... */ 0 @@ -335,19 +210,12 @@ static int const bit2media [] = { #else /* Mapping between media bitmap (in fe_softc.mbitmap) and ifm_media. */ static int const bit2media [] = { -#define MB_HA 0x0001 IFM_ETHER | IFM_AUTO, -#define MB_HM 0x0002 IFM_ETHER | IFM_MANUAL, -#define MB_HT 0x0004 IFM_ETHER | IFM_10_T, -#define MB_H2 0x0008 IFM_ETHER | IFM_10_2, -#define MB_H5 0x0010 IFM_ETHER | IFM_10_5, -#define MB_HF 0x0020 IFM_ETHER | IFM_10_FL, -#define MB_FT 0x0040 IFM_ETHER | IFM_10_T, /* More can be come here... */ 0 @@ -355,194 +223,26 @@ static int const bit2media [] = { #endif /* - * Routines to access contiguous I/O ports. - */ - -static void -inblk ( struct fe_softc * sc, int offs, u_char * mem, int len ) -{ - while ( --len >= 0 ) { - *mem++ = inb( sc->ioaddr[ offs++ ] ); - } -} - -static void -outblk ( struct fe_softc * sc, int offs, u_char const * mem, int len ) -{ - while ( --len >= 0 ) { - outb( sc->ioaddr[ offs++ ], *mem++ ); - } -} - -/* PCCARD Support */ -#if NCARD > 0 -/* - * PC-Card (PCMCIA) specific code. - */ -static int feinit (struct pccard_devinfo *); -static void feunload (struct pccard_devinfo *); -static int fe_card_intr (struct pccard_devinfo *); - -PCCARD_MODULE(fe, feinit, feunload, fe_card_intr, 0, net_imask); - -/* - * Initialize the device - called from Slot manager. - */ -static int -feinit(struct pccard_devinfo *devi) -{ - struct fe_softc *sc; - - /* validate unit number. */ - if (devi->isahd.id_unit >= NFE) return ENODEV; - - /* Prepare for the device probe process. */ - sc = &fe_softc[devi->isahd.id_unit]; - sc->sc_unit = devi->isahd.id_unit; - sc->iobase = devi->isahd.id_iobase; - - /* - * When the feinit() is called, the devi->misc holds a - * six-byte value set by the pccard daemon. If the - * corresponding entry in /etc/pccard.conf has an "ether" - * keyword, the value is the Ethernet MAC address extracted - * from CIS area of the card. If the entry has no "ether" - * keyword, the daemon fills the field with binary zero, - * instead. We passes the value (either MAC address or zero) - * to model-specific sub-probe routines through sc->sc_enaddr - * (it actually is sc->sc_arpcom.ar_enaddr, BTW) so that the - * sub-probe routies can use that info. - */ - bcopy(devi->misc, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* Probe for supported cards. */ - if (fe_probe_mbh(&devi->isahd, sc) == 0 - && fe_probe_tdk(&devi->isahd, sc) == 0) return ENXIO; - - /* We've got a supported card. Attach it, then. */ - if (fe_attach(&devi->isahd) == 0) return ENXIO; - - return 0; -} - -/* - * feunload - unload the driver and clear the table. - * XXX TODO: - * This is usually called when the card is ejected, but - * can be caused by a modunload of a controller driver. - * The idea is to reset the driver's view of the device - * and ensure that any driver entry points such as - * read and write do not hang. - */ -static void -feunload(struct pccard_devinfo *devi) -{ - struct fe_softc *sc = &fe_softc[devi->isahd.id_unit]; - printf("fe%d: unload\n", sc->sc_unit); - fe_stop(sc); - if_down(&sc->arpcom.ac_if); -} - -/* - * fe_card_intr - Shared interrupt called from - * front end of PC-Card handler. - */ -static int -fe_card_intr(struct pccard_devinfo *devi) -{ - feintr(devi->isahd.id_unit); - return (1); -} -#endif /* NCARD > 0 */ - - -/* - * Hardware probe routines. - * - * In older versions of this driver, we provided an automatic I/O - * address detection. The features is, however, removed from this - * version, for simplicity. Any comments? - */ - -/* - * Determine if the device is present at a specified I/O address. The - * main entry to the driver. - */ - -static int -fe_probe (struct isa_device * dev) -{ - struct fe_softc * sc; - int nports; - -#ifdef DIAGNOSTIC - if (dev->id_unit >= NFE) { - printf("fe%d: too large unit number for the current config\n", - dev->id_unit); - return 0; - } -#endif - - /* Prepare for the softc struct. */ - sc = &fe_softc[dev->id_unit]; - sc->sc_unit = dev->id_unit; - sc->iobase = dev->id_iobase; - - /* Probe for supported boards. */ - nports = 0; -#ifdef PC98 - if (!nports) nports = fe_probe_re1000(dev, sc); - if (!nports) nports = fe_probe_cnet9ne(dev, sc); - if (!nports) nports = fe_probe_rex(dev, sc); -#endif - if (!nports) nports = fe_probe_ssi(dev, sc); - if (!nports) nports = fe_probe_jli(dev, sc); - if (!nports) nports = fe_probe_fmv(dev, sc); - if (!nports) nports = fe_probe_lnx(dev, sc); - if (!nports) nports = fe_probe_ubn(dev, sc); - if (!nports) nports = fe_probe_gwy(dev, sc); - - /* We found supported board. */ - return nports; -} - -/* * Check for specific bits in specific registers have specific values. * A common utility function called from various sub-probe routines. */ - -struct fe_simple_probe_struct +int +fe_simple_probe (struct fe_softc const * sc, + struct fe_simple_probe_struct const * sp) { - u_char port; /* Offset from the base I/O address. */ - u_char mask; /* Bits to be checked. */ - u_char bits; /* Values to be compared against. */ -}; + struct fe_simple_probe_struct const *p; -static int -fe_simple_probe ( struct fe_softc const * sc, - struct fe_simple_probe_struct const * sp ) -{ - struct fe_simple_probe_struct const * p; - - for ( p = sp; p->mask != 0; p++ ) { -#ifdef FE_DEBUG - unsigned a = sc->ioaddr[p->port]; - printf("fe%d: Probing %02x (%04x): %02x (%02x, %02x): %s\n", - sc->sc_unit, p->port, a, inb(a), p->mask, p->bits, - (inb(a) & p->mask) == p->bits ? "OK" : "NG"); -#endif - if ( ( inb( sc->ioaddr[ p->port ] ) & p->mask ) != p->bits ) - { - return ( 0 ); - } + for (p = sp; p->mask != 0; p++) { + if ((fe_inb(sc, p->port) & p->mask) != p->bits) + return 0; } - return ( 1 ); + return 1; } /* Test if a given 6 byte value is a valid Ethernet station (MAC) address. "Vendor" is an expected vendor code (first three bytes,) or a zero when nothing expected. */ -static int +int valid_Ether_p (u_char const * addr, unsigned vendor) { #ifdef FE_DEBUG @@ -580,17 +280,9 @@ valid_Ether_p (u_char const * addr, unsigned vendor) } /* Fill our softc struct with default value. */ -static void +void fe_softc_defaults (struct fe_softc *sc) { - int i; - - /* Initialize I/O address re-mapping table for the standard - (contiguous) register layout. This routine doesn't use - ioaddr[], so the caller can safely override it after - calling fe_softc_defaults, if needed. */ - for (i = 0; i < MAXREGISTERS; i++) sc->ioaddr[i] = sc->iobase + i; - /* Prepare for typical register prototypes. We assume a "typical" board has <32KB> of <fast> SRAM connected with a <byte-wide> data lines. */ @@ -616,7 +308,7 @@ fe_softc_defaults (struct fe_softc *sc) /* Common error reporting routine used in probe routines for "soft configured IRQ"-type boards. */ -static void +void fe_irq_failure (char const *name, int unit, int irq, char const *list) { printf("fe%d: %s board is detected, but %s IRQ was given\n", @@ -628,17 +320,13 @@ fe_irq_failure (char const *name, int unit, int irq, char const *list) } /* - * Hardware (vendor) specific probe routines and hooks. - */ - -/* - * Machine independent routines. + * Hardware (vendor) specific hooks. */ /* * Generic media selection scheme for MB86965 based boards. */ -static void +void fe_msel_965 (struct fe_softc *sc) { u_char b13; @@ -651,28 +339,21 @@ fe_msel_965 (struct fe_softc *sc) } /* Write it into the register. It takes effect immediately. */ - outb(sc->ioaddr[FE_BMPR13], sc->proto_bmpr13 | b13); + fe_outb(sc, FE_BMPR13, sc->proto_bmpr13 | b13); } + /* * Fujitsu MB86965 JLI mode support routines. */ -/* Datasheet for 86965 explicitly states that it only supports serial - * EEPROM with 16 words (32 bytes) capacity. (I.e., 93C06.) However, - * ones with 64 words (128 bytes) are available in the marked, namely - * 93C46, and are also fully compatible with 86965. It is known that - * some boards (e.g., ICL) actually have 93C46 on them and use extra - * storage to keep various config info. */ -#define JLI_EEPROM_SIZE 128 - /* * Routines to read all bytes from the config EEPROM through MB86965A. * It is a MicroWire (3-wire) serial EEPROM with 6-bit address. * (93C06 or 93C46.) */ static void -fe_strobe_eeprom_jli ( u_short bmpr16 ) +fe_strobe_eeprom_jli (struct fe_softc *sc, u_short bmpr16) { /* * We must guarantee 1us (or more) interval to access slow @@ -680,75 +361,71 @@ fe_strobe_eeprom_jli ( u_short bmpr16 ) * delay with ISA timing. (Even if the bus clock is "tuned.") * Some modification will be needed on faster busses. */ - outb( bmpr16, FE_B16_SELECT ); - outb( bmpr16, FE_B16_SELECT | FE_B16_CLOCK ); - outb( bmpr16, FE_B16_SELECT | FE_B16_CLOCK ); - outb( bmpr16, FE_B16_SELECT ); + fe_outb(sc, bmpr16, FE_B16_SELECT); + fe_outb(sc, bmpr16, FE_B16_SELECT | FE_B16_CLOCK); + fe_outb(sc, bmpr16, FE_B16_SELECT | FE_B16_CLOCK); + fe_outb(sc, bmpr16, FE_B16_SELECT); } -static void -fe_read_eeprom_jli ( struct fe_softc * sc, u_char * data ) +void +fe_read_eeprom_jli (struct fe_softc * sc, u_char * data) { - u_short bmpr16 = sc->ioaddr[ FE_BMPR16 ]; - u_short bmpr17 = sc->ioaddr[ FE_BMPR17 ]; u_char n, val, bit; u_char save16, save17; /* Save the current value of the EEPROM interface registers. */ - save16 = inb(bmpr16); - save17 = inb(bmpr17); + save16 = fe_inb(sc, FE_BMPR16); + save17 = fe_inb(sc, FE_BMPR17); /* Read bytes from EEPROM; two bytes per an iteration. */ - for ( n = 0; n < JLI_EEPROM_SIZE / 2; n++ ) { + for (n = 0; n < JLI_EEPROM_SIZE / 2; n++) { /* Reset the EEPROM interface. */ - outb( bmpr16, 0x00 ); - outb( bmpr17, 0x00 ); + fe_outb(sc, FE_BMPR16, 0x00); + fe_outb(sc, FE_BMPR17, 0x00); /* Start EEPROM access. */ - outb( bmpr16, FE_B16_SELECT ); - outb( bmpr17, FE_B17_DATA ); - fe_strobe_eeprom_jli( bmpr16 ); + fe_outb(sc, FE_BMPR16, FE_B16_SELECT); + fe_outb(sc, FE_BMPR17, FE_B17_DATA); + fe_strobe_eeprom_jli(sc, FE_BMPR16); /* Pass the iteration count as well as a READ command. */ val = 0x80 | n; - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - outb( bmpr17, ( val & bit ) ? FE_B17_DATA : 0 ); - fe_strobe_eeprom_jli( bmpr16 ); + for (bit = 0x80; bit != 0x00; bit >>= 1) { + fe_outb(sc, FE_BMPR17, (val & bit) ? FE_B17_DATA : 0); + fe_strobe_eeprom_jli(sc, FE_BMPR16); } - outb( bmpr17, 0x00 ); + fe_outb(sc, FE_BMPR17, 0x00); /* Read a byte. */ val = 0; - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - fe_strobe_eeprom_jli( bmpr16 ); - if ( inb( bmpr17 ) & FE_B17_DATA ) { + for (bit = 0x80; bit != 0x00; bit >>= 1) { + fe_strobe_eeprom_jli(sc, FE_BMPR16); + if (fe_inb(sc, FE_BMPR17) & FE_B17_DATA) val |= bit; - } } *data++ = val; /* Read one more byte. */ val = 0; - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - fe_strobe_eeprom_jli( bmpr16 ); - if ( inb( bmpr17 ) & FE_B17_DATA ) { + for (bit = 0x80; bit != 0x00; bit >>= 1) { + fe_strobe_eeprom_jli(sc, FE_BMPR16); + if (fe_inb(sc, FE_BMPR17) & FE_B17_DATA) val |= bit; - } } *data++ = val; } #if 0 /* Reset the EEPROM interface, again. */ - outb( bmpr16, 0x00 ); - outb( bmpr17, 0x00 ); + fe_outb(sc, FE_BMPR16, 0x00); + fe_outb(sc, FE_BMPR17, 0x00); #else /* Make sure to restore the original value of EEPROM interface registers, since we are not yet sure we have MB86965A on the address. */ - outb(bmpr17, save17); - outb(bmpr16, save16); + fe_outb(sc, FE_BMPR17, save17); + fe_outb(sc, FE_BMPR16, save16); #endif #if 1 @@ -764,26 +441,20 @@ fe_read_eeprom_jli ( struct fe_softc * sc, u_char * data ) #endif } -static void +void fe_init_jli (struct fe_softc * sc) { /* "Reset" by writing into a magic location. */ DELAY(200); - outb(sc->ioaddr[0x1E], inb(sc->ioaddr[0x1E])); + fe_outb(sc, 0x1E, fe_inb(sc, 0x1E)); DELAY(300); } + /* * SSi 78Q8377A support routines. */ -#define SSI_EEPROM_SIZE 512 -#define SSI_DIN 0x01 -#define SSI_DAT 0x01 -#define SSI_CSL 0x02 -#define SSI_CLK 0x04 -#define SSI_EEP 0x10 - /* * Routines to read all bytes from the config EEPROM through 78Q8377A. * It is a MicroWire (3-wire) serial EEPROM with 8-bit address. (I.e., @@ -794,83 +465,84 @@ fe_init_jli (struct fe_softc * sc) * C-NET(98)P2 support routine in FreeBSD(98). */ -static void +void fe_read_eeprom_ssi (struct fe_softc *sc, u_char *data) { - u_short bmpr12 = sc->ioaddr[FE_DLCR12]; u_char val, bit; int n; u_char save6, save7, save12; /* Save the current value for the DLCR registers we are about to destroy. */ - save6 = inb(sc->ioaddr[FE_DLCR6]); - save7 = inb(sc->ioaddr[FE_DLCR7]); + save6 = fe_inb(sc, FE_DLCR6); + save7 = fe_inb(sc, FE_DLCR7); /* Put the 78Q8377A into a state that we can access the EEPROM. */ - outb(sc->ioaddr[FE_DLCR6], - FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_DLC_DISABLE); - outb(sc->ioaddr[FE_DLCR7], - FE_D7_BYTSWP_LH | FE_D7_RBS_BMPR | FE_D7_RDYPNS | FE_D7_POWER_UP); + fe_outb(sc, FE_DLCR6, + FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_DLC_DISABLE); + fe_outb(sc, FE_DLCR7, + FE_D7_BYTSWP_LH | FE_D7_RBS_BMPR | FE_D7_RDYPNS | FE_D7_POWER_UP); /* Save the current value for the BMPR12 register, too. */ - save12 = inb(bmpr12); + save12 = fe_inb(sc, FE_DLCR12); /* Read bytes from EEPROM; two bytes per an iteration. */ - for ( n = 0; n < SSI_EEPROM_SIZE / 2; n++ ) { + for (n = 0; n < SSI_EEPROM_SIZE / 2; n++) { /* Start EEPROM access */ - outb(bmpr12, SSI_EEP); - outb(bmpr12, SSI_EEP | SSI_CSL); + fe_outb(sc, FE_DLCR12, SSI_EEP); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL); /* Send the following four bits to the EEPROM in the - specified order: a dummy bit, a start bit, and - command bits (10) for READ. */ - outb(bmpr12, SSI_EEP | SSI_CSL ); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK ); /* 0 */ - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_DAT); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK | SSI_DAT); /* 1 */ - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_DAT); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK | SSI_DAT); /* 1 */ - outb(bmpr12, SSI_EEP | SSI_CSL ); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK ); /* 0 */ + specified order: a dummy bit, a start bit, and + command bits (10) for READ. */ + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL ); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK ); /* 0 */ + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_DAT); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK | SSI_DAT); /* 1 */ + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_DAT); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK | SSI_DAT); /* 1 */ + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL ); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK ); /* 0 */ /* Pass the iteration count to the chip. */ - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - val = ( n & bit ) ? SSI_DAT : 0; - outb(bmpr12, SSI_EEP | SSI_CSL | val); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK | val); + for (bit = 0x80; bit != 0x00; bit >>= 1) { + val = ( n & bit ) ? SSI_DAT : 0; + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | val); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK | val); } /* Read a byte. */ val = 0; - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - outb(bmpr12, SSI_EEP | SSI_CSL); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK); - if (inb(bmpr12) & SSI_DIN) val |= bit; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK); + if (fe_inb(sc, FE_DLCR12) & SSI_DIN) + val |= bit; } *data++ = val; /* Read one more byte. */ val = 0; - for ( bit = 0x80; bit != 0x00; bit >>= 1 ) { - outb(bmpr12, SSI_EEP | SSI_CSL); - outb(bmpr12, SSI_EEP | SSI_CSL | SSI_CLK); - if (inb(bmpr12) & SSI_DIN) val |= bit; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL); + fe_outb(sc, FE_DLCR12, SSI_EEP | SSI_CSL | SSI_CLK); + if (fe_inb(sc, FE_DLCR12) & SSI_DIN) + val |= bit; } *data++ = val; - outb(bmpr12, SSI_EEP); + fe_outb(sc, FE_DLCR12, SSI_EEP); } /* Reset the EEPROM interface. (For now.) */ - outb( bmpr12, 0x00 ); + fe_outb(sc, FE_DLCR12, 0x00); /* Restore the saved register values, for the case that we didn't have 78Q8377A at the given address. */ - outb(bmpr12, save12); - outb(sc->ioaddr[FE_DLCR7], save7); - outb(sc->ioaddr[FE_DLCR6], save6); + fe_outb(sc, FE_DLCR12, save12); + fe_outb(sc, FE_DLCR7, save7); + fe_outb(sc, FE_DLCR6, save6); #if 1 /* Report what we got. */ @@ -885,26 +557,10 @@ fe_read_eeprom_ssi (struct fe_softc *sc, u_char *data) #endif } -#define FE_SSI_EEP_IRQ 9 /* Irq ??? */ -#define FE_SSI_EEP_ADDR 16 /* Station(MAC) address */ -#define FE_SSI_EEP_DUPLEX 25 /* Duplex mode ??? */ - /* * TDK/LANX boards support routines. */ -/* AX012/AX013 equips an X24C01 chip, which has 128 bytes of memory cells. */ -#define LNX_EEPROM_SIZE 128 - -/* Bit assignments and command definitions for the serial EEPROM - interface register in LANX ASIC. */ -#define LNX_SDA_HI 0x08 /* Drive SDA line high (logical 1.) */ -#define LNX_SDA_LO 0x00 /* Drive SDA line low (logical 0.) */ -#define LNX_SDA_FL 0x08 /* Float (don't drive) SDA line. */ -#define LNX_SDA_IN 0x01 /* Mask for reading SDA line. */ -#define LNX_CLK_HI 0x04 /* Drive clock line high (active.) */ -#define LNX_CLK_LO 0x00 /* Drive clock line low (inactive.) */ - /* It is assumed that the CLK line is low and SDA is high (float) upon entry. */ #define LNX_PH(D,K,N) \ ((LNX_SDA_##D | LNX_CLK_##K) << N) @@ -918,40 +574,40 @@ fe_read_eeprom_ssi (struct fe_softc *sc, u_char *data) #define LNX_CYCLE_INIT LNX_CYCLE(LO,HI,HI,HI, LO,LO,LO,LO) static void -fe_eeprom_cycle_lnx (u_short reg20, u_long cycle) +fe_eeprom_cycle_lnx (struct fe_softc *sc, u_short reg20, u_long cycle) { - outb(reg20, (cycle ) & 0xFF); + fe_outb(sc, reg20, (cycle ) & 0xFF); DELAY(15); - outb(reg20, (cycle >> 8) & 0xFF); + fe_outb(sc, reg20, (cycle >> 8) & 0xFF); DELAY(15); - outb(reg20, (cycle >> 16) & 0xFF); + fe_outb(sc, reg20, (cycle >> 16) & 0xFF); DELAY(15); - outb(reg20, (cycle >> 24) & 0xFF); + fe_outb(sc, reg20, (cycle >> 24) & 0xFF); DELAY(15); } static u_char -fe_eeprom_receive_lnx (u_short reg20) +fe_eeprom_receive_lnx (struct fe_softc *sc, u_short reg20) { u_char dat; - outb(reg20, LNX_CLK_HI | LNX_SDA_FL); + fe_outb(sc, reg20, LNX_CLK_HI | LNX_SDA_FL); DELAY(15); - dat = inb(reg20); - outb(reg20, LNX_CLK_LO | LNX_SDA_FL); + dat = fe_inb(sc, reg20); + fe_outb(sc, reg20, LNX_CLK_LO | LNX_SDA_FL); DELAY(15); return (dat & LNX_SDA_IN); } -static void +void fe_read_eeprom_lnx (struct fe_softc *sc, u_char *data) { int i; u_char n, bit, val; u_char save20; - u_short reg20 = sc->ioaddr[0x14]; + u_short reg20 = 0x14; - save20 = inb(reg20); + save20 = fe_inb(sc, reg20); /* NOTE: DELAY() timing constants are approximately three times longer (slower) than the required minimum. This is @@ -969,30 +625,29 @@ fe_read_eeprom_lnx (struct fe_softc *sc, u_char *data) Moreover, as there are no easy way to reset, we need a _manoeuvre_ here. (It even lacks a reset pin, so pushing the RESET button on the PC doesn't help!) */ - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_INIT); - for (i = 0; i < 10; i++) { - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_START); - } - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_STOP); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_INIT); + for (i = 0; i < 10; i++) + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_START); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_STOP); DELAY(10000); #endif /* Issue a start condition. */ - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_START); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_START); /* Send seven bits of the starting address (zero, in this case) and a command bit for READ. */ val = 0x01; for (bit = 0x80; bit != 0x00; bit >>= 1) { if (val & bit) { - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_HI); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_HI); } else { - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_LO); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_LO); } } /* Receive an ACK bit. */ - if (fe_eeprom_receive_lnx(reg20)) { + if (fe_eeprom_receive_lnx(sc, reg20)) { /* ACK was not received. EEPROM is not present (i.e., this board was not a TDK/LANX) or not working properly. */ @@ -1012,23 +667,24 @@ fe_read_eeprom_lnx (struct fe_softc *sc, u_char *data) /* Read a byte and store it into the buffer. */ val = 0x00; for (bit = 0x80; bit != 0x00; bit >>= 1) { - if (fe_eeprom_receive_lnx(reg20)) val |= bit; + if (fe_eeprom_receive_lnx(sc, reg20)) + val |= bit; } *data++ = val; /* Acknowledge if we have to read more. */ if (n < LNX_EEPROM_SIZE - 1) { - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_LO); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_LO); } } /* Issue a STOP condition, de-activating the clock line. It will be safer to keep the clock line low than to leave it high. */ - fe_eeprom_cycle_lnx(reg20, LNX_CYCLE_STOP); + fe_eeprom_cycle_lnx(sc, reg20, LNX_CYCLE_STOP); RET: - outb(reg20, save20); + fe_outb(sc, reg20, save20); #if 1 /* Report what we got. */ @@ -1042,1725 +698,53 @@ fe_read_eeprom_lnx (struct fe_softc *sc, u_char *data) #endif } -static void -fe_init_lnx ( struct fe_softc * sc ) +void +fe_init_lnx (struct fe_softc * sc) { /* Reset the 86960. Do we need this? FIXME. */ - outb(sc->ioaddr[0x12], 0x06); + fe_outb(sc, 0x12, 0x06); DELAY(100); - outb(sc->ioaddr[0x12], 0x07); + fe_outb(sc, 0x12, 0x07); DELAY(100); /* Setup IRQ control register on the ASIC. */ - outb(sc->ioaddr[0x14], sc->priv_info); + fe_outb(sc, 0x14, sc->priv_info); } + /* * Ungermann-Bass boards support routine. */ -static void -fe_init_ubn ( struct fe_softc * sc ) +void +fe_init_ubn (struct fe_softc * sc) { /* Do we need this? FIXME. */ - outb(sc->ioaddr[FE_DLCR7], + fe_outb(sc, FE_DLCR7, sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP); - outb(sc->ioaddr[0x18], 0x00); - DELAY( 200 ); - - /* Setup IRQ control register on the ASIC. */ - outb(sc->ioaddr[0x14], sc->priv_info); -} - -/* - * Machine dependent probe routines. - */ - -#ifdef PC98 -static int -fe_probe_fmv ( struct isa_device * dev, struct fe_softc * sc ) -{ - /* PC-98 has no board of this architechture. */ - return 0; -} - -/* ioaddr for RE1000/1000Plus - Very dirty! */ -static u_short ioaddr_re1000[MAXREGISTERS] = { - 0x0000, 0x0001, 0x0200, 0x0201, 0x0400, 0x0401, 0x0600, 0x0601, - 0x0800, 0x0801, 0x0a00, 0x0a01, 0x0c00, 0x0c01, 0x0e00, 0x0e01, - 0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00, - 0x1001, 0x1201, 0x1401, 0x1601, 0x1801, 0x1a01, 0x1c01, 0x1e01, -}; + fe_outb(sc, 0x18, 0x00); + DELAY(200); -/* - * Probe and initialization for Allied-Telesis RE1000 series. - */ -static void -fe_init_re1000 ( struct fe_softc * sc ) -{ /* Setup IRQ control register on the ASIC. */ - outb(sc->ioaddr[FE_RE1000_IRQCONF], sc->priv_info); -} - -static int -fe_probe_re1000 ( struct isa_device * dev, struct fe_softc * sc ) -{ - int i, n; - u_char sum; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for RE1000. */ - /* [01]D[02468ACE] are allowed. */ - if ((sc->iobase & ~0x10E) != 0xD0) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for RE1000. */ - for (i = 0; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + ioaddr_re1000[i]; - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Get our station address from EEPROM. */ - inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* Make sure it is Allied-Telesis's. */ - if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) return 0; -#if 1 - /* Calculate checksum. */ - sum = inb(sc->ioaddr[0x1e]); - for (i = 0; i < ETHER_ADDR_LEN; i++) { - sum ^= sc->sc_enaddr[i]; - } - if (sum != 0) return 0; -#endif - /* Setup the board type. */ - sc->typestr = "RE1000"; - - /* This looks like an RE1000 board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3: n = 0x10; break; - case IRQ5: n = 0x20; break; - case IRQ6: n = 0x40; break; - case IRQ12: n = 0x80; break; - default: - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "3/5/6/12"); - return 0; - } - sc->priv_info = inb(sc->ioaddr[FE_RE1000_IRQCONF]) & 0x0f | n; - - /* Setup hooks. We need a special initialization procedure. */ - sc->init = fe_init_re1000; - - /* The I/O address range is fragmented in the RE1000. - It occupies 2*16 I/O addresses, by the way. */ - return 2; + fe_outb(sc, 0x14, sc->priv_info); } -/* JLI sub-probe for Allied-Telesis RE1000Plus/ME1500 series. */ -static u_short const * -fe_probe_jli_re1000p (struct fe_softc * sc, u_char const * eeprom) -{ - int i; - static u_short const irqmaps_re1000p [4] = { IRQ3, IRQ5, IRQ6, IRQ12 }; - - /* Make sure the EEPROM contains Allied-Telesis bit pattern. */ - if (eeprom[1] != 0xFF) return NULL; - for (i = 2; i < 8; i++) if (eeprom[i] != 0xFF) return NULL; - for (i = 14; i < 24; i++) if (eeprom[i] != 0xFF) return NULL; - - /* Get our station address from EEPROM, and make sure the - EEPROM contains Allied-Telesis's address. */ - bcopy(eeprom+8, sc->sc_enaddr, ETHER_ADDR_LEN); - if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) return NULL; - - /* I don't know any sub-model identification. */ - sc->typestr = "RE1000Plus/ME1500"; - - /* Returns the IRQ table for the RE1000Plus. */ - return irqmaps_re1000p; -} - -/* - * Probe for Allied-Telesis RE1000Plus/ME1500 series. - */ -static int -fe_probe_jli (struct isa_device * dev, struct fe_softc * sc) -{ - int i, n; - int irq; - u_char eeprom [JLI_EEPROM_SIZE]; - u_short const * irqmap; - - static u_short const baseaddr [8] = - { 0x1D6, 0x1D8, 0x1DA, 0x1D4, 0x0D4, 0x0D2, 0x0D8, 0x0D0 }; - static struct fe_simple_probe_struct const probe_table [] = { - /* { FE_DLCR1, 0x20, 0x00 }, Doesn't work. */ - { FE_DLCR2, 0x50, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - /* { FE_DLCR5, 0x80, 0x00 }, Doesn't work. */ -#if 0 - { FE_BMPR16, 0x1B, 0x00 }, - { FE_BMPR17, 0x7F, 0x00 }, -#endif - { 0 } - }; - - /* - * See if the specified address is possible for MB86965A JLI mode. - */ - for (i = 0; i < 8; i++) { - if (baseaddr[i] == sc->iobase) break; - } - if (i == 8) return 0; - - /* Fill the softc struct with reasonable default. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for RE1000Plus. */ - for (i = 0; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + ioaddr_re1000[i]; - - /* - * We should test if MB86965A is on the base address now. - * Unfortunately, it is very hard to probe it reliably, since - * we have no way to reset the chip under software control. - * On cold boot, we could check the "signature" bit patterns - * described in the Fujitsu document. On warm boot, however, - * we can predict almost nothing about register values. - */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Check if our I/O address matches config info on 86965. */ - n = (inb(sc->ioaddr[FE_BMPR19]) & FE_B19_ADDR) >> FE_B19_ADDR_SHIFT; - if (baseaddr[n] != sc->iobase) return 0; - - /* - * We are now almost sure we have an MB86965 at the given - * address. So, read EEPROM through it. We have to write - * into LSI registers to read from EEPROM. I want to avoid it - * at this stage, but I cannot test the presence of the chip - * any further without reading EEPROM. FIXME. - */ - fe_read_eeprom_jli(sc, eeprom); - - /* Make sure that config info in EEPROM and 86965 agree. */ - if (eeprom[FE_EEPROM_CONF] != inb(sc->ioaddr[FE_BMPR19])) { - return 0; - } - - /* Use 86965 media selection scheme, unless othewise - specified. It is "AUTO always" and "select with BMPR13". - This behaviour covers most of the 86965 based board (as - minimum requirements.) It is backward compatible with - previous versions, also. */ - sc->mbitmap = MB_HA; - sc->defmedia = MB_HA; - sc->msel = fe_msel_965; - - /* Perform board-specific probe. */ - if ((irqmap = fe_probe_jli_re1000p(sc, eeprom)) == NULL) return 0; - - /* Find the IRQ read from EEPROM. */ - n = (inb(sc->ioaddr[FE_BMPR19]) & FE_B19_IRQ) >> FE_B19_IRQ_SHIFT; - irq = irqmap[n]; - - /* Try to determine IRQ setting. */ - if (dev->id_irq == NO_IRQ && irq == NO_IRQ) { - /* The device must be configured with an explicit IRQ. */ - printf("fe%d: IRQ auto-detection does not work\n", - sc->sc_unit); - return 0; - } else if (dev->id_irq == NO_IRQ && irq != NO_IRQ) { - /* Just use the probed IRQ value. */ - dev->id_irq = irq; - } else if (dev->id_irq != NO_IRQ && irq == NO_IRQ) { - /* No problem. Go ahead. */ - } else if (dev->id_irq == irq) { - /* Good. Go ahead. */ - } else { - /* User must be warned in this case. */ - sc->stability |= UNSTABLE_IRQ; - } - - /* Setup a hook, which resets te 86965 when the driver is being - initialized. This may solve a nasty bug. FIXME. */ - sc->init = fe_init_jli; - - /* The I/O address range is fragmented in the RE1000Plus. - It occupies 2*16 I/O addresses, by the way. */ - return 2; -} - -/* - * Probe and initialization for Contec C-NET(9N)E series. - */ - -/* TODO: Should be in "if_fereg.h" */ -#define FE_CNET9NE_INTR 0x10 /* Interrupt Mask? */ - -static void -fe_init_cnet9ne ( struct fe_softc * sc ) -{ - /* Enable interrupt? FIXME. */ - outb(sc->ioaddr[FE_CNET9NE_INTR], 0x10); -} - -static int -fe_probe_cnet9ne ( struct isa_device * dev, struct fe_softc * sc ) -{ - int i; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - static u_short ioaddr[MAXREGISTERS - 16] = { - /* 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, */ - /* 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, */ - 0x400, 0x402, 0x404, 0x406, 0x408, 0x40a, 0x40c, 0x40e, - 0x401, 0x403, 0x405, 0x407, 0x409, 0x40b, 0x40d, 0x40f, - }; - - /* See if the specified I/O address is possible for C-NET(9N)E. */ - if (sc->iobase != 0x73D0) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for C-NET(9N)E. */ - for (i = 16; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + ioaddr[i - 16]; - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Get our station address from EEPROM. */ - inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* Make sure it is Contec's. */ - if (!valid_Ether_p(sc->sc_enaddr, 0x00804C)) return 0; - - /* Determine the card type. */ - if (sc->sc_enaddr[3] == 0x06) { - sc->typestr = "C-NET(9N)C"; - - /* We seems to need our own IDENT bits... FIXME. */ - sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; - - /* C-NET(9N)C requires an explicit IRQ to work. */ - if (dev->id_irq == NO_IRQ) { - fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL); - return 0; - } - } else { - sc->typestr = "C-NET(9N)E"; - - /* C-NET(9N)E works only IRQ5. */ - if (dev->id_irq != IRQ5) { - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "5"); - return 0; - } - - /* We need an init hook to initialize ASIC before we start. */ - sc->init = fe_init_cnet9ne; - } - - /* C-NET(9N)E has 64KB SRAM. */ - sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB - | FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM; - - /* The I/O address range is fragmented in the C-NET(9N)E. - This is the number of regs at iobase. */ - return 16; -} - -/* - * Probe for Contec C-NET(98)P2 series. - * (Logitec LAN-98TP/LAN-98T25P - parhaps) - */ -static int -fe_probe_ssi (struct isa_device *dev, struct fe_softc *sc) -{ - u_char eeprom [SSI_EEPROM_SIZE]; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x08, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - static u_short const irqmap[] = { - /* INT0 INT1 INT2 */ - NO_IRQ, NO_IRQ, NO_IRQ, IRQ3 , NO_IRQ, IRQ5 , IRQ6 , NO_IRQ, - NO_IRQ, IRQ9 , IRQ10 , NO_IRQ, IRQ12 , IRQ13 , NO_IRQ, NO_IRQ, - /* INT3 INT41 INT5 INT6 */ - }; - - /* See if the specified I/O address is possible for 78Q8377A. */ - /* [0-D]3D0 are allowed. */ - if ((sc->iobase & 0xFFF) != 0x3D0) return 0; /* XXX */ - - /* Fill the softc struct with default values. */ - fe_softc_defaults(sc); - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* We now have to read the config EEPROM. We should be very - careful, since doing so destroys a register. (Remember, we - are not yet sure we have a C-NET(98)P2 board here.) Don't - remember to select BMPRs bofore reading EEPROM, since other - register bank may be selected before the probe() is called. */ - fe_read_eeprom_ssi(sc, eeprom); - - /* Make sure the Ethernet (MAC) station address is of Contec's. */ - if (!valid_Ether_p(eeprom+FE_SSI_EEP_ADDR, 0x00804C)) return 0; - bcopy(eeprom+FE_SSI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* Setup the board type. */ - sc->typestr = "C-NET(98)P2"; - - /* Get IRQ configuration from EEPROM. */ - dev->id_irq = irqmap[eeprom[FE_SSI_EEP_IRQ]]; - if (dev->id_irq == NO_IRQ) { - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "3/5/6/9/10/12/13"); - return 0; - } - - /* Get Duplex-mode configuration from EEPROM. */ - sc->proto_dlcr4 |= (eeprom[FE_SSI_EEP_DUPLEX] & FE_D4_DSC); - - /* Fill softc struct accordingly. */ - sc->mbitmap = MB_HT; - sc->defmedia = MB_HT; - - /* We have 16 registers. */ - return 16; -} - -/* - * Probe for TDK LAC-98012/013/025/9N011 - parhaps. - */ -static int -fe_probe_lnx (struct isa_device *dev, struct fe_softc *sc) -{ -#ifndef FE_8BIT_SUPPORT - printf("fe%d: skip LAC-98012/013(only 16-bit cards are supported)\n", - sc->sc_unit); - return 0; -#else - int i; - u_char eeprom [LNX_EEPROM_SIZE]; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for TDK/LANX boards. */ - /* 0D0, 4D0, 8D0, and CD0 are allowed. */ - if ((sc->iobase & ~0xC00) != 0xD0) return 0; - - /* Fill the softc struct with default values. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for LAC-98. - * 0x000, 0x002, 0x004, 0x006, 0x008, 0x00a, 0x00c, 0x00e, - * 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, - * 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, - * 0x300, 0x302, 0x304, 0x306, 0x308, 0x30a, 0x30c, 0x30e, - */ - for (i = 0; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + ((i & 7) << 1) + ((i & 0x18) << 5); - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* We now have to read the config EEPROM. We should be very - careful, since doing so destroys a register. (Remember, we - are not yet sure we have a LAC-98012/98013 board here.) */ - fe_read_eeprom_lnx(sc, eeprom); - - /* Make sure the Ethernet (MAC) station address is of TDK/LANX's. */ - if (!valid_Ether_p(eeprom, 0x008098)) return 0; - bcopy(eeprom, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* Setup the board type. */ - sc->typestr = "LAC-98012/98013"; - - /* This looks like a TDK/LANX board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3 : sc->priv_info = 0x10 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ5 : sc->priv_info = 0x20 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ6 : sc->priv_info = 0x40 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ12: sc->priv_info = 0x80 | LNX_CLK_LO | LNX_SDA_HI; break; - default: - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "3/5/6/12"); - return 0; - } - - /* LAC-98's system bus width is 8-bit. */ - sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x2KB - | FE_D6_BBW_BYTE | FE_D6_SBW_BYTE | FE_D6_SRAM_150ns; - - /* Setup hooks. We need a special initialization procedure. */ - sc->init = fe_init_lnx; - - /* The I/O address range is fragmented in the LAC-98. - It occupies 16*4 I/O addresses, by the way. */ - return 16; -#endif /* FE_8BIT_SUPPORT */ -} - -/* - * Probe for Gateway Communications' old cards. - * (both as Generic MB86960 probe routine) - */ -static int -fe_probe_gwy ( struct isa_device * dev, struct fe_softc * sc ) -{ - static struct fe_simple_probe_struct probe_table [] = { - /* { FE_DLCR2, 0x70, 0x00 }, */ - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* I'm not sure which address is possible, so accepts any. FIXME. */ - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Does we need to re-map ioaddr? FIXME. */ - - /* See if the card is on its address. */ - if ( !fe_simple_probe( sc, probe_table ) ) return 0; - - /* Get our station address from EEPROM. */ - inblk( sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN ); - if (!valid_Ether_p(sc->sc_enaddr, 0x000000)) return 0; - - /* Determine the card type. */ - sc->typestr = "Generic MB86960 Ethernet"; - if (valid_Ether_p(sc->sc_enaddr, 0x000061)) - sc->typestr = "Gateway Ethernet (Fujitsu chipset)"; - - /* Gateway's board requires an explicit IRQ to work, since it - is not possible to probe the setting of jumpers. */ - if (dev->id_irq == NO_IRQ) { - fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL); - return 0; - } - - /* We should change return value when re-mapping ioaddr. FIXME. */ - return 32; -} - -/* - * Probe for Ungermann-Bass Access/PC N98C+(Model 85152). - */ -static int -fe_probe_ubn (struct isa_device * dev, struct fe_softc * sc) -{ - u_char sum, save7; - int i; - static struct fe_simple_probe_struct const probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for Access/PC. */ - /* [01][048C]D0 are allowed. */ - if ((sc->iobase & ~0x1C00) != 0xD0) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for Access/PC N98C+. - * 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, - * 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, - * 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, - * 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f, - */ - for (i = 16; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + 0x200 - 16 + i; - - /* Simple probe. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* NOTE: Access/NOTE N98 sometimes freeze when reading station - address. In case of using it togather with C-NET(9N)C, - this problem usually happens. - Writing DLCR7 prevents freezing, but I don't know why. FIXME. */ - - /* Save the current value for the DLCR7 register we are about - to destroy. */ - save7 = inb(sc->ioaddr[FE_DLCR7]); - outb(sc->ioaddr[FE_DLCR7], - sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP); - - /* Get our station address form ID ROM and make sure it is UBN's. */ - inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); - if (!valid_Ether_p(sc->sc_enaddr, 0x00DD01)) goto fail_ubn; -#if 1 - /* Calculate checksum. */ - sum = inb(sc->ioaddr[0x1e]); - for (i = 0; i < ETHER_ADDR_LEN; i++) { - sum ^= sc->sc_enaddr[i]; - } - if (sum != 0) goto fail_ubn; -#endif - /* Setup the board type. */ - sc->typestr = "Access/PC"; - - /* This looks like an AccessPC/N98C+ board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3: sc->priv_info = 0x01; break; - case IRQ5: sc->priv_info = 0x02; break; - case IRQ6: sc->priv_info = 0x04; break; - case IRQ12: sc->priv_info = 0x08; break; - default: - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "3/5/6/12"); - goto fail_ubn; - } - - /* Setup hooks. We need a special initialization procedure. */ - sc->init = fe_init_ubn; - - /* The I/O address range is fragmented in the Access/PC N98C+. - This is the number of regs at iobase. */ - return 16; - -fail_ubn: - outb(sc->ioaddr[FE_DLCR7], save7); - return 0; -} - -/* - * REX boards(non-JLI type) support routine. - */ - -#define REX_EEPROM_SIZE 32 -#define REX_DAT 0x01 - -static void -fe_read_eeprom_rex (struct fe_softc *sc, u_char *data) -{ - int i; - u_char bit, val; - u_char save16; - u_short reg16 = sc->ioaddr[0x10]; - - save16 = inb(reg16); - - /* Issue a start condition. */ - val = inb(reg16) & 0xf0; - outb(reg16, val); - - (void)inb(reg16); - (void)inb(reg16); - (void)inb(reg16); - (void)inb(reg16); - - /* Read bytes from EEPROM. */ - for (i = 0; i < REX_EEPROM_SIZE; i++) { - /* Read a byte and store it into the buffer. */ - val = 0x00; - for (bit = 0x01; bit != 0x00; bit <<= 1) { - if (inb(reg16) & REX_DAT) val |= bit; - } - *data++ = val; - } - - outb(reg16, save16); - -#if 1 - /* Report what we got. */ - if (bootverbose) { - data -= REX_EEPROM_SIZE; - for (i = 0; i < REX_EEPROM_SIZE; i += 16) { - printf("fe%d: EEPROM(REX):%3x: %16D\n", - sc->sc_unit, i, data + i, " "); - } - } -#endif -} - -static void -fe_init_rex ( struct fe_softc * sc ) -{ - /* Setup IRQ control register on the ASIC. */ - outb(sc->ioaddr[0x10], sc->priv_info); -} - -/* - * Probe for RATOC REX-9880/81/82/83 series. - */ -static int -fe_probe_rex (struct isa_device * dev, struct fe_softc * sc) -{ - int i; - u_char eeprom [REX_EEPROM_SIZE]; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for REX-9880. */ - /* 6[46CE]D0 are allowed. */ - if ((sc->iobase & ~0xA00) != 0x64D0) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Re-map ioaddr for REX-9880. */ - for (i = 16; i < MAXREGISTERS; i++) - sc->ioaddr[i] = sc->iobase + 0x100 - 16 + i; - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* We now have to read the config EEPROM. We should be very - careful, since doing so destroys a register. (Remember, we - are not yet sure we have a REX-9880 board here.) */ - fe_read_eeprom_rex(sc, eeprom); - for (i = 0; i < ETHER_ADDR_LEN; i++) - sc->sc_enaddr[i] = eeprom[7 - i]; - - /* Make sure it is RATOC's. */ - if (!valid_Ether_p(sc->sc_enaddr, 0x00C0D0)) return 0; - - /* Setup the board type. */ - sc->typestr = "REX-9880/9883"; - - /* This looks like a REX-9880 board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3: sc->priv_info = 0x10; break; - case IRQ5: sc->priv_info = 0x20; break; - case IRQ6: sc->priv_info = 0x40; break; - case IRQ12: sc->priv_info = 0x80; break; - default: - fe_irq_failure(sc->typestr, - sc->sc_unit, dev->id_irq, "3/5/6/12"); - return 0; - } - - /* Setup hooks. We need a special initialization procedure. */ - sc->init = fe_init_rex; - - /* REX-9880 has 64KB SRAM. */ - sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB - | FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM; -#if 1 - sc->proto_dlcr7 |= FE_D7_EOPPOL; /* XXX */ -#endif - /* The I/O address range is fragmented in the REX-9880. - This is the number of regs at iobase. */ - return 16; -} -#else /* !PC98 */ -/* - * Probe and initialization for Fujitsu FMV-180 series boards - */ - -static void -fe_init_fmv (struct fe_softc *sc) -{ - /* Initialize ASIC. */ - outb( sc->ioaddr[ FE_FMV3 ], 0 ); - outb( sc->ioaddr[ FE_FMV10 ], 0 ); - -#if 0 - /* "Refresh" hardware configuration. FIXME. */ - outb( sc->ioaddr[ FE_FMV2 ], inb( sc->ioaddr[ FE_FMV2 ] ) ); -#endif - - /* Turn the "master interrupt control" flag of ASIC on. */ - outb( sc->ioaddr[ FE_FMV3 ], FE_FMV3_IRQENB ); -} - -static void -fe_msel_fmv184 (struct fe_softc *sc) -{ - u_char port; - - /* FMV-184 has a special "register" to switch between AUI/BNC. - Determine the value to write into the register, based on the - user-specified media selection. */ - port = (IFM_SUBTYPE(sc->media.ifm_media) == IFM_10_2) ? 0x00 : 0x01; - - /* The register is #5 on exntesion register bank... - (Details of the register layout is not yet discovered.) */ - outb(sc->ioaddr[0x1B], 0x46); /* ??? */ - outb(sc->ioaddr[0x1E], 0x04); /* select ex-reg #4. */ - outb(sc->ioaddr[0x1F], 0xC8); /* ??? */ - outb(sc->ioaddr[0x1E], 0x05); /* select ex-reg #5. */ - outb(sc->ioaddr[0x1F], port); /* Switch the media. */ - outb(sc->ioaddr[0x1E], 0x04); /* select ex-reg #4. */ - outb(sc->ioaddr[0x1F], 0x00); /* ??? */ - outb(sc->ioaddr[0x1B], 0x00); /* ??? */ - - /* Make sure to select "external tranceiver" on MB86964. */ - outb(sc->ioaddr[FE_BMPR13], sc->proto_bmpr13 | FE_B13_PORT_AUI); -} - -static int -fe_probe_fmv ( struct isa_device * dev, struct fe_softc * sc ) -{ - int n; - - static u_short const irqmap [ 4 ] = - { IRQ3, IRQ7, IRQ10, IRQ15 }; - - static struct fe_simple_probe_struct const probe_table [] = { - { FE_DLCR2, 0x71, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - - { FE_FMV0, 0x78, 0x50 }, /* ERRDY+PRRDY */ - { FE_FMV1, 0xB0, 0x00 }, /* FMV-183/4 has 0x48 bits. */ - { FE_FMV3, 0x7F, 0x00 }, - - { 0 } - }; - - /* Board subtypes; it lists known FMV-180 variants. */ - struct subtype { - u_short mcode; - u_short mbitmap; - u_short defmedia; - char const * str; - }; - static struct subtype const typelist [] = { - { 0x0005, MB_HA|MB_HT|MB_H5, MB_HA, "FMV-181" }, - { 0x0105, MB_HA|MB_HT|MB_H5, MB_HA, "FMV-181A" }, - { 0x0003, MB_HM, MB_HM, "FMV-182" }, - { 0x0103, MB_HM, MB_HM, "FMV-182A" }, - { 0x0804, MB_HT, MB_HT, "FMV-183" }, - { 0x0C04, MB_HT, MB_HT, "FMV-183 (on-board)" }, - { 0x0803, MB_H2|MB_H5, MB_H2, "FMV-184" }, - { 0, MB_HA, MB_HA, "unknown FMV-180 (?)" }, - }; - struct subtype const * type; - - /* Media indicator and "Hardware revision ID" */ - u_short mcode; - - /* See if the specified address is possible for FMV-180 - series. 220, 240, 260, 280, 2A0, 2C0, 300, and 340 are - allowed for all boards, and 200, 2E0, 320, 360, 380, 3A0, - 3C0, and 3E0 for PnP boards. */ - if ((sc->iobase & ~0x1E0) != 0x200) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Simple probe. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Get our station address from EEPROM, and make sure it is - Fujitsu's. */ - inblk(sc, FE_FMV4, sc->sc_enaddr, ETHER_ADDR_LEN); - if (!valid_Ether_p(sc->sc_enaddr, 0x00000E)) return 0; - - /* Find the supported media and "hardware revision" to know - the model identification. */ - mcode = (inb(sc->ioaddr[FE_FMV0]) & FE_FMV0_MEDIA) - | ((inb(sc->ioaddr[FE_FMV1]) & FE_FMV1_REV) << 8); - - /* Determine the card type. */ - for (type = typelist; type->mcode != 0; type++) { - if (type->mcode == mcode) break; - } - if (type->mcode == 0) { - /* Unknown card type... Hope the driver works. */ - sc->stability |= UNSTABLE_TYPE; - if (bootverbose) { - printf("fe%d: unknown config: %x-%x-%x-%x\n", - sc->sc_unit, - inb(sc->ioaddr[FE_FMV0]), - inb(sc->ioaddr[FE_FMV1]), - inb(sc->ioaddr[FE_FMV2]), - inb(sc->ioaddr[FE_FMV3])); - } - } - - /* Setup the board type and media information. */ - sc->typestr = type->str; - sc->mbitmap = type->mbitmap; - sc->defmedia = type->defmedia; - sc->msel = fe_msel_965; - - if (type->mbitmap == (MB_H2 | MB_H5)) { - /* FMV184 requires a special media selection procedure. */ - sc->msel = fe_msel_fmv184; - } - - /* - * An FMV-180 has been probed. - * Determine which IRQ to be used. - * - * In this version, we give a priority to the kernel config file. - * If the EEPROM and config don't match, say it to the user for - * an attention. - */ - n = ( inb( sc->ioaddr[ FE_FMV2 ] ) & FE_FMV2_IRS ) - >> FE_FMV2_IRS_SHIFT; - if ( dev->id_irq == NO_IRQ ) { - /* Just use the probed value. */ - dev->id_irq = irqmap[ n ]; - } else if ( dev->id_irq != irqmap[ n ] ) { - /* Don't match. */ - sc->stability |= UNSTABLE_IRQ; - } - - /* We need an init hook to initialize ASIC before we start. */ - sc->init = fe_init_fmv; - - /* - * That's all. FMV-180 occupies 32 I/O addresses, by the way. - */ - return 32; -} - -/* - * Fujitsu MB86965 JLI mode probe routines. - * - * 86965 has a special operating mode called JLI (mode 0), under which - * the chip interfaces with ISA bus with a software-programmable - * configuration. (The Fujitsu document calls the feature "Plug and - * play," but it is not compatible with the ISA-PnP spec. designed by - * Intel and Microsoft.) Ethernet cards designed to use JLI are - * almost same, but there are two things which require board-specific - * probe routines: EEPROM layout and IRQ pin connection. - * - * JLI provides a handy way to access EEPROM which should contains the - * chip configuration information (such as I/O port address) as well - * as Ethernet station (MAC) address. The chip configuration info. is - * stored on a fixed location. However, the station address can be - * located anywhere in the EEPROM; it is up to the board designer to - * determine the location. (The manual just says "somewhere in the - * EEPROM.") The fe driver must somehow find out the correct - * location. - * - * Another problem resides in the IRQ pin connection. JLI provides a - * user to choose an IRQ from up to four predefined IRQs. The 86965 - * chip has a register to select one out of the four possibilities. - * However, the selection is against the four IRQ pins on the chip. - * (So-called IRQ-A, -B, -C and -D.) It is (again) up to the board - * designer to determine which pin to connect which IRQ line on the - * ISA bus. We need a vendor (or model, for some vendor) specific IRQ - * mapping table. - * - * The routine fe_probe_jli() provides all probe and initialization - * processes which are common to all JLI implementation, and sub-probe - * routines supply board-specific actions. - * - * JLI sub-probe routine has the following template: - * - * u_short const * func (struct fe_softc * sc, u_char const * eeprom); - * - * where eeprom is a pointer to an array of 32 byte data read from the - * config EEPROM on the board. It retuns an IRQ mapping table for the - * board, when the corresponding implementation is detected. It - * returns a NULL otherwise. - * - * Primary purpose of the functin is to analize the config EEPROM, - * determine if it matches with the pattern of that of supported card, - * and extract necessary information from it. One of the information - * expected to be extracted from EEPROM is the Ethernet station (MAC) - * address, which must be set to the softc table of the interface by - * the board-specific routine. - */ - -/* JLI sub-probe for Allied-Telesyn/Allied-Telesis AT1700/RE2000 series. */ -static u_short const * -fe_probe_jli_ati (struct fe_softc * sc, u_char const * eeprom) -{ - int i; - static u_short const irqmaps_ati [4][4] = - { - { IRQ3, IRQ4, IRQ5, IRQ9 }, - { IRQ10, IRQ11, IRQ12, IRQ15 }, - { IRQ3, IRQ11, IRQ5, IRQ15 }, - { IRQ10, IRQ11, IRQ14, IRQ15 }, - }; - - /* Make sure the EEPROM contains Allied-Telesis/Allied-Telesyn - bit pattern. */ - if (eeprom[1] != 0x00) return NULL; - for (i = 2; i < 8; i++) if (eeprom[i] != 0xFF) return NULL; - for (i = 14; i < 24; i++) if (eeprom[i] != 0xFF) return NULL; - - /* Get our station address from EEPROM, and make sure the - EEPROM contains ATI's address. */ - bcopy(eeprom+8, sc->sc_enaddr, ETHER_ADDR_LEN); - if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) return NULL; - - /* - * The following model identification codes are stolen - * from the NetBSD port of the fe driver. My reviewers - * suggested minor revision. - */ - - /* Determine the card type. */ - switch (eeprom[FE_ATI_EEP_MODEL]) { - case FE_ATI_MODEL_AT1700T: - sc->typestr = "AT-1700T/RE2001"; - sc->mbitmap = MB_HT; - sc->defmedia = MB_HT; - break; - case FE_ATI_MODEL_AT1700BT: - sc->typestr = "AT-1700BT/RE2003"; - sc->mbitmap = MB_HA | MB_HT | MB_H2; - break; - case FE_ATI_MODEL_AT1700FT: - sc->typestr = "AT-1700FT/RE2009"; - sc->mbitmap = MB_HA | MB_HT | MB_HF; - break; - case FE_ATI_MODEL_AT1700AT: - sc->typestr = "AT-1700AT/RE2005"; - sc->mbitmap = MB_HA | MB_HT | MB_H5; - break; - default: - sc->typestr = "unknown AT-1700/RE2000"; - sc->stability |= UNSTABLE_TYPE | UNSTABLE_IRQ; - break; - } - -#if 0 - /* Should we extract default media from eeprom? Linux driver - for AT1700 does it, although previous releases of FreeBSD - don't. FIXME. */ - /* Determine the default media selection from the config - EEPROM. The byte at offset EEP_MEDIA is believed to - contain BMPR13 value to be set. We just ignore STP bit or - squelch bit, since we don't support those. (It is - intentional.) */ - switch (eeprom[FE_ATI_EEP_MEDIA] & FE_B13_PORT) { - case FE_B13_AUTO: - sc->defmedia = MB_HA; - break; - case FE_B13_TP: - sc->defmedia = MB_HT; - break; - case FE_B13_AUI: - sc->defmedia = sc->mbitmap & (MB_H2|MB_H5|MB_H5); /*XXX*/ - break; - default: - sc->defmedia = MB_HA; - break; - } - - /* Make sure the default media is compatible with the supported - ones. */ - if ((sc->defmedia & sc->mbitmap) == 0) { - if (sc->defmedia == MB_HA) { - sc->defmedia = MB_HT; - } else { - sc->defmedia = MB_HA; - } - } -#endif - - /* - * Try to determine IRQ settings. - * Different models use different ranges of IRQs. - */ - switch ((eeprom[FE_ATI_EEP_REVISION] & 0xf0) - |(eeprom[FE_ATI_EEP_MAGIC] & 0x04)) { - case 0x30: case 0x34: return irqmaps_ati[3]; - case 0x10: case 0x14: - case 0x50: case 0x54: return irqmaps_ati[2]; - case 0x44: case 0x64: return irqmaps_ati[1]; - default: return irqmaps_ati[0]; - } -} - -/* JLI sub-probe and msel hook for ICL Ethernet. */ - -static void -fe_msel_icl (struct fe_softc *sc) -{ - u_char d4; - - /* Switch between UTP and "external tranceiver" as always. */ - fe_msel_965(sc); - - /* The board needs one more bit (on DLCR4) be set appropriately. */ - if (IFM_SUBTYPE(sc->media.ifm_media) == IFM_10_5) { - d4 = sc->proto_dlcr4 | FE_D4_CNTRL; - } else { - d4 = sc->proto_dlcr4 & ~FE_D4_CNTRL; - } - outb(sc->ioaddr[FE_DLCR4], d4); -} - -static u_short const * -fe_probe_jli_icl (struct fe_softc * sc, u_char const * eeprom) -{ - int i; - u_short defmedia; - u_char d6; - static u_short const irqmap_icl [4] = { IRQ9, IRQ10, IRQ5, IRQ15 }; - - /* Make sure the EEPROM contains ICL bit pattern. */ - for (i = 24; i < 39; i++) { - if (eeprom[i] != 0x20 && (eeprom[i] & 0xF0) != 0x30) return NULL; - } - for (i = 112; i < 122; i++) { - if (eeprom[i] != 0x20 && (eeprom[i] & 0xF0) != 0x30) return NULL; - } - - /* Make sure the EEPROM contains ICL's permanent station - address. If it isn't, probably this board is not an - ICL's. */ - if (!valid_Ether_p(eeprom+122, 0x00004B)) return NULL; - - /* Check if the "configured" Ethernet address in the EEPROM is - valid. Use it if it is, or use the "permanent" address instead. */ - if (valid_Ether_p(eeprom+4, 0x020000)) { - /* The configured address is valid. Use it. */ - bcopy(eeprom+4, sc->sc_enaddr, ETHER_ADDR_LEN); - } else { - /* The configured address is invalid. Use permanent. */ - bcopy(eeprom+122, sc->sc_enaddr, ETHER_ADDR_LEN); - } - - /* Determine model and supported media. */ - switch (eeprom[0x5E]) { - case 0: - sc->typestr = "EtherTeam16i/COMBO"; - sc->mbitmap = MB_HA | MB_HT | MB_H5 | MB_H2; - break; - case 1: - sc->typestr = "EtherTeam16i/TP"; - sc->mbitmap = MB_HT; - break; - case 2: - sc->typestr = "EtherTeam16i/ErgoPro"; - sc->mbitmap = MB_HA | MB_HT | MB_H5; - break; - case 4: - sc->typestr = "EtherTeam16i/DUO"; - sc->mbitmap = MB_HA | MB_HT | MB_H2; - break; - default: - sc->typestr = "EtherTeam16i"; - sc->stability |= UNSTABLE_TYPE; - if (bootverbose) { - printf("fe%d: unknown model code %02x for EtherTeam16i\n", - sc->sc_unit, eeprom[0x5E]); - } - break; - } - - /* I'm not sure the following msel hook is required by all - models or COMBO only... FIXME. */ - sc->msel = fe_msel_icl; - - /* Make the configured media selection the default media. */ - switch (eeprom[0x28]) { - case 0: defmedia = MB_HA; break; - case 1: defmedia = MB_H5; break; - case 2: defmedia = MB_HT; break; - case 3: defmedia = MB_H2; break; - default: - if (bootverbose) { - printf("fe%d: unknown default media: %02x\n", - sc->sc_unit, eeprom[0x28]); - } - defmedia = MB_HA; - break; - } - - /* Make sure the default media is compatible with the - supported media. */ - if ((defmedia & sc->mbitmap) == 0) { - if (bootverbose) { - printf("fe%d: default media adjusted\n", sc->sc_unit); - } - defmedia = sc->mbitmap; - } - - /* Keep the determined default media. */ - sc->defmedia = defmedia; - - /* ICL has "fat" models. We have to program 86965 to properly - reflect the hardware. */ - d6 = sc->proto_dlcr6 & ~(FE_D6_BUFSIZ | FE_D6_BBW); - switch ((eeprom[0x61] << 8) | eeprom[0x60]) { - case 0x2008: d6 |= FE_D6_BUFSIZ_32KB | FE_D6_BBW_BYTE; break; - case 0x4010: d6 |= FE_D6_BUFSIZ_64KB | FE_D6_BBW_WORD; break; - default: - /* We can't support it, since we don't know which bits - to set in DLCR6. */ - printf("fe%d: unknown SRAM config for ICL\n", sc->sc_unit); - return NULL; - } - sc->proto_dlcr6 = d6; - - /* Returns the IRQ table for the ICL board. */ - return irqmap_icl; -} - -/* JLI sub-probe for RATOC REX-5586/5587. */ -static u_short const * -fe_probe_jli_rex (struct fe_softc * sc, u_char const * eeprom) -{ - int i; - static u_short const irqmap_rex [4] = { IRQ3, IRQ4, IRQ5, NO_IRQ }; - - /* Make sure the EEPROM contains RATOC's config pattern. */ - if (eeprom[1] != eeprom[0]) return NULL; - for (i = 8; i < 32; i++) if (eeprom[i] != 0xFF) return NULL; - - /* Get our station address from EEPROM. Note that RATOC - stores it "byte-swapped" in each word. (I don't know why.) - So, we just can't use bcopy().*/ - sc->sc_enaddr[0] = eeprom[3]; - sc->sc_enaddr[1] = eeprom[2]; - sc->sc_enaddr[2] = eeprom[5]; - sc->sc_enaddr[3] = eeprom[4]; - sc->sc_enaddr[4] = eeprom[7]; - sc->sc_enaddr[5] = eeprom[6]; - - /* Make sure the EEPROM contains RATOC's station address. */ - if (!valid_Ether_p(sc->sc_enaddr, 0x00C0D0)) return NULL; - - /* I don't know any sub-model identification. */ - sc->typestr = "REX-5586/5587"; - - /* Returns the IRQ for the RATOC board. */ - return irqmap_rex; -} - -/* JLI sub-probe for Unknown board. */ -static u_short const * -fe_probe_jli_unk (struct fe_softc * sc, u_char const * eeprom) -{ - int i, n, romsize; - static u_short const irqmap [4] = { NO_IRQ, NO_IRQ, NO_IRQ, NO_IRQ }; - - /* The generic JLI probe considered this board has an 86965 - in JLI mode, but any other board-specific routines could - not find the matching implementation. So, we "guess" the - location by looking for a bit pattern which looks like a - MAC address. */ - - /* Determine how large the EEPROM is. */ - for (romsize = JLI_EEPROM_SIZE/2; romsize > 16; romsize >>= 1) { - for (i = 0; i < romsize; i++) { - if (eeprom[i] != eeprom[i+romsize]) break; - } - if (i < romsize) break; - } - romsize <<= 1; - - /* Look for a bit pattern which looks like a MAC address. */ - for (n = 2; n <= romsize - ETHER_ADDR_LEN; n += 2) { - if (!valid_Ether_p(eeprom + n, 0x000000)) continue; - } - - /* If no reasonable address was found, we can't go further. */ - if (n > romsize - ETHER_ADDR_LEN) return NULL; - - /* Extract our (guessed) station address. */ - bcopy(eeprom+n, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* We are not sure what type of board it is... */ - sc->typestr = "(unknown JLI)"; - sc->stability |= UNSTABLE_TYPE | UNSTABLE_MAC; - - /* Returns the totally unknown IRQ mapping table. */ - return irqmap; -} - -/* - * Probe and initialization for all JLI implementations. - */ - -static int -fe_probe_jli (struct isa_device * dev, struct fe_softc * sc) -{ - int i, n; - int irq; - u_char eeprom [JLI_EEPROM_SIZE]; - u_short const * irqmap; - - static u_short const baseaddr [8] = - { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300 }; - static struct fe_simple_probe_struct const probe_table [] = { - { FE_DLCR1, 0x20, 0x00 }, - { FE_DLCR2, 0x50, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { FE_DLCR5, 0x80, 0x00 }, -#if 0 - { FE_BMPR16, 0x1B, 0x00 }, - { FE_BMPR17, 0x7F, 0x00 }, -#endif - { 0 } - }; - - /* - * See if the specified address is possible for MB86965A JLI mode. - */ - for (i = 0; i < 8; i++) { - if (baseaddr[i] == sc->iobase) break; - } - if (i == 8) return 0; - - /* Fill the softc struct with reasonable default. */ - fe_softc_defaults(sc); - - /* - * We should test if MB86965A is on the base address now. - * Unfortunately, it is very hard to probe it reliably, since - * we have no way to reset the chip under software control. - * On cold boot, we could check the "signature" bit patterns - * described in the Fujitsu document. On warm boot, however, - * we can predict almost nothing about register values. - */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Check if our I/O address matches config info on 86965. */ - n = (inb(sc->ioaddr[FE_BMPR19]) & FE_B19_ADDR) >> FE_B19_ADDR_SHIFT; - if (baseaddr[n] != sc->iobase) return 0; - - /* - * We are now almost sure we have an MB86965 at the given - * address. So, read EEPROM through it. We have to write - * into LSI registers to read from EEPROM. I want to avoid it - * at this stage, but I cannot test the presence of the chip - * any further without reading EEPROM. FIXME. - */ - fe_read_eeprom_jli(sc, eeprom); - - /* Make sure that config info in EEPROM and 86965 agree. */ - if (eeprom[FE_EEPROM_CONF] != inb(sc->ioaddr[FE_BMPR19])) { - return 0; - } - - /* Use 86965 media selection scheme, unless othewise - specified. It is "AUTO always" and "select with BMPR13." - This behaviour covers most of the 86965 based board (as - minimum requirements.) It is backward compatible with - previous versions, also. */ - sc->mbitmap = MB_HA; - sc->defmedia = MB_HA; - sc->msel = fe_msel_965; - - /* Perform board-specific probe, one by one. Note that the - order of probe is important and should not be changed - arbitrarily. */ - if ((irqmap = fe_probe_jli_ati(sc, eeprom)) == NULL - && (irqmap = fe_probe_jli_rex(sc, eeprom)) == NULL - && (irqmap = fe_probe_jli_icl(sc, eeprom)) == NULL - && (irqmap = fe_probe_jli_unk(sc, eeprom)) == NULL) return 0; - - /* Find the IRQ read from EEPROM. */ - n = (inb(sc->ioaddr[FE_BMPR19]) & FE_B19_IRQ) >> FE_B19_IRQ_SHIFT; - irq = irqmap[n]; - - /* Try to determine IRQ setting. */ - if (dev->id_irq == NO_IRQ && irq == NO_IRQ) { - /* The device must be configured with an explicit IRQ. */ - printf("fe%d: IRQ auto-detection does not work\n", - sc->sc_unit); - return 0; - } else if (dev->id_irq == NO_IRQ && irq != NO_IRQ) { - /* Just use the probed IRQ value. */ - dev->id_irq = irq; - } else if (dev->id_irq != NO_IRQ && irq == NO_IRQ) { - /* No problem. Go ahead. */ - } else if (dev->id_irq == irq) { - /* Good. Go ahead. */ - } else { - /* User must be warned in this case. */ - sc->stability |= UNSTABLE_IRQ; - } - - /* Setup a hook, which resets te 86965 when the driver is being - initialized. This may solve a nasty bug. FIXME. */ - sc->init = fe_init_jli; - - /* - * That's all. 86965 JLI occupies 32 I/O addresses, by the way. - */ - return 32; -} - -/* Probe for TDK LAK-AX031, which is an SSi 78Q8377A based board. */ - -static int -fe_probe_ssi (struct isa_device *dev, struct fe_softc *sc) -{ - u_char eeprom [SSI_EEPROM_SIZE]; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x08, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for 78Q8377A. */ - if ((sc->iobase & ~0x3F0) != 0x000) return 0; - - /* Fill the softc struct with default values. */ - fe_softc_defaults(sc); - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* We now have to read the config EEPROM. We should be very - careful, since doing so destroys a register. (Remember, we - are not yet sure we have a LAK-AX031 board here.) Don't - remember to select BMPRs bofore reading EEPROM, since other - register bank may be selected before the probe() is called. */ - fe_read_eeprom_ssi(sc, eeprom); - - /* Make sure the Ethernet (MAC) station address is of TDK's. */ - if (!valid_Ether_p(eeprom+FE_SSI_EEP_ADDR, 0x008098)) return 0; - bcopy(eeprom+FE_SSI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* This looks like a TDK-AX031 board. It requires an explicit - IRQ setting in config, since we currently don't know how we - can find the IRQ value assigned by ISA PnP manager. */ - if (dev->id_irq == NO_IRQ) { - fe_irq_failure("LAK-AX031", sc->sc_unit, dev->id_irq, NULL); - return 0; - } - - /* Fill softc struct accordingly. */ - sc->typestr = "LAK-AX031"; - sc->mbitmap = MB_HT; - sc->defmedia = MB_HT; - - /* We have 16 registers. */ - return 16; -} - -/* - * Probe and initialization for TDK/LANX LAC-AX012/013 boards. - */ -static int -fe_probe_lnx (struct isa_device *dev, struct fe_softc *sc) -{ - u_char eeprom [LNX_EEPROM_SIZE]; - - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for TDK/LANX boards. */ - /* 300, 320, 340, and 360 are allowed. */ - if ((sc->iobase & ~0x060) != 0x300) return 0; - - /* Fill the softc struct with default values. */ - fe_softc_defaults(sc); - - /* See if the card is on its address. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* We now have to read the config EEPROM. We should be very - careful, since doing so destroys a register. (Remember, we - are not yet sure we have a LAC-AX012/AX013 board here.) */ - fe_read_eeprom_lnx(sc, eeprom); - - /* Make sure the Ethernet (MAC) station address is of TDK/LANX's. */ - if (!valid_Ether_p(eeprom, 0x008098)) return 0; - bcopy(eeprom, sc->sc_enaddr, ETHER_ADDR_LEN); - - /* This looks like a TDK/LANX board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3: sc->priv_info = 0x40 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ4: sc->priv_info = 0x20 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ5: sc->priv_info = 0x10 | LNX_CLK_LO | LNX_SDA_HI; break; - case IRQ9: sc->priv_info = 0x80 | LNX_CLK_LO | LNX_SDA_HI; break; - default: - fe_irq_failure("LAC-AX012/AX013", - sc->sc_unit, dev->id_irq, "3/4/5/9"); - return 0; - } - - /* Fill softc struct accordingly. */ - sc->typestr = "LAC-AX012/AX013"; - sc->init = fe_init_lnx; - - /* We have 32 registers. */ - return 32; -} - -/* - * Probe and initialization for Gateway Communications' old cards. - */ -static int -fe_probe_gwy ( struct isa_device * dev, struct fe_softc * sc ) -{ - static struct fe_simple_probe_struct probe_table [] = { - /* { FE_DLCR2, 0x70, 0x00 }, */ - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for Gateway boards. */ - if ((sc->iobase & ~0x1E0) != 0x200) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* See if the card is on its address. */ - if ( !fe_simple_probe( sc, probe_table ) ) return 0; - - /* Get our station address from EEPROM. */ - inblk( sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN ); - - /* Make sure it is Gateway Communication's. */ - if (!valid_Ether_p(sc->sc_enaddr, 0x000061)) return 0; - - /* Gateway's board requires an explicit IRQ to work, since it - is not possible to probe the setting of jumpers. */ - if (dev->id_irq == NO_IRQ) { - fe_irq_failure("Gateway Ethernet", sc->sc_unit, NO_IRQ, NULL); - return 0; - } - - /* Fill softc struct accordingly. */ - sc->typestr = "Gateway Ethernet (Fujitsu chipset)"; - - /* That's all. The card occupies 32 I/O addresses, as always. */ - return 32; -} - -/* Probe and initialization for Ungermann-Bass Network - K.K. "Access/PC" boards. */ -static int -fe_probe_ubn (struct isa_device * dev, struct fe_softc * sc) -{ -#if 0 - u_char sum; -#endif - static struct fe_simple_probe_struct const probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { 0 } - }; - - /* See if the specified I/O address is possible for AccessPC/ISA. */ - if ((sc->iobase & ~0x0E0) != 0x300) return 0; - - /* Setup an I/O address mapping table and some others. */ - fe_softc_defaults(sc); - - /* Simple probe. */ - if (!fe_simple_probe(sc, probe_table)) return 0; - - /* Get our station address form ID ROM and make sure it is UBN's. */ - inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); - if (!valid_Ether_p(sc->sc_enaddr, 0x00DD01)) return 0; -#if 0 - /* Calculate checksum. */ - sum = inb(sc->ioaddr[0x1e]); - for (i = 0; i < ETHER_ADDR_LEN; i++) { - sum ^= sc->sc_enaddr[i]; - } - if (sum != 0) return 0; -#endif - /* This looks like an AccessPC/ISA board. It requires an - explicit IRQ setting in config. Make sure we have one, - determining an appropriate value for the IRQ control - register. */ - switch (dev->id_irq) { - case IRQ3: sc->priv_info = 0x02; break; - case IRQ4: sc->priv_info = 0x04; break; - case IRQ5: sc->priv_info = 0x08; break; - case IRQ10: sc->priv_info = 0x10; break; - default: - fe_irq_failure("Access/PC", - sc->sc_unit, dev->id_irq, "3/4/5/10"); - return 0; - } - - /* Fill softc struct accordingly. */ - sc->typestr = "Access/PC"; - sc->init = fe_init_ubn; - - /* We have 32 registers. */ - return 32; -} -#endif /* PC98 */ - -#if NCARD > 0 -/* - * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. - * Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk(). - */ - -static void -fe_init_mbh ( struct fe_softc * sc ) -{ - /* Minimal initialization of 86960. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); - DELAY( 200 ); - - /* Disable all interrupts. */ - outb( sc->ioaddr[ FE_DLCR2 ], 0 ); - outb( sc->ioaddr[ FE_DLCR3 ], 0 ); - - /* Enable master interrupt flag. */ - outb( sc->ioaddr[ FE_MBH0 ], FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE ); -} - -static int -fe_probe_mbh ( struct isa_device * dev, struct fe_softc * sc ) -{ - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x58, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - { FE_DLCR6, 0xFF, 0xB6 }, - { 0 } - }; - -#ifdef DIAGNOSTIC - /* We need an explicit IRQ. */ - if (dev->id_irq == NO_IRQ) return 0; -#endif - - /* Ethernet MAC address should *NOT* have been given by pccardd, - if this is a true MBH10302; i.e., Ethernet address must be - "all-zero" upon entry. */ - if (sc->sc_enaddr[0] || sc->sc_enaddr[1] || sc->sc_enaddr[2] || - sc->sc_enaddr[3] || sc->sc_enaddr[4] || sc->sc_enaddr[5]) { - return 0; - } - - /* Fill the softc struct with default values. */ - fe_softc_defaults(sc); - - /* - * See if MBH10302 is on its address. - * I'm not sure the following probe code works. FIXME. - */ - if ( !fe_simple_probe( sc, probe_table ) ) return 0; - - /* Get our station address from EEPROM. */ - inblk( sc, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN ); - - /* Make sure we got a valid station address. */ - if (!valid_Ether_p(sc->sc_enaddr, 0)) return 0; - - /* Determine the card type. */ - sc->typestr = "MBH10302 (PCMCIA)"; - - /* We seems to need our own IDENT bits... FIXME. */ - sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; - - /* Setup hooks. We need a special initialization procedure. */ - sc->init = fe_init_mbh; - - /* - * That's all. MBH10302 occupies 32 I/O addresses, by the way. - */ - return 32; -} - -/* - * Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface. - * by MASUI Kenji <masui@cs.titech.ac.jp> - * - * (Contec uses TDK Ethenet chip -- hosokawa) - * - * This version of fe_probe_tdk has been rewrote to handle - * *generic* PC card implementation of Fujitsu MB8696x family. The - * name _tdk is just for a historical reason. :-) - */ -static int -fe_probe_tdk ( struct isa_device * dev, struct fe_softc * sc ) -{ - static struct fe_simple_probe_struct probe_table [] = { - { FE_DLCR2, 0x50, 0x00 }, - { FE_DLCR4, 0x08, 0x00 }, - /* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */ - { 0 } - }; - - if ( dev->id_irq == NO_IRQ ) { - return ( 0 ); - } - - fe_softc_defaults(sc); - - /* - * See if C-NET(PC)C is on its address. - */ - - if ( !fe_simple_probe( sc, probe_table ) ) return 0; - - /* Determine the card type. */ - sc->typestr = "Generic MB8696x/78Q837x Ethernet (PCMCIA)"; - - /* - * Initialize constants in the per-line structure. - */ - - /* Make sure we got a valid station address. */ - if (!valid_Ether_p(sc->sc_enaddr, 0)) return 0; - - /* - * That's all. C-NET(PC)C occupies 16 I/O addresses. - * XXX: Are there any card with 32 I/O addresses? FIXME. - */ - return 16; -} -#endif /* NCARD > 0 */ /* * Install interface into kernel networking data structures */ -static int -fe_attach ( struct isa_device * dev ) +int +fe_attach (device_t dev) { -#if NCARD > 0 - static int already_ifattach[NFE]; -#endif - struct fe_softc *sc = &fe_softc[dev->id_unit]; - int b; + struct fe_softc *sc = device_get_softc(dev); + int flags = device_get_flags(dev); + int b, error; - dev->id_ointr = feintr; + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, + fe_intr, sc, &sc->irq_handle); + if (error) { + fe_release_resource(dev); + return ENXIO; + } /* * Initialize ifnet structure @@ -2796,9 +780,8 @@ fe_attach ( struct isa_device * dev ) * since it must be a common workaround for all network drivers. * FIXME. */ - if ( sc->sc_if.if_snd.ifq_maxlen == 0 ) { + if (sc->sc_if.if_snd.ifq_maxlen == 0) sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; - } #endif #if FE_SINGLE_TRANSMISSION @@ -2808,12 +791,11 @@ fe_attach ( struct isa_device * dev ) #endif /* Modify hardware config if it is requested. */ - if ( dev->id_flags & FE_FLAGS_OVERRIDE_DLCR6 ) { - sc->proto_dlcr6 = dev->id_flags & FE_FLAGS_DLCR6_VALUE; - } + if (flags & FE_FLAGS_OVERRIDE_DLCR6) + sc->proto_dlcr6 = flags & FE_FLAGS_DLCR6_VALUE; /* Find TX buffer size, based on the hardware dependent proto. */ - switch ( sc->proto_dlcr6 & FE_D6_TXBSIZ ) { + switch (sc->proto_dlcr6 & FE_D6_TXBSIZ) { case FE_D6_TXBSIZ_2x2KB: sc->txb_size = 2048; break; case FE_D6_TXBSIZ_2x4KB: sc->txb_size = 4096; break; case FE_D6_TXBSIZ_2x8KB: sc->txb_size = 8192; break; @@ -2830,7 +812,7 @@ fe_attach ( struct isa_device * dev ) } /* Initialize the if_media interface. */ - ifmedia_init(&sc->media, 0, fe_medchange, fe_medstat ); + ifmedia_init(&sc->media, 0, fe_medchange, fe_medstat); for (b = 0; bit2media[b] != 0; b++) { if (sc->mbitmap & (1 << b)) { ifmedia_add(&sc->media, bit2media[b], 0, NULL); @@ -2847,20 +829,13 @@ fe_attach ( struct isa_device * dev ) #endif /* Attach and stop the interface. */ -#if NCARD > 0 - if (already_ifattach[dev->id_unit] != 1) { - ether_ifattach(&sc->sc_if, ETHER_BPF_SUPPORTED); - already_ifattach[dev->id_unit] = 1; - } -#else ether_ifattach(&sc->sc_if, ETHER_BPF_SUPPORTED); -#endif fe_stop(sc); /* Print additional info when attached. */ - printf("fe%d: address %6D, type %s%s\n", sc->sc_unit, - sc->sc_enaddr, ":" , sc->typestr, - (sc->proto_dlcr4 & FE_D4_DSC) ? ", full duplex" : ""); + device_printf(dev, "address %6D, type %s%s\n", + sc->sc_enaddr, ":" , sc->typestr, + (sc->proto_dlcr4 & FE_D4_DSC) ? ", full duplex" : ""); if (bootverbose) { int buf, txb, bbw, sbw, ram; @@ -2888,23 +863,71 @@ fe_attach ( struct isa_device * dev ) case FE_D6_SRAM_100ns: ram = 100; break; case FE_D6_SRAM_150ns: ram = 150; break; } - printf("fe%d: SRAM %dKB %dbit %dns, TXB %dKBx2, %dbit I/O\n", - sc->sc_unit, buf, bbw, ram, txb, sbw); + device_printf(dev, "SRAM %dKB %dbit %dns, TXB %dKBx2, %dbit I/O\n", + buf, bbw, ram, txb, sbw); } - if (sc->stability & UNSTABLE_IRQ) { - printf("fe%d: warning: IRQ number may be incorrect\n", - sc->sc_unit); - } - if (sc->stability & UNSTABLE_MAC) { - printf("fe%d: warning: above MAC address may be incorrect\n", - sc->sc_unit); + if (sc->stability & UNSTABLE_IRQ) + device_printf(dev, "warning: IRQ number may be incorrect\n"); + if (sc->stability & UNSTABLE_MAC) + device_printf(dev, "warning: above MAC address may be incorrect\n"); + if (sc->stability & UNSTABLE_TYPE) + device_printf(dev, "warning: hardware type was not validated\n"); + + return 0; +} + +int +fe_alloc_port(device_t dev, int size) +{ + struct fe_softc *sc = device_get_softc(dev); + struct resource *res; + int rid; + + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0ul, ~0ul, size, RF_ACTIVE); + if (res) { + sc->port_used = size; + sc->port_res = res; + sc->iot = rman_get_bustag(res); + sc->ioh = rman_get_bushandle(res); + return (0); } - if (sc->stability & UNSTABLE_TYPE) { - printf("fe%d: warning: hardware type was not validated\n", - sc->sc_unit); + + return (ENOENT); +} + +int +fe_alloc_irq(device_t dev, int flags) +{ + struct fe_softc *sc = device_get_softc(dev); + struct resource *res; + int rid; + + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0ul, ~0ul, 1, RF_ACTIVE | flags); + if (res) { + sc->irq_res = res; + return (0); } - return 1; + return (ENOENT); +} + +void +fe_release_resource(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + if (sc->port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res); + sc->port_res = NULL; + } + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); + sc->irq_res = NULL; + } } /* @@ -2919,7 +942,8 @@ fe_reset (struct fe_softc *sc) /* Put the interface into known initial state. */ fe_stop(sc); - if (sc->sc_if.if_flags & IFF_UP) fe_init(sc); + if (sc->sc_if.if_flags & IFF_UP) + fe_init(sc); } /* @@ -2928,7 +952,7 @@ fe_reset (struct fe_softc *sc) * All buffered packets, both transmitting and receiving, * if any, will be lost by stopping the interface. */ -static void +void fe_stop (struct fe_softc *sc) { int s; @@ -2936,25 +960,25 @@ fe_stop (struct fe_softc *sc) s = splimp(); /* Disable interrupts. */ - outb( sc->ioaddr[ FE_DLCR2 ], 0x00 ); - outb( sc->ioaddr[ FE_DLCR3 ], 0x00 ); + fe_outb(sc, FE_DLCR2, 0x00); + fe_outb(sc, FE_DLCR3, 0x00); /* Stop interface hardware. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE); + DELAY(200); /* Clear all interrupt status. */ - outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); - outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); + fe_outb(sc, FE_DLCR0, 0xFF); + fe_outb(sc, FE_DLCR1, 0xFF); /* Put the chip in stand-by mode. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR7 ], sc->proto_dlcr7 | FE_D7_POWER_DOWN ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR7, sc->proto_dlcr7 | FE_D7_POWER_DOWN); + DELAY(200); /* Reset transmitter variables and interface flags. */ - sc->sc_if.if_flags &= ~( IFF_OACTIVE | IFF_RUNNING ); + sc->sc_if.if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); sc->sc_if.if_timer = 0; sc->txb_free = sc->txb_size; sc->txb_count = 0; @@ -2964,7 +988,8 @@ fe_stop (struct fe_softc *sc) sc->filter_change = 0; /* Call a device-specific hook. */ - if ( sc->stop ) sc->stop( sc ); + if (sc->stop) + sc->stop(sc); (void) splx(s); } @@ -2982,10 +1007,9 @@ fe_watchdog ( struct ifnet *ifp ) printf("fe%d: transmission timeout (%d+%d)%s\n", ifp->if_unit, sc->txb_sched, sc->txb_count, (ifp->if_flags & IFF_UP) ? "" : " when down"); - if ( sc->sc_if.if_opackets == 0 && sc->sc_if.if_ipackets == 0 ) { + if (sc->sc_if.if_opackets == 0 && sc->sc_if.if_ipackets == 0) printf("fe%d: wrong IRQ setting in config?\n", ifp->if_unit); - } - fe_reset( sc ); + fe_reset(sc); } /* @@ -3009,60 +1033,62 @@ fe_init (void * xsc) s = splimp(); /* Call a hook before we start initializing the chip. */ - if ( sc->init ) sc->init( sc ); + if (sc->init) + sc->init(sc); /* * Make sure to disable the chip, also. * This may also help re-programming the chip after * hot insertion of PCMCIAs. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE); + DELAY(200); /* Power up the chip and select register bank for DLCRs. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR7 ], - sc->proto_dlcr7 | FE_D7_RBS_DLCR | FE_D7_POWER_UP ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR7, + sc->proto_dlcr7 | FE_D7_RBS_DLCR | FE_D7_POWER_UP); + DELAY(200); /* Feed the station address. */ - outblk( sc, FE_DLCR8, sc->sc_enaddr, ETHER_ADDR_LEN ); + fe_outblk(sc, FE_DLCR8, sc->sc_enaddr, ETHER_ADDR_LEN); /* Clear multicast address filter to receive nothing. */ - outb( sc->ioaddr[ FE_DLCR7 ], - sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP ); - outblk( sc, FE_MAR8, fe_filter_nothing.data, FE_FILTER_LEN ); + fe_outb(sc, FE_DLCR7, + sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP); + fe_outblk(sc, FE_MAR8, fe_filter_nothing.data, FE_FILTER_LEN); /* Select the BMPR bank for runtime register access. */ - outb( sc->ioaddr[ FE_DLCR7 ], - sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP ); + fe_outb(sc, FE_DLCR7, + sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP); /* Initialize registers. */ - outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */ - outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */ - outb( sc->ioaddr[ FE_DLCR2 ], 0x00 ); - outb( sc->ioaddr[ FE_DLCR3 ], 0x00 ); - outb( sc->ioaddr[ FE_DLCR4 ], sc->proto_dlcr4 ); - outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 ); - outb( sc->ioaddr[ FE_BMPR10 ], 0x00 ); - outb( sc->ioaddr[ FE_BMPR11 ], FE_B11_CTRL_SKIP | FE_B11_MODE1 ); - outb( sc->ioaddr[ FE_BMPR12 ], 0x00 ); - outb( sc->ioaddr[ FE_BMPR13 ], sc->proto_bmpr13 ); - outb( sc->ioaddr[ FE_BMPR14 ], 0x00 ); - outb( sc->ioaddr[ FE_BMPR15 ], 0x00 ); + fe_outb(sc, FE_DLCR0, 0xFF); /* Clear all bits. */ + fe_outb(sc, FE_DLCR1, 0xFF); /* ditto. */ + fe_outb(sc, FE_DLCR2, 0x00); + fe_outb(sc, FE_DLCR3, 0x00); + fe_outb(sc, FE_DLCR4, sc->proto_dlcr4); + fe_outb(sc, FE_DLCR5, sc->proto_dlcr5); + fe_outb(sc, FE_BMPR10, 0x00); + fe_outb(sc, FE_BMPR11, FE_B11_CTRL_SKIP | FE_B11_MODE1); + fe_outb(sc, FE_BMPR12, 0x00); + fe_outb(sc, FE_BMPR13, sc->proto_bmpr13); + fe_outb(sc, FE_BMPR14, 0x00); + fe_outb(sc, FE_BMPR15, 0x00); /* Enable interrupts. */ - outb( sc->ioaddr[ FE_DLCR2 ], FE_TMASK ); - outb( sc->ioaddr[ FE_DLCR3 ], FE_RMASK ); + fe_outb(sc, FE_DLCR2, FE_TMASK); + fe_outb(sc, FE_DLCR3, FE_RMASK); /* Select requested media, just before enabling DLC. */ - if (sc->msel) sc->msel(sc); + if (sc->msel) + sc->msel(sc); /* Enable transmitter and receiver. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_ENABLE); + DELAY(200); #ifdef DIAGNOSTIC /* @@ -3082,15 +1108,15 @@ fe_init (void * xsc) * 8696x, the receive buffer can have some data at this point. * The following message helps discovering the fact. FIXME. */ - if ( !( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) ) { + if (!(fe_inb(sc, FE_DLCR5) & FE_D5_BUFEMP)) { printf("fe%d: receive buffer has some data after reset\n", sc->sc_unit); - fe_emptybuffer( sc ); + fe_emptybuffer(sc); } /* Do we need this here? Actually, no. I must be paranoia. */ - outb( sc->ioaddr[ FE_DLCR0 ], 0xFF ); /* Clear all bits. */ - outb( sc->ioaddr[ FE_DLCR1 ], 0xFF ); /* ditto. */ + fe_outb(sc, FE_DLCR0, 0xFF); /* Clear all bits. */ + fe_outb(sc, FE_DLCR1, 0xFF); /* ditto. */ #endif /* Set 'running' flag, because we are now running. */ @@ -3103,7 +1129,7 @@ fe_init (void * xsc) * received, based on the if_flags and multicast group * list. It completes the initialization process. */ - fe_setmode( sc ); + fe_setmode(sc); #if 0 /* ...and attempt to start output queued packets. */ @@ -3111,7 +1137,7 @@ fe_init (void * xsc) the interface keeping it idle. The upper layer will soon start the interface anyway, and there are no significant delay. */ - fe_start( &sc->sc_if ); + fe_start(&sc->sc_if); #endif (void) splx(s); @@ -3121,7 +1147,7 @@ fe_init (void * xsc) * This routine actually starts the transmission on the interface */ static void -fe_xmit ( struct fe_softc * sc ) +fe_xmit (struct fe_softc *sc) { /* * Set a timer just in case we never hear from the board again. @@ -3137,7 +1163,7 @@ fe_xmit ( struct fe_softc * sc ) sc->tx_excolls = 0; /* Start transmitter, passing packets in TX buffer. */ - outb( sc->ioaddr[ FE_BMPR10 ], sc->txb_sched | FE_B10_START ); + fe_outb(sc, FE_BMPR10, sc->txb_sched | FE_B10_START); } /* @@ -3150,14 +1176,14 @@ fe_xmit ( struct fe_softc * sc ) * (i.e. that the output part of the interface is idle) */ void -fe_start ( struct ifnet *ifp ) +fe_start (struct ifnet *ifp) { struct fe_softc *sc = ifp->if_softc; struct mbuf *m; #ifdef DIAGNOSTIC /* Just a sanity check. */ - if ( ( sc->txb_count == 0 ) != ( sc->txb_free == sc->txb_size ) ) { + if ((sc->txb_count == 0) != (sc->txb_free == sc->txb_size)) { /* * Txb_count and txb_free co-works to manage the * transmission buffer. Txb_count keeps track of the @@ -3191,10 +1217,10 @@ fe_start ( struct ifnet *ifp ) * First, see if there are buffered packets and an idle * transmitter - should never happen at this point. */ - if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) { + if ((sc->txb_count > 0) && (sc->txb_sched == 0)) { printf("fe%d: transmitter idle with %d buffered packets\n", sc->sc_unit, sc->txb_count); - fe_xmit( sc ); + fe_xmit(sc); } /* @@ -3204,7 +1230,7 @@ fe_start ( struct ifnet *ifp ) * until all buffered transmission packets have been sent * out. */ - if ( sc->filter_change ) { + if (sc->filter_change) { /* * Filter change request is delayed only when the DLC is * working. DLC soon raise an interrupt after finishing @@ -3229,14 +1255,14 @@ fe_start ( struct ifnet *ifp ) * (i.e., minimum packet sized) packets rapidly. An 8KB * buffer can hold 130 blocks of 62 bytes long... */ - if ( sc->txb_free - < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN ) { + if (sc->txb_free + < ETHER_MAX_LEN - ETHER_CRC_LEN + FE_DATA_LEN_LEN) { /* No room. */ goto indicate_active; } #if FE_SINGLE_TRANSMISSION - if ( sc->txb_count > 0 ) { + if (sc->txb_count > 0) { /* Just one packet per a transmission buffer. */ goto indicate_active; } @@ -3245,8 +1271,8 @@ fe_start ( struct ifnet *ifp ) /* * Get the next mbuf chain for a packet to send. */ - IF_DEQUEUE( &sc->sc_if.if_snd, m ); - if ( m == NULL ) { + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if (m == NULL) { /* No more packets to send. */ goto indicate_inactive; } @@ -3255,12 +1281,11 @@ fe_start ( struct ifnet *ifp ) * Copy the mbuf chain into the transmission buffer. * txb_* variables are updated as necessary. */ - fe_write_mbufs( sc, m ); + fe_write_mbufs(sc, m); /* Start transmitter if it's idle. */ - if ( ( sc->txb_count > 0 ) && ( sc->txb_sched == 0 ) ) { - fe_xmit( sc ); - } + if ((sc->txb_count > 0) && (sc->txb_sched == 0)) + fe_xmit(sc); /* * Tap off here if there is a bpf listener, @@ -3269,12 +1294,11 @@ fe_start ( struct ifnet *ifp ) * and only if it is in "receive everything" * mode.) */ - if ( sc->sc_if.if_bpf - && !( sc->sc_if.if_flags & IFF_PROMISC ) ) { - bpf_mtap( &sc->sc_if, m ); - } + if (sc->sc_if.if_bpf && + !(sc->sc_if.if_flags & IFF_PROMISC)) + bpf_mtap(&sc->sc_if, m); - m_freem( m ); + m_freem(m); } indicate_inactive: @@ -3303,7 +1327,7 @@ fe_start ( struct ifnet *ifp ) * Drop (skip) a packet from receive buffer in 86960 memory. */ static void -fe_droppacket ( struct fe_softc * sc, int len ) +fe_droppacket (struct fe_softc * sc, int len) { int i; @@ -3313,38 +1337,36 @@ fe_droppacket ( struct fe_softc * sc, int len ) * remaining in the buffer when issue a skip command. * Remember, we have already read 4 bytes before come here. */ - if ( len > 12 ) { + if (len > 12) { /* Read 4 more bytes, and skip the rest of the packet. */ #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); + (void) fe_inb(sc, FE_BMPR8); + (void) fe_inb(sc, FE_BMPR8); + (void) fe_inb(sc, FE_BMPR8); + (void) fe_inb(sc, FE_BMPR8); } else #endif { - ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); - ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); + (void) fe_inw(sc, FE_BMPR8); + (void) fe_inw(sc, FE_BMPR8); } - outb( sc->ioaddr[ FE_BMPR14 ], FE_B14_SKIP ); + fe_outb(sc, FE_BMPR14, FE_B14_SKIP); } else { /* We should not come here unless receiving RUNTs. */ #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - for ( i = 0; i < len; i++ ) { - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); - } + for (i = 0; i < len; i++) + (void) fe_inb(sc, FE_BMPR8); } else #endif { - for ( i = 0; i < len; i += 2 ) { - ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); - } + for (i = 0; i < len; i += 2) + (void) fe_inw(sc, FE_BMPR8); } } } @@ -3354,7 +1376,7 @@ fe_droppacket ( struct fe_softc * sc, int len ) * Empty receiving buffer. */ static void -fe_emptybuffer ( struct fe_softc * sc ) +fe_emptybuffer (struct fe_softc * sc) { int i; u_char saved_dlcr5; @@ -3366,8 +1388,8 @@ fe_emptybuffer ( struct fe_softc * sc ) /* * Stop receiving packets, temporarily. */ - saved_dlcr5 = inb( sc->ioaddr[ FE_DLCR5 ] ); - outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 ); + saved_dlcr5 = fe_inb(sc, FE_DLCR5); + fe_outb(sc, FE_DLCR5, sc->proto_dlcr5); DELAY(1300); /* @@ -3378,24 +1400,26 @@ fe_emptybuffer ( struct fe_softc * sc ) #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - for ( i = 0; i < 65536; i++ ) { - if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break; - ( void )inb( sc->ioaddr[ FE_BMPR8 ] ); + for (i = 0; i < 65536; i++) { + if (fe_inb(sc, FE_DLCR5) & FE_D5_BUFEMP) + break; + (void) fe_inb(sc, FE_BMPR8); } } else #endif { - for ( i = 0; i < 65536; i += 2 ) { - if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) break; - ( void )inw( sc->ioaddr[ FE_BMPR8 ] ); + for (i = 0; i < 65536; i += 2) { + if (fe_inb(sc, FE_DLCR5) & FE_D5_BUFEMP) + break; + (void) fe_inw(sc, FE_BMPR8); } } /* * Double check. */ - if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) { + if (fe_inb(sc, FE_DLCR5) & FE_D5_BUFEMP) { printf("fe%d: could not empty receive buffer\n", sc->sc_unit); /* Hmm. What should I do if this happens? FIXME. */ } @@ -3403,7 +1427,7 @@ fe_emptybuffer ( struct fe_softc * sc ) /* * Restart receiving packets. */ - outb( sc->ioaddr[ FE_DLCR5 ], saved_dlcr5 ); + fe_outb(sc, FE_DLCR5, saved_dlcr5); } #endif @@ -3412,7 +1436,7 @@ fe_emptybuffer ( struct fe_softc * sc ) * The control flow of this function looks silly. FIXME. */ static void -fe_tint ( struct fe_softc * sc, u_char tstat ) +fe_tint (struct fe_softc * sc, u_char tstat) { int left; int col; @@ -3420,13 +1444,13 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) /* * Handle "excessive collision" interrupt. */ - if ( tstat & FE_D0_COLL16 ) { + if (tstat & FE_D0_COLL16) { /* * Find how many packets (including this collided one) * are left unsent in transmission buffer. */ - left = inb( sc->ioaddr[ FE_BMPR10 ] ); + left = fe_inb(sc, FE_BMPR10); printf("fe%d: excessive collision (%d/%d)\n", sc->sc_unit, left, sc->txb_sched); @@ -3434,7 +1458,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * Clear the collision flag (in 86960) here * to avoid confusing statistics. */ - outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID ); + fe_outb(sc, FE_DLCR0, FE_D0_COLLID); /* * Restart transmitter, skipping the @@ -3449,8 +1473,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * to reliable transport (such as TCP) are resent * by some upper layer. */ - outb( sc->ioaddr[ FE_BMPR11 ], - FE_B11_CTRL_SKIP | FE_B11_MODE1 ); + fe_outb(sc, FE_BMPR11, FE_B11_CTRL_SKIP | FE_B11_MODE1); /* Update statistics. */ sc->tx_excolls++; @@ -3459,7 +1482,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) /* * Handle "transmission complete" interrupt. */ - if ( tstat & FE_D0_TXDONE ) { + if (tstat & FE_D0_TXDONE) { /* * Add in total number of collisions on last @@ -3479,15 +1502,15 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * count is not so important, anyway. Any comments? FIXME. */ - if ( inb( sc->ioaddr[ FE_DLCR0 ] ) & FE_D0_COLLID ) { + if (fe_inb(sc, FE_DLCR0) & FE_D0_COLLID) { /* Clear collision flag. */ - outb( sc->ioaddr[ FE_DLCR0 ], FE_D0_COLLID ); + fe_outb(sc, FE_DLCR0, FE_D0_COLLID); /* Extract collision count from 86960. */ - col = inb( sc->ioaddr[ FE_DLCR4 ] ); - col = ( col & FE_D4_COL ) >> FE_D4_COL_SHIFT; - if ( col == 0 ) { + col = fe_inb(sc, FE_DLCR4); + col = (col & FE_D4_COL) >> FE_D4_COL_SHIFT; + if (col == 0) { /* * Status register indicates collisions, * while the collision count is zero. @@ -3502,11 +1525,10 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) col = 1; } sc->sc_if.if_collisions += col; - if ( col == 1 ) { + if (col == 1) sc->mibdata.dot3StatsSingleCollisionFrames++; - } else { + else sc->mibdata.dot3StatsMultipleCollisionFrames++; - } sc->mibdata.dot3StatsCollFrequencies[col-1]++; } @@ -3535,7 +1557,8 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * even if more data is queued. This gives receive * process a slight priority. */ - if ( sc->txb_count > 0 ) fe_xmit( sc ); + if (sc->txb_count > 0) + fe_xmit(sc); } } @@ -3543,7 +1566,7 @@ fe_tint ( struct fe_softc * sc, u_char tstat ) * Ethernet interface receiver interrupt. */ static void -fe_rint ( struct fe_softc * sc, u_char rstat ) +fe_rint (struct fe_softc * sc, u_char rstat) { u_short len; u_char status; @@ -3557,13 +1580,12 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * was scheduled, they are ignored, and the following error stats * give less than real values. */ - if ( rstat & ( FE_D1_OVRFLO | FE_D1_CRCERR - | FE_D1_ALGERR | FE_D1_SRTPKT ) ) { - if ( rstat & FE_D1_OVRFLO ) + if (rstat & (FE_D1_OVRFLO | FE_D1_CRCERR | FE_D1_ALGERR | FE_D1_SRTPKT)) { + if (rstat & FE_D1_OVRFLO) sc->mibdata.dot3StatsInternalMacReceiveErrors++; - if ( rstat & FE_D1_CRCERR ) + if (rstat & FE_D1_CRCERR) sc->mibdata.dot3StatsFCSErrors++; - if ( rstat & FE_D1_ALGERR ) + if (rstat & FE_D1_ALGERR) sc->mibdata.dot3StatsAlignmentErrors++; #if 0 /* The reference MAC receiver defined in 802.3 @@ -3571,7 +1593,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) notifying upper layer. RFC 1650 (dot3 MIB) is based on the 802.3, and it has no stats entry for RUNTs... */ - if ( rstat & FE_D1_SRTPKT ) + if (rstat & FE_D1_SRTPKT) sc->mibdata.dot3StatsFrameTooShorts++; /* :-) */ #endif sc->sc_if.if_ierrors++; @@ -3585,10 +1607,11 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * We limit the number of iterations to avoid infinite-loop. * The upper bound is set to unrealistic high value. */ - for ( i = 0; i < FE_MAX_RECV_COUNT * 2; i++ ) { + for (i = 0; i < FE_MAX_RECV_COUNT * 2; i++) { /* Stop the iteration if 86960 indicates no packets. */ - if ( inb( sc->ioaddr[ FE_DLCR5 ] ) & FE_D5_BUFEMP ) return; + if (fe_inb(sc, FE_DLCR5) & FE_D5_BUFEMP) + return; /* * Extract a receive status byte. @@ -3599,13 +1622,13 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - status = inb( sc->ioaddr[ FE_BMPR8 ] ); - ( void ) inb( sc->ioaddr[ FE_BMPR8 ] ); + status = fe_inb(sc, FE_BMPR8); + (void) fe_inb(sc, FE_BMPR8); } else #endif { - status = ( u_char )inw( sc->ioaddr[ FE_BMPR8 ] ); + status = (u_char) fe_inw(sc, FE_BMPR8); } /* @@ -3616,13 +1639,13 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - len = inb( sc->ioaddr[ FE_BMPR8 ] ); - len |= ( inb( sc->ioaddr[ FE_BMPR8 ] ) << 8 ); + len = fe_inb(sc, FE_BMPR8); + len |= (fe_inb(sc, FE_BMPR8) << 8); } else #endif { - len = inw( sc->ioaddr[ FE_BMPR8 ] ); + len = fe_inw(sc, FE_BMPR8); } /* @@ -3632,9 +1655,9 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * serious error, e.g., out-of-sync of the receive * buffer pointers. */ - if ( ( status & 0xF0 ) != 0x20 - || len > ETHER_MAX_LEN - ETHER_CRC_LEN - || len < ETHER_MIN_LEN - ETHER_CRC_LEN ) { + if ((status & 0xF0) != 0x20 || + len > ETHER_MAX_LEN - ETHER_CRC_LEN || + len < ETHER_MIN_LEN - ETHER_CRC_LEN) { printf("fe%d: RX buffer out-of-sync\n", sc->sc_unit); sc->sc_if.if_ierrors++; sc->mibdata.dot3StatsInternalMacReceiveErrors++; @@ -3645,7 +1668,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) /* * Go get a packet. */ - if ( fe_get_packet( sc, len ) < 0 ) { + if (fe_get_packet(sc, len) < 0) { /* * Negative return from fe_get_packet() * indicates no available mbuf. We stop @@ -3655,7 +1678,7 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) */ sc->sc_if.if_ierrors++; sc->mibdata.dot3StatsMissedFrames++; - fe_droppacket( sc, len ); + fe_droppacket(sc, len); return; } @@ -3674,9 +1697,9 @@ fe_rint ( struct fe_softc * sc, u_char rstat ) * Ethernet interface interrupt processor */ static void -feintr ( int unit ) +fe_intr (void *arg) { - struct fe_softc *sc = &fe_softc[unit]; + struct fe_softc *sc = arg; u_char tstat, rstat; int loop_count = FE_MAX_LOOP; @@ -3685,29 +1708,28 @@ feintr ( int unit ) /* * Get interrupt conditions, masking unneeded flags. */ - tstat = inb( sc->ioaddr[ FE_DLCR0 ] ) & FE_TMASK; - rstat = inb( sc->ioaddr[ FE_DLCR1 ] ) & FE_RMASK; - if ( tstat == 0 && rstat == 0 ) return; + tstat = fe_inb(sc, FE_DLCR0) & FE_TMASK; + rstat = fe_inb(sc, FE_DLCR1) & FE_RMASK; + if (tstat == 0 && rstat == 0) + return; /* * Reset the conditions we are acknowledging. */ - outb( sc->ioaddr[ FE_DLCR0 ], tstat ); - outb( sc->ioaddr[ FE_DLCR1 ], rstat ); + fe_outb(sc, FE_DLCR0, tstat); + fe_outb(sc, FE_DLCR1, rstat); /* * Handle transmitter interrupts. */ - if ( tstat ) { - fe_tint( sc, tstat ); - } + if (tstat) + fe_tint(sc, tstat); /* * Handle receiver interrupts */ - if ( rstat ) { - fe_rint( sc, rstat ); - } + if (rstat) + fe_rint(sc, rstat); /* * Update the multicast address filter if it is @@ -3717,8 +1739,8 @@ feintr ( int unit ) * is empty. It will minimize the possibility of * packet loss. */ - if ( sc->filter_change - && sc->txb_count == 0 && sc->txb_sched == 0 ) { + if (sc->filter_change && + sc->txb_count == 0 && sc->txb_sched == 0) { fe_loadmar(sc); sc->sc_if.if_flags &= ~IFF_OACTIVE; } @@ -3736,14 +1758,11 @@ feintr ( int unit ) * receiver interrupts. 86960 can raise a receiver * interrupt when the transmission buffer is full. */ - if ( ( sc->sc_if.if_flags & IFF_OACTIVE ) == 0 ) { - fe_start( &sc->sc_if ); - } - + if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) + fe_start(&sc->sc_if); } printf("fe%d: too many loops\n", sc->sc_unit); - return; } /* @@ -3751,7 +1770,7 @@ feintr ( int unit ) * pretty ugly. */ static int -fe_ioctl ( struct ifnet * ifp, u_long command, caddr_t data ) +fe_ioctl (struct ifnet * ifp, u_long command, caddr_t data) { struct fe_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; @@ -3773,21 +1792,19 @@ fe_ioctl ( struct ifnet * ifp, u_long command, caddr_t data ) * Switch interface state between "running" and * "stopped", reflecting the UP flag. */ - if ( sc->sc_if.if_flags & IFF_UP ) { - if ( ( sc->sc_if.if_flags & IFF_RUNNING ) == 0 ) { + if (sc->sc_if.if_flags & IFF_UP) { + if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) fe_init(sc); - } } else { - if ( ( sc->sc_if.if_flags & IFF_RUNNING ) != 0 ) { + if ((sc->sc_if.if_flags & IFF_RUNNING) != 0) fe_stop(sc); - } } /* * Promiscuous and/or multicast flags may have changed, * so reprogram the multicast filter and/or receive mode. */ - fe_setmode( sc ); + fe_setmode(sc); /* Done. */ break; @@ -3798,7 +1815,7 @@ fe_ioctl ( struct ifnet * ifp, u_long command, caddr_t data ) * Multicast list has changed; set the hardware filter * accordingly. */ - fe_setmode( sc ); + fe_setmode(sc); break; case SIOCSIFMEDIA: @@ -3823,7 +1840,7 @@ fe_ioctl ( struct ifnet * ifp, u_long command, caddr_t data ) * Returns 0 if success, -1 if error (i.e., mbuf allocation failure). */ static int -fe_get_packet ( struct fe_softc * sc, u_short len ) +fe_get_packet (struct fe_softc * sc, u_short len) { struct ether_header *eh; struct mbuf *m; @@ -3861,13 +1878,14 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) /* Allocate an mbuf with packet header info. */ MGETHDR(m, M_DONTWAIT, MT_DATA); - if ( m == NULL ) return -1; + if (m == NULL) + return -1; /* Attach a cluster if this packet doesn't fit in a normal mbuf. */ - if ( len > MHLEN - NFS_MAGIC_OFFSET ) { - MCLGET( m, M_DONTWAIT ); - if ( !( m->m_flags & M_EXT ) ) { - m_freem( m ); + if (len > MHLEN - NFS_MAGIC_OFFSET) { + MCLGET(m, M_DONTWAIT); + if (!(m->m_flags & M_EXT)) { + m_freem(m); return -1; } } @@ -3889,21 +1907,21 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - insb( sc->ioaddr[ FE_BMPR8 ], eh, len ); + fe_insb(sc, FE_BMPR8, (u_int8_t *)eh, len); } else #endif { - insw( sc->ioaddr[ FE_BMPR8 ], eh, ( len + 1 ) >> 1 ); + fe_insw(sc, FE_BMPR8, (u_int16_t *)eh, (len + 1) >> 1); } /* Strip off the Ethernet header. */ - m->m_pkthdr.len -= sizeof ( struct ether_header ); - m->m_len -= sizeof ( struct ether_header ); - m->m_data += sizeof ( struct ether_header ); + m->m_pkthdr.len -= sizeof (struct ether_header); + m->m_len -= sizeof (struct ether_header); + m->m_data += sizeof (struct ether_header); /* Feed the packet to upper layer. */ - ether_input( &sc->sc_if, eh, m ); + ether_input(&sc->sc_if, eh, m); return 0; } @@ -3917,25 +1935,24 @@ fe_get_packet ( struct fe_softc * sc, u_short len ) * shorter than mandatory Ethernet header. */ static void -fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) +fe_write_mbufs (struct fe_softc *sc, struct mbuf *m) { - u_short addr_bmpr8 = sc->ioaddr[ FE_BMPR8 ]; u_short length, len; struct mbuf *mp; u_char *data; u_short savebyte; /* WARNING: Architecture dependent! */ #define NO_PENDING_BYTE 0xFFFF - static u_char padding [ ETHER_MIN_LEN - ETHER_CRC_LEN - ETHER_HDR_LEN ]; + static u_char padding [ETHER_MIN_LEN - ETHER_CRC_LEN - ETHER_HDR_LEN]; #ifdef DIAGNOSTIC /* First, count up the total number of bytes to copy */ length = 0; - for ( mp = m; mp != NULL; mp = mp->m_next ) { + for (mp = m; mp != NULL; mp = mp->m_next) length += mp->m_len; - } + /* Check if this matches the one in the packet header. */ - if ( length != m->m_pkthdr.len ) { + if (length != m->m_pkthdr.len) { printf("fe%d: packet length mismatch? (%d/%d)\n", sc->sc_unit, length, m->m_pkthdr.len); } @@ -3950,8 +1967,8 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) * it should be a bug of upper layer. We just ignore it. * ... Partial (too short) packets, neither. */ - if ( length < ETHER_HDR_LEN - || length > ETHER_MAX_LEN - ETHER_CRC_LEN ) { + if (length < ETHER_HDR_LEN || + length > ETHER_MAX_LEN - ETHER_CRC_LEN) { printf("fe%d: got an out-of-spec packet (%u bytes) to send\n", sc->sc_unit, length); sc->sc_if.if_oerrors++; @@ -3971,14 +1988,15 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - len = max( length, ETHER_MIN_LEN - ETHER_CRC_LEN ); - outb( addr_bmpr8, len & 0x00ff ); - outb( addr_bmpr8, ( len & 0xff00 ) >> 8 ); + len = max(length, ETHER_MIN_LEN - ETHER_CRC_LEN); + fe_outb(sc, FE_BMPR8, len & 0x00ff); + fe_outb(sc, FE_BMPR8, (len & 0xff00) >> 8); } else #endif { - outw( addr_bmpr8, max( length, ETHER_MIN_LEN - ETHER_CRC_LEN ) ); + fe_outw(sc, FE_BMPR8, + max(length, ETHER_MIN_LEN - ETHER_CRC_LEN)); } /* @@ -3989,9 +2007,10 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) if ((sc->proto_dlcr6 & FE_D6_SBW) != FE_D6_SBW_BYTE) #endif { - length = ( length + 1 ) & ~1; + length = (length + 1) & ~1; } - sc->txb_free -= FE_DATA_LEN_LEN + max( length, ETHER_MIN_LEN - ETHER_CRC_LEN); + sc->txb_free -= FE_DATA_LEN_LEN + + max(length, ETHER_MIN_LEN - ETHER_CRC_LEN); sc->txb_count++; /* @@ -4004,10 +2023,10 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { /* 8-bit cards are easy. */ - for ( mp = m; mp != 0; mp = mp->m_next ) { - if ( mp->m_len ) { - outsb( addr_bmpr8, mtod(mp, caddr_t), mp->m_len ); - } + for (mp = m; mp != 0; mp = mp->m_next) { + if (mp->m_len) + fe_outsb(sc, FE_BMPR8, mtod(mp, caddr_t), + mp->m_len); } } else @@ -4015,18 +2034,19 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) { /* 16-bit cards are a pain. */ savebyte = NO_PENDING_BYTE; - for ( mp = m; mp != 0; mp = mp->m_next ) { + for (mp = m; mp != 0; mp = mp->m_next) { /* Ignore empty mbuf. */ len = mp->m_len; - if ( len == 0 ) continue; + if (len == 0) + continue; /* Find the actual data to send. */ data = mtod(mp, caddr_t); /* Finish the last byte. */ - if ( savebyte != NO_PENDING_BYTE ) { - outw( addr_bmpr8, savebyte | ( *data << 8 ) ); + if (savebyte != NO_PENDING_BYTE) { + fe_outw(sc, FE_BMPR8, savebyte | (*data << 8)); data++; len--; savebyte = NO_PENDING_BYTE; @@ -4034,34 +2054,35 @@ fe_write_mbufs ( struct fe_softc *sc, struct mbuf *m ) /* output contiguous words */ if (len > 1) { - outsw( addr_bmpr8, data, len >> 1); + fe_outsw(sc, FE_BMPR8, (u_int16_t *)data, + len >> 1); data += len & ~1; len &= 1; } /* Save a remaining byte, if there is one. */ - if ( len > 0 ) { + if (len > 0) savebyte = *data; - } } /* Spit the last byte, if the length is odd. */ - if ( savebyte != NO_PENDING_BYTE ) { - outw( addr_bmpr8, savebyte ); - } + if (savebyte != NO_PENDING_BYTE) + fe_outw(sc, FE_BMPR8, savebyte); } /* Pad to the Ethernet minimum length, if the packet is too short. */ - if ( length < ETHER_MIN_LEN - ETHER_CRC_LEN ) { + if (length < ETHER_MIN_LEN - ETHER_CRC_LEN) { #ifdef FE_8BIT_SUPPORT if ((sc->proto_dlcr6 & FE_D6_SBW) == FE_D6_SBW_BYTE) { - outsb( addr_bmpr8, padding, ETHER_MIN_LEN - ETHER_CRC_LEN - length ); + fe_outsb(sc, FE_BMPR8, padding, + ETHER_MIN_LEN - ETHER_CRC_LEN - length); } else #endif { - outsw( addr_bmpr8, padding, ( ETHER_MIN_LEN - ETHER_CRC_LEN - length ) >> 1); + fe_outsw(sc, FE_BMPR8, (u_int16_t *)padding, + (ETHER_MIN_LEN - ETHER_CRC_LEN - length) >> 1); } } } @@ -4123,7 +2144,7 @@ fe_mcaf ( struct fe_softc *sc ) * receiver in appropriate mode. */ static void -fe_setmode ( struct fe_softc *sc ) +fe_setmode (struct fe_softc *sc) { int flags = sc->sc_if.if_flags; @@ -4137,12 +2158,13 @@ fe_setmode ( struct fe_softc *sc ) * To complete the trick, fe_init() calls fe_setmode() after * restarting the interface. */ - if ( !( flags & IFF_RUNNING ) ) return; + if (!(flags & IFF_RUNNING)) + return; /* * Promiscuous mode is handled separately. */ - if ( flags & IFF_PROMISC ) { + if (flags & IFF_PROMISC) { /* * Program 86960 to receive all packets on the segment * including those directed to other stations. @@ -4154,8 +2176,8 @@ fe_setmode ( struct fe_softc *sc ) * So, we ignore erroneous ones even in this mode. * (Older versions of fe driver mistook the point.) */ - outb( sc->ioaddr[ FE_DLCR5 ], - sc->proto_dlcr5 | FE_D5_AFM0 | FE_D5_AFM1 ); + fe_outb(sc, FE_DLCR5, + sc->proto_dlcr5 | FE_D5_AFM0 | FE_D5_AFM1); sc->filter_change = 0; return; } @@ -4163,16 +2185,15 @@ fe_setmode ( struct fe_softc *sc ) /* * Turn the chip to the normal (non-promiscuous) mode. */ - outb( sc->ioaddr[ FE_DLCR5 ], sc->proto_dlcr5 | FE_D5_AFM1 ); + fe_outb(sc, FE_DLCR5, sc->proto_dlcr5 | FE_D5_AFM1); /* * Find the new multicast filter value. */ - if ( flags & IFF_ALLMULTI ) { + if (flags & IFF_ALLMULTI) sc->filter = fe_filter_all; - } else { - sc->filter = fe_mcaf( sc ); - } + else + sc->filter = fe_mcaf(sc); sc->filter_change = 1; /* @@ -4186,8 +2207,8 @@ fe_setmode ( struct fe_softc *sc ) * To reduce the packet loss, we delay the filter update * process until buffers are empty. */ - if ( sc->txb_sched == 0 && sc->txb_count == 0 - && !( inb( sc->ioaddr[ FE_DLCR1 ] ) & FE_D1_PKTRDY ) ) { + if (sc->txb_sched == 0 && sc->txb_count == 0 && + !(fe_inb(sc, FE_DLCR1) & FE_D1_PKTRDY)) { /* * Buffers are (apparently) empty. Load * the new filter value into MARs now. @@ -4211,28 +2232,27 @@ fe_setmode ( struct fe_softc *sc ) * a device is RUNNING. (I mistook the point in previous versions.) */ static void -fe_loadmar ( struct fe_softc * sc ) +fe_loadmar (struct fe_softc * sc) { /* Stop the DLC (transmitter and receiver). */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_DISABLE ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE); + DELAY(200); /* Select register bank 1 for MARs. */ - outb( sc->ioaddr[ FE_DLCR7 ], - sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP ); + fe_outb(sc, FE_DLCR7, sc->proto_dlcr7 | FE_D7_RBS_MAR | FE_D7_POWER_UP); /* Copy filter value into the registers. */ - outblk( sc, FE_MAR8, sc->filter.data, FE_FILTER_LEN ); + fe_outblk(sc, FE_MAR8, sc->filter.data, FE_FILTER_LEN); /* Restore the bank selection for BMPRs (i.e., runtime registers). */ - outb( sc->ioaddr[ FE_DLCR7 ], - sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP ); + fe_outb(sc, FE_DLCR7, + sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP); /* Restart the DLC. */ - DELAY( 200 ); - outb( sc->ioaddr[ FE_DLCR6 ], sc->proto_dlcr6 | FE_D6_DLC_ENABLE ); - DELAY( 200 ); + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_ENABLE); + DELAY(200); /* We have just updated the filter. */ sc->filter_change = 0; diff --git a/sys/dev/fe/if_fe_cbus.c b/sys/dev/fe/if_fe_cbus.c new file mode 100644 index 0000000..7d993f2 --- /dev/null +++ b/sys/dev/fe/if_fe_cbus.c @@ -0,0 +1,1018 @@ +/* + * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 + * + * This software may be used, modified, copied, distributed, and sold, in + * both source and binary form provided that the above copyright, these + * terms and the following disclaimer are retained. The name of the author + * and/or the contributor may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR 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. + * + * $FreeBSD$ + */ + +#include "opt_fe.h" +#include "opt_inet.h" +#include "opt_ipx.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <machine/clock.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <net/bpf.h> + +#include <i386/isa/ic/mb86960.h> +#include <dev/fe/if_fereg.h> +#include <dev/fe/if_fevar.h> + +#include <isa/isavar.h> + +/* + * Cbus specific code. + */ +static int fe_isa_probe(device_t); +static int fe_isa_attach(device_t); + +static device_method_t fe_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fe_isa_probe), + DEVMETHOD(device_attach, fe_isa_attach), + + { 0, 0 } +}; + +static driver_t fe_isa_driver = { + "fe", + fe_isa_methods, + sizeof (struct fe_softc) +}; + +DRIVER_MODULE(fe, isa, fe_isa_driver, fe_devclass, 0, 0); + + +static int fe98_alloc_port(device_t, int); + +static int fe_probe_re1000(device_t); +static int fe_probe_cnet9ne(device_t); +static int fe_probe_rex(device_t); +static int fe_probe_ssi(device_t); +static int fe_probe_jli(device_t); +static int fe_probe_lnx(device_t); +static int fe_probe_gwy(device_t); +static int fe_probe_ubn(device_t); + +/* + * Determine if the device is present at a specified I/O address. The + * main entry to the driver. + */ + +static int +fe_isa_probe(device_t dev) +{ + struct fe_softc * sc; + int error; + + /* Prepare for the softc struct. */ + sc = device_get_softc(dev); + sc->sc_unit = device_get_unit(dev); + + /* Probe for supported boards. */ +#ifdef PC98 + if ((error = fe_probe_re1000(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_cnet9ne(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_rex(dev)) == 0) + goto end; + fe_release_resource(dev); +#endif + + if ((error = fe_probe_ssi(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_jli(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_lnx(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_ubn(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_gwy(dev)) == 0) + goto end; + fe_release_resource(dev); + +end: + if (error == 0) + error = fe_alloc_irq(dev, 0); + + fe_release_resource(dev); + return (error); +} + +static int +fe_isa_attach(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + if (sc->port_used) + fe98_alloc_port(dev, sc->type); + fe_alloc_irq(dev, 0); + + return fe_attach(dev); +} + + +/* Generic I/O address table */ +static bus_addr_t ioaddr_generic[MAXREGISTERS] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, + 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017, + 0x018, 0x019, 0x01a, 0x01b, 0x01c, 0x01d, 0x01e, 0x01f, +}; + +/* I/O address table for RE1000/1000Plus */ +static bus_addr_t ioaddr_re1000[MAXREGISTERS] = { + 0x0000, 0x0001, 0x0200, 0x0201, 0x0400, 0x0401, 0x0600, 0x0601, + 0x0800, 0x0801, 0x0a00, 0x0a01, 0x0c00, 0x0c01, 0x0e00, 0x0e01, + 0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00, + 0x1001, 0x1201, 0x1401, 0x1601, 0x1801, 0x1a01, 0x1c01, 0x1e01, +}; + +/* I/O address table for CNET9NE */ +static bus_addr_t ioaddr_cnet9ne[MAXREGISTERS] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, + 0x400, 0x402, 0x404, 0x406, 0x408, 0x40a, 0x40c, 0x40e, + 0x401, 0x403, 0x405, 0x407, 0x409, 0x40b, 0x40d, 0x40f, +}; + +/* I/O address table for LAC-98 */ +static bus_addr_t ioaddr_lnx[MAXREGISTERS] = { + 0x000, 0x002, 0x004, 0x006, 0x008, 0x00a, 0x00c, 0x00e, + 0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e, + 0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e, + 0x300, 0x302, 0x304, 0x306, 0x308, 0x30a, 0x30c, 0x30e, +}; + +/* I/O address table for Access/PC N98C+ */ +static bus_addr_t ioaddr_ubn[MAXREGISTERS] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, + 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, + 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f, +}; + +/* I/O address table for REX-9880 */ +static bus_addr_t ioaddr_rex[MAXREGISTERS] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, + 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f, + 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, + 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, 0x10f, +}; + +static int +fe98_alloc_port(device_t dev, int type) +{ + struct fe_softc *sc = device_get_softc(dev); + struct resource *res; + bus_addr_t *iat; + int size, rid; + + switch (type) { + case FE_TYPE_RE1000: + iat = ioaddr_re1000; + size = MAXREGISTERS; + break; + case FE_TYPE_CNET9NE: + iat = &ioaddr_cnet9ne[16]; + size = 16; + break; + case FE_TYPE_SSI: + iat = ioaddr_generic; + size = MAXREGISTERS; + break; + case FE_TYPE_LNX: + iat = ioaddr_lnx; + size = MAXREGISTERS; + break; + case FE_TYPE_GWY: + iat = ioaddr_generic; + size = MAXREGISTERS; + break; + case FE_TYPE_UBN: + iat = ioaddr_ubn; + size = MAXREGISTERS; + break; + case FE_TYPE_REX: + iat = ioaddr_rex; + size = MAXREGISTERS; + break; + default: + iat = ioaddr_generic; + size = MAXREGISTERS; + break; + } + + rid = 0; + res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, + iat, size, RF_ACTIVE); + if (res == NULL) + return ENOENT; + + switch (type) { + case FE_TYPE_CNET9NE: + iat = ioaddr_cnet9ne; + size = MAXREGISTERS; + break; + } + + isa_load_resourcev(res, iat, size); + + sc->type = type; + sc->port_used = size; + sc->port_res = res; + sc->iot = rman_get_bustag(res); + sc->ioh = rman_get_bushandle(res); + return (0); +} + + +/* + * Probe and initialization for Allied-Telesis RE1000 series. + */ +static void +fe_init_re1000(struct fe_softc *sc) +{ + /* Setup IRQ control register on the ASIC. */ + fe_outb(sc, FE_RE1000_IRQCONF, sc->priv_info); +} + +static int +fe_probe_re1000(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + int i, n; + u_long iobase, irq; + u_char sum; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for RE1000. */ + /* [01]D[02468ACE] are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x10E) != 0xD0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_RE1000)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Make sure it is Allied-Telesis's. */ + if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) + return ENXIO; +#if 1 + /* Calculate checksum. */ + sum = fe_inb(sc, 0x1e); + for (i = 0; i < ETHER_ADDR_LEN; i++) + sum ^= sc->sc_enaddr[i]; + if (sum != 0) + return ENXIO; +#endif + /* Setup the board type. */ + sc->typestr = "RE1000"; + + /* This looks like an RE1000 board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + switch (irq) { + case 3: n = 0x10; break; + case 5: n = 0x20; break; + case 6: n = 0x40; break; + case 12: n = 0x80; break; + default: + fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12"); + return ENXIO; + } + sc->priv_info = (fe_inb(sc, FE_RE1000_IRQCONF) & 0x0f) | n; + + /* Setup hooks. We need a special initialization procedure. */ + sc->init = fe_init_re1000; + + return 0; +} + +/* JLI sub-probe for Allied-Telesis RE1000Plus/ME1500 series. */ +static u_short const * +fe_probe_jli_re1000p(struct fe_softc * sc, u_char const * eeprom) +{ + int i; + static u_short const irqmaps_re1000p [4] = { 3, 5, 6, 12 }; + + /* Make sure the EEPROM contains Allied-Telesis bit pattern. */ + if (eeprom[1] != 0xFF) return NULL; + for (i = 2; i < 8; i++) if (eeprom[i] != 0xFF) return NULL; + for (i = 14; i < 24; i++) if (eeprom[i] != 0xFF) return NULL; + + /* Get our station address from EEPROM, and make sure the + EEPROM contains Allied-Telesis's address. */ + bcopy(eeprom + 8, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) + return NULL; + + /* I don't know any sub-model identification. */ + sc->typestr = "RE1000Plus/ME1500"; + + /* Returns the IRQ table for the RE1000Plus. */ + return irqmaps_re1000p; +} + + +/* + * Probe for Allied-Telesis RE1000Plus/ME1500 series. + */ +static int +fe_probe_jli(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + int i, n, xirq, error; + u_long iobase, irq; + u_char eeprom [JLI_EEPROM_SIZE]; + u_short const * irqmap; + + static u_short const baseaddr [8] = + { 0x1D6, 0x1D8, 0x1DA, 0x1D4, 0x0D4, 0x0D2, 0x0D8, 0x0D0 }; + static struct fe_simple_probe_struct const probe_table [] = { + /* { FE_DLCR1, 0x20, 0x00 }, Doesn't work. */ + { FE_DLCR2, 0x50, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + /* { FE_DLCR5, 0x80, 0x00 }, Doesn't work. */ +#if 0 + { FE_BMPR16, 0x1B, 0x00 }, + { FE_BMPR17, 0x7F, 0x00 }, +#endif + { 0 } + }; + + /* + * See if the specified address is possible for MB86965A JLI mode. + */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + for (i = 0; i < 8; i++) { + if (baseaddr[i] == iobase) + break; + } + if (i == 8) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_RE1000)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* + * We should test if MB86965A is on the base address now. + * Unfortunately, it is very hard to probe it reliably, since + * we have no way to reset the chip under software control. + * On cold boot, we could check the "signature" bit patterns + * described in the Fujitsu document. On warm boot, however, + * we can predict almost nothing about register values. + */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Check if our I/O address matches config info on 86965. */ + n = (fe_inb(sc, FE_BMPR19) & FE_B19_ADDR) >> FE_B19_ADDR_SHIFT; + if (baseaddr[n] != iobase) + return ENXIO; + + /* + * We are now almost sure we have an MB86965 at the given + * address. So, read EEPROM through it. We have to write + * into LSI registers to read from EEPROM. I want to avoid it + * at this stage, but I cannot test the presence of the chip + * any further without reading EEPROM. FIXME. + */ + fe_read_eeprom_jli(sc, eeprom); + + /* Make sure that config info in EEPROM and 86965 agree. */ + if (eeprom[FE_EEPROM_CONF] != fe_inb(sc, FE_BMPR19)) + return ENXIO; + + /* Use 86965 media selection scheme, unless othewise + specified. It is "AUTO always" and "select with BMPR13". + This behaviour covers most of the 86965 based board (as + minimum requirements.) It is backward compatible with + previous versions, also. */ + sc->mbitmap = MB_HA; + sc->defmedia = MB_HA; + sc->msel = fe_msel_965; + + /* Perform board-specific probe. */ + if ((irqmap = fe_probe_jli_re1000p(sc, eeprom)) == NULL) + return ENXIO; + + /* Find the IRQ read from EEPROM. */ + n = (fe_inb(sc, FE_BMPR19) & FE_B19_IRQ) >> FE_B19_IRQ_SHIFT; + xirq = irqmap[n]; + + /* Try to determine IRQ setting. */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + if (error && xirq == NO_IRQ) { + /* The device must be configured with an explicit IRQ. */ + device_printf(dev, "IRQ auto-detection does not work\n"); + return ENXIO; + } else if (error && xirq != NO_IRQ) { + /* Just use the probed IRQ value. */ + bus_set_resource(dev, SYS_RES_IRQ, 0, xirq, 1); + } else if (!error && xirq == NO_IRQ) { + /* No problem. Go ahead. */ + } else if (irq == xirq) { + /* Good. Go ahead. */ + } else { + /* User must be warned in this case. */ + sc->stability |= UNSTABLE_IRQ; + } + + /* Setup a hook, which resets te 86965 when the driver is being + initialized. This may solve a nasty bug. FIXME. */ + sc->init = fe_init_jli; + + return 0; +} + + +/* + * Probe and initialization for Contec C-NET(9N)E series. + */ + +/* TODO: Should be in "if_fereg.h" */ +#define FE_CNET9NE_INTR 0x10 /* Interrupt Mask? */ + +static void +fe_init_cnet9ne(struct fe_softc *sc) +{ + /* Enable interrupt? FIXME. */ + fe_outb(sc, FE_CNET9NE_INTR, 0x10); +} + +static int +fe_probe_cnet9ne (device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for C-NET(9N)E. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if (iobase != 0x73D0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_CNET9NE)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Make sure it is Contec's. */ + if (!valid_Ether_p(sc->sc_enaddr, 0x00804C)) + return ENXIO; + + /* Determine the card type. */ + if (sc->sc_enaddr[3] == 0x06) { + sc->typestr = "C-NET(9N)C"; + + /* We seems to need our own IDENT bits... FIXME. */ + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; + + /* C-NET(9N)C requires an explicit IRQ to work. */ + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) { + fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL); + return ENXIO; + } + } else { + sc->typestr = "C-NET(9N)E"; + + /* C-NET(9N)E works only IRQ5. */ + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) + return ENXIO; + if (irq != 5) { + fe_irq_failure(sc->typestr, sc->sc_unit, irq, "5"); + return ENXIO; + } + + /* We need an init hook to initialize ASIC before we start. */ + sc->init = fe_init_cnet9ne; + } + + /* C-NET(9N)E has 64KB SRAM. */ + sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB + | FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM; + + return 0; +} + + +/* + * Probe for Contec C-NET(98)P2 series. + * (Logitec LAN-98TP/LAN-98T25P - parhaps) + */ +static int +fe_probe_ssi(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; + + u_char eeprom [SSI_EEPROM_SIZE]; + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x08, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + static u_short const irqmap[] = { + /* INT0 INT1 INT2 */ + NO_IRQ, NO_IRQ, NO_IRQ, 3, NO_IRQ, 5, 6, NO_IRQ, + NO_IRQ, 9, 10, NO_IRQ, 12, 13, NO_IRQ, NO_IRQ, + /* INT3 INT41 INT5 INT6 */ + }; + + /* See if the specified I/O address is possible for 78Q8377A. */ + /* [0-D]3D0 are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & 0xFFF) != 0x3D0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_SSI)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* We now have to read the config EEPROM. We should be very + careful, since doing so destroys a register. (Remember, we + are not yet sure we have a C-NET(98)P2 board here.) Don't + remember to select BMPRs bofore reading EEPROM, since other + register bank may be selected before the probe() is called. */ + fe_read_eeprom_ssi(sc, eeprom); + + /* Make sure the Ethernet (MAC) station address is of Contec's. */ + if (!valid_Ether_p(eeprom + FE_SSI_EEP_ADDR, 0x00804C)) + return ENXIO; + bcopy(eeprom + FE_SSI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Setup the board type. */ + sc->typestr = "C-NET(98)P2"; + + /* Get IRQ configuration from EEPROM. */ + irq = irqmap[eeprom[FE_SSI_EEP_IRQ]]; + if (irq == NO_IRQ) { + fe_irq_failure(sc->typestr, sc->sc_unit, irq, + "3/5/6/9/10/12/13"); + return ENXIO; + } + bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); + + /* Get Duplex-mode configuration from EEPROM. */ + sc->proto_dlcr4 |= (eeprom[FE_SSI_EEP_DUPLEX] & FE_D4_DSC); + + /* Fill softc struct accordingly. */ + sc->mbitmap = MB_HT; + sc->defmedia = MB_HT; + + return 0; +} + + +/* + * Probe for TDK LAC-98012/013/025/9N011 - parhaps. + */ +static int +fe_probe_lnx(device_t dev) +{ +#ifndef FE_8BIT_SUPPORT + device_printf(dev, + "skip LAC-98012/013(only 16-bit cards are supported)\n"); + return ENXIO; +#else + struct fe_softc *sc = device_get_softc(dev); + + u_long iobase, irq; + u_char eeprom [LNX_EEPROM_SIZE]; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for TDK/LANX boards. */ + /* 0D0, 4D0, 8D0, and CD0 are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0xC00) != 0xD0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_LNX)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* We now have to read the config EEPROM. We should be very + careful, since doing so destroys a register. (Remember, we + are not yet sure we have a LAC-98012/98013 board here.) */ + fe_read_eeprom_lnx(sc, eeprom); + + /* Make sure the Ethernet (MAC) station address is of TDK/LANX's. */ + if (!valid_Ether_p(eeprom, 0x008098)) + return ENXIO; + bcopy(eeprom, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Setup the board type. */ + sc->typestr = "LAC-98012/98013"; + + /* This looks like a TDK/LANX board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) + return ENXIO; + switch (irq) { + case 3 : sc->priv_info = 0x10 | LNX_CLK_LO | LNX_SDA_HI; break; + case 5 : sc->priv_info = 0x20 | LNX_CLK_LO | LNX_SDA_HI; break; + case 6 : sc->priv_info = 0x40 | LNX_CLK_LO | LNX_SDA_HI; break; + case 12: sc->priv_info = 0x80 | LNX_CLK_LO | LNX_SDA_HI; break; + default: + fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12"); + return ENXIO; + } + + /* LAC-98's system bus width is 8-bit. */ + sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x2KB + | FE_D6_BBW_BYTE | FE_D6_SBW_BYTE | FE_D6_SRAM_150ns; + + /* Setup hooks. We need a special initialization procedure. */ + sc->init = fe_init_lnx; + + return 0; +#endif /* FE_8BIT_SUPPORT */ +} + + +/* + * Probe for Gateway Communications' old cards. + * (both as Generic MB86960 probe routine) + */ +static int +fe_probe_gwy(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + static struct fe_simple_probe_struct probe_table [] = { + /* { FE_DLCR2, 0x70, 0x00 }, */ + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* + * XXX + * I'm not sure which address is possible, so accepts any. + */ + + if (fe98_alloc_port(dev, FE_TYPE_GWY)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x000000)) + return ENXIO; + + /* Determine the card type. */ + sc->typestr = "Generic MB86960 Ethernet"; + if (valid_Ether_p(sc->sc_enaddr, 0x000061)) + sc->typestr = "Gateway Ethernet (Fujitsu chipset)"; + + /* Gateway's board requires an explicit IRQ to work, since it + is not possible to probe the setting of jumpers. */ + if (bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0) { + fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL); + return ENXIO; + } + + return 0; +} + + +/* + * Probe for Ungermann-Bass Access/PC N98C+(Model 85152). + */ +static int +fe_probe_ubn(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + u_char sum, save7; + u_long iobase, irq; + int i; + static struct fe_simple_probe_struct const probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for Access/PC. */ + /* [01][048C]D0 are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x1C00) != 0xD0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_UBN)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* Simple probe. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* NOTE: Access/NOTE N98 sometimes freeze when reading station + address. In case of using it togather with C-NET(9N)C, + this problem usually happens. + Writing DLCR7 prevents freezing, but I don't know why. FIXME. */ + + /* Save the current value for the DLCR7 register we are about + to destroy. */ + save7 = fe_inb(sc, FE_DLCR7); + fe_outb(sc, FE_DLCR7, + sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP); + + /* Get our station address form ID ROM and make sure it is UBN's. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x00DD01)) + goto fail_ubn; +#if 1 + /* Calculate checksum. */ + sum = fe_inb(sc, 0x1e); + for (i = 0; i < ETHER_ADDR_LEN; i++) + sum ^= sc->sc_enaddr[i]; + if (sum != 0) + goto fail_ubn; +#endif + + /* Setup the board type. */ + sc->typestr = "Access/PC"; + + /* This looks like an AccessPC/N98C+ board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + switch (irq) { + case 3: sc->priv_info = 0x01; break; + case 5: sc->priv_info = 0x02; break; + case 6: sc->priv_info = 0x04; break; + case 12: sc->priv_info = 0x08; break; + default: + fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12"); + goto fail_ubn; + } + + /* Setup hooks. We need a special initialization procedure. */ + sc->init = fe_init_ubn; + + return 0; + +fail_ubn: + fe_outb(sc, FE_DLCR7, save7); + return ENXIO; +} + + +/* + * REX boards(non-JLI type) support routine. + */ + +#define REX_EEPROM_SIZE 32 +#define REX_DAT 0x01 + +static void +fe_read_eeprom_rex(struct fe_softc *sc, u_char *data) +{ + int i; + u_char bit, val; + u_char save16; + + save16 = fe_inb(sc, 0x10); + + /* Issue a start condition. */ + val = fe_inb(sc, 0x10) & 0xf0; + fe_outb(sc, 0x10, val); + + (void) fe_inb(sc, 0x10); + (void) fe_inb(sc, 0x10); + (void) fe_inb(sc, 0x10); + (void) fe_inb(sc, 0x10); + + /* Read bytes from EEPROM. */ + for (i = 0; i < REX_EEPROM_SIZE; i++) { + /* Read a byte and store it into the buffer. */ + val = 0x00; + for (bit = 0x01; bit != 0x00; bit <<= 1) + if (fe_inb(sc, 0x10) & REX_DAT) + val |= bit; + *data++ = val; + } + + fe_outb(sc, 0x10, save16); + +#if 1 + /* Report what we got. */ + if (bootverbose) { + data -= REX_EEPROM_SIZE; + for (i = 0; i < REX_EEPROM_SIZE; i += 16) { + printf("fe%d: EEPROM(REX):%3x: %16D\n", + sc->sc_unit, i, data + i, " "); + } + } +#endif +} + + +static void +fe_init_rex(struct fe_softc *sc) +{ + /* Setup IRQ control register on the ASIC. */ + fe_outb(sc, 0x10, sc->priv_info); +} + +/* + * Probe for RATOC REX-9880/81/82/83 series. + */ +static int +fe_probe_rex(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + int i; + u_long iobase, irq; + u_char eeprom [REX_EEPROM_SIZE]; + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for REX-9880. */ + /* 6[46CE]D0 are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0xA00) != 0x64D0) + return ENXIO; + + if (fe98_alloc_port(dev, FE_TYPE_REX)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* We now have to read the config EEPROM. We should be very + careful, since doing so destroys a register. (Remember, we + are not yet sure we have a REX-9880 board here.) */ + fe_read_eeprom_rex(sc, eeprom); + for (i = 0; i < ETHER_ADDR_LEN; i++) + sc->sc_enaddr[i] = eeprom[7 - i]; + + /* Make sure it is RATOC's. */ + if (!valid_Ether_p(sc->sc_enaddr, 0x00C0D0) && + !valid_Ether_p(sc->sc_enaddr, 0x00803D)) + return 0; + + /* Setup the board type. */ + sc->typestr = "REX-9880/9883"; + + /* This looks like a REX-9880 board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + switch (irq) { + case 3: sc->priv_info = 0x10; break; + case 5: sc->priv_info = 0x20; break; + case 6: sc->priv_info = 0x40; break; + case 12: sc->priv_info = 0x80; break; + default: + fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12"); + return ENXIO; + } + + /* Setup hooks. We need a special initialization procedure. */ + sc->init = fe_init_rex; + + /* REX-9880 has 64KB SRAM. */ + sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB + | FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM; +#if 1 + sc->proto_dlcr7 |= FE_D7_EOPPOL; /* XXX */ +#endif + + return 0; +} diff --git a/sys/dev/fe/if_fe_isa.c b/sys/dev/fe/if_fe_isa.c new file mode 100644 index 0000000..c72f401 --- /dev/null +++ b/sys/dev/fe/if_fe_isa.c @@ -0,0 +1,1063 @@ +/* + * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 + * + * This software may be used, modified, copied, distributed, and sold, in + * both source and binary form provided that the above copyright, these + * terms and the following disclaimer are retained. The name of the author + * and/or the contributor may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR 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. + * + * $FreeBSD$ + */ + +#include "opt_fe.h" +#include "opt_inet.h" +#include "opt_ipx.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <machine/clock.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <net/bpf.h> + +#include <i386/isa/ic/mb86960.h> +#include <dev/fe/if_fereg.h> +#include <dev/fe/if_fevar.h> + +#include <isa/isavar.h> + +/* + * ISA specific code. + */ +static int fe_isa_probe(device_t); +static int fe_isa_attach(device_t); + +static device_method_t fe_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fe_isa_probe), + DEVMETHOD(device_attach, fe_isa_attach), + + { 0, 0 } +}; + +static driver_t fe_isa_driver = { + "fe", + fe_isa_methods, + sizeof (struct fe_softc) +}; + +DRIVER_MODULE(fe, isa, fe_isa_driver, fe_devclass, 0, 0); + + +static int fe_probe_ssi(device_t); +static int fe_probe_jli(device_t); +static int fe_probe_fmv(device_t); +static int fe_probe_lnx(device_t); +static int fe_probe_gwy(device_t); +static int fe_probe_ubn(device_t); + +/* + * Determine if the device is present at a specified I/O address. The + * main entry to the driver. + */ +static int +fe_isa_probe(device_t dev) +{ + struct fe_softc *sc; + int error; + + /* Check isapnp ids */ + if (isa_get_vendorid(dev)) + return (ENXIO); + + /* Prepare for the softc struct. */ + sc = device_get_softc(dev); + sc->sc_unit = device_get_unit(dev); + + /* Probe for supported boards. */ + if ((error = fe_probe_ssi(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_jli(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_fmv(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_lnx(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_ubn(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_gwy(dev)) == 0) + goto end; + fe_release_resource(dev); + +end: + if (error == 0) + error = fe_alloc_irq(dev, 0); + + fe_release_resource(dev); + return (error); +} + +static int +fe_isa_attach(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + if (sc->port_used) + fe_alloc_port(dev, sc->port_used); + fe_alloc_irq(dev, 0); + + return fe_attach(dev); +} + + +/* + * Probe and initialization for Fujitsu FMV-180 series boards + */ + +static void +fe_init_fmv(struct fe_softc *sc) +{ + /* Initialize ASIC. */ + fe_outb(sc, FE_FMV3, 0); + fe_outb(sc, FE_FMV10, 0); + +#if 0 + /* "Refresh" hardware configuration. FIXME. */ + fe_outb(sc, FE_FMV2, fe_inb(sc, FE_FMV2)); +#endif + + /* Turn the "master interrupt control" flag of ASIC on. */ + fe_outb(sc, FE_FMV3, FE_FMV3_IRQENB); +} + +static void +fe_msel_fmv184(struct fe_softc *sc) +{ + u_char port; + + /* FMV-184 has a special "register" to switch between AUI/BNC. + Determine the value to write into the register, based on the + user-specified media selection. */ + port = (IFM_SUBTYPE(sc->media.ifm_media) == IFM_10_2) ? 0x00 : 0x01; + + /* The register is #5 on exntesion register bank... + (Details of the register layout is not yet discovered.) */ + fe_outb(sc, 0x1B, 0x46); /* ??? */ + fe_outb(sc, 0x1E, 0x04); /* select ex-reg #4. */ + fe_outb(sc, 0x1F, 0xC8); /* ??? */ + fe_outb(sc, 0x1E, 0x05); /* select ex-reg #5. */ + fe_outb(sc, 0x1F, port); /* Switch the media. */ + fe_outb(sc, 0x1E, 0x04); /* select ex-reg #4. */ + fe_outb(sc, 0x1F, 0x00); /* ??? */ + fe_outb(sc, 0x1B, 0x00); /* ??? */ + + /* Make sure to select "external tranceiver" on MB86964. */ + fe_outb(sc, FE_BMPR13, sc->proto_bmpr13 | FE_B13_PORT_AUI); +} + +static int +fe_probe_fmv(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + int n; + u_long iobase, irq; + + static u_short const irqmap [ 4 ] = { 3, 7, 10, 15 }; + + static struct fe_simple_probe_struct const probe_table [] = { + { FE_DLCR2, 0x71, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + + { FE_FMV0, 0x78, 0x50 }, /* ERRDY+PRRDY */ + { FE_FMV1, 0xB0, 0x00 }, /* FMV-183/4 has 0x48 bits. */ + { FE_FMV3, 0x7F, 0x00 }, + + { 0 } + }; + + /* Board subtypes; it lists known FMV-180 variants. */ + struct subtype { + u_short mcode; + u_short mbitmap; + u_short defmedia; + char const * str; + }; + static struct subtype const typelist [] = { + { 0x0005, MB_HA|MB_HT|MB_H5, MB_HA, "FMV-181" }, + { 0x0105, MB_HA|MB_HT|MB_H5, MB_HA, "FMV-181A" }, + { 0x0003, MB_HM, MB_HM, "FMV-182" }, + { 0x0103, MB_HM, MB_HM, "FMV-182A" }, + { 0x0804, MB_HT, MB_HT, "FMV-183" }, + { 0x0C04, MB_HT, MB_HT, "FMV-183 (on-board)" }, + { 0x0803, MB_H2|MB_H5, MB_H2, "FMV-184" }, + { 0, MB_HA, MB_HA, "unknown FMV-180 (?)" }, + }; + struct subtype const * type; + + /* Media indicator and "Hardware revision ID" */ + u_short mcode; + + /* See if the specified address is possible for FMV-180 + series. 220, 240, 260, 280, 2A0, 2C0, 300, and 340 are + allowed for all boards, and 200, 2E0, 320, 360, 380, 3A0, + 3C0, and 3E0 for PnP boards. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x1E0) != 0x200) + return ENXIO; + + /* FMV-180 occupies 32 I/O addresses. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Setup an I/O address mapping table and some others. */ + fe_softc_defaults(sc); + + /* Simple probe. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM, and make sure it is + Fujitsu's. */ + fe_inblk(sc, FE_FMV4, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x00000E)) + return ENXIO; + + /* Find the supported media and "hardware revision" to know + the model identification. */ + mcode = (fe_inb(sc, FE_FMV0) & FE_FMV0_MEDIA) + | ((fe_inb(sc, FE_FMV1) & FE_FMV1_REV) << 8); + + /* Determine the card type. */ + for (type = typelist; type->mcode != 0; type++) { + if (type->mcode == mcode) + break; + } + if (type->mcode == 0) { + /* Unknown card type... Hope the driver works. */ + sc->stability |= UNSTABLE_TYPE; + if (bootverbose) { + device_printf(dev, "unknown config: %x-%x-%x-%x\n", + fe_inb(sc, FE_FMV0), + fe_inb(sc, FE_FMV1), + fe_inb(sc, FE_FMV2), + fe_inb(sc, FE_FMV3)); + } + } + + /* Setup the board type and media information. */ + sc->type = FE_TYPE_FMV; + sc->typestr = type->str; + sc->mbitmap = type->mbitmap; + sc->defmedia = type->defmedia; + sc->msel = fe_msel_965; + + if (type->mbitmap == (MB_H2 | MB_H5)) { + /* FMV184 requires a special media selection procedure. */ + sc->msel = fe_msel_fmv184; + } + + /* + * An FMV-180 has been probed. + * Determine which IRQ to be used. + * + * In this version, we give a priority to the kernel config file. + * If the EEPROM and config don't match, say it to the user for + * an attention. + */ + n = (fe_inb(sc, FE_FMV2) & FE_FMV2_IRS) >> FE_FMV2_IRS_SHIFT; + + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + if (irq == NO_IRQ) { + /* Just use the probed value. */ + bus_set_resource(dev, SYS_RES_IRQ, 0, irqmap[n], 1); + } else if (irq != irqmap[n]) { + /* Don't match. */ + sc->stability |= UNSTABLE_IRQ; + } + + /* We need an init hook to initialize ASIC before we start. */ + sc->init = fe_init_fmv; + + return 0; +} + +/* + * Fujitsu MB86965 JLI mode probe routines. + * + * 86965 has a special operating mode called JLI (mode 0), under which + * the chip interfaces with ISA bus with a software-programmable + * configuration. (The Fujitsu document calls the feature "Plug and + * play," but it is not compatible with the ISA-PnP spec. designed by + * Intel and Microsoft.) Ethernet cards designed to use JLI are + * almost same, but there are two things which require board-specific + * probe routines: EEPROM layout and IRQ pin connection. + * + * JLI provides a handy way to access EEPROM which should contains the + * chip configuration information (such as I/O port address) as well + * as Ethernet station (MAC) address. The chip configuration info. is + * stored on a fixed location. However, the station address can be + * located anywhere in the EEPROM; it is up to the board designer to + * determine the location. (The manual just says "somewhere in the + * EEPROM.") The fe driver must somehow find out the correct + * location. + * + * Another problem resides in the IRQ pin connection. JLI provides a + * user to choose an IRQ from up to four predefined IRQs. The 86965 + * chip has a register to select one out of the four possibilities. + * However, the selection is against the four IRQ pins on the chip. + * (So-called IRQ-A, -B, -C and -D.) It is (again) up to the board + * designer to determine which pin to connect which IRQ line on the + * ISA bus. We need a vendor (or model, for some vendor) specific IRQ + * mapping table. + * + * The routine fe_probe_jli() provides all probe and initialization + * processes which are common to all JLI implementation, and sub-probe + * routines supply board-specific actions. + * + * JLI sub-probe routine has the following template: + * + * u_short const * func (struct fe_softc * sc, u_char const * eeprom); + * + * where eeprom is a pointer to an array of 32 byte data read from the + * config EEPROM on the board. It retuns an IRQ mapping table for the + * board, when the corresponding implementation is detected. It + * returns a NULL otherwise. + * + * Primary purpose of the functin is to analize the config EEPROM, + * determine if it matches with the pattern of that of supported card, + * and extract necessary information from it. One of the information + * expected to be extracted from EEPROM is the Ethernet station (MAC) + * address, which must be set to the softc table of the interface by + * the board-specific routine. + */ + +/* JLI sub-probe for Allied-Telesyn/Allied-Telesis AT1700/RE2000 series. */ +static u_short const * +fe_probe_jli_ati(struct fe_softc * sc, u_char const * eeprom) +{ + int i; + static u_short const irqmaps_ati [4][4] = + { + { 3, 4, 5, 9 }, + { 10, 11, 12, 15 }, + { 3, 11, 5, 15 }, + { 10, 11, 14, 15 }, + }; + + /* Make sure the EEPROM contains Allied-Telesis/Allied-Telesyn + bit pattern. */ + if (eeprom[1] != 0x00) return NULL; + for (i = 2; i < 8; i++) if (eeprom[i] != 0xFF) return NULL; + for (i = 14; i < 24; i++) if (eeprom[i] != 0xFF) return NULL; + + /* Get our station address from EEPROM, and make sure the + EEPROM contains ATI's address. */ + bcopy(eeprom + 8, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4)) + return NULL; + + /* + * The following model identification codes are stolen + * from the NetBSD port of the fe driver. My reviewers + * suggested minor revision. + */ + + /* Determine the card type. */ + switch (eeprom[FE_ATI_EEP_MODEL]) { + case FE_ATI_MODEL_AT1700T: + sc->typestr = "AT-1700T/RE2001"; + sc->mbitmap = MB_HT; + sc->defmedia = MB_HT; + break; + case FE_ATI_MODEL_AT1700BT: + sc->typestr = "AT-1700BT/RE2003"; + sc->mbitmap = MB_HA | MB_HT | MB_H2; + break; + case FE_ATI_MODEL_AT1700FT: + sc->typestr = "AT-1700FT/RE2009"; + sc->mbitmap = MB_HA | MB_HT | MB_HF; + break; + case FE_ATI_MODEL_AT1700AT: + sc->typestr = "AT-1700AT/RE2005"; + sc->mbitmap = MB_HA | MB_HT | MB_H5; + break; + default: + sc->typestr = "unknown AT-1700/RE2000"; + sc->stability |= UNSTABLE_TYPE | UNSTABLE_IRQ; + break; + } + sc->type = FE_TYPE_JLI; + +#if 0 + /* Should we extract default media from eeprom? Linux driver + for AT1700 does it, although previous releases of FreeBSD + don't. FIXME. */ + /* Determine the default media selection from the config + EEPROM. The byte at offset EEP_MEDIA is believed to + contain BMPR13 value to be set. We just ignore STP bit or + squelch bit, since we don't support those. (It is + intentional.) */ + switch (eeprom[FE_ATI_EEP_MEDIA] & FE_B13_PORT) { + case FE_B13_AUTO: + sc->defmedia = MB_HA; + break; + case FE_B13_TP: + sc->defmedia = MB_HT; + break; + case FE_B13_AUI: + sc->defmedia = sc->mbitmap & (MB_H2|MB_H5|MB_H5); /*XXX*/ + break; + default: + sc->defmedia = MB_HA; + break; + } + + /* Make sure the default media is compatible with the supported + ones. */ + if ((sc->defmedia & sc->mbitmap) == 0) { + if (sc->defmedia == MB_HA) { + sc->defmedia = MB_HT; + } else { + sc->defmedia = MB_HA; + } + } +#endif + + /* + * Try to determine IRQ settings. + * Different models use different ranges of IRQs. + */ + switch ((eeprom[FE_ATI_EEP_REVISION] & 0xf0) + |(eeprom[FE_ATI_EEP_MAGIC] & 0x04)) { + case 0x30: case 0x34: return irqmaps_ati[3]; + case 0x10: case 0x14: + case 0x50: case 0x54: return irqmaps_ati[2]; + case 0x44: case 0x64: return irqmaps_ati[1]; + default: return irqmaps_ati[0]; + } +} + +/* JLI sub-probe and msel hook for ICL Ethernet. */ +static void +fe_msel_icl(struct fe_softc *sc) +{ + u_char d4; + + /* Switch between UTP and "external tranceiver" as always. */ + fe_msel_965(sc); + + /* The board needs one more bit (on DLCR4) be set appropriately. */ + if (IFM_SUBTYPE(sc->media.ifm_media) == IFM_10_5) { + d4 = sc->proto_dlcr4 | FE_D4_CNTRL; + } else { + d4 = sc->proto_dlcr4 & ~FE_D4_CNTRL; + } + fe_outb(sc, FE_DLCR4, d4); +} + +static u_short const * +fe_probe_jli_icl(struct fe_softc * sc, u_char const * eeprom) +{ + int i; + u_short defmedia; + u_char d6; + static u_short const irqmap_icl [4] = { 9, 10, 5, 15 }; + + /* Make sure the EEPROM contains ICL bit pattern. */ + for (i = 24; i < 39; i++) { + if (eeprom[i] != 0x20 && (eeprom[i] & 0xF0) != 0x30) return NULL; + } + for (i = 112; i < 122; i++) { + if (eeprom[i] != 0x20 && (eeprom[i] & 0xF0) != 0x30) return NULL; + } + + /* Make sure the EEPROM contains ICL's permanent station + address. If it isn't, probably this board is not an + ICL's. */ + if (!valid_Ether_p(eeprom+122, 0x00004B)) + return NULL; + + /* Check if the "configured" Ethernet address in the EEPROM is + valid. Use it if it is, or use the "permanent" address instead. */ + if (valid_Ether_p(eeprom+4, 0x020000)) { + /* The configured address is valid. Use it. */ + bcopy(eeprom+4, sc->sc_enaddr, ETHER_ADDR_LEN); + } else { + /* The configured address is invalid. Use permanent. */ + bcopy(eeprom+122, sc->sc_enaddr, ETHER_ADDR_LEN); + } + + /* Determine model and supported media. */ + switch (eeprom[0x5E]) { + case 0: + sc->typestr = "EtherTeam16i/COMBO"; + sc->mbitmap = MB_HA | MB_HT | MB_H5 | MB_H2; + break; + case 1: + sc->typestr = "EtherTeam16i/TP"; + sc->mbitmap = MB_HT; + break; + case 2: + sc->typestr = "EtherTeam16i/ErgoPro"; + sc->mbitmap = MB_HA | MB_HT | MB_H5; + break; + case 4: + sc->typestr = "EtherTeam16i/DUO"; + sc->mbitmap = MB_HA | MB_HT | MB_H2; + break; + default: + sc->typestr = "EtherTeam16i"; + sc->stability |= UNSTABLE_TYPE; + if (bootverbose) { + printf("fe%d: unknown model code %02x for EtherTeam16i\n", + sc->sc_unit, eeprom[0x5E]); + } + break; + } + sc->type = FE_TYPE_JLI; + + /* I'm not sure the following msel hook is required by all + models or COMBO only... FIXME. */ + sc->msel = fe_msel_icl; + + /* Make the configured media selection the default media. */ + switch (eeprom[0x28]) { + case 0: defmedia = MB_HA; break; + case 1: defmedia = MB_H5; break; + case 2: defmedia = MB_HT; break; + case 3: defmedia = MB_H2; break; + default: + if (bootverbose) { + printf("fe%d: unknown default media: %02x\n", + sc->sc_unit, eeprom[0x28]); + } + defmedia = MB_HA; + break; + } + + /* Make sure the default media is compatible with the + supported media. */ + if ((defmedia & sc->mbitmap) == 0) { + if (bootverbose) { + printf("fe%d: default media adjusted\n", sc->sc_unit); + } + defmedia = sc->mbitmap; + } + + /* Keep the determined default media. */ + sc->defmedia = defmedia; + + /* ICL has "fat" models. We have to program 86965 to properly + reflect the hardware. */ + d6 = sc->proto_dlcr6 & ~(FE_D6_BUFSIZ | FE_D6_BBW); + switch ((eeprom[0x61] << 8) | eeprom[0x60]) { + case 0x2008: d6 |= FE_D6_BUFSIZ_32KB | FE_D6_BBW_BYTE; break; + case 0x4010: d6 |= FE_D6_BUFSIZ_64KB | FE_D6_BBW_WORD; break; + default: + /* We can't support it, since we don't know which bits + to set in DLCR6. */ + printf("fe%d: unknown SRAM config for ICL\n", sc->sc_unit); + return NULL; + } + sc->proto_dlcr6 = d6; + + /* Returns the IRQ table for the ICL board. */ + return irqmap_icl; +} + +/* JLI sub-probe for RATOC REX-5586/5587. */ +static u_short const * +fe_probe_jli_rex(struct fe_softc * sc, u_char const * eeprom) +{ + int i; + static u_short const irqmap_rex [4] = { 3, 4, 5, NO_IRQ }; + + /* Make sure the EEPROM contains RATOC's config pattern. */ + if (eeprom[1] != eeprom[0]) return NULL; + for (i = 8; i < 32; i++) if (eeprom[i] != 0xFF) return NULL; + + /* Get our station address from EEPROM. Note that RATOC + stores it "byte-swapped" in each word. (I don't know why.) + So, we just can't use bcopy().*/ + sc->sc_enaddr[0] = eeprom[3]; + sc->sc_enaddr[1] = eeprom[2]; + sc->sc_enaddr[2] = eeprom[5]; + sc->sc_enaddr[3] = eeprom[4]; + sc->sc_enaddr[4] = eeprom[7]; + sc->sc_enaddr[5] = eeprom[6]; + + /* Make sure the EEPROM contains RATOC's station address. */ + if (!valid_Ether_p(sc->sc_enaddr, 0x00C0D0)) + return NULL; + + /* I don't know any sub-model identification. */ + sc->type = FE_TYPE_JLI; + sc->typestr = "REX-5586/5587"; + + /* Returns the IRQ for the RATOC board. */ + return irqmap_rex; +} + +/* JLI sub-probe for Unknown board. */ +static u_short const * +fe_probe_jli_unk(struct fe_softc * sc, u_char const * eeprom) +{ + int i, n, romsize; + static u_short const irqmap [4] = { NO_IRQ, NO_IRQ, NO_IRQ, NO_IRQ }; + + /* The generic JLI probe considered this board has an 86965 + in JLI mode, but any other board-specific routines could + not find the matching implementation. So, we "guess" the + location by looking for a bit pattern which looks like a + MAC address. */ + + /* Determine how large the EEPROM is. */ + for (romsize = JLI_EEPROM_SIZE/2; romsize > 16; romsize >>= 1) { + for (i = 0; i < romsize; i++) { + if (eeprom[i] != eeprom[i+romsize]) + break; + } + if (i < romsize) + break; + } + romsize <<= 1; + + /* Look for a bit pattern which looks like a MAC address. */ + for (n = 2; n <= romsize - ETHER_ADDR_LEN; n += 2) { + if (!valid_Ether_p(eeprom + n, 0x000000)) + continue; + } + + /* If no reasonable address was found, we can't go further. */ + if (n > romsize - ETHER_ADDR_LEN) + return NULL; + + /* Extract our (guessed) station address. */ + bcopy(eeprom+n, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* We are not sure what type of board it is... */ + sc->type = FE_TYPE_JLI; + sc->typestr = "(unknown JLI)"; + sc->stability |= UNSTABLE_TYPE | UNSTABLE_MAC; + + /* Returns the totally unknown IRQ mapping table. */ + return irqmap; +} + +/* + * Probe and initialization for all JLI implementations. + */ + +static int +fe_probe_jli(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + int i, n, error, xirq; + u_long iobase, irq; + u_char eeprom [JLI_EEPROM_SIZE]; + u_short const * irqmap; + + static u_short const baseaddr [8] = + { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300 }; + static struct fe_simple_probe_struct const probe_table [] = { + { FE_DLCR1, 0x20, 0x00 }, + { FE_DLCR2, 0x50, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { FE_DLCR5, 0x80, 0x00 }, +#if 0 + { FE_BMPR16, 0x1B, 0x00 }, + { FE_BMPR17, 0x7F, 0x00 }, +#endif + { 0 } + }; + + /* + * See if the specified address is possible for MB86965A JLI mode. + */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + for (i = 0; i < 8; i++) { + if (baseaddr[i] == iobase) + break; + } + if (i == 8) + return ENXIO; + + /* 86965 JLI occupies 32 I/O addresses. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Fill the softc struct with reasonable default. */ + fe_softc_defaults(sc); + + /* + * We should test if MB86965A is on the base address now. + * Unfortunately, it is very hard to probe it reliably, since + * we have no way to reset the chip under software control. + * On cold boot, we could check the "signature" bit patterns + * described in the Fujitsu document. On warm boot, however, + * we can predict almost nothing about register values. + */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Check if our I/O address matches config info on 86965. */ + n = (fe_inb(sc, FE_BMPR19) & FE_B19_ADDR) >> FE_B19_ADDR_SHIFT; + if (baseaddr[n] != iobase) + return ENXIO; + + /* + * We are now almost sure we have an MB86965 at the given + * address. So, read EEPROM through it. We have to write + * into LSI registers to read from EEPROM. I want to avoid it + * at this stage, but I cannot test the presence of the chip + * any further without reading EEPROM. FIXME. + */ + fe_read_eeprom_jli(sc, eeprom); + + /* Make sure that config info in EEPROM and 86965 agree. */ + if (eeprom[FE_EEPROM_CONF] != fe_inb(sc, FE_BMPR19)) + return ENXIO; + + /* Use 86965 media selection scheme, unless othewise + specified. It is "AUTO always" and "select with BMPR13." + This behaviour covers most of the 86965 based board (as + minimum requirements.) It is backward compatible with + previous versions, also. */ + sc->mbitmap = MB_HA; + sc->defmedia = MB_HA; + sc->msel = fe_msel_965; + + /* Perform board-specific probe, one by one. Note that the + order of probe is important and should not be changed + arbitrarily. */ + if ((irqmap = fe_probe_jli_ati(sc, eeprom)) == NULL + && (irqmap = fe_probe_jli_rex(sc, eeprom)) == NULL + && (irqmap = fe_probe_jli_icl(sc, eeprom)) == NULL + && (irqmap = fe_probe_jli_unk(sc, eeprom)) == NULL) + return ENXIO; + + /* Find the IRQ read from EEPROM. */ + n = (fe_inb(sc, FE_BMPR19) & FE_B19_IRQ) >> FE_B19_IRQ_SHIFT; + xirq = irqmap[n]; + + /* Try to determine IRQ setting. */ + error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + if (error && xirq == NO_IRQ) { + /* The device must be configured with an explicit IRQ. */ + device_printf(dev, "IRQ auto-detection does not work\n"); + return ENXIO; + } else if (error && xirq != NO_IRQ) { + /* Just use the probed IRQ value. */ + bus_set_resource(dev, SYS_RES_IRQ, 0, xirq, 1); + } else if (!error && xirq == NO_IRQ) { + /* No problem. Go ahead. */ + } else if (irq == xirq) { + /* Good. Go ahead. */ + } else { + /* User must be warned in this case. */ + sc->stability |= UNSTABLE_IRQ; + } + + /* Setup a hook, which resets te 86965 when the driver is being + initialized. This may solve a nasty bug. FIXME. */ + sc->init = fe_init_jli; + + return 0; +} + +/* Probe for TDK LAK-AX031, which is an SSi 78Q8377A based board. */ +static int +fe_probe_ssi(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; + + u_char eeprom [SSI_EEPROM_SIZE]; + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x08, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for 78Q8377A. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x3F0) != 0x000) + return ENXIO; + + /* We have 16 registers. */ + if (fe_alloc_port(dev, 16)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* We now have to read the config EEPROM. We should be very + careful, since doing so destroys a register. (Remember, we + are not yet sure we have a LAK-AX031 board here.) Don't + remember to select BMPRs bofore reading EEPROM, since other + register bank may be selected before the probe() is called. */ + fe_read_eeprom_ssi(sc, eeprom); + + /* Make sure the Ethernet (MAC) station address is of TDK's. */ + if (!valid_Ether_p(eeprom+FE_SSI_EEP_ADDR, 0x008098)) + return ENXIO; + bcopy(eeprom + FE_SSI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* This looks like a TDK-AX031 board. It requires an explicit + IRQ setting in config, since we currently don't know how we + can find the IRQ value assigned by ISA PnP manager. */ + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) { + fe_irq_failure("LAK-AX031", sc->sc_unit, NO_IRQ, NULL); + return ENXIO; + } + + /* Fill softc struct accordingly. */ + sc->type = FE_TYPE_SSI; + sc->typestr = "LAK-AX031"; + sc->mbitmap = MB_HT; + sc->defmedia = MB_HT; + + return 0; +} + +/* + * Probe and initialization for TDK/LANX LAC-AX012/013 boards. + */ +static int +fe_probe_lnx(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; + + u_char eeprom [LNX_EEPROM_SIZE]; + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for TDK/LANX boards. */ + /* 300, 320, 340, and 360 are allowed. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x060) != 0x300) + return ENXIO; + + /* We have 32 registers. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* We now have to read the config EEPROM. We should be very + careful, since doing so destroys a register. (Remember, we + are not yet sure we have a LAC-AX012/AX013 board here.) */ + fe_read_eeprom_lnx(sc, eeprom); + + /* Make sure the Ethernet (MAC) station address is of TDK/LANX's. */ + if (!valid_Ether_p(eeprom, 0x008098)) + return ENXIO; + bcopy(eeprom, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* This looks like a TDK/LANX board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + switch (irq) { + case 3: sc->priv_info = 0x40 | LNX_CLK_LO | LNX_SDA_HI; break; + case 4: sc->priv_info = 0x20 | LNX_CLK_LO | LNX_SDA_HI; break; + case 5: sc->priv_info = 0x10 | LNX_CLK_LO | LNX_SDA_HI; break; + case 9: sc->priv_info = 0x80 | LNX_CLK_LO | LNX_SDA_HI; break; + default: + fe_irq_failure("LAC-AX012/AX013", sc->sc_unit, irq, "3/4/5/9"); + return ENXIO; + } + + /* Fill softc struct accordingly. */ + sc->type = FE_TYPE_LNX; + sc->typestr = "LAC-AX012/AX013"; + sc->init = fe_init_lnx; + + return 0; +} + +/* + * Probe and initialization for Gateway Communications' old cards. + */ +static int +fe_probe_gwy(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; + + static struct fe_simple_probe_struct probe_table [] = { + /* { FE_DLCR2, 0x70, 0x00 }, */ + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for Gateway boards. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x1E0) != 0x200) + return ENXIO; + + /* That's all. The card occupies 32 I/O addresses, as always. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Setup an I/O address mapping table and some others. */ + fe_softc_defaults(sc); + + /* See if the card is on its address. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Make sure it is Gateway Communication's. */ + if (!valid_Ether_p(sc->sc_enaddr, 0x000061)) + return ENXIO; + + /* Gateway's board requires an explicit IRQ to work, since it + is not possible to probe the setting of jumpers. */ + if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) { + fe_irq_failure("Gateway Ethernet", sc->sc_unit, NO_IRQ, NULL); + return ENXIO; + } + + /* Fill softc struct accordingly. */ + sc->type = FE_TYPE_GWY; + sc->typestr = "Gateway Ethernet (Fujitsu chipset)"; + + return 0; +} + +/* Probe and initialization for Ungermann-Bass Network + K.K. "Access/PC" boards. */ +static int +fe_probe_ubn(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + u_long iobase, irq; +#if 0 + u_char sum; +#endif + static struct fe_simple_probe_struct const probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { 0 } + }; + + /* See if the specified I/O address is possible for AccessPC/ISA. */ + if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0) + return ENXIO; + if ((iobase & ~0x0E0) != 0x300) + return ENXIO; + + /* We have 32 registers. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Setup an I/O address mapping table and some others. */ + fe_softc_defaults(sc); + + /* Simple probe. */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address form ID ROM and make sure it is UBN's. */ + fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN); + if (!valid_Ether_p(sc->sc_enaddr, 0x00DD01)) + return ENXIO; +#if 0 + /* Calculate checksum. */ + sum = fe_inb(sc, 0x1e); + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sum ^= sc->sc_enaddr[i]; + } + if (sum != 0) + return ENXIO; +#endif + /* This looks like an AccessPC/ISA board. It requires an + explicit IRQ setting in config. Make sure we have one, + determining an appropriate value for the IRQ control + register. */ + irq = 0; + bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL); + switch (irq) { + case 3: sc->priv_info = 0x02; break; + case 4: sc->priv_info = 0x04; break; + case 5: sc->priv_info = 0x08; break; + case 10: sc->priv_info = 0x10; break; + default: + fe_irq_failure("Access/PC", sc->sc_unit, irq, "3/4/5/10"); + return ENXIO; + } + + /* Fill softc struct accordingly. */ + sc->type = FE_TYPE_UBN; + sc->typestr = "Access/PC"; + sc->init = fe_init_ubn; + + return 0; +} diff --git a/sys/dev/fe/if_fe_pccard.c b/sys/dev/fe/if_fe_pccard.c new file mode 100644 index 0000000..9f96200 --- /dev/null +++ b/sys/dev/fe/if_fe_pccard.c @@ -0,0 +1,277 @@ +/* + * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 + * + * This software may be used, modified, copied, distributed, and sold, in + * both source and binary form provided that the above copyright, these + * terms and the following disclaimer are retained. The name of the author + * and/or the contributor may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR 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. + * + * $FreeBSD$ + */ + +#include "opt_fe.h" +#include "opt_inet.h" +#include "opt_ipx.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <machine/clock.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_mib.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <net/bpf.h> + +#include <i386/isa/ic/mb86960.h> +#include <dev/fe/if_fereg.h> +#include <dev/fe/if_fevar.h> + +#include <dev/pccard/pccardvar.h> +#include <pccard/cardinfo.h> +#include <pccard/slot.h> + +/* + * PC-Card (PCMCIA) specific code. + */ +static int fe_pccard_probe(device_t); +static int fe_pccard_attach(device_t); +static int fe_pccard_detach(device_t); + +static device_method_t fe_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fe_pccard_probe), + DEVMETHOD(device_attach, fe_pccard_attach), + DEVMETHOD(device_detach, fe_pccard_detach), + + { 0, 0 } +}; + +static driver_t fe_pccard_driver = { + "fe", + fe_pccard_methods, + sizeof (struct fe_softc) +}; + +DRIVER_MODULE(fe, pccard, fe_pccard_driver, fe_devclass, 0, 0); + + +static int fe_probe_mbh(device_t); +static int fe_probe_tdk(device_t); + +/* + * Initialize the device - called from Slot manager. + */ +static int +fe_pccard_probe(device_t dev) +{ + struct fe_softc *sc; + int error; + + /* Prepare for the device probe process. */ + sc = device_get_softc(dev); + sc->sc_unit = device_get_unit(dev); + + pccard_get_ether(dev, sc->sc_enaddr); + + /* Probe for supported cards. */ + if ((error = fe_probe_mbh(dev)) == 0) + goto end; + fe_release_resource(dev); + + if ((error = fe_probe_tdk(dev)) == 0) + goto end; + fe_release_resource(dev); + +end: + if (error == 0) + error = fe_alloc_irq(dev, 0); + + fe_release_resource(dev); + return (error); +} + +static int +fe_pccard_attach(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + if (sc->port_used) + fe_alloc_port(dev, sc->port_used); + fe_alloc_irq(dev, 0); + + return fe_attach(dev); +} + +/* + * feunload - unload the driver and clear the table. + * XXX TODO: + * This is usually called when the card is ejected, but + * can be caused by a modunload of a controller driver. + * The idea is to reset the driver's view of the device + * and ensure that any driver entry points such as + * read and write do not hang. + */ +static int +fe_pccard_detach(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + struct ifnet *ifp = &sc->arpcom.ac_if; + + fe_stop(sc); + ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); + bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); + fe_release_resource(dev); + + return 0; +} + + +/* + * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. + * Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk(). + */ +static void +fe_init_mbh(struct fe_softc *sc) +{ + /* Minimal initialization of 86960. */ + DELAY(200); + fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE); + DELAY(200); + + /* Disable all interrupts. */ + fe_outb(sc, FE_DLCR2, 0); + fe_outb(sc, FE_DLCR3, 0); + + /* Enable master interrupt flag. */ + fe_outb(sc, FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE); +} + +static int +fe_probe_mbh(device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x58, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + { FE_DLCR6, 0xFF, 0xB6 }, + { 0 } + }; + + /* MBH10302 occupies 32 I/O addresses. */ + if (fe_alloc_port(dev, 32)) + return ENXIO; + + /* Ethernet MAC address should *NOT* have been given by pccardd, + if this is a true MBH10302; i.e., Ethernet address must be + "all-zero" upon entry. */ + if (sc->sc_enaddr[0] || sc->sc_enaddr[1] || sc->sc_enaddr[2] || + sc->sc_enaddr[3] || sc->sc_enaddr[4] || sc->sc_enaddr[5]) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* + * See if MBH10302 is on its address. + * I'm not sure the following probe code works. FIXME. + */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Get our station address from EEPROM. */ + fe_inblk(sc, FE_MBH10, sc->sc_enaddr, ETHER_ADDR_LEN); + + /* Make sure we got a valid station address. */ + if (!valid_Ether_p(sc->sc_enaddr, 0)) + return ENXIO; + + /* Determine the card type. */ + sc->type = FE_TYPE_MBH; + sc->typestr = "MBH10302 (PCMCIA)"; + + /* We seems to need our own IDENT bits... FIXME. */ + sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; + + /* Setup hooks. We need a special initialization procedure. */ + sc->init = fe_init_mbh; + + return 0; +} + +/* + * Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface. + * by MASUI Kenji <masui@cs.titech.ac.jp> + * + * (Contec uses TDK Ethenet chip -- hosokawa) + * + * This version of fe_probe_tdk has been rewrote to handle + * *generic* PC card implementation of Fujitsu MB8696x family. The + * name _tdk is just for a historical reason. :-) + */ +static int +fe_probe_tdk (device_t dev) +{ + struct fe_softc *sc = device_get_softc(dev); + + static struct fe_simple_probe_struct probe_table [] = { + { FE_DLCR2, 0x50, 0x00 }, + { FE_DLCR4, 0x08, 0x00 }, + /* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */ + { 0 } + }; + + /* C-NET(PC)C occupies 16 I/O addresses. */ + if (fe_alloc_port(dev, 16)) + return ENXIO; + + /* Fill the softc struct with default values. */ + fe_softc_defaults(sc); + + /* + * See if C-NET(PC)C is on its address. + */ + if (!fe_simple_probe(sc, probe_table)) + return ENXIO; + + /* Determine the card type. */ + sc->type = FE_TYPE_TDK; + sc->typestr = "Generic MB8696x/78Q837x Ethernet (PCMCIA)"; + + /* Make sure we got a valid station address. */ + if (!valid_Ether_p(sc->sc_enaddr, 0)) + return ENXIO; + + return 0; +} diff --git a/sys/dev/fe/if_fereg.h b/sys/dev/fe/if_fereg.h index 7e28201..21da37a 100644 --- a/sys/dev/fe/if_fereg.h +++ b/sys/dev/fe/if_fereg.h @@ -76,6 +76,7 @@ /* Card config register #1: IRQ enable */ #define FE_FMV3_IRQENB 0x80 /* IRQ enable. */ + /* * Register(?) specific to AT1700/RE2000. */ @@ -95,6 +96,7 @@ #define FE_ATI_MODEL_AT1700FT 0x02 #define FE_ATI_MODEL_AT1700AT 0x03 + /* * Registers on MBH10302. */ @@ -110,9 +112,55 @@ #define FE_MBH0_INTR_ENABLE 0x10 /* Enable interrupts. */ #define FE_MBH0_INTR_DISABLE 0x00 /* Disable interrupts. */ + /* * Registers on RE1000. (*NOT* on RE1000 Plus.) */ /* IRQ configuration. */ #define FE_RE1000_IRQCONF 0x10 + + +/* + * Fujitsu MB86965 JLI mode support routines. + */ + +/* Datasheet for 86965 explicitly states that it only supports serial + * EEPROM with 16 words (32 bytes) capacity. (I.e., 93C06.) However, + * ones with 64 words (128 bytes) are available in the marked, namely + * 93C46, and are also fully compatible with 86965. It is known that + * some boards (e.g., ICL) actually have 93C46 on them and use extra + * storage to keep various config info. */ +#define JLI_EEPROM_SIZE 128 + + +/* + * SSi 78Q8377A support routines. + */ +#define SSI_EEPROM_SIZE 512 +#define SSI_DIN 0x01 +#define SSI_DAT 0x01 +#define SSI_CSL 0x02 +#define SSI_CLK 0x04 +#define SSI_EEP 0x10 + +#define FE_SSI_EEP_IRQ 9 /* Irq ??? */ +#define FE_SSI_EEP_ADDR 16 /* Station(MAC) address */ +#define FE_SSI_EEP_DUPLEX 25 /* Duplex mode ??? */ + + +/* + * TDK/LANX boards support routines. + */ + +/* AX012/AX013 equips an X24C01 chip, which has 128 bytes of memory cells. */ +#define LNX_EEPROM_SIZE 128 + +/* Bit assignments and command definitions for the serial EEPROM + interface register in LANX ASIC. */ +#define LNX_SDA_HI 0x08 /* Drive SDA line high (logical 1.) */ +#define LNX_SDA_LO 0x00 /* Drive SDA line low (logical 0.) */ +#define LNX_SDA_FL 0x08 /* Float (don't drive) SDA line. */ +#define LNX_SDA_IN 0x01 /* Mask for reading SDA line. */ +#define LNX_CLK_HI 0x04 /* Drive clock line high (active.) */ +#define LNX_CLK_LO 0x00 /* Drive clock line low (inactive.) */ diff --git a/sys/dev/fe/if_fevar.h b/sys/dev/fe/if_fevar.h new file mode 100644 index 0000000..37842b2 --- /dev/null +++ b/sys/dev/fe/if_fevar.h @@ -0,0 +1,182 @@ +/* + * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 + * + * This software may be used, modified, copied, distributed, and sold, in + * both source and binary form provided that the above copyright, these + * terms and the following disclaimer are retained. The name of the author + * and/or the contributor may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR 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. + * + * $FreeBSD$ + */ + +/* How many registers does an fe-supported adapter have at maximum? */ +#define MAXREGISTERS 32 + +/* Shouldn't these be defined somewhere else such as isa_device.h? */ +#define NO_IRQ 0 + +/* Flags for stability. */ +#define UNSTABLE_IRQ 0x01 /* IRQ setting may be incorrect. */ +#define UNSTABLE_MAC 0x02 /* Probed MAC address may be incorrect. */ +#define UNSTABLE_TYPE 0x04 /* Probed vendor/model may be incorrect. */ + +/* Mapping between media bitmap (in fe_softc.mbitmap) and ifm_media. */ +#define MB_HA 0x0001 +#define MB_HM 0x0002 +#define MB_HT 0x0004 +#define MB_H2 0x0008 +#define MB_H5 0x0010 +#define MB_HF 0x0020 +#define MB_FT 0x0040 + +/* Card types. */ +#define FE_TYPE_SSI 1 +#define FE_TYPE_JLI 2 +#define FE_TYPE_FMV 3 +#define FE_TYPE_LNX 4 +#define FE_TYPE_UBN 5 +#define FE_TYPE_GWY 6 +#define FE_TYPE_MBH 7 +#define FE_TYPE_TDK 8 +#define FE_TYPE_RE1000 9 +#define FE_TYPE_CNET9NE 10 +#define FE_TYPE_REX 11 + +/* + * Data type for a multicast address filter on 8696x. + */ +struct fe_filter { + u_char data [FE_FILTER_LEN]; +}; + +/* + * fe_softc: per line info and status + */ +struct fe_softc { + + /* Used by "common" codes. */ + struct arpcom arpcom; /* Ethernet common */ + + /* Used by config codes. */ + int type; + int port_used; + struct resource * port_res; + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct resource * irq_res; + void * irq_handle; + + /* Set by probe() and not modified in later phases. */ + char const * typestr; /* printable name of the interface. */ + u_short txb_size; /* size of TX buffer, in bytes */ + u_char proto_dlcr4; /* DLCR4 prototype. */ + u_char proto_dlcr5; /* DLCR5 prototype. */ + u_char proto_dlcr6; /* DLCR6 prototype. */ + u_char proto_dlcr7; /* DLCR7 prototype. */ + u_char proto_bmpr13; /* BMPR13 prototype. */ + u_char stability; /* How stable is this? */ + u_short priv_info; /* info specific to a vendor/model. */ + + /* Vendor/model specific hooks. */ + void (*init)(struct fe_softc *); /* Just before fe_init(). */ + void (*stop)(struct fe_softc *); /* Just after fe_stop(). */ + + /* Transmission buffer management. */ + u_short txb_free; /* free bytes in TX buffer */ + u_char txb_count; /* number of packets in TX buffer */ + u_char txb_sched; /* number of scheduled packets */ + + /* Excessive collision counter (see fe_tint() for details.) */ + u_char tx_excolls; /* # of excessive collisions. */ + + /* Multicast address filter management. */ + u_char filter_change; /* MARs must be changed ASAP. */ + struct fe_filter filter;/* new filter value. */ + + /* Network management. */ + struct ifmib_iso_8802_3 mibdata; + + /* Media information. */ + struct ifmedia media; /* used by if_media. */ + u_short mbitmap; /* bitmap for supported media; see bit2media */ + int defmedia; /* default media */ + void (* msel)(struct fe_softc *); /* media selector. */ + +}; + +#define sc_if arpcom.ac_if +#define sc_unit arpcom.ac_if.if_unit +#define sc_enaddr arpcom.ac_enaddr + + +struct fe_simple_probe_struct { + u_char port; /* Offset from the base I/O address. */ + u_char mask; /* Bits to be checked. */ + u_char bits; /* Values to be compared against. */ +}; + + +extern devclass_t fe_devclass; + +int fe_attach(device_t); +int fe_alloc_port(device_t, int); +int fe_alloc_irq(device_t, int); +void fe_release_resource(device_t); + +int fe_simple_probe(struct fe_softc const *, + struct fe_simple_probe_struct const *); +int valid_Ether_p(u_char const *, unsigned); +void fe_softc_defaults(struct fe_softc *); +void fe_stop(struct fe_softc *sc); +void fe_irq_failure(char const *, int, int, char const *); +void fe_msel_965(struct fe_softc *); +void fe_read_eeprom_jli(struct fe_softc *, u_char *); +void fe_init_jli(struct fe_softc *); +void fe_read_eeprom_ssi(struct fe_softc *, u_char *); +void fe_read_eeprom_lnx(struct fe_softc *, u_char *); +void fe_init_lnx(struct fe_softc *); +void fe_init_ubn(struct fe_softc *); + + +#define fe_inb(sc, port) \ + bus_space_read_1((sc)->iot, (sc)->ioh, (port)) + +#define fe_outb(sc, port, value) \ + bus_space_write_1((sc)->iot, (sc)->ioh, (port), (value)) + +#define fe_inw(sc, port) \ + bus_space_read_2((sc)->iot, (sc)->ioh, (port)) + +#define fe_outw(sc, port, value) \ + bus_space_write_2((sc)->iot, (sc)->ioh, (port), (value)) + +#define fe_insb(sc, port, addr, count) \ + bus_space_read_multi_1((sc)->iot, (sc)->ioh, (port), (addr), (count)) + +#define fe_outsb(sc, port, addr, count) \ + bus_space_write_multi_1((sc)->iot, (sc)->ioh, (port), (addr), (count)) + +#define fe_insw(sc, port, addr, count) \ + bus_space_read_multi_2((sc)->iot, (sc)->ioh, (port), (addr), (count)) + +#define fe_outsw(sc, port, addr, count) \ + bus_space_write_multi_2((sc)->iot, (sc)->ioh, (port), (addr), (count)) + +#define fe_inblk(sc, port, addr, count) \ + bus_space_read_region_1((sc)->iot, (sc)->ioh, (port), (addr), (count)) + +#define fe_outblk(sc, port, addr, count) \ + bus_space_write_region_1((sc)->iot, (sc)->ioh, (port), (addr), (count)) |