if_fe_cbus.c revision 67442
165832Snyan/*
265832Snyan * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
365832Snyan *
465832Snyan * This software may be used, modified, copied, distributed, and sold, in
565832Snyan * both source and binary form provided that the above copyright, these
665832Snyan * terms and the following disclaimer are retained.  The name of the author
765832Snyan * and/or the contributor may not be used to endorse or promote products
865832Snyan * derived from this software without specific prior written permission.
965832Snyan *
1065832Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
1165832Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1265832Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1365832Snyan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
1465832Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1565832Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1665832Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
1765832Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1865832Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1965832Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2065832Snyan * SUCH DAMAGE.
2165832Snyan *
2265832Snyan * $FreeBSD: head/sys/dev/fe/if_fe_cbus.c 67442 2000-10-22 16:48:08Z nyan $
2365832Snyan */
2465832Snyan
2565832Snyan#include "opt_fe.h"
2665832Snyan#include "opt_inet.h"
2765832Snyan#include "opt_ipx.h"
2865832Snyan
2965832Snyan#include <sys/param.h>
3065832Snyan#include <sys/systm.h>
3165832Snyan#include <sys/kernel.h>
3265832Snyan#include <sys/socket.h>
3365832Snyan#include <sys/module.h>
3465832Snyan
3565832Snyan#include <sys/bus.h>
3665832Snyan#include <machine/bus.h>
3765832Snyan#include <sys/rman.h>
3865832Snyan#include <machine/resource.h>
3965832Snyan
4065832Snyan#include <net/ethernet.h>
4165832Snyan#include <net/if.h>
4265832Snyan#include <net/if_mib.h>
4365832Snyan#include <net/if_media.h>
4465832Snyan
4565832Snyan#include <netinet/in.h>
4665832Snyan#include <netinet/if_ether.h>
4765832Snyan
4865832Snyan#include <i386/isa/ic/mb86960.h>
4965832Snyan#include <dev/fe/if_fereg.h>
5065832Snyan#include <dev/fe/if_fevar.h>
5165832Snyan
5267442Snyan#include <isa/isavar.h>
5367442Snyan
5465832Snyan/*
5565832Snyan *	Cbus specific code.
5665832Snyan */
5765832Snyanstatic int fe_isa_probe(device_t);
5865832Snyanstatic int fe_isa_attach(device_t);
5965832Snyan
6065832Snyanstatic device_method_t fe_isa_methods[] = {
6165832Snyan	/* Device interface */
6265832Snyan	DEVMETHOD(device_probe,		fe_isa_probe),
6365832Snyan	DEVMETHOD(device_attach,	fe_isa_attach),
6465832Snyan
6565832Snyan	{ 0, 0 }
6665832Snyan};
6765832Snyan
6865832Snyanstatic driver_t fe_isa_driver = {
6965832Snyan	"fe",
7065832Snyan	fe_isa_methods,
7165832Snyan	sizeof (struct fe_softc)
7265832Snyan};
7365832Snyan
7465832SnyanDRIVER_MODULE(fe, isa, fe_isa_driver, fe_devclass, 0, 0);
7565832Snyan
7665832Snyan
7765832Snyanstatic int fe98_alloc_port(device_t, int);
7865832Snyan
7965832Snyanstatic int fe_probe_re1000(device_t);
8065832Snyanstatic int fe_probe_cnet9ne(device_t);
8165832Snyanstatic int fe_probe_rex(device_t);
8265832Snyanstatic int fe_probe_ssi(device_t);
8365832Snyanstatic int fe_probe_jli(device_t);
8465832Snyanstatic int fe_probe_lnx(device_t);
8565832Snyanstatic int fe_probe_gwy(device_t);
8665832Snyanstatic int fe_probe_ubn(device_t);
8765832Snyan
8865832Snyan/*
8965832Snyan * Determine if the device is present at a specified I/O address.  The
9065832Snyan * main entry to the driver.
9165832Snyan */
9265832Snyan
9365832Snyanstatic int
9465832Snyanfe_isa_probe(device_t dev)
9565832Snyan{
9665832Snyan	struct fe_softc * sc;
9765832Snyan	int error;
9865832Snyan
9965832Snyan	/* Prepare for the softc struct.  */
10065832Snyan	sc = device_get_softc(dev);
10165832Snyan	sc->sc_unit = device_get_unit(dev);
10265832Snyan
10365832Snyan	/* Probe for supported boards.  */
10465832Snyan#ifdef PC98
10565832Snyan	if ((error = fe_probe_re1000(dev)) == 0)
10665832Snyan		goto end;
10765832Snyan	fe_release_resource(dev);
10865832Snyan
10965832Snyan	if ((error = fe_probe_cnet9ne(dev)) == 0)
11065832Snyan		goto end;
11165832Snyan	fe_release_resource(dev);
11265832Snyan
11365832Snyan	if ((error = fe_probe_rex(dev)) == 0)
11465832Snyan		goto end;
11565832Snyan	fe_release_resource(dev);
11665832Snyan#endif
11765832Snyan
11865832Snyan	if ((error = fe_probe_ssi(dev)) == 0)
11965832Snyan		goto end;
12065832Snyan	fe_release_resource(dev);
12165832Snyan
12265832Snyan	if ((error = fe_probe_jli(dev)) == 0)
12365832Snyan		goto end;
12465832Snyan	fe_release_resource(dev);
12565832Snyan
12665832Snyan	if ((error = fe_probe_lnx(dev)) == 0)
12765832Snyan		goto end;
12865832Snyan	fe_release_resource(dev);
12965832Snyan
13065832Snyan	if ((error = fe_probe_ubn(dev)) == 0)
13165832Snyan		goto end;
13265832Snyan	fe_release_resource(dev);
13365832Snyan
13465832Snyan	if ((error = fe_probe_gwy(dev)) == 0)
13565832Snyan		goto end;
13665832Snyan	fe_release_resource(dev);
13765832Snyan
13865832Snyanend:
13965832Snyan	if (error == 0)
14065832Snyan		error = fe_alloc_irq(dev, 0);
14165832Snyan
14265832Snyan	fe_release_resource(dev);
14365832Snyan	return (error);
14465832Snyan}
14565832Snyan
14665832Snyanstatic int
14765832Snyanfe_isa_attach(device_t dev)
14865832Snyan{
14965832Snyan	struct fe_softc *sc = device_get_softc(dev);
15065832Snyan
15165832Snyan	if (sc->port_used)
15265832Snyan		fe98_alloc_port(dev, sc->type);
15365832Snyan	fe_alloc_irq(dev, 0);
15465832Snyan
15565832Snyan	return fe_attach(dev);
15665832Snyan}
15765832Snyan
15865832Snyan
15965832Snyan/* Generic I/O address table */
16065832Snyanstatic bus_addr_t ioaddr_generic[MAXREGISTERS] = {
16165832Snyan	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
16265832Snyan	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
16365832Snyan	0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x017,
16465832Snyan	0x018, 0x019, 0x01a, 0x01b, 0x01c, 0x01d, 0x01e, 0x01f,
16565832Snyan};
16665832Snyan
16765832Snyan/* I/O address table for RE1000/1000Plus */
16865832Snyanstatic bus_addr_t ioaddr_re1000[MAXREGISTERS] = {
16965832Snyan	0x0000, 0x0001, 0x0200, 0x0201, 0x0400, 0x0401, 0x0600, 0x0601,
17065832Snyan	0x0800, 0x0801, 0x0a00, 0x0a01, 0x0c00, 0x0c01, 0x0e00, 0x0e01,
17165832Snyan	0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00,
17265832Snyan	0x1001, 0x1201, 0x1401, 0x1601, 0x1801, 0x1a01, 0x1c01, 0x1e01,
17365832Snyan};
17465832Snyan
17565832Snyan/* I/O address table for CNET9NE */
17665832Snyanstatic bus_addr_t ioaddr_cnet9ne[MAXREGISTERS] = {
17765832Snyan	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
17865832Snyan	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
17965832Snyan	0x400, 0x402, 0x404, 0x406, 0x408, 0x40a, 0x40c, 0x40e,
18065832Snyan	0x401, 0x403, 0x405, 0x407, 0x409, 0x40b, 0x40d, 0x40f,
18165832Snyan};
18265832Snyan
18365832Snyan/* I/O address table for LAC-98 */
18465832Snyanstatic bus_addr_t ioaddr_lnx[MAXREGISTERS] = {
18565832Snyan	0x000, 0x002, 0x004, 0x006, 0x008, 0x00a, 0x00c, 0x00e,
18665832Snyan	0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e,
18765832Snyan	0x200, 0x202, 0x204, 0x206, 0x208, 0x20a, 0x20c, 0x20e,
18865832Snyan	0x300, 0x302, 0x304, 0x306, 0x308, 0x30a, 0x30c, 0x30e,
18965832Snyan};
19065832Snyan
19165832Snyan/* I/O address table for Access/PC N98C+ */
19265832Snyanstatic bus_addr_t ioaddr_ubn[MAXREGISTERS] = {
19365832Snyan	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
19465832Snyan	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
19565832Snyan	0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207,
19665832Snyan	0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f,
19765832Snyan};
19865832Snyan
19965832Snyan/* I/O address table for REX-9880 */
20065832Snyanstatic bus_addr_t ioaddr_rex[MAXREGISTERS] = {
20165832Snyan	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
20265832Snyan	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
20365832Snyan	0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107,
20465832Snyan	0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, 0x10f,
20565832Snyan};
20665832Snyan
20765832Snyanstatic int
20865832Snyanfe98_alloc_port(device_t dev, int type)
20965832Snyan{
21065832Snyan	struct fe_softc *sc = device_get_softc(dev);
21165832Snyan	struct resource *res;
21265832Snyan	bus_addr_t *iat;
21365832Snyan	int size, rid;
21465832Snyan
21565832Snyan	switch (type) {
21665832Snyan	case FE_TYPE_RE1000:
21765832Snyan		iat = ioaddr_re1000;
21865832Snyan		size = MAXREGISTERS;
21965832Snyan		break;
22065832Snyan	case FE_TYPE_CNET9NE:
22165832Snyan		iat = &ioaddr_cnet9ne[16];
22265832Snyan		size = 16;
22365832Snyan		break;
22465832Snyan	case FE_TYPE_SSI:
22565832Snyan		iat = ioaddr_generic;
22665832Snyan		size = MAXREGISTERS;
22765832Snyan		break;
22865832Snyan	case FE_TYPE_LNX:
22965832Snyan		iat = ioaddr_lnx;
23065832Snyan		size = MAXREGISTERS;
23165832Snyan		break;
23265832Snyan	case FE_TYPE_GWY:
23365832Snyan		iat = ioaddr_generic;
23465832Snyan		size = MAXREGISTERS;
23565832Snyan		break;
23665832Snyan	case FE_TYPE_UBN:
23765832Snyan		iat = ioaddr_ubn;
23865832Snyan		size = MAXREGISTERS;
23965832Snyan		break;
24065832Snyan	case FE_TYPE_REX:
24165832Snyan		iat = ioaddr_rex;
24265832Snyan		size = MAXREGISTERS;
24365832Snyan		break;
24465832Snyan	default:
24565832Snyan		iat = ioaddr_generic;
24665832Snyan		size = MAXREGISTERS;
24765832Snyan		break;
24865832Snyan	}
24965832Snyan
25065832Snyan	rid = 0;
25165832Snyan	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
25265832Snyan				  iat, size, RF_ACTIVE);
25365832Snyan	if (res == NULL)
25465832Snyan		return ENOENT;
25565832Snyan
25665832Snyan	switch (type) {
25765832Snyan	case FE_TYPE_CNET9NE:
25865832Snyan		iat = ioaddr_cnet9ne;
25965832Snyan		size = MAXREGISTERS;
26065832Snyan		break;
26165832Snyan	}
26265832Snyan
26365832Snyan	isa_load_resourcev(res, iat, size);
26465832Snyan
26565832Snyan	sc->type = type;
26665832Snyan	sc->port_used = size;
26765832Snyan	sc->port_res = res;
26865832Snyan	sc->iot = rman_get_bustag(res);
26965832Snyan	sc->ioh = rman_get_bushandle(res);
27065832Snyan	return (0);
27165832Snyan}
27265832Snyan
27365832Snyan
27465832Snyan/*
27565832Snyan * Probe and initialization for Allied-Telesis RE1000 series.
27665832Snyan */
27765832Snyanstatic void
27865832Snyanfe_init_re1000(struct fe_softc *sc)
27965832Snyan{
28065832Snyan	/* Setup IRQ control register on the ASIC.  */
28165832Snyan	fe_outb(sc, FE_RE1000_IRQCONF, sc->priv_info);
28265832Snyan}
28365832Snyan
28465832Snyanstatic int
28565832Snyanfe_probe_re1000(device_t dev)
28665832Snyan{
28765832Snyan	struct fe_softc *sc = device_get_softc(dev);
28865832Snyan	int i, n;
28965832Snyan	u_long iobase, irq;
29065832Snyan	u_char sum;
29165832Snyan
29265832Snyan	static struct fe_simple_probe_struct probe_table [] = {
29365832Snyan		{ FE_DLCR2, 0x58, 0x00 },
29465832Snyan		{ FE_DLCR4, 0x08, 0x00 },
29565832Snyan		{ 0 }
29665832Snyan	};
29765832Snyan
29865832Snyan	/* See if the specified I/O address is possible for RE1000.  */
29965832Snyan	/* [01]D[02468ACE] are allowed.  */
30065832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
30165832Snyan		return ENXIO;
30265832Snyan	if ((iobase & ~0x10E) != 0xD0)
30365832Snyan		return ENXIO;
30465832Snyan
30565832Snyan	if (fe98_alloc_port(dev, FE_TYPE_RE1000))
30665832Snyan		return ENXIO;
30765832Snyan
30865832Snyan	/* Fill the softc struct with default values.  */
30965832Snyan	fe_softc_defaults(sc);
31065832Snyan
31165832Snyan	/* See if the card is on its address.  */
31265832Snyan	if (!fe_simple_probe(sc, probe_table))
31365832Snyan		return ENXIO;
31465832Snyan
31565832Snyan	/* Get our station address from EEPROM.  */
31665832Snyan	fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN);
31765832Snyan
31865832Snyan	/* Make sure it is Allied-Telesis's.  */
31965832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4))
32065832Snyan		return ENXIO;
32165832Snyan#if 1
32265832Snyan	/* Calculate checksum.  */
32365832Snyan	sum = fe_inb(sc, 0x1e);
32465832Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++)
32565832Snyan		sum ^= sc->sc_enaddr[i];
32665832Snyan	if (sum != 0)
32765832Snyan		return ENXIO;
32865832Snyan#endif
32965832Snyan	/* Setup the board type.  */
33065832Snyan	sc->typestr = "RE1000";
33165832Snyan
33265832Snyan	/* This looks like an RE1000 board.  It requires an
33365832Snyan	   explicit IRQ setting in config.  Make sure we have one,
33465832Snyan	   determining an appropriate value for the IRQ control
33565832Snyan	   register.  */
33665832Snyan	irq = 0;
33765832Snyan	bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL);
33865832Snyan	switch (irq) {
33965832Snyan	case 3:  n = 0x10; break;
34065832Snyan	case 5:  n = 0x20; break;
34165832Snyan	case 6:  n = 0x40; break;
34265832Snyan	case 12: n = 0x80; break;
34365832Snyan	default:
34465832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12");
34565832Snyan		return ENXIO;
34665832Snyan	}
34765832Snyan	sc->priv_info = (fe_inb(sc, FE_RE1000_IRQCONF) & 0x0f) | n;
34865832Snyan
34965832Snyan	/* Setup hooks.  We need a special initialization procedure.  */
35065832Snyan	sc->init = fe_init_re1000;
35165832Snyan
35265832Snyan	return 0;
35365832Snyan}
35465832Snyan
35565832Snyan/* JLI sub-probe for Allied-Telesis RE1000Plus/ME1500 series.  */
35665832Snyanstatic u_short const *
35765832Snyanfe_probe_jli_re1000p(struct fe_softc * sc, u_char const * eeprom)
35865832Snyan{
35965832Snyan	int i;
36065832Snyan	static u_short const irqmaps_re1000p [4] = { 3, 5, 6, 12 };
36165832Snyan
36265832Snyan	/* Make sure the EEPROM contains Allied-Telesis bit pattern.  */
36365832Snyan	if (eeprom[1] != 0xFF) return NULL;
36465832Snyan	for (i =  2; i <  8; i++) if (eeprom[i] != 0xFF) return NULL;
36565832Snyan	for (i = 14; i < 24; i++) if (eeprom[i] != 0xFF) return NULL;
36665832Snyan
36765832Snyan	/* Get our station address from EEPROM, and make sure the
36865832Snyan           EEPROM contains Allied-Telesis's address.  */
36965832Snyan	bcopy(eeprom + 8, sc->sc_enaddr, ETHER_ADDR_LEN);
37065832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x0000F4))
37165832Snyan		return NULL;
37265832Snyan
37365832Snyan	/* I don't know any sub-model identification.  */
37465832Snyan	sc->typestr = "RE1000Plus/ME1500";
37565832Snyan
37665832Snyan	/* Returns the IRQ table for the RE1000Plus.  */
37765832Snyan	return irqmaps_re1000p;
37865832Snyan}
37965832Snyan
38065832Snyan
38165832Snyan/*
38265832Snyan * Probe for Allied-Telesis RE1000Plus/ME1500 series.
38365832Snyan */
38465832Snyanstatic int
38565832Snyanfe_probe_jli(device_t dev)
38665832Snyan{
38765832Snyan	struct fe_softc *sc = device_get_softc(dev);
38865832Snyan	int i, n, xirq, error;
38965832Snyan	u_long iobase, irq;
39065832Snyan	u_char eeprom [JLI_EEPROM_SIZE];
39165832Snyan	u_short const * irqmap;
39265832Snyan
39365832Snyan	static u_short const baseaddr [8] =
39465832Snyan		{ 0x1D6, 0x1D8, 0x1DA, 0x1D4, 0x0D4, 0x0D2, 0x0D8, 0x0D0 };
39565832Snyan	static struct fe_simple_probe_struct const probe_table [] = {
39665832Snyan	/*	{ FE_DLCR1,  0x20, 0x00 },	Doesn't work. */
39765832Snyan		{ FE_DLCR2,  0x50, 0x00 },
39865832Snyan		{ FE_DLCR4,  0x08, 0x00 },
39965832Snyan	/*	{ FE_DLCR5,  0x80, 0x00 },	Doesn't work. */
40065832Snyan#if 0
40165832Snyan		{ FE_BMPR16, 0x1B, 0x00 },
40265832Snyan		{ FE_BMPR17, 0x7F, 0x00 },
40365832Snyan#endif
40465832Snyan		{ 0 }
40565832Snyan	};
40665832Snyan
40765832Snyan	/*
40865832Snyan	 * See if the specified address is possible for MB86965A JLI mode.
40965832Snyan	 */
41065832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
41165832Snyan		return ENXIO;
41265832Snyan	for (i = 0; i < 8; i++) {
41365832Snyan		if (baseaddr[i] == iobase)
41465832Snyan			break;
41565832Snyan	}
41665832Snyan	if (i == 8)
41765832Snyan		return ENXIO;
41865832Snyan
41965832Snyan	if (fe98_alloc_port(dev, FE_TYPE_RE1000))
42065832Snyan		return ENXIO;
42165832Snyan
42265832Snyan	/* Fill the softc struct with default values.  */
42365832Snyan	fe_softc_defaults(sc);
42465832Snyan
42565832Snyan	/*
42665832Snyan	 * We should test if MB86965A is on the base address now.
42765832Snyan	 * Unfortunately, it is very hard to probe it reliably, since
42865832Snyan	 * we have no way to reset the chip under software control.
42965832Snyan	 * On cold boot, we could check the "signature" bit patterns
43065832Snyan	 * described in the Fujitsu document.  On warm boot, however,
43165832Snyan	 * we can predict almost nothing about register values.
43265832Snyan	 */
43365832Snyan	if (!fe_simple_probe(sc, probe_table))
43465832Snyan		return ENXIO;
43565832Snyan
43665832Snyan	/* Check if our I/O address matches config info on 86965.  */
43765832Snyan	n = (fe_inb(sc, FE_BMPR19) & FE_B19_ADDR) >> FE_B19_ADDR_SHIFT;
43865832Snyan	if (baseaddr[n] != iobase)
43965832Snyan		return ENXIO;
44065832Snyan
44165832Snyan	/*
44265832Snyan	 * We are now almost sure we have an MB86965 at the given
44365832Snyan	 * address.  So, read EEPROM through it.  We have to write
44465832Snyan	 * into LSI registers to read from EEPROM.  I want to avoid it
44565832Snyan	 * at this stage, but I cannot test the presence of the chip
44665832Snyan	 * any further without reading EEPROM.  FIXME.
44765832Snyan	 */
44865832Snyan	fe_read_eeprom_jli(sc, eeprom);
44965832Snyan
45065832Snyan	/* Make sure that config info in EEPROM and 86965 agree.  */
45165832Snyan	if (eeprom[FE_EEPROM_CONF] != fe_inb(sc, FE_BMPR19))
45265832Snyan		return ENXIO;
45365832Snyan
45465832Snyan	/* Use 86965 media selection scheme, unless othewise
45565832Snyan           specified.  It is "AUTO always" and "select with BMPR13".
45665832Snyan           This behaviour covers most of the 86965 based board (as
45765832Snyan           minimum requirements.)  It is backward compatible with
45865832Snyan           previous versions, also.  */
45965832Snyan	sc->mbitmap = MB_HA;
46065832Snyan	sc->defmedia = MB_HA;
46165832Snyan	sc->msel = fe_msel_965;
46265832Snyan
46365832Snyan	/* Perform board-specific probe.  */
46465832Snyan	if ((irqmap = fe_probe_jli_re1000p(sc, eeprom)) == NULL)
46565832Snyan		return ENXIO;
46665832Snyan
46765832Snyan	/* Find the IRQ read from EEPROM.  */
46865832Snyan	n = (fe_inb(sc, FE_BMPR19) & FE_B19_IRQ) >> FE_B19_IRQ_SHIFT;
46965832Snyan	xirq = irqmap[n];
47065832Snyan
47165832Snyan	/* Try to determine IRQ setting.  */
47265832Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL);
47365832Snyan	if (error && xirq == NO_IRQ) {
47465832Snyan		/* The device must be configured with an explicit IRQ.  */
47565832Snyan		device_printf(dev, "IRQ auto-detection does not work\n");
47665832Snyan		return ENXIO;
47765832Snyan	} else if (error && xirq != NO_IRQ) {
47865832Snyan		/* Just use the probed IRQ value.  */
47965832Snyan		bus_set_resource(dev, SYS_RES_IRQ, 0, xirq, 1);
48065832Snyan	} else if (!error && xirq == NO_IRQ) {
48165832Snyan		/* No problem.  Go ahead.  */
48265832Snyan	} else if (irq == xirq) {
48365832Snyan		/* Good.  Go ahead.  */
48465832Snyan	} else {
48565832Snyan		/* User must be warned in this case.  */
48665832Snyan		sc->stability |= UNSTABLE_IRQ;
48765832Snyan	}
48865832Snyan
48965832Snyan	/* Setup a hook, which resets te 86965 when the driver is being
49065832Snyan           initialized.  This may solve a nasty bug.  FIXME.  */
49165832Snyan	sc->init = fe_init_jli;
49265832Snyan
49365832Snyan	return 0;
49465832Snyan}
49565832Snyan
49665832Snyan
49765832Snyan/*
49865832Snyan * Probe and initialization for Contec C-NET(9N)E series.
49965832Snyan */
50065832Snyan
50165832Snyan/* TODO: Should be in "if_fereg.h" */
50265832Snyan#define FE_CNET9NE_INTR		0x10		/* Interrupt Mask? */
50365832Snyan
50465832Snyanstatic void
50565832Snyanfe_init_cnet9ne(struct fe_softc *sc)
50665832Snyan{
50765832Snyan	/* Enable interrupt?  FIXME.  */
50865832Snyan	fe_outb(sc, FE_CNET9NE_INTR, 0x10);
50965832Snyan}
51065832Snyan
51165832Snyanstatic int
51265832Snyanfe_probe_cnet9ne (device_t dev)
51365832Snyan{
51465832Snyan	struct fe_softc *sc = device_get_softc(dev);
51565832Snyan	u_long iobase, irq;
51665832Snyan
51765832Snyan	static struct fe_simple_probe_struct probe_table [] = {
51865832Snyan		{ FE_DLCR2, 0x58, 0x00 },
51965832Snyan		{ FE_DLCR4, 0x08, 0x00 },
52065832Snyan		{ 0 }
52165832Snyan	};
52265832Snyan
52365832Snyan	/* See if the specified I/O address is possible for C-NET(9N)E.  */
52465832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
52565832Snyan		return ENXIO;
52665832Snyan	if (iobase != 0x73D0)
52765832Snyan		return ENXIO;
52865832Snyan
52965832Snyan	if (fe98_alloc_port(dev, FE_TYPE_CNET9NE))
53065832Snyan		return ENXIO;
53165832Snyan
53265832Snyan	/* Fill the softc struct with default values.  */
53365832Snyan	fe_softc_defaults(sc);
53465832Snyan
53565832Snyan	/* See if the card is on its address.  */
53665832Snyan	if (!fe_simple_probe(sc, probe_table))
53765832Snyan		return ENXIO;
53865832Snyan
53965832Snyan	/* Get our station address from EEPROM.  */
54065832Snyan	fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN);
54165832Snyan
54265832Snyan	/* Make sure it is Contec's.  */
54365832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x00804C))
54465832Snyan		return ENXIO;
54565832Snyan
54665832Snyan	/* Determine the card type.  */
54765832Snyan	if (sc->sc_enaddr[3] == 0x06) {
54865832Snyan		sc->typestr = "C-NET(9N)C";
54965832Snyan
55065832Snyan		/* We seems to need our own IDENT bits...  FIXME.  */
55165832Snyan		sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE;
55265832Snyan
55365832Snyan		/* C-NET(9N)C requires an explicit IRQ to work.  */
55465832Snyan		if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0) {
55565832Snyan			fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL);
55665832Snyan			return ENXIO;
55765832Snyan		}
55865832Snyan	} else {
55965832Snyan		sc->typestr = "C-NET(9N)E";
56065832Snyan
56165832Snyan		/* C-NET(9N)E works only IRQ5.  */
56265832Snyan		if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0)
56365832Snyan			return ENXIO;
56465832Snyan		if (irq != 5) {
56565832Snyan			fe_irq_failure(sc->typestr, sc->sc_unit, irq, "5");
56665832Snyan			return ENXIO;
56765832Snyan		}
56865832Snyan
56965832Snyan		/* We need an init hook to initialize ASIC before we start.  */
57065832Snyan		sc->init = fe_init_cnet9ne;
57165832Snyan	}
57265832Snyan
57365832Snyan	/* C-NET(9N)E has 64KB SRAM.  */
57465832Snyan	sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB
57565832Snyan			| FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM;
57665832Snyan
57765832Snyan	return 0;
57865832Snyan}
57965832Snyan
58065832Snyan
58165832Snyan/*
58265832Snyan * Probe for Contec C-NET(98)P2 series.
58365832Snyan * (Logitec LAN-98TP/LAN-98T25P - parhaps)
58465832Snyan */
58565832Snyanstatic int
58665832Snyanfe_probe_ssi(device_t dev)
58765832Snyan{
58865832Snyan	struct fe_softc *sc = device_get_softc(dev);
58965832Snyan	u_long iobase, irq;
59065832Snyan
59165832Snyan	u_char eeprom [SSI_EEPROM_SIZE];
59265832Snyan	static struct fe_simple_probe_struct probe_table [] = {
59365832Snyan		{ FE_DLCR2, 0x08, 0x00 },
59465832Snyan		{ FE_DLCR4, 0x08, 0x00 },
59565832Snyan		{ 0 }
59665832Snyan	};
59765832Snyan	static u_short const irqmap[] = {
59865832Snyan		/*                        INT0          INT1    INT2       */
59965832Snyan		NO_IRQ, NO_IRQ, NO_IRQ,      3, NO_IRQ,    5,      6, NO_IRQ,
60065832Snyan		NO_IRQ,      9,     10, NO_IRQ,     12,   13, NO_IRQ, NO_IRQ,
60165832Snyan		/*        INT3   INT41            INT5  INT6               */
60265832Snyan	};
60365832Snyan
60465832Snyan	/* See if the specified I/O address is possible for 78Q8377A.  */
60565832Snyan	/* [0-D]3D0 are allowed.  */
60665832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
60765832Snyan		return ENXIO;
60865832Snyan	if ((iobase & 0xFFF) != 0x3D0)
60965832Snyan		return ENXIO;
61065832Snyan
61165832Snyan	if (fe98_alloc_port(dev, FE_TYPE_SSI))
61265832Snyan		return ENXIO;
61365832Snyan
61465832Snyan	/* Fill the softc struct with default values.  */
61565832Snyan	fe_softc_defaults(sc);
61665832Snyan
61765832Snyan	/* See if the card is on its address.  */
61865832Snyan	if (!fe_simple_probe(sc, probe_table))
61965832Snyan		return ENXIO;
62065832Snyan
62165832Snyan	/* We now have to read the config EEPROM.  We should be very
62265832Snyan           careful, since doing so destroys a register.  (Remember, we
62365832Snyan           are not yet sure we have a C-NET(98)P2 board here.)  Don't
62465832Snyan           remember to select BMPRs bofore reading EEPROM, since other
62565832Snyan           register bank may be selected before the probe() is called.  */
62665832Snyan	fe_read_eeprom_ssi(sc, eeprom);
62765832Snyan
62865832Snyan	/* Make sure the Ethernet (MAC) station address is of Contec's.  */
62965832Snyan	if (!valid_Ether_p(eeprom + FE_SSI_EEP_ADDR, 0x00804C))
63065832Snyan		return ENXIO;
63165832Snyan	bcopy(eeprom + FE_SSI_EEP_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN);
63265832Snyan
63365832Snyan	/* Setup the board type.  */
63465832Snyan        sc->typestr = "C-NET(98)P2";
63565832Snyan
63665832Snyan	/* Get IRQ configuration from EEPROM.  */
63765832Snyan	irq = irqmap[eeprom[FE_SSI_EEP_IRQ]];
63865832Snyan	if (irq == NO_IRQ) {
63965832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, irq,
64065832Snyan			       "3/5/6/9/10/12/13");
64165832Snyan		return ENXIO;
64265832Snyan	}
64365832Snyan	bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
64465832Snyan
64565832Snyan	/* Get Duplex-mode configuration from EEPROM.  */
64665832Snyan	sc->proto_dlcr4 |= (eeprom[FE_SSI_EEP_DUPLEX] & FE_D4_DSC);
64765832Snyan
64865832Snyan	/* Fill softc struct accordingly.  */
64965832Snyan	sc->mbitmap = MB_HT;
65065832Snyan	sc->defmedia = MB_HT;
65165832Snyan
65265832Snyan	return 0;
65365832Snyan}
65465832Snyan
65565832Snyan
65665832Snyan/*
65765832Snyan * Probe for TDK LAC-98012/013/025/9N011 - parhaps.
65865832Snyan */
65965832Snyanstatic int
66065832Snyanfe_probe_lnx(device_t dev)
66165832Snyan{
66265832Snyan#ifndef FE_8BIT_SUPPORT
66365832Snyan	device_printf(dev,
66465832Snyan		      "skip LAC-98012/013(only 16-bit cards are supported)\n");
66565832Snyan	return ENXIO;
66665832Snyan#else
66765832Snyan	struct fe_softc *sc = device_get_softc(dev);
66865832Snyan
66965832Snyan	u_long iobase, irq;
67065832Snyan	u_char eeprom [LNX_EEPROM_SIZE];
67165832Snyan
67265832Snyan	static struct fe_simple_probe_struct probe_table [] = {
67365832Snyan		{ FE_DLCR2, 0x58, 0x00 },
67465832Snyan		{ FE_DLCR4, 0x08, 0x00 },
67565832Snyan		{ 0 }
67665832Snyan	};
67765832Snyan
67865832Snyan	/* See if the specified I/O address is possible for TDK/LANX boards. */
67965832Snyan	/* 0D0, 4D0, 8D0, and CD0 are allowed.  */
68065832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
68165832Snyan		return ENXIO;
68265832Snyan	if ((iobase & ~0xC00) != 0xD0)
68365832Snyan		return ENXIO;
68465832Snyan
68565832Snyan	if (fe98_alloc_port(dev, FE_TYPE_LNX))
68665832Snyan		return ENXIO;
68765832Snyan
68865832Snyan	/* Fill the softc struct with default values.  */
68965832Snyan	fe_softc_defaults(sc);
69065832Snyan
69165832Snyan	/* See if the card is on its address.  */
69265832Snyan	if (!fe_simple_probe(sc, probe_table))
69365832Snyan		return ENXIO;
69465832Snyan
69565832Snyan	/* We now have to read the config EEPROM.  We should be very
69665832Snyan           careful, since doing so destroys a register.  (Remember, we
69765832Snyan           are not yet sure we have a LAC-98012/98013 board here.)  */
69865832Snyan	fe_read_eeprom_lnx(sc, eeprom);
69965832Snyan
70065832Snyan	/* Make sure the Ethernet (MAC) station address is of TDK/LANX's.  */
70165832Snyan	if (!valid_Ether_p(eeprom, 0x008098))
70265832Snyan		return ENXIO;
70365832Snyan	bcopy(eeprom, sc->sc_enaddr, ETHER_ADDR_LEN);
70465832Snyan
70565832Snyan	/* Setup the board type.  */
70665832Snyan	sc->typestr = "LAC-98012/98013";
70765832Snyan
70865832Snyan	/* This looks like a TDK/LANX board.  It requires an
70965832Snyan	   explicit IRQ setting in config.  Make sure we have one,
71065832Snyan	   determining an appropriate value for the IRQ control
71165832Snyan	   register.  */
71265832Snyan	irq = 0;
71365832Snyan	if (bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL) != 0)
71465832Snyan		return ENXIO;
71565832Snyan	switch (irq) {
71665832Snyan	case 3 : sc->priv_info = 0x10 | LNX_CLK_LO | LNX_SDA_HI; break;
71765832Snyan	case 5 : sc->priv_info = 0x20 | LNX_CLK_LO | LNX_SDA_HI; break;
71865832Snyan	case 6 : sc->priv_info = 0x40 | LNX_CLK_LO | LNX_SDA_HI; break;
71965832Snyan	case 12: sc->priv_info = 0x80 | LNX_CLK_LO | LNX_SDA_HI; break;
72065832Snyan	default:
72165832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12");
72265832Snyan		return ENXIO;
72365832Snyan	}
72465832Snyan
72565832Snyan	/* LAC-98's system bus width is 8-bit.  */
72665832Snyan	sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x2KB
72765832Snyan			| FE_D6_BBW_BYTE | FE_D6_SBW_BYTE | FE_D6_SRAM_150ns;
72865832Snyan
72965832Snyan	/* Setup hooks.  We need a special initialization procedure.  */
73065832Snyan	sc->init = fe_init_lnx;
73165832Snyan
73265832Snyan	return 0;
73365832Snyan#endif /* FE_8BIT_SUPPORT */
73465832Snyan}
73565832Snyan
73665832Snyan
73765832Snyan/*
73865832Snyan * Probe for Gateway Communications' old cards.
73965832Snyan * (both as Generic MB86960 probe routine)
74065832Snyan */
74165832Snyanstatic int
74265832Snyanfe_probe_gwy(device_t dev)
74365832Snyan{
74465832Snyan	struct fe_softc *sc = device_get_softc(dev);
74565832Snyan
74665832Snyan	static struct fe_simple_probe_struct probe_table [] = {
74765832Snyan	    /*	{ FE_DLCR2, 0x70, 0x00 }, */
74865832Snyan		{ FE_DLCR2, 0x58, 0x00 },
74965832Snyan		{ FE_DLCR4, 0x08, 0x00 },
75065832Snyan		{ 0 }
75165832Snyan	};
75265832Snyan
75365832Snyan	/*
75465832Snyan	 * XXX
75565832Snyan	 * I'm not sure which address is possible, so accepts any.
75665832Snyan	 */
75765832Snyan
75865832Snyan	if (fe98_alloc_port(dev, FE_TYPE_GWY))
75965832Snyan		return ENXIO;
76065832Snyan
76165832Snyan	/* Fill the softc struct with default values.  */
76265832Snyan	fe_softc_defaults(sc);
76365832Snyan
76465832Snyan	/* See if the card is on its address.  */
76565832Snyan	if (!fe_simple_probe(sc, probe_table))
76665832Snyan		return ENXIO;
76765832Snyan
76865832Snyan	/* Get our station address from EEPROM. */
76965832Snyan	fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN);
77065832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x000000))
77165832Snyan		return ENXIO;
77265832Snyan
77365832Snyan	/* Determine the card type.  */
77465832Snyan	sc->typestr = "Generic MB86960 Ethernet";
77565832Snyan	if (valid_Ether_p(sc->sc_enaddr, 0x000061))
77665832Snyan		sc->typestr = "Gateway Ethernet (Fujitsu chipset)";
77765832Snyan
77865832Snyan	/* Gateway's board requires an explicit IRQ to work, since it
77965832Snyan	   is not possible to probe the setting of jumpers.  */
78065832Snyan	if (bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0) {
78165832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, NO_IRQ, NULL);
78265832Snyan		return ENXIO;
78365832Snyan	}
78465832Snyan
78565832Snyan	return 0;
78665832Snyan}
78765832Snyan
78865832Snyan
78965832Snyan/*
79065832Snyan * Probe for Ungermann-Bass Access/PC N98C+(Model 85152).
79165832Snyan */
79265832Snyanstatic int
79365832Snyanfe_probe_ubn(device_t dev)
79465832Snyan{
79565832Snyan	struct fe_softc *sc = device_get_softc(dev);
79665832Snyan
79765832Snyan	u_char sum, save7;
79865832Snyan	u_long iobase, irq;
79965832Snyan	int i;
80065832Snyan	static struct fe_simple_probe_struct const probe_table [] = {
80165832Snyan		{ FE_DLCR2, 0x58, 0x00 },
80265832Snyan		{ FE_DLCR4, 0x08, 0x00 },
80365832Snyan		{ 0 }
80465832Snyan	};
80565832Snyan
80665832Snyan	/* See if the specified I/O address is possible for Access/PC.  */
80765832Snyan	/* [01][048C]D0 are allowed.  */
80865832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
80965832Snyan		return ENXIO;
81065832Snyan	if ((iobase & ~0x1C00) != 0xD0)
81165832Snyan		return ENXIO;
81265832Snyan
81365832Snyan	if (fe98_alloc_port(dev, FE_TYPE_UBN))
81465832Snyan		return ENXIO;
81565832Snyan
81665832Snyan	/* Fill the softc struct with default values.  */
81765832Snyan	fe_softc_defaults(sc);
81865832Snyan
81965832Snyan	/* Simple probe.  */
82065832Snyan	if (!fe_simple_probe(sc, probe_table))
82165832Snyan		return ENXIO;
82265832Snyan
82365832Snyan	/* NOTE: Access/NOTE N98 sometimes freeze when reading station
82465832Snyan	   address.  In case of using it togather with C-NET(9N)C,
82565832Snyan	   this problem usually happens.
82665832Snyan	   Writing DLCR7 prevents freezing, but I don't know why.  FIXME.  */
82765832Snyan
82865832Snyan	/* Save the current value for the DLCR7 register we are about
82965832Snyan	   to destroy.  */
83065832Snyan	save7 = fe_inb(sc, FE_DLCR7);
83165832Snyan	fe_outb(sc, FE_DLCR7,
83265832Snyan		sc->proto_dlcr7 | FE_D7_RBS_BMPR | FE_D7_POWER_UP);
83365832Snyan
83465832Snyan	/* Get our station address form ID ROM and make sure it is UBN's.  */
83565832Snyan	fe_inblk(sc, 0x18, sc->sc_enaddr, ETHER_ADDR_LEN);
83665832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x00DD01))
83765832Snyan		goto fail_ubn;
83865832Snyan#if 1
83965832Snyan	/* Calculate checksum.  */
84065832Snyan	sum = fe_inb(sc, 0x1e);
84165832Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++)
84265832Snyan		sum ^= sc->sc_enaddr[i];
84365832Snyan	if (sum != 0)
84465832Snyan		goto fail_ubn;
84565832Snyan#endif
84665832Snyan
84765832Snyan	/* Setup the board type.  */
84865832Snyan	sc->typestr = "Access/PC";
84965832Snyan
85065832Snyan	/* This looks like an AccessPC/N98C+ board.  It requires an
85165832Snyan	   explicit IRQ setting in config.  Make sure we have one,
85265832Snyan	   determining an appropriate value for the IRQ control
85365832Snyan	   register.  */
85465832Snyan	irq = 0;
85565832Snyan	bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL);
85665832Snyan	switch (irq) {
85765832Snyan	case 3:  sc->priv_info = 0x01; break;
85865832Snyan	case 5:  sc->priv_info = 0x02; break;
85965832Snyan	case 6:  sc->priv_info = 0x04; break;
86065832Snyan	case 12: sc->priv_info = 0x08; break;
86165832Snyan	default:
86265832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12");
86365832Snyan		goto fail_ubn;
86465832Snyan	}
86565832Snyan
86665832Snyan	/* Setup hooks.  We need a special initialization procedure.  */
86765832Snyan	sc->init = fe_init_ubn;
86865832Snyan
86965832Snyan	return 0;
87065832Snyan
87165832Snyanfail_ubn:
87265832Snyan	fe_outb(sc, FE_DLCR7, save7);
87365832Snyan	return ENXIO;
87465832Snyan}
87565832Snyan
87665832Snyan
87765832Snyan/*
87865832Snyan * REX boards(non-JLI type) support routine.
87965832Snyan */
88065832Snyan
88165832Snyan#define REX_EEPROM_SIZE	32
88265832Snyan#define REX_DAT	0x01
88365832Snyan
88465832Snyanstatic void
88565832Snyanfe_read_eeprom_rex(struct fe_softc *sc, u_char *data)
88665832Snyan{
88765832Snyan	int i;
88865832Snyan	u_char bit, val;
88965832Snyan	u_char save16;
89065832Snyan
89165832Snyan	save16 = fe_inb(sc, 0x10);
89265832Snyan
89365832Snyan	/* Issue a start condition.  */
89465832Snyan	val = fe_inb(sc, 0x10) & 0xf0;
89565832Snyan	fe_outb(sc, 0x10, val);
89665832Snyan
89765832Snyan	(void) fe_inb(sc, 0x10);
89865832Snyan	(void) fe_inb(sc, 0x10);
89965832Snyan	(void) fe_inb(sc, 0x10);
90065832Snyan	(void) fe_inb(sc, 0x10);
90165832Snyan
90265832Snyan	/* Read bytes from EEPROM.  */
90365832Snyan	for (i = 0; i < REX_EEPROM_SIZE; i++) {
90465832Snyan		/* Read a byte and store it into the buffer.  */
90565832Snyan		val = 0x00;
90665832Snyan		for (bit = 0x01; bit != 0x00; bit <<= 1)
90765832Snyan			if (fe_inb(sc, 0x10) & REX_DAT)
90865832Snyan				val |= bit;
90965832Snyan		*data++ = val;
91065832Snyan	}
91165832Snyan
91265832Snyan	fe_outb(sc, 0x10, save16);
91365832Snyan
91465832Snyan#if 1
91565832Snyan	/* Report what we got.  */
91665832Snyan	if (bootverbose) {
91765832Snyan		data -= REX_EEPROM_SIZE;
91865832Snyan		for (i = 0; i < REX_EEPROM_SIZE; i += 16) {
91965832Snyan			printf("fe%d: EEPROM(REX):%3x: %16D\n",
92065832Snyan			       sc->sc_unit, i, data + i, " ");
92165832Snyan		}
92265832Snyan	}
92365832Snyan#endif
92465832Snyan}
92565832Snyan
92665832Snyan
92765832Snyanstatic void
92865832Snyanfe_init_rex(struct fe_softc *sc)
92965832Snyan{
93065832Snyan	/* Setup IRQ control register on the ASIC.  */
93165832Snyan	fe_outb(sc, 0x10, sc->priv_info);
93265832Snyan}
93365832Snyan
93465832Snyan/*
93565832Snyan * Probe for RATOC REX-9880/81/82/83 series.
93665832Snyan */
93765832Snyanstatic int
93865832Snyanfe_probe_rex(device_t dev)
93965832Snyan{
94065832Snyan	struct fe_softc *sc = device_get_softc(dev);
94165832Snyan
94265832Snyan	int i;
94365832Snyan	u_long iobase, irq;
94465832Snyan	u_char eeprom [REX_EEPROM_SIZE];
94565832Snyan
94665832Snyan	static struct fe_simple_probe_struct probe_table [] = {
94765832Snyan		{ FE_DLCR2, 0x58, 0x00 },
94865832Snyan		{ FE_DLCR4, 0x08, 0x00 },
94965832Snyan		{ 0 }
95065832Snyan	};
95165832Snyan
95265832Snyan	/* See if the specified I/O address is possible for REX-9880.  */
95365832Snyan	/* 6[46CE]D0 are allowed.  */
95465832Snyan	if (bus_get_resource(dev, SYS_RES_IOPORT, 0, &iobase, NULL) != 0)
95565832Snyan		return ENXIO;
95665832Snyan	if ((iobase & ~0xA00) != 0x64D0)
95765832Snyan		return ENXIO;
95865832Snyan
95965832Snyan	if (fe98_alloc_port(dev, FE_TYPE_REX))
96065832Snyan		return ENXIO;
96165832Snyan
96265832Snyan	/* Fill the softc struct with default values.  */
96365832Snyan	fe_softc_defaults(sc);
96465832Snyan
96565832Snyan	/* See if the card is on its address.  */
96665832Snyan	if (!fe_simple_probe(sc, probe_table))
96765832Snyan		return ENXIO;
96865832Snyan
96965832Snyan	/* We now have to read the config EEPROM.  We should be very
97065832Snyan           careful, since doing so destroys a register.  (Remember, we
97165832Snyan           are not yet sure we have a REX-9880 board here.)  */
97265832Snyan	fe_read_eeprom_rex(sc, eeprom);
97365832Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++)
97465832Snyan		sc->sc_enaddr[i] = eeprom[7 - i];
97565832Snyan
97665832Snyan	/* Make sure it is RATOC's.  */
97765832Snyan	if (!valid_Ether_p(sc->sc_enaddr, 0x00C0D0) &&
97865832Snyan	    !valid_Ether_p(sc->sc_enaddr, 0x00803D))
97965832Snyan		return 0;
98065832Snyan
98165832Snyan	/* Setup the board type.  */
98265832Snyan	sc->typestr = "REX-9880/9883";
98365832Snyan
98465832Snyan	/* This looks like a REX-9880 board.  It requires an
98565832Snyan	   explicit IRQ setting in config.  Make sure we have one,
98665832Snyan	   determining an appropriate value for the IRQ control
98765832Snyan	   register.  */
98865832Snyan	irq = 0;
98965832Snyan	bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, NULL);
99065832Snyan	switch (irq) {
99165832Snyan	case 3:  sc->priv_info = 0x10; break;
99265832Snyan	case 5:  sc->priv_info = 0x20; break;
99365832Snyan	case 6:  sc->priv_info = 0x40; break;
99465832Snyan	case 12: sc->priv_info = 0x80; break;
99565832Snyan	default:
99665832Snyan		fe_irq_failure(sc->typestr, sc->sc_unit, irq, "3/5/6/12");
99765832Snyan		return ENXIO;
99865832Snyan	}
99965832Snyan
100065832Snyan	/* Setup hooks.  We need a special initialization procedure.  */
100165832Snyan	sc->init = fe_init_rex;
100265832Snyan
100365832Snyan	/* REX-9880 has 64KB SRAM.  */
100465832Snyan	sc->proto_dlcr6 = FE_D6_BUFSIZ_64KB | FE_D6_TXBSIZ_2x4KB
100565832Snyan			| FE_D6_BBW_WORD | FE_D6_SBW_WORD | FE_D6_SRAM;
100665832Snyan#if 1
100765832Snyan	sc->proto_dlcr7 |= FE_D7_EOPPOL;	/* XXX */
100865832Snyan#endif
100965832Snyan
101065832Snyan	return 0;
101165832Snyan}
1012