if_ed_cbus.c revision 149558
1139749Simp/*-
264777Snyan * Copyright (c) 1995, David Greenman
364777Snyan * All rights reserved.
464777Snyan *
564777Snyan * Redistribution and use in source and binary forms, with or without
664777Snyan * modification, are permitted provided that the following conditions
764777Snyan * are met:
864777Snyan * 1. Redistributions of source code must retain the above copyright
964777Snyan *    notice unmodified, this list of conditions, and the following
1064777Snyan *    disclaimer.
1164777Snyan * 2. Redistributions in binary form must reproduce the above copyright
1264777Snyan *    notice, this list of conditions and the following disclaimer in the
1364777Snyan *    documentation and/or other materials provided with the distribution.
1464777Snyan *
1564777Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1664777Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1764777Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1864777Snyan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1964777Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2064777Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2164777Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2264777Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2364777Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2464777Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2564777Snyan * SUCH DAMAGE.
2664777Snyan *
2764777Snyan * $FreeBSD: head/sys/dev/ed/if_ed_cbus.c 149558 2005-08-28 23:56:25Z imp $
2864777Snyan */
2964777Snyan
3064777Snyan#include <sys/param.h>
3164777Snyan#include <sys/systm.h>
3264777Snyan#include <sys/socket.h>
3364777Snyan#include <sys/kernel.h>
3464777Snyan
3564777Snyan#include <sys/module.h>
3664777Snyan#include <sys/bus.h>
3764777Snyan#include <machine/bus.h>
3864777Snyan#include <sys/rman.h>
3964777Snyan#include <machine/resource.h>
4064777Snyan#include <machine/clock.h>
4164777Snyan
4264777Snyan#include <net/ethernet.h>
4364777Snyan#include <net/if.h>
4464777Snyan#include <net/if_arp.h>
4564777Snyan#include <net/if_mib.h>
4664777Snyan
4764777Snyan#include <isa/isavar.h>
4864777Snyan
4964777Snyan#include <dev/ed/if_edvar.h>
5064777Snyan#include <dev/ed/if_edreg.h>
5164777Snyan#include <dev/ed/if_ed98.h>
5264777Snyan
53141550Simpstatic int ed98_alloc_port(device_t, int);
54141550Simpstatic int ed98_alloc_memory(device_t, int);
55141550Simpstatic int ed_pio_testmem(struct ed_softc *, int, int, int);
56141550Simpstatic int ed_probe_SIC98(device_t, int, int);
57141550Simpstatic int ed_probe_CNET98(device_t, int, int);
58141550Simpstatic int ed_probe_CNET98EL(device_t, int, int);
59141550Simpstatic int ed_probe_NEC77(device_t, int, int);
60141550Simpstatic int ed_probe_NW98X(device_t, int, int);
61141550Simpstatic int ed_probe_SB98(device_t, int, int);
62141550Simpstatic int ed_probe_EZ98(device_t, int, int);
63141550Simpstatic int ed98_probe_Novell(device_t, int, int);
64141550Simpstatic int ed98_probe_generic8390(struct ed_softc *);
65141550Simpstatic void ed_reset_CNET98(struct ed_softc *, int);
66141550Simpstatic void ed_winsel_CNET98(struct ed_softc *, u_short);
67141550Simpstatic void ed_get_SB98(struct ed_softc *);
6864777Snyan
69141550Simpstatic int ed_cbus_probe(device_t);
70141550Simpstatic int ed_cbus_attach(device_t);
7164777Snyan
7264777Snyanstatic struct isa_pnp_id ed_ids[] = {
7364777Snyan/* TODO - list up PnP boards for PC-98 */
7464777Snyan	{ 0,		NULL }
7564777Snyan};
7664777Snyan
7764777Snyanstatic int
78141550Simped_cbus_probe(device_t dev)
7964777Snyan{
8064777Snyan	struct ed_softc *sc = device_get_softc(dev);
8164777Snyan	int flags = device_get_flags(dev);
8264777Snyan	int error = 0;
8364777Snyan
8464777Snyan	sc->type = ED_TYPE98(flags);
8564777Snyan#ifdef ED_DEBUG
86141550Simp	device_printf(dev, "ed_cbus_probe: sc->type=%x\n", sc->type);
8764777Snyan#endif
8864777Snyan
8964777Snyan	/* Check isapnp ids */
9064777Snyan	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ed_ids);
9164777Snyan#ifdef ED_DEBUG
92141550Simp	device_printf(dev, "ed_cbus_probe: ISA_PNP_PROBE returns %d\n", error);
9364777Snyan#endif
9464777Snyan
9564777Snyan	/* If the card had a PnP ID that didn't match any we know about */
96141552Simp	if (error == ENXIO)
9764777Snyan		goto end;
9864777Snyan
9964777Snyan	/* If we had some other problem. */
100141552Simp	if (!(error == 0 || error == ENOENT))
10164777Snyan		goto end;
10264777Snyan
10364777Snyan	/* Heuristic probes */
10464777Snyan#ifdef ED_DEBUG
105141550Simp	device_printf(dev, "ed_cbus_probe: Heuristic probes start\n");
10664777Snyan#endif
10764777Snyan	switch (sc->type) {
10864777Snyan	case ED_TYPE98_GENERIC:
10964777Snyan		/*
11064777Snyan		 * CAUTION!
11164777Snyan		 * sc->type of these boards are overwritten by PC/AT's value.
11264777Snyan		 */
11364777Snyan
11464777Snyan		/*
11564777Snyan		 * SMC EtherEZ98
11664777Snyan		 */
11764777Snyan		error = ed_probe_EZ98(dev, 0, flags);
118141552Simp		if (error == 0)
11964777Snyan			goto end;
12064777Snyan
12164777Snyan		ed_release_resources(dev);
12264777Snyan
12364777Snyan		/*
12464777Snyan		 * Allied Telesis CenterCom LA-98-T
12564777Snyan		 */
12664777Snyan		error = ed_probe_Novell(dev, 0, flags);
127141932Simp		if (error == 0) {
128141932Simp			ed_Novell_read_mac(sc);
12964777Snyan			goto end;
130141932Simp		}
13164777Snyan		break;
13264777Snyan
13364777Snyan	/*
13464777Snyan	 * NE2000-like boards probe routine
13564777Snyan	 */
13664777Snyan	case ED_TYPE98_BDN:
13764777Snyan		/*
13864777Snyan		 * ELECOM LANEED LD-BDN
13964777Snyan		 * PLANET SMART COM 98 EN-2298
14064777Snyan		 */
14164777Snyan	case ED_TYPE98_LGY:
14264777Snyan		/*
14364777Snyan		 * MELCO LGY-98, IND-SP, IND-SS
14464777Snyan		 * MACNICA NE2098
14564777Snyan		 */
14664777Snyan	case ED_TYPE98_ICM:
14764777Snyan		/*
14864777Snyan		 * ICM DT-ET-25, DT-ET-T5, IF-2766ET, IF-2771ET
14964777Snyan		 * D-Link DE-298P, DE-298
15064777Snyan		 */
15164777Snyan	case ED_TYPE98_EGY:
15264777Snyan		/*
15364777Snyan		 * MELCO EGY-98
15464777Snyan		 * Contec C-NET(98)E-A, C-NET(98)L-A
15564777Snyan		 */
15664777Snyan	case ED_TYPE98_108:
15764777Snyan		/*
15864777Snyan		 * NEC PC-9801-107,108
15964777Snyan		 */
16064777Snyan	case ED_TYPE98_NC5098:
16164777Snyan		/*
16264777Snyan		 * NextCom NC5098
16364777Snyan		 */
16464777Snyan		error = ed98_probe_Novell(dev, 0, flags);
16564777Snyan		break;
16664777Snyan
16764777Snyan	/*
16864777Snyan	 * other boards with special probe routine
16964777Snyan	 */
17064777Snyan	case ED_TYPE98_SIC:
17164777Snyan		/*
17264777Snyan		 * Allied Telesis SIC-98
17364777Snyan		 */
17464777Snyan		error = ed_probe_SIC98(dev, 0, flags);
17564777Snyan		break;
17664777Snyan
17764777Snyan	case ED_TYPE98_CNET98EL:
17864777Snyan		/*
17964777Snyan		 * Contec C-NET(98)E/L
18064777Snyan		 */
18164777Snyan		error = ed_probe_CNET98EL(dev, 0, flags);
18264777Snyan		break;
18364777Snyan
18464777Snyan	case ED_TYPE98_CNET98:
18564777Snyan		/*
18664777Snyan		 * Contec C-NET(98)
18764777Snyan		 */
18864777Snyan		error = ed_probe_CNET98(dev, 0, flags);
18964777Snyan		break;
19064777Snyan
19164777Snyan	case ED_TYPE98_LA98:
19264777Snyan		/*
19364777Snyan		 * IO-DATA LA/T-98
19464777Snyan		 * NEC PC-9801-77,78
19564777Snyan		 */
19664777Snyan		error = ed_probe_NEC77(dev, 0, flags);
19764777Snyan		break;
19864777Snyan
19964777Snyan	case ED_TYPE98_NW98X:
20064777Snyan		/*
20164777Snyan		 * Networld EC/EP-98X
20264777Snyan		 */
20364777Snyan		error = ed_probe_NW98X(dev, 0, flags);
20464777Snyan		break;
20564777Snyan
20664777Snyan	case ED_TYPE98_SB98:
20764777Snyan		/*
20864777Snyan		 * Soliton SB-9801
20964777Snyan		 * Fujikura FN-9801
21064777Snyan		 */
21164777Snyan		error = ed_probe_SB98(dev, 0, flags);
21264777Snyan		break;
21364777Snyan	}
21464777Snyan
21564777Snyanend:
21664777Snyan#ifdef ED_DEBUG
217141550Simp	device_printf(dev, "ed_cbus_probe: end, error=%d\n", error);
21864777Snyan#endif
21964777Snyan	if (error == 0)
22064777Snyan		error = ed_alloc_irq(dev, 0, 0);
22164777Snyan
22264777Snyan	ed_release_resources(dev);
22364777Snyan	return (error);
22464777Snyan}
22564777Snyan
22664777Snyanstatic int
227141550Simped_cbus_attach(dev)
22864777Snyan	device_t dev;
22964777Snyan{
23064777Snyan	struct ed_softc *sc = device_get_softc(dev);
23164777Snyan	int flags = device_get_flags(dev);
23264777Snyan	int error;
23364777Snyan
23464777Snyan	if (sc->port_used > 0) {
235141552Simp		if (ED_TYPE98(flags) == ED_TYPE98_GENERIC)
23664777Snyan			ed_alloc_port(dev, sc->port_rid, sc->port_used);
237141552Simp		else
23864777Snyan			ed98_alloc_port(dev, sc->port_rid);
23964777Snyan	}
24064777Snyan	if (sc->mem_used)
24164777Snyan		ed_alloc_memory(dev, sc->mem_rid, sc->mem_used);
24264777Snyan
24364777Snyan	ed_alloc_irq(dev, sc->irq_rid, 0);
24464777Snyan
245149558Simp	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
246141552Simp	    edintr, sc, &sc->irq_handle);
24764777Snyan	if (error) {
24864777Snyan		ed_release_resources(dev);
24964777Snyan		return (error);
25064777Snyan	}
25164777Snyan
252121816Sbrooks	return ed_attach(dev);
25364777Snyan}
25464777Snyan
25564777Snyan/*
25664777Snyan * Interrupt conversion table for EtherEZ98
25764777Snyan */
258141495Simpstatic uint16_t ed_EZ98_intr_val[] = {
25964777Snyan	0,
26064777Snyan	3,
26164777Snyan	5,
26264777Snyan	6,
26364777Snyan	0,
26464777Snyan	9,
26564777Snyan	12,
26664777Snyan	13
26764777Snyan};
26864777Snyan
26964777Snyanstatic int
270141550Simped_probe_EZ98(device_t dev, int port_rid, int flags)
27164777Snyan{
27264777Snyan	struct ed_softc *sc = device_get_softc(dev);
27364777Snyan	int error;
27464777Snyan	static unsigned short *intr_vals[] = {NULL, ed_EZ98_intr_val};
27564777Snyan
27664777Snyan	error = ed_alloc_port(dev, port_rid, ED_EZ98_IO_PORTS);
27764777Snyan	if (error) {
27864777Snyan		return (error);
27964777Snyan	}
28064777Snyan
28164777Snyan	sc->asic_offset = ED_EZ98_ASIC_OFFSET;
28264777Snyan	sc->nic_offset  = ED_EZ98_NIC_OFFSET;
28364777Snyan
28464777Snyan	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
28564777Snyan}
28664777Snyan
28764777Snyan/*
28864777Snyan * I/O conversion tables
28964777Snyan */
29064777Snyan
29164777Snyan/* LGY-98, ICM, C-NET(98)E/L */
29264777Snyanstatic	bus_addr_t ed98_ioaddr_generic[] = {
29364777Snyan	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
29464777Snyan};
29564777Snyan
29664777Snyan/*
29764777Snyan *		Definitions for Contec C-NET(98)E/L
29864777Snyan */
29964777Snyan#define	ED_CNET98EL_ICR         2	/* Interrupt Configuration Register */
30064777Snyan
30164777Snyan#define	ED_CNET98EL_ICR_IRQ3	0x01
30264777Snyan#define	ED_CNET98EL_ICR_IRQ5	0x02
30364777Snyan#define	ED_CNET98EL_ICR_IRQ6	0x04
30464777Snyan#define	ED_CNET98EL_ICR_IRQ12	0x20
30564777Snyan
30664777Snyan#define	ED_CNET98EL_IMR         4	/* Interrupt Mask Register	*/
30764777Snyan#define	ED_CNET98EL_ISR         5	/* Interrupt Status Register	*/
30864777Snyan
30964777Snyan/* EGY-98 */
31064777Snyanstatic	bus_addr_t ed98_ioaddr_egy98[] = {
31164777Snyan	0,     0x02,  0x04,  0x06,  0x08,  0x0a,  0x0c,  0x0e,
31264777Snyan	0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e
31364777Snyan};
31464777Snyan
31564777Snyan/* SIC-98 */
31664777Snyanstatic	bus_addr_t ed98_ioaddr_sic98[] = {
31764777Snyan	0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00,
31864777Snyan	0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00
31964777Snyan};
32064777Snyan
32164777Snyan/* LA/T-98, LD-BDN, PC-9801-77, SB-9801 */
32264777Snyanstatic	bus_addr_t ed98_ioaddr_la98[] = {
32364777Snyan	0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000,
32464777Snyan	0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000,
32564777Snyan	0x0100	/* for NEC 77(see below) */
32664777Snyan};
32764777Snyan
32864777Snyan/*
32964777Snyan *		Definitions for NEC PC-9801-77
33064777Snyan */
33164777Snyan#define	ED_NEC77_IRQ		16	/* Interrupt Configuration Register */
33264777Snyan
33364777Snyan#define	ED_NEC77_IRQ3		0x04
33464777Snyan#define	ED_NEC77_IRQ5		0x06
33564777Snyan#define	ED_NEC77_IRQ6		0x08
33664777Snyan#define	ED_NEC77_IRQ12		0x0a
33764777Snyan#define	ED_NEC77_IRQ13		0x02
33864777Snyan
33964777Snyan/*
34064777Snyan *		Definitions for Soliton SB-9801
34164777Snyan */
34264777Snyan#define	ED_SB98_CFG		1	/* Board configuration		*/
34364777Snyan
34464777Snyan#define	ED_SB98_CFG_IRQ3	0x00
34564777Snyan#define	ED_SB98_CFG_IRQ5	0x04
34664777Snyan#define	ED_SB98_CFG_IRQ6	0x08
34764777Snyan#define	ED_SB98_CFG_IRQ12	0x0c
34864777Snyan#define	ED_SB98_CFG_ALTPORT	0x40		/* use EXTERNAL media	*/
34964777Snyan#define	ED_SB98_CFG_ENABLE	0xa0		/* enable configuration	*/
35064777Snyan
35164777Snyan#define	ED_SB98_EEPENA		2	/* EEPROM access enable		*/
35264777Snyan
35364777Snyan#define	ED_SB98_EEPENA_DISABLE	0x00
35464777Snyan#define	ED_SB98_EEPENA_ENABLE	0x01
35564777Snyan
35664777Snyan#define	ED_SB98_EEP		3	/* EEPROM access		*/
35764777Snyan
35864777Snyan#define	ED_SB98_EEP_SDA		0x01		/* Serial Data	*/
35964777Snyan#define	ED_SB98_EEP_SCL		0x02		/* Serial Clock	*/
36064777Snyan#define	ED_SB98_EEP_READ	0x01		/* Read Command	*/
36164777Snyan
36264777Snyan#define	ED_SB98_EEP_DELAY	300
36364777Snyan
36464777Snyan#define	ED_SB98_ADDRESS		0x01		/* Station Address(1-6)	*/
36564777Snyan
36664777Snyan#define	ED_SB98_POLARITY	4	/* Polarity			*/
36764777Snyan
36864777Snyan/* PC-9801-108 */
36964777Snyanstatic	bus_addr_t ed98_ioaddr_nec108[] = {
37064777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
37164777Snyan	0x1000, 0x1002, 0x1004, 0x1006, 0x1008, 0x100a, 0x100c, 0x100e
37264777Snyan};
37364777Snyan
37464777Snyan/* C-NET(98) */
37564777Snyanstatic	bus_addr_t ed98_ioaddr_cnet98[] = {
37664777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
37764777Snyan	0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e
37864777Snyan};
37964777Snyan
38064777Snyan/*
38164777Snyan *		Definitions for Contec C-NET(98)
38264777Snyan */
38364777Snyan#define	ED_CNET98_MAP_REG0L	0	/* MAPPING register0 Low	*/
38464777Snyan#define	ED_CNET98_MAP_REG1L	1	/* MAPPING register1 Low	*/
38564777Snyan#define	ED_CNET98_MAP_REG2L	2	/* MAPPING register2 Low	*/
38664777Snyan#define	ED_CNET98_MAP_REG3L	3	/* MAPPING register3 Low	*/
38764777Snyan#define	ED_CNET98_MAP_REG0H	4	/* MAPPING register0 Hi		*/
38864777Snyan#define	ED_CNET98_MAP_REG1H	5	/* MAPPING register1 Hi		*/
38964777Snyan#define	ED_CNET98_MAP_REG2H	6	/* MAPPING register2 Hi		*/
39064777Snyan#define	ED_CNET98_MAP_REG3H	7	/* MAPPING register3 Hi		*/
39164777Snyan#define	ED_CNET98_WIN_REG	8	/* Window register		*/
39264777Snyan#define	ED_CNET98_INT_LEV	9	/* Init level register		*/
39364777Snyan
39464777Snyan#define	ED_CNET98_INT_IRQ3	0x01		/* INT 0 */
39564777Snyan#define	ED_CNET98_INT_IRQ5	0x02		/* INT 1 */
39664777Snyan#define	ED_CNET98_INT_IRQ6	0x04		/* INT 2 */
39764777Snyan#define	ED_CNET98_INT_IRQ9	0x08		/* INT 3 */
39864777Snyan#define	ED_CNET98_INT_IRQ12	0x20		/* INT 5 */
39964777Snyan#define	ED_CNET98_INT_IRQ13	0x40		/* INT 6 */
40064777Snyan
40164777Snyan#define	ED_CNET98_INT_REQ	10	/* Init request register	*/
40264777Snyan#define	ED_CNET98_INT_MASK	11	/* Init mask register		*/
40364777Snyan#define	ED_CNET98_INT_STAT	12	/* Init status register		*/
40464777Snyan#define	ED_CNET98_INT_CLR	12	/* Init clear register		*/
40564777Snyan#define	ED_CNET98_RESERVE1	13
40664777Snyan#define	ED_CNET98_RESERVE2	14
40764777Snyan#define	ED_CNET98_RESERVE3	15
40864777Snyan
40964777Snyan/* EC/EP-98X, NC5098 */
41064777Snyanstatic	bus_addr_t ed98_ioaddr_nw98x[] = {
41164777Snyan	0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
41264777Snyan	0x0800, 0x0900, 0x0a00, 0x0b00, 0x0c00, 0x0d00, 0x0e00, 0x0f00,
41364777Snyan	0x1000	/* for EC/EP-98X(see below) */
41464777Snyan};
41564777Snyan
41664777Snyan/*
41764777Snyan *		Definitions for Networld EC/EP-98X
41864777Snyan */
41964777Snyan#define	ED_NW98X_IRQ            16	/* Interrupt Configuration Register */
42064777Snyan
42164777Snyan#define	ED_NW98X_IRQ3           0x04
42264777Snyan#define	ED_NW98X_IRQ5           0x06
42364777Snyan#define	ED_NW98X_IRQ6           0x08
42464777Snyan#define	ED_NW98X_IRQ12          0x0a
42564777Snyan#define	ED_NW98X_IRQ13          0x02
42664777Snyan
42764777Snyan/* NC5098 ASIC */
42864777Snyanstatic bus_addr_t ed98_asic_nc5098[] = {
42964777Snyan/*	DATA    ENADDR						RESET	*/
43064777Snyan	0x0000, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x4000,
43164777Snyan	     0,      0,      0,      0,      0,      0,      0,      0
43264777Snyan};
43364777Snyan
43464777Snyan/*
43564777Snyan *		Definitions for NextCom NC5098
43664777Snyan */
43764777Snyan#define	ED_NC5098_ENADDR	1	/* Station Address(1-6)		*/
43864777Snyan
43964777Snyan/*
44064777Snyan * Allocate a port resource with the given resource id.
44164777Snyan */
44264777Snyanstatic int
443141550Simped98_alloc_port(device_t dev, int rid)
44464777Snyan{
44564777Snyan	struct ed_softc *sc = device_get_softc(dev);
44664777Snyan	struct resource *res;
44764777Snyan	int error;
44864777Snyan	bus_addr_t *io_nic, *io_asic, adj;
44964777Snyan	static bus_addr_t io_res[ED_NOVELL_IO_PORTS + 1];
45064777Snyan	int i, n;
45164777Snyan	int offset, reset, data;
45264777Snyan
45364777Snyan	/* Set i/o table for resource manager */
45464777Snyan	io_nic = io_asic = ed98_ioaddr_generic;
45564777Snyan	offset = ED_NOVELL_ASIC_OFFSET;
45664777Snyan	reset = ED_NOVELL_RESET;
45764777Snyan	data  = ED_NOVELL_DATA;
45864777Snyan	n = ED_NOVELL_IO_PORTS;
45964777Snyan
46064777Snyan	switch (sc->type) {
46164777Snyan	case ED_TYPE98_LGY:
46264777Snyan		io_asic = ed98_ioaddr_egy98; /* XXX - Yes, we use egy98 */
46364777Snyan		offset = 0x0200;
46464777Snyan		reset = 8;
46564777Snyan		break;
46664777Snyan
46764777Snyan	case ED_TYPE98_EGY:
46864777Snyan		io_nic = io_asic = ed98_ioaddr_egy98;
46964777Snyan		offset = 0x0200;
47064777Snyan		reset = 8;
47164777Snyan		break;
47264777Snyan
47364777Snyan	case ED_TYPE98_ICM:
47464777Snyan		offset = 0x0100;
47564777Snyan		break;
47664777Snyan
47764777Snyan	case ED_TYPE98_BDN:
47864777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
47964777Snyan		offset = 0x0100;
48064777Snyan		reset = 0x0c;
48164777Snyan		break;
48264777Snyan
48364777Snyan	case ED_TYPE98_SIC:
48464777Snyan		io_nic = io_asic = ed98_ioaddr_sic98;
48564777Snyan		offset = 0x2000;
48664777Snyan		n = 16+1;
48764777Snyan		break;
48864777Snyan
48964777Snyan	case ED_TYPE98_108:
49064777Snyan		io_nic = io_asic = ed98_ioaddr_nec108;
49164777Snyan		offset = 0x0888;	/* XXX - overwritten after */
49264777Snyan		reset = 1;
49364777Snyan		n = 16;	/* XXX - does not set ASIC i/o here */
49464777Snyan		break;
49564777Snyan
49664777Snyan	case ED_TYPE98_LA98:
49764777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
49864777Snyan		offset = 0x0100;
49964777Snyan		break;
50064777Snyan
50164777Snyan	case ED_TYPE98_CNET98EL:
50264777Snyan		offset = 0x0400;
50364777Snyan		data = 0x0e;
50464777Snyan		break;
50564777Snyan
50664777Snyan	case ED_TYPE98_CNET98:
50764777Snyan		/* XXX - Yes, we use generic i/o here */
50864777Snyan		offset = 0x0400;
50964777Snyan		break;
51064777Snyan
51164777Snyan	case ED_TYPE98_NW98X:
51264777Snyan		io_nic = io_asic = ed98_ioaddr_nw98x;
51364777Snyan		offset = 0x1000;
51464777Snyan		break;
51564777Snyan
51664777Snyan	case ED_TYPE98_SB98:
51764777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
51864777Snyan		offset = 0x0400;
51964777Snyan		reset = 7;
52064777Snyan		break;
52164777Snyan
52264777Snyan	case ED_TYPE98_NC5098:
52364777Snyan		io_nic  = ed98_ioaddr_nw98x;
52464777Snyan		io_asic = ed98_asic_nc5098;
52564777Snyan		offset = 0x2000;
52664777Snyan		reset = 7;
52764777Snyan		n = 16+8;	/* XXX */
52864777Snyan		break;
52964777Snyan	}
53064777Snyan
53164777Snyan	bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
532141552Simp	for (i = ED_NOVELL_ASIC_OFFSET; i < ED_NOVELL_IO_PORTS; i++)
53364777Snyan		io_res[i] = io_asic[i - ED_NOVELL_ASIC_OFFSET] + offset;
53464777Snyan
535141552Simp	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, io_res, n,
536141552Simp	    RF_ACTIVE);
537141552Simp	if (!res)
53864777Snyan		return (ENOENT);
53964777Snyan
54064777Snyan	sc->port_rid = rid;
54164777Snyan	sc->port_res = res;
54264777Snyan	sc->port_used = n;
54364777Snyan
54464777Snyan	/* Re-map i/o table if needed */
54564777Snyan	switch (sc->type) {
54664777Snyan	case ED_TYPE98_LA98:
54764777Snyan	case ED_TYPE98_NW98X:
54864777Snyan		io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
54964777Snyan		n++;
55064777Snyan		break;
55164777Snyan
55264777Snyan	case ED_TYPE98_108:
55364777Snyan		adj = (rman_get_start(res) & 0xf000) / 2;
55464777Snyan		offset = (offset | adj) - rman_get_start(res);
55564777Snyan
556141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
55764777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
55864777Snyan		break;
55964777Snyan
56064777Snyan	case ED_TYPE98_CNET98:
56164777Snyan		io_nic = io_asic = ed98_ioaddr_cnet98;
56264777Snyan		offset = 1;
56364777Snyan
56464777Snyan		bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
565141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
56664777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
56764777Snyan		break;
56864777Snyan
56964777Snyan	case ED_TYPE98_NC5098:
57064777Snyan		n = ED_NOVELL_IO_PORTS;
57164777Snyan		break;
57264777Snyan	}
57364777Snyan
574141552Simp	if (reset != ED_NOVELL_RESET)
57564777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_RESET] =
57664777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + reset];
57764777Snyan	if (data  != ED_NOVELL_DATA) {
57864777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA] =
57964777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data];
58064777Snyan#if 0
58164777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA + 1] =
58264777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data + 1];
58364777Snyan#endif
58464777Snyan	}
58564777Snyan
58664777Snyan	error = isa_load_resourcev(res, io_res, n);
587141552Simp	if (error != 0)
58864777Snyan		return (ENOENT);
58964777Snyan#ifdef ED_DEBUG
59064777Snyan	device_printf(dev, "ed98_alloc_port: i/o ports = %d\n", n);
591141552Simp	for (i = 0; i < n; i++)
59264777Snyan		printf("%x,", io_res[i]);
59364777Snyan	printf("\n");
59464777Snyan#endif
59564777Snyan	return (0);
59664777Snyan}
59764777Snyan
59864777Snyanstatic int
59964777Snyaned98_alloc_memory(dev, rid)
60064777Snyan	device_t dev;
60164777Snyan	int rid;
60264777Snyan{
60364777Snyan	struct ed_softc *sc = device_get_softc(dev);
60464777Snyan	int error;
60564777Snyan	u_long conf_maddr, conf_msize;
60664777Snyan
607141552Simp	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &conf_maddr,
608141552Simp	    &conf_msize);
609141552Simp	if (error)
61064777Snyan		return (error);
61164777Snyan
612141552Simp	if ((conf_maddr == 0) || (conf_msize == 0))
61364777Snyan		return (ENXIO);
61464777Snyan
61564777Snyan	error = ed_alloc_memory(dev, rid, (int) conf_msize);
616141552Simp	if (error)
61764777Snyan		return (error);
61864777Snyan
619149558Simp	sc->mem_start = 0;
62064777Snyan	sc->mem_size  = conf_msize;
62164777Snyan
62264777Snyan	return (0);
62364777Snyan}
62464777Snyan
62564777Snyan/*
62664777Snyan * Generic probe routine for testing for the existance of a DS8390.
62764777Snyan *	Must be called after the NIC has just been reset. This routine
62864777Snyan *	works by looking at certain register values that are guaranteed
62964777Snyan *	to be initialized a certain way after power-up or reset. Seems
63064777Snyan *	not to currently work on the 83C690.
63164777Snyan *
63264777Snyan * Specifically:
63364777Snyan *
63464777Snyan *	Register			reset bits	set bits
63564777Snyan *	Command Register (CR)		TXP, STA	RD2, STP
63664777Snyan *	Interrupt Status (ISR)				RST
63764777Snyan *	Interrupt Mask (IMR)		All bits
63864777Snyan *	Data Control (DCR)				LAS
63964777Snyan *	Transmit Config. (TCR)		LB1, LB0
64064777Snyan *
64164777Snyan * XXX - We only check the CR register.
64264777Snyan *
64364777Snyan * Return 1 if 8390 was found, 0 if not.
64464777Snyan */
64564777Snyan
64664777Snyanstatic int
647141550Simped98_probe_generic8390(struct ed_softc *sc)
64864777Snyan{
64964777Snyan	u_char tmp = ed_nic_inb(sc, ED_P0_CR);
65064777Snyan#ifdef DIAGNOSTIC
65164777Snyan	printf("ed?: inb(ED_P0_CR)=%x\n", tmp);
65264777Snyan#endif
65364777Snyan	if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
654141552Simp	    (ED_CR_RD2 | ED_CR_STP))
65564777Snyan		return (0);
65664777Snyan
65764777Snyan	(void) ed_nic_inb(sc, ED_P0_ISR);
65864777Snyan
65964777Snyan	return (1);
66064777Snyan}
66164777Snyan
66264777Snyanstatic int
663141550Simped98_probe_Novell(device_t dev, int port_rid, int flags)
66464777Snyan{
66564777Snyan	struct ed_softc *sc = device_get_softc(dev);
66664777Snyan	int error;
66764777Snyan	int n;
66864777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
66964777Snyan
67064777Snyan#ifdef ED_DEBUG
67164777Snyan	device_printf(dev, "ed98_probe_Novell: start\n");
67264777Snyan#endif
67364777Snyan	error = ed98_alloc_port(dev, port_rid);
674141552Simp	if (error)
67564777Snyan		return (error);
67664777Snyan
67764777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
67864777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
67964777Snyan
68064777Snyan	/* Reset the board */
68164777Snyan#ifdef ED_DEBUG
68264777Snyan	device_printf(dev, "ed98_probe_Novell: reset\n");
68364777Snyan#endif
68464777Snyan	switch (sc->type) {
68564777Snyan#if 1	/* XXX - I'm not sure this is really necessary... */
68664777Snyan	case ED_TYPE98_BDN:
68764777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
68864777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, (tmp & 0xf0) | 0x08);
68964777Snyan		ed_nic_outb(sc, 0x04, tmp);
69064777Snyan		(void) ed_asic_inb(sc, 0x08);
69164777Snyan		ed_asic_outb(sc, 0x08, tmp);
69264777Snyan		ed_asic_outb(sc, 0x08, tmp & 0x7f);
69364777Snyan		break;
69464777Snyan#endif
69564777Snyan	case ED_TYPE98_NC5098:
69664777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x00);
69764777Snyan		DELAY(5000);
69864777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x01);
69964777Snyan		break;
70064777Snyan
70164777Snyan	default:
70264777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
70364777Snyan
70464777Snyan	/*
70564777Snyan	 * I don't know if this is necessary; probably cruft leftover from
70664777Snyan	 * Clarkson packet driver code. Doesn't do a thing on the boards I've
707108533Sschweikh	 * tested. -DG [note that an outb(0x84, 0) seems to work here, and is
70864777Snyan	 * non-invasive...but some boards don't seem to reset and I don't have
70964777Snyan	 * complete documentation on what the 'right' thing to do is...so we
71064777Snyan	 * do the invasive thing for now. Yuck.]
71164777Snyan	 */
71264777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
71364777Snyan		break;
71464777Snyan	}
71564777Snyan	DELAY(5000);
71664777Snyan
71764777Snyan	/*
71864777Snyan	 * This is needed because some NE clones apparently don't reset the
71964777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
72064777Snyan	 * - this makes the probe invasive! ...Done against my better
72164777Snyan	 * judgement. -DLG
72264777Snyan	 */
72364777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
72464777Snyan	DELAY(5000);
72564777Snyan
72664777Snyan	/* Make sure that we really have an 8390 based board */
727141552Simp	if (!ed98_probe_generic8390(sc))
72864777Snyan		return (ENXIO);
72964777Snyan
73064777Snyan	/* Test memory via PIO */
73164777Snyan#ifdef ED_DEBUG
73264777Snyan	device_printf(dev, "ed98_probe_Novell: test memory\n");
73364777Snyan#endif
73464777Snyan	sc->cr_proto = ED_CR_RD2;
735141552Simp	if (!ed_pio_testmem(sc,  8192, 0, flags) &&
736141552Simp	    !ed_pio_testmem(sc, 16384, 1, flags))
73764777Snyan		return (ENXIO);
73864777Snyan
73964777Snyan	/* Setup the board type */
74064777Snyan#ifdef ED_DEBUG
74164777Snyan	device_printf(dev, "ed98_probe_Novell: board type\n");
74264777Snyan#endif
74364777Snyan	switch (sc->type) {
74464777Snyan	case ED_TYPE98_BDN:
74564777Snyan		sc->type_str = "LD-BDN";
74664777Snyan		break;
74764777Snyan	case ED_TYPE98_EGY:
74864777Snyan		sc->type_str = "EGY-98";
74964777Snyan		break;
75064777Snyan	case ED_TYPE98_LGY:
75164777Snyan		sc->type_str = "LGY-98";
75264777Snyan		break;
75364777Snyan	case ED_TYPE98_ICM:
75464777Snyan		sc->type_str = "ICM";
75564777Snyan		break;
75664777Snyan	case ED_TYPE98_108:
75764777Snyan		sc->type_str = "PC-9801-108";
75864777Snyan		break;
75964777Snyan	case ED_TYPE98_LA98:
76064777Snyan		sc->type_str = "LA-98";
76164777Snyan		break;
76264777Snyan	case ED_TYPE98_NW98X:
76364777Snyan		sc->type_str = "NW98X";
76464777Snyan		break;
76564777Snyan	case ED_TYPE98_NC5098:
76664777Snyan		sc->type_str = "NC5098";
76764777Snyan		break;
76864777Snyan	default:
76964777Snyan		sc->type_str = NULL;
77064777Snyan		break;
77164777Snyan	}
77264777Snyan
77364777Snyan	/* Get station address */
77464777Snyan	switch (sc->type) {
77564777Snyan	case ED_TYPE98_NC5098:
776141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
777147256Sbrooks			sc->enaddr[n] = ed_asic_inb(sc, ED_NC5098_ENADDR + n);
77864777Snyan		break;
77964777Snyan
78064777Snyan	default:
78164777Snyan		ed_pio_readmem(sc, 0, romdata, sizeof(romdata));
782141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
783147256Sbrooks			sc->enaddr[n] = romdata[n * (sc->isa16bit + 1)];
78464777Snyan		break;
78564777Snyan	}
78664777Snyan
78764777Snyan	/* clear any pending interrupts that might have occurred above */
78864777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
78964777Snyan
79064777Snyan	return (0);
79164777Snyan}
79264777Snyan
79364777Snyan/*
79464777Snyan * Probe and vendor-specific initialization routine for SIC-98 boards
79564777Snyan */
79664777Snyanstatic int
797141550Simped_probe_SIC98(device_t dev, int port_rid, int flags)
79864777Snyan{
79964777Snyan	struct ed_softc *sc = device_get_softc(dev);
80064777Snyan	int error;
80164777Snyan	int i;
80264777Snyan	u_char sum;
80364777Snyan
80464777Snyan	/*
80564777Snyan	 * Setup card RAM and I/O address
80664777Snyan	 * Kernel Virtual to segment C0000-DFFFF????
80764777Snyan	 */
80864777Snyan	error = ed98_alloc_port(dev, port_rid);
809141552Simp	if (error)
81064777Snyan		return (error);
81164777Snyan
812121118Sshiba	sc->asic_offset = ED_SIC_ASIC_OFFSET;
813121118Sshiba	sc->nic_offset  = ED_SIC_NIC_OFFSET;
81464777Snyan
81564777Snyan	error = ed98_alloc_memory(dev, 0);
816141552Simp	if (error)
81764777Snyan		return (error);
81864777Snyan
81964777Snyan	/* Reset card to force it into a known state. */
82064777Snyan	ed_asic_outb(sc, 0, 0x00);
82164777Snyan	DELAY(100);
82264777Snyan	if (ED_TYPE98SUB(flags) == 0) {
82364777Snyan		/* SIC-98/SIU-98 */
82464777Snyan		ed_asic_outb(sc, 0, 0x94);
82564777Snyan		DELAY(100);
82664777Snyan		ed_asic_outb(sc, 0, 0x94);
82764777Snyan	} else {
82864777Snyan		/* SIU-98-D */
82964777Snyan		ed_asic_outb(sc, 0, 0x80);
83064777Snyan		DELAY(100);
83164777Snyan		ed_asic_outb(sc, 0, 0x94);
83264777Snyan		DELAY(100);
83364777Snyan		ed_asic_outb(sc, 0, 0x9e);
83464777Snyan	}
83564777Snyan	DELAY(100);
83664777Snyan
83764777Snyan	/*
83864777Snyan	 * Here we check the card ROM, if the checksum passes, and the
83964777Snyan	 * type code and ethernet address check out, then we know we have
84064777Snyan	 * an SIC card.
84164777Snyan	 */
842149558Simp	sum = bus_space_read_1(sc->mem_bst, sc->mem_bsh, 6 * 2);
843141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
844149558Simp		sum ^= (sc->enaddr[i] =
845149558Simp		    bus_space_read_1(sc->mem_bst, sc->mem_bsh, i * 2));
84664777Snyan#ifdef ED_DEBUG
84764777Snyan	device_printf(dev, "ed_probe_sic98: got address %6D\n",
848147256Sbrooks		      sc->enaddr, ":");
84964777Snyan#endif
850141552Simp	if (sum != 0)
85164777Snyan		return (ENXIO);
852147256Sbrooks	if ((sc->enaddr[0] | sc->enaddr[1] | sc->enaddr[2]) == 0)
85364777Snyan		return (ENXIO);
85464777Snyan
855121118Sshiba	sc->vendor   = ED_VENDOR_SIC;
85664777Snyan	sc->type_str = "SIC98";
85764777Snyan	sc->isa16bit = 1;
85864777Snyan	sc->cr_proto = 0;
85964777Snyan
86064777Snyan	/*
86164777Snyan	 * SIC RAM page 0x0000-0x3fff(or 0x7fff)
86264777Snyan	 */
863141552Simp	if (ED_TYPE98SUB(flags) == 0)
86464777Snyan		ed_asic_outb(sc, 0, 0x90);
865141552Simp	else
86664777Snyan		ed_asic_outb(sc, 0, 0x8e);
86764777Snyan	DELAY(100);
86864777Snyan
869141550Simp	error = ed_clear_memory(dev);
870141550Simp	if (error)
871141550Simp		return (error);
87264777Snyan
87364777Snyan	sc->mem_shared = 1;
87464777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
87564777Snyan
87664777Snyan	/*
87764777Snyan	 * allocate one xmit buffer if < 16k, two buffers otherwise
87864777Snyan	 */
879141552Simp	if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
88064777Snyan		sc->txb_cnt = 1;
881141552Simp	else
88264777Snyan		sc->txb_cnt = 2;
88364777Snyan	sc->tx_page_start = 0;
88464777Snyan
88564777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt;
88664777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
88764777Snyan
88864777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
88964777Snyan
89064777Snyan	return (0);
89164777Snyan}
89264777Snyan
89364777Snyan/*
89464777Snyan * Contec C-NET(98) series support routines
89564777Snyan */
89664777Snyanstatic void
897141550Simped_reset_CNET98(struct ed_softc *sc, int flags)
89864777Snyan{
899118557Sbde	u_int init_addr = ED_CNET98_INIT;
90064777Snyan	u_char tmp;
90164777Snyan
90264777Snyan	/* Choose initial register address */
90364777Snyan	if (ED_TYPE98SUB(flags) != 0) {
90464777Snyan		init_addr = ED_CNET98_INIT2;
90564777Snyan	}
90664777Snyan#ifdef ED_DEBUG
90764777Snyan	printf("ed?: initial register=%x\n", init_addr);
90864777Snyan#endif
90964777Snyan	/*
91064777Snyan	 * Reset the board to force it into a known state.
91164777Snyan	 */
91264777Snyan	outb(init_addr, 0x00);	/* request */
91364777Snyan	DELAY(5000);
91464777Snyan	outb(init_addr, 0x01);	/* cancel */
91564777Snyan	DELAY(5000);
91664777Snyan
91764777Snyan	/*
91864777Snyan	 * Set I/O address(A15-12) and cpu type
91964777Snyan	 *
92064777Snyan	 *   AAAAIXXC(8bit)
92164777Snyan	 *   AAAA: A15-A12,  I: I/O enable, XX: reserved, C: CPU type
92264777Snyan	 *
92364777Snyan	 * CPU type is 1:80286 or higher, 0:not.
92464777Snyan	 * But FreeBSD runs under i386 or higher, thus it must be 1.
92564777Snyan	 */
92664777Snyan	tmp = (rman_get_start(sc->port_res) & 0xf000) >> 8;
92764777Snyan	tmp |= (0x08 | 0x01);
92864777Snyan#ifdef ED_DEBUG
92964777Snyan	printf("ed?: outb(%x, %x)\n", init_addr + 2, tmp);
93064777Snyan#endif
93164777Snyan	outb(init_addr + 2, tmp);
93264777Snyan	DELAY(5000);
93364777Snyan
93464777Snyan	/*
93564777Snyan	 * This is needed because some NE clones apparently don't reset the
93664777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
93764777Snyan	 * - this makes the probe invasive! ...Done against my better
93864777Snyan	 * judgement. -DLG
93964777Snyan	 */
94064777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
94164777Snyan	DELAY(5000);
94264777Snyan}
94364777Snyan
94464777Snyanstatic void
945141550Simped_winsel_CNET98(struct ed_softc *sc, u_short bank)
94664777Snyan{
947141550Simp	u_char mem = (rman_get_start(sc->mem_res) >> 12) & 0xff;
94864777Snyan
94964777Snyan	/*
95064777Snyan	 * Disable window memory
95164777Snyan	 *    bit7 is 0:disable
95264777Snyan	 */
95364777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem & 0x7f);
95464777Snyan	DELAY(10);
95564777Snyan
95664777Snyan	/*
95764777Snyan	 * Select window address
95864777Snyan	 *    FreeBSD address 0xf00xxxxx
95964777Snyan	 */
96064777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0L, bank & 0xff);
96164777Snyan	DELAY(10);
96264777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0H, (bank >> 8) & 0xff);
96364777Snyan	DELAY(10);
96464777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1L, 0x00);
96564777Snyan	DELAY(10);
96664777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1H, 0x41);
96764777Snyan	DELAY(10);
96864777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2L, 0x00);
96964777Snyan	DELAY(10);
97064777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2H, 0x42);
97164777Snyan	DELAY(10);
97264777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3L, 0x00);
97364777Snyan	DELAY(10);
97464777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3H, 0x43);
97564777Snyan	DELAY(10);
97664777Snyan
97764777Snyan	/*
97864777Snyan	 * Enable window memory(16Kbyte)
97964777Snyan	 *    bit7 is 1:enable
98064777Snyan	 */
98164777Snyan#ifdef ED_DEBUG
98264777Snyan	printf("ed?: window start address=%x\n", mem);
98364777Snyan#endif
98464777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem);
98564777Snyan	DELAY(10);
98664777Snyan}
98764777Snyan
98864777Snyan/*
98964777Snyan * Probe and vendor-specific initialization routine for C-NET(98) boards
99064777Snyan */
99164777Snyanstatic int
992141550Simped_probe_CNET98(device_t dev, int port_rid, int flags)
99364777Snyan{
99464777Snyan	struct ed_softc *sc = device_get_softc(dev);
99564777Snyan	int error;
99664777Snyan	u_char tmp;
99764777Snyan	u_long conf_irq, junk;
99864777Snyan#ifdef DIAGNOSTIC
99964777Snyan	u_char tmp_s;
100064777Snyan#endif
100164777Snyan
100264777Snyan	error = ed98_alloc_port(dev, port_rid);
1003141552Simp	if (error)
100464777Snyan		return (error);
100564777Snyan
100664777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
100764777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
100864777Snyan
100964777Snyan	error = ed98_alloc_memory(dev, 0);
1010141552Simp	if (error)
101164777Snyan		return (error);
101264777Snyan
101364777Snyan	/* Check I/O address. 0x[a-f]3d0 are allowed. */
101464777Snyan	if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
101564777Snyan	||  ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
101664777Snyan#ifdef DIAGNOSTIC
1017111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
101864777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
101964777Snyan			"0x[a-f]3d0", "CNET98");
102064777Snyan#endif
102164777Snyan		return (ENXIO);
102264777Snyan	}
102364777Snyan
102464777Snyan#ifdef DIAGNOSTIC
102564777Snyan	/* Check window area address */
1026141550Simp	tmp_s = rman_get_start(sc->mem_res) >> 12;
102764777Snyan	if (tmp_s < 0x80) {
1028141550Simp		device_printf(dev, "Please change window address(0x%lx)\n",
1029141550Simp		    rman_get_start(sc->mem_res));
103064777Snyan		return (ENXIO);
103164777Snyan	}
103264777Snyan
103364777Snyan	tmp_s &= 0x0f;
103464777Snyan	tmp    = rman_get_start(sc->port_res) >> 12;
103564777Snyan	if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
1036111427Snyan		device_printf(dev, "Please change iobase address(0x%lx) "
1037141550Simp		    "or window address(0x%lx)\n",
1038141550Simp		    rman_get_start(sc->port_res),
1039141550Simp		    rman_get_start(sc->mem_res));
104064777Snyan		return (ENXIO);
104164777Snyan	}
104264777Snyan#endif
104364777Snyan	/* Reset the board */
104464777Snyan	ed_reset_CNET98(sc, flags);
104564777Snyan
104664777Snyan	/*
104764777Snyan	 * This is needed because some NE clones apparently don't reset the
104864777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
104964777Snyan	 * - this makes the probe invasive! ...Done against my better
105064777Snyan	 * judgement. -DLG
105164777Snyan	 */
105264777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
105364777Snyan	DELAY(5000);
105464777Snyan
105564777Snyan	/* Make sure that we really have an 8390 based board */
1056141552Simp	if (!ed98_probe_generic8390(sc))
105764777Snyan		return (ENXIO);
105864777Snyan
105964777Snyan	/*
106064777Snyan	 *  Set window ethernet address area
106164777Snyan	 *    board memory base 0x480000  data 256byte
106264777Snyan	 */
106364777Snyan	ed_winsel_CNET98(sc, 0x4800);
106464777Snyan
106564777Snyan	/*
106664777Snyan	 * Get station address from on-board ROM
106764777Snyan	 */
1068149558Simp	bus_space_read_region_1(sc->mem_bst, sc->mem_bsh, sc->mem_start,
1069149558Simp	    sc->enaddr, ETHER_ADDR_LEN);
107064777Snyan
107164777Snyan	sc->vendor    = ED_VENDOR_MISC;
107264777Snyan	sc->type_str  = "CNET98";
107364777Snyan	sc->isa16bit  = 0;
107464777Snyan	sc->cr_proto  = ED_CR_RD2;
107564777Snyan
107664777Snyan	/*
107764777Snyan	 * Set window buffer memory area
107864777Snyan	 *    board memory base 0x400000  data 16kbyte
107964777Snyan	 */
108064777Snyan	ed_winsel_CNET98(sc, 0x4000);
108164777Snyan
1082141550Simp	error = ed_clear_memory(dev);
1083141550Simp	if (error)
1084141550Simp		return (error);
108564777Snyan
108664777Snyan	sc->mem_shared = 1;
108764777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
108864777Snyan
108964777Snyan	sc->txb_cnt = 1;	/* XXX */
109064777Snyan	sc->tx_page_start = 0;
109164777Snyan
109264777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
109364777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
109464777Snyan
109564777Snyan	sc->mem_ring = sc->mem_start + ED_PAGE_SIZE * ED_TXBUF_SIZE;
109664777Snyan
109764777Snyan	/*
109864777Snyan	 *   Set interrupt level
109964777Snyan	 */
1100141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
110164777Snyan	if (error)
110264777Snyan		return (error);
110364777Snyan
110464777Snyan	switch (conf_irq) {
110564777Snyan	case 3:
110664777Snyan		tmp = ED_CNET98_INT_IRQ3;
110764777Snyan		break;
110864777Snyan	case 5:
110964777Snyan		tmp = ED_CNET98_INT_IRQ5;
111064777Snyan		break;
111164777Snyan	case 6:
111264777Snyan		tmp = ED_CNET98_INT_IRQ6;
111364777Snyan		break;
111464777Snyan	case 9:
111564777Snyan		tmp = ED_CNET98_INT_IRQ9;
111664777Snyan		break;
111764777Snyan	case 12:
111864777Snyan		tmp = ED_CNET98_INT_IRQ12;
111964777Snyan		break;
112064777Snyan	case 13:
112164777Snyan		tmp = ED_CNET98_INT_IRQ13;
112264777Snyan		break;
112364777Snyan	default:
112464777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
112564777Snyan			"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
112664777Snyan		return (ENXIO);
112764777Snyan	}
112864777Snyan	ed_asic_outb(sc, ED_CNET98_INT_LEV, tmp);
112964777Snyan	DELAY(1000);
113064777Snyan	/*
113164777Snyan	 *   Set interrupt mask.
113264777Snyan	 *     bit7:1 all interrupt mask
113364777Snyan	 *     bit1:1 timer interrupt mask
113464777Snyan	 *     bit0:0 NS controler interrupt enable
113564777Snyan	 */
113664777Snyan	ed_asic_outb(sc, ED_CNET98_INT_MASK, 0x7e);
113764777Snyan	DELAY(1000);
113864777Snyan
113964777Snyan	return (0);
114064777Snyan}
114164777Snyan
114264777Snyan/*
114364777Snyan * Probe and vendor-specific initialization routine for C-NET(98)E/L boards
114464777Snyan */
114564777Snyanstatic int
1146141550Simped_probe_CNET98EL(device_t dev, int port_rid, int flags)
114764777Snyan{
114864777Snyan	struct ed_softc *sc = device_get_softc(dev);
114964777Snyan	int error;
115064777Snyan	int i;
115164777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
115264777Snyan	u_long conf_irq, junk;
115364777Snyan
115464777Snyan	error = ed98_alloc_port(dev, port_rid);
1155141552Simp	if (error)
115664777Snyan		return (error);
115764777Snyan
115864777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
115964777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
116064777Snyan
116164777Snyan	/* Check I/O address. 0x[0-f]3d0 are allowed. */
116264777Snyan	if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
116364777Snyan#ifdef DIAGNOSTIC
1164111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
116564777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
116664777Snyan			"0x?3d0", "CNET98E/L");
116764777Snyan#endif
116864777Snyan		return (ENXIO);
116964777Snyan	}
117064777Snyan
117164777Snyan	/* Reset the board */
117264777Snyan	ed_reset_CNET98(sc, flags);
117364777Snyan
117464777Snyan	/*
117564777Snyan	 * This is needed because some NE clones apparently don't reset the
117664777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
117764777Snyan	 * - this makes the probe invasive! ...Done against my better
117864777Snyan	 * judgement. -DLG
117964777Snyan	 */
118064777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
118164777Snyan	DELAY(5000);
118264777Snyan
118364777Snyan	/* Make sure that we really have an 8390 based board */
1184141552Simp	if (!ed98_probe_generic8390(sc))
118564777Snyan		return (ENXIO);
118664777Snyan
118764777Snyan	/* Test memory via PIO */
118864777Snyan	sc->cr_proto = ED_CR_RD2;
1189141552Simp	if (!ed_pio_testmem(sc, ED_CNET98EL_PAGE_OFFSET, 1, flags))
119064777Snyan		return (ENXIO);
119164777Snyan
119264777Snyan	/* This looks like a C-NET(98)E/L board. */
119364777Snyan	sc->type_str = "CNET98E/L";
119464777Snyan
119564777Snyan	/*
119664777Snyan	 * Set IRQ. C-NET(98)E/L only allows a choice of irq 3,5,6.
119764777Snyan	 */
1198141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1199141552Simp	if (error)
120064777Snyan		return (error);
120164777Snyan
120264777Snyan	switch (conf_irq) {
120364777Snyan	case 3:
120464777Snyan		tmp = ED_CNET98EL_ICR_IRQ3;
120564777Snyan		break;
120664777Snyan	case 5:
120764777Snyan		tmp = ED_CNET98EL_ICR_IRQ5;
120864777Snyan		break;
120964777Snyan	case 6:
121064777Snyan		tmp = ED_CNET98EL_ICR_IRQ6;
121164777Snyan		break;
121264777Snyan#if 0
121364777Snyan	case 12:
121464777Snyan		tmp = ED_CNET98EL_ICR_IRQ12;
121564777Snyan		break;
121664777Snyan#endif
121764777Snyan	default:
121864777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
121964777Snyan			"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
122064777Snyan		return (ENXIO);
122164777Snyan	}
122264777Snyan	ed_asic_outb(sc, ED_CNET98EL_ICR, tmp);
122364777Snyan	ed_asic_outb(sc, ED_CNET98EL_IMR, 0x7e);
122464777Snyan
122564777Snyan	/* Get station address from on-board ROM */
122664777Snyan	ed_pio_readmem(sc, 16384, romdata, sizeof(romdata));
1227141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
1228147256Sbrooks		sc->enaddr[i] = romdata[i * 2];
122964777Snyan
123064777Snyan	/* clear any pending interrupts that might have occurred above */
123164777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
123264777Snyan
123364777Snyan	return (0);
123464777Snyan}
123564777Snyan
123664777Snyan/*
123764777Snyan * Probe and vendor-specific initialization routine for PC-9801-77 boards
123864777Snyan */
123964777Snyanstatic int
1240141550Simped_probe_NEC77(device_t dev, int port_rid, int flags)
124164777Snyan{
124264777Snyan	struct ed_softc *sc = device_get_softc(dev);
124364777Snyan	int error;
124464777Snyan	u_char tmp;
124564777Snyan	u_long conf_irq, junk;
124664777Snyan
124764777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1248141552Simp	if (error)
124964777Snyan		return (error);
125064777Snyan
125164777Snyan	/* LA/T-98 does not need IRQ setting. */
1252141552Simp	if (ED_TYPE98SUB(flags) == 0)
125364777Snyan		return (0);
125464777Snyan
125564777Snyan	/*
125664777Snyan	 * Set IRQ. PC-9801-77 only allows a choice of irq 3,5,6,12,13.
125764777Snyan	 */
1258141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1259141552Simp	if (error)
126064777Snyan		return (error);
126164777Snyan
126264777Snyan	switch (conf_irq) {
126364777Snyan	case 3:
126464777Snyan		tmp = ED_NEC77_IRQ3;
126564777Snyan		break;
126664777Snyan	case 5:
126764777Snyan		tmp = ED_NEC77_IRQ5;
126864777Snyan		break;
126964777Snyan	case 6:
127064777Snyan		tmp = ED_NEC77_IRQ6;
127164777Snyan		break;
127264777Snyan	case 12:
127364777Snyan		tmp = ED_NEC77_IRQ12;
127464777Snyan		break;
127564777Snyan	case 13:
127664777Snyan		tmp = ED_NEC77_IRQ13;
127764777Snyan		break;
127864777Snyan	default:
127964777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
128064777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
128164777Snyan		return (ENXIO);
128264777Snyan	}
128364777Snyan	ed_asic_outb(sc, ED_NEC77_IRQ, tmp);
128464777Snyan
128564777Snyan	return (0);
128664777Snyan}
128764777Snyan
128864777Snyan/*
128964777Snyan * Probe and vendor-specific initialization routine for EC/EP-98X boards
129064777Snyan */
129164777Snyanstatic int
1292141550Simped_probe_NW98X(device_t dev, int port_rid, int flags)
129364777Snyan{
129464777Snyan	struct ed_softc *sc = device_get_softc(dev);
129564777Snyan	int error;
129664777Snyan	u_char tmp;
129764777Snyan	u_long conf_irq, junk;
129864777Snyan
129964777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1300141552Simp	if (error)
130164777Snyan		return (error);
130264777Snyan
130364777Snyan	/* Networld 98X3 does not need IRQ setting. */
1304141552Simp	if (ED_TYPE98SUB(flags) == 0)
130564777Snyan		return (0);
130664777Snyan
130764777Snyan	/*
130864777Snyan	 * Set IRQ. EC/EP-98X only allows a choice of irq 3,5,6,12,13.
130964777Snyan	 */
1310141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1311141552Simp	if (error)
131264777Snyan		return (error);
131364777Snyan
131464777Snyan	switch (conf_irq) {
131564777Snyan	case 3:
131664777Snyan		tmp = ED_NW98X_IRQ3;
131764777Snyan		break;
131864777Snyan	case 5:
131964777Snyan		tmp = ED_NW98X_IRQ5;
132064777Snyan		break;
132164777Snyan	case 6:
132264777Snyan		tmp = ED_NW98X_IRQ6;
132364777Snyan		break;
132464777Snyan	case 12:
132564777Snyan		tmp = ED_NW98X_IRQ12;
132664777Snyan		break;
132764777Snyan	case 13:
132864777Snyan		tmp = ED_NW98X_IRQ13;
132964777Snyan		break;
133064777Snyan	default:
133164777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
133264777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
133364777Snyan		return (ENXIO);
133464777Snyan	}
133564777Snyan	ed_asic_outb(sc, ED_NW98X_IRQ, tmp);
133664777Snyan
133764777Snyan	return (0);
133864777Snyan}
133964777Snyan
134064777Snyan/*
134164777Snyan * Read SB-9801 station address from Serial Two-Wire EEPROM
134264777Snyan */
134364777Snyanstatic void
1344141550Simped_get_SB98(struct ed_softc *sc)
134564777Snyan{
134664777Snyan	int i, j;
134764777Snyan	u_char mask, val;
134864777Snyan
134964777Snyan        /* enable EEPROM acceess */
135064777Snyan        ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_ENABLE);
135164777Snyan
135264777Snyan	/* output start command */
135364777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
135464777Snyan	DELAY(ED_SB98_EEP_DELAY);
135564777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
135664777Snyan	DELAY(ED_SB98_EEP_DELAY);
135764777Snyan
135864777Snyan       	/* output address (7bit) */
135964777Snyan	for (mask = 0x40; mask != 0; mask >>= 1) {
136064777Snyan		val = 0;
136164777Snyan		if (ED_SB98_ADDRESS & mask)
136264777Snyan			val = ED_SB98_EEP_SDA;
136364777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val);
136464777Snyan		DELAY(ED_SB98_EEP_DELAY);
136564777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val | ED_SB98_EEP_SCL);
136664777Snyan		DELAY(ED_SB98_EEP_DELAY);
136764777Snyan	}
136864777Snyan
136964777Snyan	/* output READ command */
137064777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ);
137164777Snyan	DELAY(ED_SB98_EEP_DELAY);
137264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ | ED_SB98_EEP_SCL);
137364777Snyan	DELAY(ED_SB98_EEP_DELAY);
137464777Snyan
137564777Snyan	/* read station address */
137664777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
137764777Snyan		/* output ACK */
137864777Snyan		ed_asic_outb(sc, ED_SB98_EEP, 0);
137964777Snyan		DELAY(ED_SB98_EEP_DELAY);
138064777Snyan		ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
138164777Snyan		DELAY(ED_SB98_EEP_DELAY);
138264777Snyan
138364777Snyan		val = 0;
138464777Snyan		for (j = 0; j < 8; j++) {
138564777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
138664777Snyan			DELAY(ED_SB98_EEP_DELAY);
138764777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
138864777Snyan			DELAY(ED_SB98_EEP_DELAY);
138964777Snyan			val <<= 1;
139064777Snyan			val |= (ed_asic_inb(sc, ED_SB98_EEP) & ED_SB98_EEP_SDA);
139164777Snyan			DELAY(ED_SB98_EEP_DELAY);
139264777Snyan	  	}
1393147256Sbrooks		sc->enaddr[i] = val;
139464777Snyan	}
139564777Snyan
139664777Snyan	/* output Last ACK */
139764777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
139864777Snyan        DELAY(ED_SB98_EEP_DELAY);
139964777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
140064777Snyan        DELAY(ED_SB98_EEP_DELAY);
140164777Snyan
140264777Snyan	/* output stop command */
140364777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
140464777Snyan	DELAY(ED_SB98_EEP_DELAY);
140564777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
140664777Snyan	DELAY(ED_SB98_EEP_DELAY);
140764777Snyan
140864777Snyan	/* disable EEPROM access */
140964777Snyan	ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_DISABLE);
141064777Snyan}
141164777Snyan
141264777Snyan/*
141364777Snyan * Probe and vendor-specific initialization routine for SB-9801 boards
141464777Snyan */
141564777Snyanstatic int
1416141550Simped_probe_SB98(device_t dev, int port_rid, int flags)
141764777Snyan{
141864777Snyan	struct ed_softc *sc = device_get_softc(dev);
141964777Snyan	int error;
142064777Snyan	u_char tmp;
142164777Snyan	u_long conf_irq, junk;
142264777Snyan
142364777Snyan	error = ed98_alloc_port(dev, port_rid);
1424141552Simp	if (error)
142564777Snyan		return (error);
142664777Snyan
142764777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
142864777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
142964777Snyan
143064777Snyan	/* Check I/O address. 00d[02468ace] are allowed. */
143164777Snyan	if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
143264777Snyan#ifdef DIAGNOSTIC
1433111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
1434141552Simp		    "must be %s for %s\n", rman_get_start(sc->port_res),
1435141552Simp		    "0xd?", "SB9801");
143664777Snyan#endif
143764777Snyan		return (ENXIO);
143864777Snyan	}
143964777Snyan
144064777Snyan	/* Write I/O port address and read 4 times */
144164777Snyan	outb(ED_SB98_IO_INHIBIT, rman_get_start(sc->port_res) & 0xff);
144264777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144364777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144464777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144564777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144664777Snyan
144764777Snyan	/*
144864777Snyan	 * Check IRQ. Soliton SB-9801 only allows a choice of
144964777Snyan	 * irq 3,5,6,12
145064777Snyan	 */
1451141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1452141552Simp	if (error)
145364777Snyan		return (error);
145464777Snyan
145564777Snyan	switch (conf_irq) {
145664777Snyan	case 3:
145764777Snyan		tmp = ED_SB98_CFG_IRQ3;
145864777Snyan		break;
145964777Snyan	case 5:
146064777Snyan		tmp = ED_SB98_CFG_IRQ5;
146164777Snyan		break;
146264777Snyan	case 6:
146364777Snyan		tmp = ED_SB98_CFG_IRQ6;
146464777Snyan		break;
146564777Snyan	case 12:
146664777Snyan		tmp = ED_SB98_CFG_IRQ12;
146764777Snyan		break;
146864777Snyan	default:
146964777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
147064777Snyan			"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
147164777Snyan		return (ENXIO);
147264777Snyan	}
147364777Snyan
1474141552Simp	if (flags & ED_FLAGS_DISABLE_TRANCEIVER)
147564777Snyan		tmp |= ED_SB98_CFG_ALTPORT;
147664777Snyan	ed_asic_outb(sc, ED_SB98_CFG, ED_SB98_CFG_ENABLE | tmp);
147764777Snyan	ed_asic_outb(sc, ED_SB98_POLARITY, 0x01);
147864777Snyan
147964777Snyan	/* Reset the board. */
148064777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x7a);
148164777Snyan	DELAY(300);
148264777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x79);
148364777Snyan	DELAY(300);
148464777Snyan
148564777Snyan	/*
148664777Snyan	 * This is needed because some NE clones apparently don't reset the
148764777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
148864777Snyan	 * - this makes the probe invasive! ...Done against my better
148964777Snyan	 * judgement. -DLG
149064777Snyan	 */
149164777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
149264777Snyan	DELAY(5000);
149364777Snyan
149464777Snyan	/* Make sure that we really have an 8390 based board */
1495141552Simp	if (!ed98_probe_generic8390(sc))
149664777Snyan		return (ENXIO);
149764777Snyan
149864777Snyan	/* Test memory via PIO */
149964777Snyan	sc->cr_proto = ED_CR_RD2;
150064777Snyan	if (!ed_pio_testmem(sc, 16384, 1, flags)) {
150164777Snyan		return (ENXIO);
150264777Snyan	}
150364777Snyan
150464777Snyan	/* This looks like an SB9801 board. */
150564777Snyan	sc->type_str = "SB9801";
150664777Snyan
150764777Snyan	/* Get station address */
150864777Snyan	ed_get_SB98(sc);
150964777Snyan
151064777Snyan	/* clear any pending interrupts that might have occurred above */
151164777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
151264777Snyan
151364777Snyan	return (0);
151464777Snyan}
151564777Snyan
151664777Snyan/*
151764777Snyan * Test the ability to read and write to the NIC memory.
151864777Snyan */
151964777Snyanstatic int
1520141550Simped_pio_testmem(struct ed_softc *sc, int page_offset, int isa16bit, int flags)
152164777Snyan{
152264777Snyan	u_long memsize;
152364777Snyan	static char test_pattern[32] = "THIS is A memory TEST pattern";
152464777Snyan	char test_buffer[32];
152564777Snyan#ifdef DIAGNOSTIC
152664777Snyan	int page_end;
152764777Snyan#endif
152864777Snyan
152964777Snyan	sc->vendor = ED_VENDOR_NOVELL;
153064777Snyan	sc->mem_shared = 0;
153164777Snyan	sc->isa16bit = isa16bit;
153264777Snyan
153364777Snyan	/* 8k of memory plus an additional 8k if 16bit */
153464777Snyan	memsize = (isa16bit ? 16384 : 8192);
153564777Snyan
153664777Snyan	/*
153764777Snyan	 * This prevents packets from being stored in the NIC memory when the
153864777Snyan	 * readmem routine turns on the start bit in the CR.
153964777Snyan	 */
154064777Snyan	ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON);
154164777Snyan
154264777Snyan	/* Initialize DCR for byte/word operations */
1543141550Simp	if (isa16bit)
154464777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
1545141550Simp	else
154664777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
154764777Snyan	ed_nic_outb(sc, ED_P0_PSTART, page_offset / ED_PAGE_SIZE);
154864777Snyan	ed_nic_outb(sc, ED_P0_PSTOP, (page_offset + memsize) / ED_PAGE_SIZE);
154964777Snyan#ifdef ED_DEBUG
1550137531Snyan	printf("ed?: ed_pio_testmem: page start=%x, end=%lx",
1551141552Simp	    page_offset, page_offset + memsize);
155264777Snyan#endif
155364777Snyan
155464777Snyan	/*
155564777Snyan	 * Write a test pattern. If this fails, then we don't know
155664777Snyan	 * what this board is.
155764777Snyan	 */
155864777Snyan	ed_pio_writemem(sc, test_pattern, page_offset, sizeof(test_pattern));
155964777Snyan	ed_pio_readmem(sc, page_offset, test_buffer, sizeof(test_pattern));
156064777Snyan
156164777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
156264777Snyan#ifdef ED_DEBUG
1563141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_offset);
156464777Snyan#endif
156564777Snyan		return (0);
156664777Snyan	}
156764777Snyan
156864777Snyan#ifdef DIAGNOSTIC
156964777Snyan	/* Check the bottom. */
157064777Snyan	page_end = page_offset + memsize - ED_PAGE_SIZE;
157164777Snyan	ed_pio_writemem(sc, test_pattern, page_end, sizeof(test_pattern));
157264777Snyan	ed_pio_readmem(sc, page_end, test_buffer, sizeof(test_pattern));
157364777Snyan
157464777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
157564777Snyan#ifdef ED_DEBUG
1576141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_end);
157764777Snyan#endif
157864777Snyan		return (0);
157964777Snyan	}
158064777Snyan#endif
158164777Snyan	sc->mem_size = memsize;
1582149558Simp	sc->mem_start = page_offset;
158364777Snyan	sc->mem_end   = sc->mem_start + memsize;
158464777Snyan	sc->tx_page_start = page_offset / ED_PAGE_SIZE;
158564777Snyan
158664777Snyan	/*
158764777Snyan	 * Use one xmit buffer if < 16k, two buffers otherwise (if not told
158864777Snyan	 * otherwise).
158964777Snyan	 */
1590141552Simp	if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
159164777Snyan		sc->txb_cnt = 1;
1592141552Simp	else
159364777Snyan		sc->txb_cnt = 2;
159464777Snyan
159564777Snyan	sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
159664777Snyan	sc->rec_page_stop  = sc->tx_page_start + memsize / ED_PAGE_SIZE;
159764777Snyan
159864777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
159964777Snyan
160064777Snyan	return (1);
160164777Snyan}
160270355Simp
1603141550Simpstatic device_method_t ed_cbus_methods[] = {
160470355Simp	/* Device interface */
1605141550Simp	DEVMETHOD(device_probe,		ed_cbus_probe),
1606141550Simp	DEVMETHOD(device_attach,	ed_cbus_attach),
1607141494Simp	DEVMETHOD(device_attach,	ed_detach),
160870355Simp
160970355Simp	{ 0, 0 }
161070355Simp};
161170355Simp
1612141550Simpstatic driver_t ed_cbus_driver = {
161370355Simp	"ed",
1614141550Simp	ed_cbus_methods,
161570355Simp	sizeof(struct ed_softc)
161670355Simp};
161770355Simp
1618141550SimpDRIVER_MODULE(ed, isa, ed_cbus_driver, ed_devclass, 0, 0);
1619113506SmdoddMODULE_DEPEND(ed, isa, 1, 1, 1);
1620113506SmdoddMODULE_DEPEND(ed, ether, 1, 1, 1);
1621