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/if_fe_isa.c | |
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/if_fe_isa.c')
-rw-r--r-- | sys/dev/fe/if_fe_isa.c | 1063 |
1 files changed, 1063 insertions, 0 deletions
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; +} |