if_ed_cbus.c revision 154924
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 154924 2006-01-27 19:10:13Z 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>
45149609Simp#include <net/if_media.h>
4664777Snyan#include <net/if_mib.h>
4764777Snyan
4864777Snyan#include <isa/isavar.h>
4964777Snyan
5064777Snyan#include <dev/ed/if_edvar.h>
5164777Snyan#include <dev/ed/if_edreg.h>
5264777Snyan#include <dev/ed/if_ed98.h>
5364777Snyan
54141550Simpstatic int ed98_alloc_port(device_t, int);
55141550Simpstatic int ed98_alloc_memory(device_t, int);
56141550Simpstatic int ed_pio_testmem(struct ed_softc *, int, int, int);
57141550Simpstatic int ed_probe_CNET98(device_t, int, int);
58141550Simpstatic int ed_probe_CNET98EL(device_t, int, int);
59154924Simpstatic int ed_probe_EZ98(device_t, int, int);
60141550Simpstatic int ed_probe_NEC77(device_t, int, int);
61141550Simpstatic int ed_probe_NW98X(device_t, int, int);
62141550Simpstatic int ed_probe_SB98(device_t, int, int);
63154924Simpstatic int ed_probe_SIC98(device_t, int, int);
64141550Simpstatic int ed98_probe_Novell(device_t, int, int);
65141550Simpstatic int ed98_probe_generic8390(struct ed_softc *);
66141550Simpstatic void ed_reset_CNET98(struct ed_softc *, int);
67141550Simpstatic void ed_winsel_CNET98(struct ed_softc *, u_short);
68141550Simpstatic void ed_get_SB98(struct ed_softc *);
6964777Snyan
70141550Simpstatic int ed_cbus_probe(device_t);
71141550Simpstatic int ed_cbus_attach(device_t);
7264777Snyan
7364777Snyanstatic struct isa_pnp_id ed_ids[] = {
7464777Snyan/* TODO - list up PnP boards for PC-98 */
7564777Snyan	{ 0,		NULL }
7664777Snyan};
7764777Snyan
7864777Snyanstatic int
79141550Simped_cbus_probe(device_t dev)
8064777Snyan{
8164777Snyan	struct ed_softc *sc = device_get_softc(dev);
8264777Snyan	int flags = device_get_flags(dev);
8364777Snyan	int error = 0;
8464777Snyan
8564777Snyan	sc->type = ED_TYPE98(flags);
8664777Snyan#ifdef ED_DEBUG
87141550Simp	device_printf(dev, "ed_cbus_probe: sc->type=%x\n", sc->type);
8864777Snyan#endif
8964777Snyan
9064777Snyan	/* Check isapnp ids */
9164777Snyan	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ed_ids);
9264777Snyan#ifdef ED_DEBUG
93141550Simp	device_printf(dev, "ed_cbus_probe: ISA_PNP_PROBE returns %d\n", error);
9464777Snyan#endif
9564777Snyan
9664777Snyan	/* If the card had a PnP ID that didn't match any we know about */
97141552Simp	if (error == ENXIO)
9864777Snyan		goto end;
9964777Snyan
10064777Snyan	/* If we had some other problem. */
101141552Simp	if (!(error == 0 || error == ENOENT))
10264777Snyan		goto end;
10364777Snyan
10464777Snyan	/* Heuristic probes */
10564777Snyan#ifdef ED_DEBUG
106141550Simp	device_printf(dev, "ed_cbus_probe: Heuristic probes start\n");
10764777Snyan#endif
10864777Snyan	switch (sc->type) {
10964777Snyan	case ED_TYPE98_GENERIC:
11064777Snyan		/*
11164777Snyan		 * CAUTION!
11264777Snyan		 * sc->type of these boards are overwritten by PC/AT's value.
11364777Snyan		 */
11464777Snyan
11564777Snyan		/*
11664777Snyan		 * SMC EtherEZ98
11764777Snyan		 */
11864777Snyan		error = ed_probe_EZ98(dev, 0, flags);
119141552Simp		if (error == 0)
12064777Snyan			goto end;
12164777Snyan
12264777Snyan		ed_release_resources(dev);
12364777Snyan
12464777Snyan		/*
12564777Snyan		 * Allied Telesis CenterCom LA-98-T
12664777Snyan		 */
12764777Snyan		error = ed_probe_Novell(dev, 0, flags);
128141932Simp		if (error == 0) {
129141932Simp			ed_Novell_read_mac(sc);
13064777Snyan			goto end;
131141932Simp		}
13264777Snyan		break;
13364777Snyan
13464777Snyan	/*
13564777Snyan	 * NE2000-like boards probe routine
13664777Snyan	 */
13764777Snyan	case ED_TYPE98_BDN:
13864777Snyan		/*
13964777Snyan		 * ELECOM LANEED LD-BDN
14064777Snyan		 * PLANET SMART COM 98 EN-2298
14164777Snyan		 */
14264777Snyan	case ED_TYPE98_LGY:
14364777Snyan		/*
14464777Snyan		 * MELCO LGY-98, IND-SP, IND-SS
14564777Snyan		 * MACNICA NE2098
14664777Snyan		 */
14764777Snyan	case ED_TYPE98_ICM:
14864777Snyan		/*
14964777Snyan		 * ICM DT-ET-25, DT-ET-T5, IF-2766ET, IF-2771ET
15064777Snyan		 * D-Link DE-298P, DE-298
15164777Snyan		 */
15264777Snyan	case ED_TYPE98_EGY:
15364777Snyan		/*
15464777Snyan		 * MELCO EGY-98
15564777Snyan		 * Contec C-NET(98)E-A, C-NET(98)L-A
15664777Snyan		 */
15764777Snyan	case ED_TYPE98_108:
15864777Snyan		/*
15964777Snyan		 * NEC PC-9801-107,108
16064777Snyan		 */
16164777Snyan	case ED_TYPE98_NC5098:
16264777Snyan		/*
16364777Snyan		 * NextCom NC5098
16464777Snyan		 */
16564777Snyan		error = ed98_probe_Novell(dev, 0, flags);
16664777Snyan		break;
16764777Snyan
16864777Snyan	/*
16964777Snyan	 * other boards with special probe routine
17064777Snyan	 */
17164777Snyan	case ED_TYPE98_SIC:
17264777Snyan		/*
17364777Snyan		 * Allied Telesis SIC-98
17464777Snyan		 */
17564777Snyan		error = ed_probe_SIC98(dev, 0, flags);
17664777Snyan		break;
17764777Snyan
17864777Snyan	case ED_TYPE98_CNET98EL:
17964777Snyan		/*
18064777Snyan		 * Contec C-NET(98)E/L
18164777Snyan		 */
18264777Snyan		error = ed_probe_CNET98EL(dev, 0, flags);
18364777Snyan		break;
18464777Snyan
18564777Snyan	case ED_TYPE98_CNET98:
18664777Snyan		/*
18764777Snyan		 * Contec C-NET(98)
18864777Snyan		 */
18964777Snyan		error = ed_probe_CNET98(dev, 0, flags);
19064777Snyan		break;
19164777Snyan
19264777Snyan	case ED_TYPE98_LA98:
19364777Snyan		/*
19464777Snyan		 * IO-DATA LA/T-98
19564777Snyan		 * NEC PC-9801-77,78
19664777Snyan		 */
19764777Snyan		error = ed_probe_NEC77(dev, 0, flags);
19864777Snyan		break;
19964777Snyan
20064777Snyan	case ED_TYPE98_NW98X:
20164777Snyan		/*
20264777Snyan		 * Networld EC/EP-98X
20364777Snyan		 */
20464777Snyan		error = ed_probe_NW98X(dev, 0, flags);
20564777Snyan		break;
20664777Snyan
20764777Snyan	case ED_TYPE98_SB98:
20864777Snyan		/*
20964777Snyan		 * Soliton SB-9801
21064777Snyan		 * Fujikura FN-9801
21164777Snyan		 */
21264777Snyan		error = ed_probe_SB98(dev, 0, flags);
21364777Snyan		break;
21464777Snyan	}
21564777Snyan
21664777Snyanend:
21764777Snyan#ifdef ED_DEBUG
218141550Simp	device_printf(dev, "ed_cbus_probe: end, error=%d\n", error);
21964777Snyan#endif
22064777Snyan	if (error == 0)
22164777Snyan		error = ed_alloc_irq(dev, 0, 0);
22264777Snyan
22364777Snyan	ed_release_resources(dev);
22464777Snyan	return (error);
22564777Snyan}
22664777Snyan
22764777Snyanstatic int
228141550Simped_cbus_attach(dev)
22964777Snyan	device_t dev;
23064777Snyan{
23164777Snyan	struct ed_softc *sc = device_get_softc(dev);
23264777Snyan	int flags = device_get_flags(dev);
23364777Snyan	int error;
23464777Snyan
23564777Snyan	if (sc->port_used > 0) {
236141552Simp		if (ED_TYPE98(flags) == ED_TYPE98_GENERIC)
23764777Snyan			ed_alloc_port(dev, sc->port_rid, sc->port_used);
238141552Simp		else
23964777Snyan			ed98_alloc_port(dev, sc->port_rid);
24064777Snyan	}
24164777Snyan	if (sc->mem_used)
24264777Snyan		ed_alloc_memory(dev, sc->mem_rid, sc->mem_used);
24364777Snyan
24464777Snyan	ed_alloc_irq(dev, sc->irq_rid, 0);
24564777Snyan
246149558Simp	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
247141552Simp	    edintr, sc, &sc->irq_handle);
24864777Snyan	if (error) {
24964777Snyan		ed_release_resources(dev);
25064777Snyan		return (error);
25164777Snyan	}
25264777Snyan
253121816Sbrooks	return ed_attach(dev);
25464777Snyan}
25564777Snyan
25664777Snyan/*
25764777Snyan * Interrupt conversion table for EtherEZ98
25864777Snyan */
259141495Simpstatic uint16_t ed_EZ98_intr_val[] = {
26064777Snyan	0,
26164777Snyan	3,
26264777Snyan	5,
26364777Snyan	6,
26464777Snyan	0,
26564777Snyan	9,
26664777Snyan	12,
26764777Snyan	13
26864777Snyan};
26964777Snyan
27064777Snyanstatic int
271141550Simped_probe_EZ98(device_t dev, int port_rid, int flags)
27264777Snyan{
27364777Snyan	struct ed_softc *sc = device_get_softc(dev);
27464777Snyan	int error;
27564777Snyan	static unsigned short *intr_vals[] = {NULL, ed_EZ98_intr_val};
27664777Snyan
27764777Snyan	error = ed_alloc_port(dev, port_rid, ED_EZ98_IO_PORTS);
27864777Snyan	if (error) {
27964777Snyan		return (error);
28064777Snyan	}
28164777Snyan
28264777Snyan	sc->asic_offset = ED_EZ98_ASIC_OFFSET;
28364777Snyan	sc->nic_offset  = ED_EZ98_NIC_OFFSET;
28464777Snyan
28564777Snyan	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
28664777Snyan}
28764777Snyan
28864777Snyan/*
28964777Snyan * I/O conversion tables
29064777Snyan */
29164777Snyan
29264777Snyan/* LGY-98, ICM, C-NET(98)E/L */
29364777Snyanstatic	bus_addr_t ed98_ioaddr_generic[] = {
29464777Snyan	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
29564777Snyan};
29664777Snyan
29764777Snyan/*
29864777Snyan *		Definitions for Contec C-NET(98)E/L
29964777Snyan */
30064777Snyan#define	ED_CNET98EL_ICR         2	/* Interrupt Configuration Register */
30164777Snyan
30264777Snyan#define	ED_CNET98EL_ICR_IRQ3	0x01
30364777Snyan#define	ED_CNET98EL_ICR_IRQ5	0x02
30464777Snyan#define	ED_CNET98EL_ICR_IRQ6	0x04
30564777Snyan#define	ED_CNET98EL_ICR_IRQ12	0x20
30664777Snyan
30764777Snyan#define	ED_CNET98EL_IMR         4	/* Interrupt Mask Register	*/
30864777Snyan#define	ED_CNET98EL_ISR         5	/* Interrupt Status Register	*/
30964777Snyan
31064777Snyan/* EGY-98 */
31164777Snyanstatic	bus_addr_t ed98_ioaddr_egy98[] = {
31264777Snyan	0,     0x02,  0x04,  0x06,  0x08,  0x0a,  0x0c,  0x0e,
31364777Snyan	0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e
31464777Snyan};
31564777Snyan
31664777Snyan/* SIC-98 */
31764777Snyanstatic	bus_addr_t ed98_ioaddr_sic98[] = {
31864777Snyan	0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00,
31964777Snyan	0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00
32064777Snyan};
32164777Snyan
32264777Snyan/* LA/T-98, LD-BDN, PC-9801-77, SB-9801 */
32364777Snyanstatic	bus_addr_t ed98_ioaddr_la98[] = {
32464777Snyan	0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000,
32564777Snyan	0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000,
32664777Snyan	0x0100	/* for NEC 77(see below) */
32764777Snyan};
32864777Snyan
32964777Snyan/*
33064777Snyan *		Definitions for NEC PC-9801-77
33164777Snyan */
33264777Snyan#define	ED_NEC77_IRQ		16	/* Interrupt Configuration Register */
33364777Snyan
33464777Snyan#define	ED_NEC77_IRQ3		0x04
33564777Snyan#define	ED_NEC77_IRQ5		0x06
33664777Snyan#define	ED_NEC77_IRQ6		0x08
33764777Snyan#define	ED_NEC77_IRQ12		0x0a
33864777Snyan#define	ED_NEC77_IRQ13		0x02
33964777Snyan
34064777Snyan/*
34164777Snyan *		Definitions for Soliton SB-9801
34264777Snyan */
34364777Snyan#define	ED_SB98_CFG		1	/* Board configuration		*/
34464777Snyan
34564777Snyan#define	ED_SB98_CFG_IRQ3	0x00
34664777Snyan#define	ED_SB98_CFG_IRQ5	0x04
34764777Snyan#define	ED_SB98_CFG_IRQ6	0x08
34864777Snyan#define	ED_SB98_CFG_IRQ12	0x0c
34964777Snyan#define	ED_SB98_CFG_ALTPORT	0x40		/* use EXTERNAL media	*/
35064777Snyan#define	ED_SB98_CFG_ENABLE	0xa0		/* enable configuration	*/
35164777Snyan
35264777Snyan#define	ED_SB98_EEPENA		2	/* EEPROM access enable		*/
35364777Snyan
35464777Snyan#define	ED_SB98_EEPENA_DISABLE	0x00
35564777Snyan#define	ED_SB98_EEPENA_ENABLE	0x01
35664777Snyan
35764777Snyan#define	ED_SB98_EEP		3	/* EEPROM access		*/
35864777Snyan
35964777Snyan#define	ED_SB98_EEP_SDA		0x01		/* Serial Data	*/
36064777Snyan#define	ED_SB98_EEP_SCL		0x02		/* Serial Clock	*/
36164777Snyan#define	ED_SB98_EEP_READ	0x01		/* Read Command	*/
36264777Snyan
36364777Snyan#define	ED_SB98_EEP_DELAY	300
36464777Snyan
36564777Snyan#define	ED_SB98_ADDRESS		0x01		/* Station Address(1-6)	*/
36664777Snyan
36764777Snyan#define	ED_SB98_POLARITY	4	/* Polarity			*/
36864777Snyan
36964777Snyan/* PC-9801-108 */
37064777Snyanstatic	bus_addr_t ed98_ioaddr_nec108[] = {
37164777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
37264777Snyan	0x1000, 0x1002, 0x1004, 0x1006, 0x1008, 0x100a, 0x100c, 0x100e
37364777Snyan};
37464777Snyan
37564777Snyan/* C-NET(98) */
37664777Snyanstatic	bus_addr_t ed98_ioaddr_cnet98[] = {
37764777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
37864777Snyan	0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e
37964777Snyan};
38064777Snyan
38164777Snyan/*
38264777Snyan *		Definitions for Contec C-NET(98)
38364777Snyan */
38464777Snyan#define	ED_CNET98_MAP_REG0L	0	/* MAPPING register0 Low	*/
38564777Snyan#define	ED_CNET98_MAP_REG1L	1	/* MAPPING register1 Low	*/
38664777Snyan#define	ED_CNET98_MAP_REG2L	2	/* MAPPING register2 Low	*/
38764777Snyan#define	ED_CNET98_MAP_REG3L	3	/* MAPPING register3 Low	*/
38864777Snyan#define	ED_CNET98_MAP_REG0H	4	/* MAPPING register0 Hi		*/
38964777Snyan#define	ED_CNET98_MAP_REG1H	5	/* MAPPING register1 Hi		*/
39064777Snyan#define	ED_CNET98_MAP_REG2H	6	/* MAPPING register2 Hi		*/
39164777Snyan#define	ED_CNET98_MAP_REG3H	7	/* MAPPING register3 Hi		*/
39264777Snyan#define	ED_CNET98_WIN_REG	8	/* Window register		*/
39364777Snyan#define	ED_CNET98_INT_LEV	9	/* Init level register		*/
39464777Snyan
39564777Snyan#define	ED_CNET98_INT_IRQ3	0x01		/* INT 0 */
39664777Snyan#define	ED_CNET98_INT_IRQ5	0x02		/* INT 1 */
39764777Snyan#define	ED_CNET98_INT_IRQ6	0x04		/* INT 2 */
39864777Snyan#define	ED_CNET98_INT_IRQ9	0x08		/* INT 3 */
39964777Snyan#define	ED_CNET98_INT_IRQ12	0x20		/* INT 5 */
40064777Snyan#define	ED_CNET98_INT_IRQ13	0x40		/* INT 6 */
40164777Snyan
40264777Snyan#define	ED_CNET98_INT_REQ	10	/* Init request register	*/
40364777Snyan#define	ED_CNET98_INT_MASK	11	/* Init mask register		*/
40464777Snyan#define	ED_CNET98_INT_STAT	12	/* Init status register		*/
40564777Snyan#define	ED_CNET98_INT_CLR	12	/* Init clear register		*/
40664777Snyan#define	ED_CNET98_RESERVE1	13
40764777Snyan#define	ED_CNET98_RESERVE2	14
40864777Snyan#define	ED_CNET98_RESERVE3	15
40964777Snyan
41064777Snyan/* EC/EP-98X, NC5098 */
41164777Snyanstatic	bus_addr_t ed98_ioaddr_nw98x[] = {
41264777Snyan	0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
41364777Snyan	0x0800, 0x0900, 0x0a00, 0x0b00, 0x0c00, 0x0d00, 0x0e00, 0x0f00,
41464777Snyan	0x1000	/* for EC/EP-98X(see below) */
41564777Snyan};
41664777Snyan
41764777Snyan/*
41864777Snyan *		Definitions for Networld EC/EP-98X
41964777Snyan */
42064777Snyan#define	ED_NW98X_IRQ            16	/* Interrupt Configuration Register */
42164777Snyan
42264777Snyan#define	ED_NW98X_IRQ3           0x04
42364777Snyan#define	ED_NW98X_IRQ5           0x06
42464777Snyan#define	ED_NW98X_IRQ6           0x08
42564777Snyan#define	ED_NW98X_IRQ12          0x0a
42664777Snyan#define	ED_NW98X_IRQ13          0x02
42764777Snyan
42864777Snyan/* NC5098 ASIC */
42964777Snyanstatic bus_addr_t ed98_asic_nc5098[] = {
43064777Snyan/*	DATA    ENADDR						RESET	*/
43164777Snyan	0x0000, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x4000,
43264777Snyan	     0,      0,      0,      0,      0,      0,      0,      0
43364777Snyan};
43464777Snyan
43564777Snyan/*
43664777Snyan *		Definitions for NextCom NC5098
43764777Snyan */
43864777Snyan#define	ED_NC5098_ENADDR	1	/* Station Address(1-6)		*/
43964777Snyan
44064777Snyan/*
44164777Snyan * Allocate a port resource with the given resource id.
44264777Snyan */
44364777Snyanstatic int
444141550Simped98_alloc_port(device_t dev, int rid)
44564777Snyan{
44664777Snyan	struct ed_softc *sc = device_get_softc(dev);
44764777Snyan	struct resource *res;
44864777Snyan	int error;
44964777Snyan	bus_addr_t *io_nic, *io_asic, adj;
45064777Snyan	static bus_addr_t io_res[ED_NOVELL_IO_PORTS + 1];
45164777Snyan	int i, n;
45264777Snyan	int offset, reset, data;
45364777Snyan
45464777Snyan	/* Set i/o table for resource manager */
45564777Snyan	io_nic = io_asic = ed98_ioaddr_generic;
45664777Snyan	offset = ED_NOVELL_ASIC_OFFSET;
45764777Snyan	reset = ED_NOVELL_RESET;
45864777Snyan	data  = ED_NOVELL_DATA;
45964777Snyan	n = ED_NOVELL_IO_PORTS;
46064777Snyan
46164777Snyan	switch (sc->type) {
46264777Snyan	case ED_TYPE98_LGY:
46364777Snyan		io_asic = ed98_ioaddr_egy98; /* XXX - Yes, we use egy98 */
46464777Snyan		offset = 0x0200;
46564777Snyan		reset = 8;
46664777Snyan		break;
46764777Snyan
46864777Snyan	case ED_TYPE98_EGY:
46964777Snyan		io_nic = io_asic = ed98_ioaddr_egy98;
47064777Snyan		offset = 0x0200;
47164777Snyan		reset = 8;
47264777Snyan		break;
47364777Snyan
47464777Snyan	case ED_TYPE98_ICM:
47564777Snyan		offset = 0x0100;
47664777Snyan		break;
47764777Snyan
47864777Snyan	case ED_TYPE98_BDN:
47964777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
48064777Snyan		offset = 0x0100;
48164777Snyan		reset = 0x0c;
48264777Snyan		break;
48364777Snyan
48464777Snyan	case ED_TYPE98_SIC:
48564777Snyan		io_nic = io_asic = ed98_ioaddr_sic98;
48664777Snyan		offset = 0x2000;
48764777Snyan		n = 16+1;
48864777Snyan		break;
48964777Snyan
49064777Snyan	case ED_TYPE98_108:
49164777Snyan		io_nic = io_asic = ed98_ioaddr_nec108;
49264777Snyan		offset = 0x0888;	/* XXX - overwritten after */
49364777Snyan		reset = 1;
49464777Snyan		n = 16;	/* XXX - does not set ASIC i/o here */
49564777Snyan		break;
49664777Snyan
49764777Snyan	case ED_TYPE98_LA98:
49864777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
49964777Snyan		offset = 0x0100;
50064777Snyan		break;
50164777Snyan
50264777Snyan	case ED_TYPE98_CNET98EL:
50364777Snyan		offset = 0x0400;
50464777Snyan		data = 0x0e;
50564777Snyan		break;
50664777Snyan
50764777Snyan	case ED_TYPE98_CNET98:
50864777Snyan		/* XXX - Yes, we use generic i/o here */
50964777Snyan		offset = 0x0400;
51064777Snyan		break;
51164777Snyan
51264777Snyan	case ED_TYPE98_NW98X:
51364777Snyan		io_nic = io_asic = ed98_ioaddr_nw98x;
51464777Snyan		offset = 0x1000;
51564777Snyan		break;
51664777Snyan
51764777Snyan	case ED_TYPE98_SB98:
51864777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
51964777Snyan		offset = 0x0400;
52064777Snyan		reset = 7;
52164777Snyan		break;
52264777Snyan
52364777Snyan	case ED_TYPE98_NC5098:
52464777Snyan		io_nic  = ed98_ioaddr_nw98x;
52564777Snyan		io_asic = ed98_asic_nc5098;
52664777Snyan		offset = 0x2000;
52764777Snyan		reset = 7;
52864777Snyan		n = 16+8;	/* XXX */
52964777Snyan		break;
53064777Snyan	}
53164777Snyan
53264777Snyan	bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
533141552Simp	for (i = ED_NOVELL_ASIC_OFFSET; i < ED_NOVELL_IO_PORTS; i++)
53464777Snyan		io_res[i] = io_asic[i - ED_NOVELL_ASIC_OFFSET] + offset;
53564777Snyan
536141552Simp	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, io_res, n,
537141552Simp	    RF_ACTIVE);
538141552Simp	if (!res)
53964777Snyan		return (ENOENT);
54064777Snyan
54164777Snyan	sc->port_rid = rid;
54264777Snyan	sc->port_res = res;
54364777Snyan	sc->port_used = n;
54464777Snyan
54564777Snyan	/* Re-map i/o table if needed */
54664777Snyan	switch (sc->type) {
54764777Snyan	case ED_TYPE98_LA98:
54864777Snyan	case ED_TYPE98_NW98X:
54964777Snyan		io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
55064777Snyan		n++;
55164777Snyan		break;
55264777Snyan
55364777Snyan	case ED_TYPE98_108:
55464777Snyan		adj = (rman_get_start(res) & 0xf000) / 2;
55564777Snyan		offset = (offset | adj) - rman_get_start(res);
55664777Snyan
557141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
55864777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
55964777Snyan		break;
56064777Snyan
56164777Snyan	case ED_TYPE98_CNET98:
56264777Snyan		io_nic = io_asic = ed98_ioaddr_cnet98;
56364777Snyan		offset = 1;
56464777Snyan
56564777Snyan		bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
566141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
56764777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
56864777Snyan		break;
56964777Snyan
57064777Snyan	case ED_TYPE98_NC5098:
57164777Snyan		n = ED_NOVELL_IO_PORTS;
57264777Snyan		break;
57364777Snyan	}
57464777Snyan
575141552Simp	if (reset != ED_NOVELL_RESET)
57664777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_RESET] =
57764777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + reset];
57864777Snyan	if (data  != ED_NOVELL_DATA) {
57964777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA] =
58064777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data];
58164777Snyan#if 0
58264777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA + 1] =
58364777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data + 1];
58464777Snyan#endif
58564777Snyan	}
58664777Snyan
58764777Snyan	error = isa_load_resourcev(res, io_res, n);
588141552Simp	if (error != 0)
58964777Snyan		return (ENOENT);
59064777Snyan#ifdef ED_DEBUG
59164777Snyan	device_printf(dev, "ed98_alloc_port: i/o ports = %d\n", n);
592141552Simp	for (i = 0; i < n; i++)
59364777Snyan		printf("%x,", io_res[i]);
59464777Snyan	printf("\n");
59564777Snyan#endif
59664777Snyan	return (0);
59764777Snyan}
59864777Snyan
59964777Snyanstatic int
60064777Snyaned98_alloc_memory(dev, rid)
60164777Snyan	device_t dev;
60264777Snyan	int rid;
60364777Snyan{
60464777Snyan	struct ed_softc *sc = device_get_softc(dev);
60564777Snyan	int error;
60664777Snyan	u_long conf_maddr, conf_msize;
60764777Snyan
608141552Simp	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &conf_maddr,
609141552Simp	    &conf_msize);
610141552Simp	if (error)
61164777Snyan		return (error);
61264777Snyan
613141552Simp	if ((conf_maddr == 0) || (conf_msize == 0))
61464777Snyan		return (ENXIO);
61564777Snyan
61664777Snyan	error = ed_alloc_memory(dev, rid, (int) conf_msize);
617141552Simp	if (error)
61864777Snyan		return (error);
61964777Snyan
620149558Simp	sc->mem_start = 0;
62164777Snyan	sc->mem_size  = conf_msize;
62264777Snyan
62364777Snyan	return (0);
62464777Snyan}
62564777Snyan
62664777Snyan/*
62764777Snyan * Generic probe routine for testing for the existance of a DS8390.
62864777Snyan *	Must be called after the NIC has just been reset. This routine
62964777Snyan *	works by looking at certain register values that are guaranteed
63064777Snyan *	to be initialized a certain way after power-up or reset. Seems
63164777Snyan *	not to currently work on the 83C690.
63264777Snyan *
63364777Snyan * Specifically:
63464777Snyan *
63564777Snyan *	Register			reset bits	set bits
63664777Snyan *	Command Register (CR)		TXP, STA	RD2, STP
63764777Snyan *	Interrupt Status (ISR)				RST
63864777Snyan *	Interrupt Mask (IMR)		All bits
63964777Snyan *	Data Control (DCR)				LAS
64064777Snyan *	Transmit Config. (TCR)		LB1, LB0
64164777Snyan *
64264777Snyan * XXX - We only check the CR register.
64364777Snyan *
64464777Snyan * Return 1 if 8390 was found, 0 if not.
64564777Snyan */
64664777Snyan
64764777Snyanstatic int
648141550Simped98_probe_generic8390(struct ed_softc *sc)
64964777Snyan{
65064777Snyan	u_char tmp = ed_nic_inb(sc, ED_P0_CR);
65164777Snyan#ifdef DIAGNOSTIC
65264777Snyan	printf("ed?: inb(ED_P0_CR)=%x\n", tmp);
65364777Snyan#endif
65464777Snyan	if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
655141552Simp	    (ED_CR_RD2 | ED_CR_STP))
65664777Snyan		return (0);
65764777Snyan
65864777Snyan	(void) ed_nic_inb(sc, ED_P0_ISR);
65964777Snyan
66064777Snyan	return (1);
66164777Snyan}
66264777Snyan
66364777Snyanstatic int
664141550Simped98_probe_Novell(device_t dev, int port_rid, int flags)
66564777Snyan{
66664777Snyan	struct ed_softc *sc = device_get_softc(dev);
66764777Snyan	int error;
66864777Snyan	int n;
66964777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
67064777Snyan
67164777Snyan#ifdef ED_DEBUG
67264777Snyan	device_printf(dev, "ed98_probe_Novell: start\n");
67364777Snyan#endif
67464777Snyan	error = ed98_alloc_port(dev, port_rid);
675141552Simp	if (error)
67664777Snyan		return (error);
67764777Snyan
67864777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
67964777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
68064777Snyan
68164777Snyan	/* Reset the board */
68264777Snyan#ifdef ED_DEBUG
68364777Snyan	device_printf(dev, "ed98_probe_Novell: reset\n");
68464777Snyan#endif
68564777Snyan	switch (sc->type) {
68664777Snyan#if 1	/* XXX - I'm not sure this is really necessary... */
68764777Snyan	case ED_TYPE98_BDN:
68864777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
68964777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, (tmp & 0xf0) | 0x08);
69064777Snyan		ed_nic_outb(sc, 0x04, tmp);
69164777Snyan		(void) ed_asic_inb(sc, 0x08);
69264777Snyan		ed_asic_outb(sc, 0x08, tmp);
69364777Snyan		ed_asic_outb(sc, 0x08, tmp & 0x7f);
69464777Snyan		break;
69564777Snyan#endif
69664777Snyan	case ED_TYPE98_NC5098:
69764777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x00);
69864777Snyan		DELAY(5000);
69964777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x01);
70064777Snyan		break;
70164777Snyan
70264777Snyan	default:
70364777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
70464777Snyan
70564777Snyan	/*
70664777Snyan	 * I don't know if this is necessary; probably cruft leftover from
70764777Snyan	 * Clarkson packet driver code. Doesn't do a thing on the boards I've
708108533Sschweikh	 * tested. -DG [note that an outb(0x84, 0) seems to work here, and is
70964777Snyan	 * non-invasive...but some boards don't seem to reset and I don't have
71064777Snyan	 * complete documentation on what the 'right' thing to do is...so we
71164777Snyan	 * do the invasive thing for now. Yuck.]
71264777Snyan	 */
71364777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
71464777Snyan		break;
71564777Snyan	}
71664777Snyan	DELAY(5000);
71764777Snyan
71864777Snyan	/*
71964777Snyan	 * This is needed because some NE clones apparently don't reset the
72064777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
72164777Snyan	 * - this makes the probe invasive! ...Done against my better
72264777Snyan	 * judgement. -DLG
72364777Snyan	 */
72464777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
72564777Snyan	DELAY(5000);
72664777Snyan
72764777Snyan	/* Make sure that we really have an 8390 based board */
728141552Simp	if (!ed98_probe_generic8390(sc))
72964777Snyan		return (ENXIO);
73064777Snyan
73164777Snyan	/* Test memory via PIO */
73264777Snyan#ifdef ED_DEBUG
73364777Snyan	device_printf(dev, "ed98_probe_Novell: test memory\n");
73464777Snyan#endif
73564777Snyan	sc->cr_proto = ED_CR_RD2;
736141552Simp	if (!ed_pio_testmem(sc,  8192, 0, flags) &&
737141552Simp	    !ed_pio_testmem(sc, 16384, 1, flags))
73864777Snyan		return (ENXIO);
73964777Snyan
74064777Snyan	/* Setup the board type */
74164777Snyan#ifdef ED_DEBUG
74264777Snyan	device_printf(dev, "ed98_probe_Novell: board type\n");
74364777Snyan#endif
74464777Snyan	switch (sc->type) {
74564777Snyan	case ED_TYPE98_BDN:
74664777Snyan		sc->type_str = "LD-BDN";
74764777Snyan		break;
74864777Snyan	case ED_TYPE98_EGY:
74964777Snyan		sc->type_str = "EGY-98";
75064777Snyan		break;
75164777Snyan	case ED_TYPE98_LGY:
75264777Snyan		sc->type_str = "LGY-98";
75364777Snyan		break;
75464777Snyan	case ED_TYPE98_ICM:
75564777Snyan		sc->type_str = "ICM";
75664777Snyan		break;
75764777Snyan	case ED_TYPE98_108:
75864777Snyan		sc->type_str = "PC-9801-108";
75964777Snyan		break;
76064777Snyan	case ED_TYPE98_LA98:
76164777Snyan		sc->type_str = "LA-98";
76264777Snyan		break;
76364777Snyan	case ED_TYPE98_NW98X:
76464777Snyan		sc->type_str = "NW98X";
76564777Snyan		break;
76664777Snyan	case ED_TYPE98_NC5098:
76764777Snyan		sc->type_str = "NC5098";
76864777Snyan		break;
76964777Snyan	default:
77064777Snyan		sc->type_str = NULL;
77164777Snyan		break;
77264777Snyan	}
77364777Snyan
77464777Snyan	/* Get station address */
77564777Snyan	switch (sc->type) {
77664777Snyan	case ED_TYPE98_NC5098:
777141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
778147256Sbrooks			sc->enaddr[n] = ed_asic_inb(sc, ED_NC5098_ENADDR + n);
77964777Snyan		break;
78064777Snyan
78164777Snyan	default:
78264777Snyan		ed_pio_readmem(sc, 0, romdata, sizeof(romdata));
783141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
784147256Sbrooks			sc->enaddr[n] = romdata[n * (sc->isa16bit + 1)];
78564777Snyan		break;
78664777Snyan	}
78764777Snyan
78864777Snyan	/* clear any pending interrupts that might have occurred above */
78964777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
79064777Snyan
791154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
79264777Snyan	return (0);
79364777Snyan}
79464777Snyan
79564777Snyan/*
79664777Snyan * Probe and vendor-specific initialization routine for SIC-98 boards
79764777Snyan */
79864777Snyanstatic int
799141550Simped_probe_SIC98(device_t dev, int port_rid, int flags)
80064777Snyan{
80164777Snyan	struct ed_softc *sc = device_get_softc(dev);
80264777Snyan	int error;
80364777Snyan	int i;
80464777Snyan	u_char sum;
80564777Snyan
80664777Snyan	/*
80764777Snyan	 * Setup card RAM and I/O address
80864777Snyan	 * Kernel Virtual to segment C0000-DFFFF????
80964777Snyan	 */
81064777Snyan	error = ed98_alloc_port(dev, port_rid);
811141552Simp	if (error)
81264777Snyan		return (error);
81364777Snyan
814121118Sshiba	sc->asic_offset = ED_SIC_ASIC_OFFSET;
815121118Sshiba	sc->nic_offset  = ED_SIC_NIC_OFFSET;
81664777Snyan
81764777Snyan	error = ed98_alloc_memory(dev, 0);
818141552Simp	if (error)
81964777Snyan		return (error);
82064777Snyan
82164777Snyan	/* Reset card to force it into a known state. */
82264777Snyan	ed_asic_outb(sc, 0, 0x00);
82364777Snyan	DELAY(100);
82464777Snyan	if (ED_TYPE98SUB(flags) == 0) {
82564777Snyan		/* SIC-98/SIU-98 */
82664777Snyan		ed_asic_outb(sc, 0, 0x94);
82764777Snyan		DELAY(100);
82864777Snyan		ed_asic_outb(sc, 0, 0x94);
82964777Snyan	} else {
83064777Snyan		/* SIU-98-D */
83164777Snyan		ed_asic_outb(sc, 0, 0x80);
83264777Snyan		DELAY(100);
83364777Snyan		ed_asic_outb(sc, 0, 0x94);
83464777Snyan		DELAY(100);
83564777Snyan		ed_asic_outb(sc, 0, 0x9e);
83664777Snyan	}
83764777Snyan	DELAY(100);
83864777Snyan
83964777Snyan	/*
84064777Snyan	 * Here we check the card ROM, if the checksum passes, and the
84164777Snyan	 * type code and ethernet address check out, then we know we have
84264777Snyan	 * an SIC card.
84364777Snyan	 */
844149558Simp	sum = bus_space_read_1(sc->mem_bst, sc->mem_bsh, 6 * 2);
845141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
846149558Simp		sum ^= (sc->enaddr[i] =
847149558Simp		    bus_space_read_1(sc->mem_bst, sc->mem_bsh, i * 2));
84864777Snyan#ifdef ED_DEBUG
84964777Snyan	device_printf(dev, "ed_probe_sic98: got address %6D\n",
850147256Sbrooks		      sc->enaddr, ":");
85164777Snyan#endif
852141552Simp	if (sum != 0)
85364777Snyan		return (ENXIO);
854147256Sbrooks	if ((sc->enaddr[0] | sc->enaddr[1] | sc->enaddr[2]) == 0)
85564777Snyan		return (ENXIO);
85664777Snyan
857121118Sshiba	sc->vendor   = ED_VENDOR_SIC;
85864777Snyan	sc->type_str = "SIC98";
85964777Snyan	sc->isa16bit = 1;
86064777Snyan	sc->cr_proto = 0;
86164777Snyan
86264777Snyan	/*
86364777Snyan	 * SIC RAM page 0x0000-0x3fff(or 0x7fff)
86464777Snyan	 */
865141552Simp	if (ED_TYPE98SUB(flags) == 0)
86664777Snyan		ed_asic_outb(sc, 0, 0x90);
867141552Simp	else
86864777Snyan		ed_asic_outb(sc, 0, 0x8e);
86964777Snyan	DELAY(100);
87064777Snyan
871141550Simp	error = ed_clear_memory(dev);
872141550Simp	if (error)
873141550Simp		return (error);
87464777Snyan
87564777Snyan	sc->mem_shared = 1;
87664777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
87764777Snyan
87864777Snyan	/*
87964777Snyan	 * allocate one xmit buffer if < 16k, two buffers otherwise
88064777Snyan	 */
881141552Simp	if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
88264777Snyan		sc->txb_cnt = 1;
883141552Simp	else
88464777Snyan		sc->txb_cnt = 2;
88564777Snyan	sc->tx_page_start = 0;
88664777Snyan
88764777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt;
88864777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
88964777Snyan
89064777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
89164777Snyan
892154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
89364777Snyan	return (0);
89464777Snyan}
89564777Snyan
89664777Snyan/*
89764777Snyan * Contec C-NET(98) series support routines
89864777Snyan */
89964777Snyanstatic void
900141550Simped_reset_CNET98(struct ed_softc *sc, int flags)
90164777Snyan{
902118557Sbde	u_int init_addr = ED_CNET98_INIT;
90364777Snyan	u_char tmp;
90464777Snyan
90564777Snyan	/* Choose initial register address */
90664777Snyan	if (ED_TYPE98SUB(flags) != 0) {
90764777Snyan		init_addr = ED_CNET98_INIT2;
90864777Snyan	}
90964777Snyan#ifdef ED_DEBUG
91064777Snyan	printf("ed?: initial register=%x\n", init_addr);
91164777Snyan#endif
91264777Snyan	/*
91364777Snyan	 * Reset the board to force it into a known state.
91464777Snyan	 */
91564777Snyan	outb(init_addr, 0x00);	/* request */
91664777Snyan	DELAY(5000);
91764777Snyan	outb(init_addr, 0x01);	/* cancel */
91864777Snyan	DELAY(5000);
91964777Snyan
92064777Snyan	/*
92164777Snyan	 * Set I/O address(A15-12) and cpu type
92264777Snyan	 *
92364777Snyan	 *   AAAAIXXC(8bit)
92464777Snyan	 *   AAAA: A15-A12,  I: I/O enable, XX: reserved, C: CPU type
92564777Snyan	 *
92664777Snyan	 * CPU type is 1:80286 or higher, 0:not.
92764777Snyan	 * But FreeBSD runs under i386 or higher, thus it must be 1.
92864777Snyan	 */
92964777Snyan	tmp = (rman_get_start(sc->port_res) & 0xf000) >> 8;
93064777Snyan	tmp |= (0x08 | 0x01);
93164777Snyan#ifdef ED_DEBUG
93264777Snyan	printf("ed?: outb(%x, %x)\n", init_addr + 2, tmp);
93364777Snyan#endif
93464777Snyan	outb(init_addr + 2, tmp);
93564777Snyan	DELAY(5000);
93664777Snyan
93764777Snyan	/*
93864777Snyan	 * This is needed because some NE clones apparently don't reset the
93964777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
94064777Snyan	 * - this makes the probe invasive! ...Done against my better
94164777Snyan	 * judgement. -DLG
94264777Snyan	 */
94364777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
94464777Snyan	DELAY(5000);
94564777Snyan}
94664777Snyan
94764777Snyanstatic void
948141550Simped_winsel_CNET98(struct ed_softc *sc, u_short bank)
94964777Snyan{
950141550Simp	u_char mem = (rman_get_start(sc->mem_res) >> 12) & 0xff;
95164777Snyan
95264777Snyan	/*
95364777Snyan	 * Disable window memory
95464777Snyan	 *    bit7 is 0:disable
95564777Snyan	 */
95664777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem & 0x7f);
95764777Snyan	DELAY(10);
95864777Snyan
95964777Snyan	/*
96064777Snyan	 * Select window address
96164777Snyan	 *    FreeBSD address 0xf00xxxxx
96264777Snyan	 */
96364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0L, bank & 0xff);
96464777Snyan	DELAY(10);
96564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0H, (bank >> 8) & 0xff);
96664777Snyan	DELAY(10);
96764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1L, 0x00);
96864777Snyan	DELAY(10);
96964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1H, 0x41);
97064777Snyan	DELAY(10);
97164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2L, 0x00);
97264777Snyan	DELAY(10);
97364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2H, 0x42);
97464777Snyan	DELAY(10);
97564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3L, 0x00);
97664777Snyan	DELAY(10);
97764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3H, 0x43);
97864777Snyan	DELAY(10);
97964777Snyan
98064777Snyan	/*
98164777Snyan	 * Enable window memory(16Kbyte)
98264777Snyan	 *    bit7 is 1:enable
98364777Snyan	 */
98464777Snyan#ifdef ED_DEBUG
98564777Snyan	printf("ed?: window start address=%x\n", mem);
98664777Snyan#endif
98764777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem);
98864777Snyan	DELAY(10);
98964777Snyan}
99064777Snyan
99164777Snyan/*
99264777Snyan * Probe and vendor-specific initialization routine for C-NET(98) boards
99364777Snyan */
99464777Snyanstatic int
995141550Simped_probe_CNET98(device_t dev, int port_rid, int flags)
99664777Snyan{
99764777Snyan	struct ed_softc *sc = device_get_softc(dev);
99864777Snyan	int error;
99964777Snyan	u_char tmp;
100064777Snyan	u_long conf_irq, junk;
100164777Snyan#ifdef DIAGNOSTIC
100264777Snyan	u_char tmp_s;
100364777Snyan#endif
100464777Snyan
100564777Snyan	error = ed98_alloc_port(dev, port_rid);
1006141552Simp	if (error)
100764777Snyan		return (error);
100864777Snyan
100964777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
101064777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
101164777Snyan
101264777Snyan	error = ed98_alloc_memory(dev, 0);
1013141552Simp	if (error)
101464777Snyan		return (error);
101564777Snyan
101664777Snyan	/* Check I/O address. 0x[a-f]3d0 are allowed. */
101764777Snyan	if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
101864777Snyan	||  ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
101964777Snyan#ifdef DIAGNOSTIC
1020111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
102164777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
102264777Snyan			"0x[a-f]3d0", "CNET98");
102364777Snyan#endif
102464777Snyan		return (ENXIO);
102564777Snyan	}
102664777Snyan
102764777Snyan#ifdef DIAGNOSTIC
102864777Snyan	/* Check window area address */
1029141550Simp	tmp_s = rman_get_start(sc->mem_res) >> 12;
103064777Snyan	if (tmp_s < 0x80) {
1031141550Simp		device_printf(dev, "Please change window address(0x%lx)\n",
1032141550Simp		    rman_get_start(sc->mem_res));
103364777Snyan		return (ENXIO);
103464777Snyan	}
103564777Snyan
103664777Snyan	tmp_s &= 0x0f;
103764777Snyan	tmp    = rman_get_start(sc->port_res) >> 12;
103864777Snyan	if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
1039111427Snyan		device_printf(dev, "Please change iobase address(0x%lx) "
1040141550Simp		    "or window address(0x%lx)\n",
1041141550Simp		    rman_get_start(sc->port_res),
1042141550Simp		    rman_get_start(sc->mem_res));
104364777Snyan		return (ENXIO);
104464777Snyan	}
104564777Snyan#endif
104664777Snyan	/* Reset the board */
104764777Snyan	ed_reset_CNET98(sc, flags);
104864777Snyan
104964777Snyan	/*
105064777Snyan	 * This is needed because some NE clones apparently don't reset the
105164777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
105264777Snyan	 * - this makes the probe invasive! ...Done against my better
105364777Snyan	 * judgement. -DLG
105464777Snyan	 */
105564777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
105664777Snyan	DELAY(5000);
105764777Snyan
105864777Snyan	/* Make sure that we really have an 8390 based board */
1059141552Simp	if (!ed98_probe_generic8390(sc))
106064777Snyan		return (ENXIO);
106164777Snyan
106264777Snyan	/*
106364777Snyan	 *  Set window ethernet address area
106464777Snyan	 *    board memory base 0x480000  data 256byte
106564777Snyan	 */
106664777Snyan	ed_winsel_CNET98(sc, 0x4800);
106764777Snyan
106864777Snyan	/*
106964777Snyan	 * Get station address from on-board ROM
107064777Snyan	 */
1071149558Simp	bus_space_read_region_1(sc->mem_bst, sc->mem_bsh, sc->mem_start,
1072149558Simp	    sc->enaddr, ETHER_ADDR_LEN);
107364777Snyan
107464777Snyan	sc->vendor    = ED_VENDOR_MISC;
107564777Snyan	sc->type_str  = "CNET98";
107664777Snyan	sc->isa16bit  = 0;
107764777Snyan	sc->cr_proto  = ED_CR_RD2;
107864777Snyan
107964777Snyan	/*
108064777Snyan	 * Set window buffer memory area
108164777Snyan	 *    board memory base 0x400000  data 16kbyte
108264777Snyan	 */
108364777Snyan	ed_winsel_CNET98(sc, 0x4000);
108464777Snyan
1085141550Simp	error = ed_clear_memory(dev);
1086141550Simp	if (error)
1087141550Simp		return (error);
108864777Snyan
108964777Snyan	sc->mem_shared = 1;
109064777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
109164777Snyan
109264777Snyan	sc->txb_cnt = 1;	/* XXX */
109364777Snyan	sc->tx_page_start = 0;
109464777Snyan
109564777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
109664777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
109764777Snyan
109864777Snyan	sc->mem_ring = sc->mem_start + ED_PAGE_SIZE * ED_TXBUF_SIZE;
109964777Snyan
110064777Snyan	/*
110164777Snyan	 *   Set interrupt level
110264777Snyan	 */
1103141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
110464777Snyan	if (error)
110564777Snyan		return (error);
110664777Snyan
110764777Snyan	switch (conf_irq) {
110864777Snyan	case 3:
110964777Snyan		tmp = ED_CNET98_INT_IRQ3;
111064777Snyan		break;
111164777Snyan	case 5:
111264777Snyan		tmp = ED_CNET98_INT_IRQ5;
111364777Snyan		break;
111464777Snyan	case 6:
111564777Snyan		tmp = ED_CNET98_INT_IRQ6;
111664777Snyan		break;
111764777Snyan	case 9:
111864777Snyan		tmp = ED_CNET98_INT_IRQ9;
111964777Snyan		break;
112064777Snyan	case 12:
112164777Snyan		tmp = ED_CNET98_INT_IRQ12;
112264777Snyan		break;
112364777Snyan	case 13:
112464777Snyan		tmp = ED_CNET98_INT_IRQ13;
112564777Snyan		break;
112664777Snyan	default:
112764777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
112864777Snyan			"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
112964777Snyan		return (ENXIO);
113064777Snyan	}
113164777Snyan	ed_asic_outb(sc, ED_CNET98_INT_LEV, tmp);
113264777Snyan	DELAY(1000);
113364777Snyan	/*
113464777Snyan	 *   Set interrupt mask.
113564777Snyan	 *     bit7:1 all interrupt mask
113664777Snyan	 *     bit1:1 timer interrupt mask
113764777Snyan	 *     bit0:0 NS controler interrupt enable
113864777Snyan	 */
113964777Snyan	ed_asic_outb(sc, ED_CNET98_INT_MASK, 0x7e);
114064777Snyan	DELAY(1000);
114164777Snyan
1142154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
114364777Snyan	return (0);
114464777Snyan}
114564777Snyan
114664777Snyan/*
114764777Snyan * Probe and vendor-specific initialization routine for C-NET(98)E/L boards
114864777Snyan */
114964777Snyanstatic int
1150141550Simped_probe_CNET98EL(device_t dev, int port_rid, int flags)
115164777Snyan{
115264777Snyan	struct ed_softc *sc = device_get_softc(dev);
115364777Snyan	int error;
115464777Snyan	int i;
115564777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
115664777Snyan	u_long conf_irq, junk;
115764777Snyan
115864777Snyan	error = ed98_alloc_port(dev, port_rid);
1159141552Simp	if (error)
116064777Snyan		return (error);
116164777Snyan
116264777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
116364777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
116464777Snyan
116564777Snyan	/* Check I/O address. 0x[0-f]3d0 are allowed. */
116664777Snyan	if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
116764777Snyan#ifdef DIAGNOSTIC
1168111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
116964777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
117064777Snyan			"0x?3d0", "CNET98E/L");
117164777Snyan#endif
117264777Snyan		return (ENXIO);
117364777Snyan	}
117464777Snyan
117564777Snyan	/* Reset the board */
117664777Snyan	ed_reset_CNET98(sc, flags);
117764777Snyan
117864777Snyan	/*
117964777Snyan	 * This is needed because some NE clones apparently don't reset the
118064777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
118164777Snyan	 * - this makes the probe invasive! ...Done against my better
118264777Snyan	 * judgement. -DLG
118364777Snyan	 */
118464777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
118564777Snyan	DELAY(5000);
118664777Snyan
118764777Snyan	/* Make sure that we really have an 8390 based board */
1188141552Simp	if (!ed98_probe_generic8390(sc))
118964777Snyan		return (ENXIO);
119064777Snyan
119164777Snyan	/* Test memory via PIO */
119264777Snyan	sc->cr_proto = ED_CR_RD2;
1193141552Simp	if (!ed_pio_testmem(sc, ED_CNET98EL_PAGE_OFFSET, 1, flags))
119464777Snyan		return (ENXIO);
119564777Snyan
119664777Snyan	/* This looks like a C-NET(98)E/L board. */
119764777Snyan	sc->type_str = "CNET98E/L";
119864777Snyan
119964777Snyan	/*
120064777Snyan	 * Set IRQ. C-NET(98)E/L only allows a choice of irq 3,5,6.
120164777Snyan	 */
1202141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1203141552Simp	if (error)
120464777Snyan		return (error);
120564777Snyan
120664777Snyan	switch (conf_irq) {
120764777Snyan	case 3:
120864777Snyan		tmp = ED_CNET98EL_ICR_IRQ3;
120964777Snyan		break;
121064777Snyan	case 5:
121164777Snyan		tmp = ED_CNET98EL_ICR_IRQ5;
121264777Snyan		break;
121364777Snyan	case 6:
121464777Snyan		tmp = ED_CNET98EL_ICR_IRQ6;
121564777Snyan		break;
121664777Snyan#if 0
121764777Snyan	case 12:
121864777Snyan		tmp = ED_CNET98EL_ICR_IRQ12;
121964777Snyan		break;
122064777Snyan#endif
122164777Snyan	default:
122264777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
122364777Snyan			"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
122464777Snyan		return (ENXIO);
122564777Snyan	}
122664777Snyan	ed_asic_outb(sc, ED_CNET98EL_ICR, tmp);
122764777Snyan	ed_asic_outb(sc, ED_CNET98EL_IMR, 0x7e);
122864777Snyan
122964777Snyan	/* Get station address from on-board ROM */
123064777Snyan	ed_pio_readmem(sc, 16384, romdata, sizeof(romdata));
1231141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
1232147256Sbrooks		sc->enaddr[i] = romdata[i * 2];
123364777Snyan
123464777Snyan	/* clear any pending interrupts that might have occurred above */
123564777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
123664777Snyan
1237154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
123864777Snyan	return (0);
123964777Snyan}
124064777Snyan
124164777Snyan/*
124264777Snyan * Probe and vendor-specific initialization routine for PC-9801-77 boards
124364777Snyan */
124464777Snyanstatic int
1245141550Simped_probe_NEC77(device_t dev, int port_rid, int flags)
124664777Snyan{
124764777Snyan	struct ed_softc *sc = device_get_softc(dev);
124864777Snyan	int error;
124964777Snyan	u_char tmp;
125064777Snyan	u_long conf_irq, junk;
125164777Snyan
125264777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1253141552Simp	if (error)
125464777Snyan		return (error);
125564777Snyan
125664777Snyan	/* LA/T-98 does not need IRQ setting. */
1257141552Simp	if (ED_TYPE98SUB(flags) == 0)
125864777Snyan		return (0);
125964777Snyan
126064777Snyan	/*
126164777Snyan	 * Set IRQ. PC-9801-77 only allows a choice of irq 3,5,6,12,13.
126264777Snyan	 */
1263141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1264141552Simp	if (error)
126564777Snyan		return (error);
126664777Snyan
126764777Snyan	switch (conf_irq) {
126864777Snyan	case 3:
126964777Snyan		tmp = ED_NEC77_IRQ3;
127064777Snyan		break;
127164777Snyan	case 5:
127264777Snyan		tmp = ED_NEC77_IRQ5;
127364777Snyan		break;
127464777Snyan	case 6:
127564777Snyan		tmp = ED_NEC77_IRQ6;
127664777Snyan		break;
127764777Snyan	case 12:
127864777Snyan		tmp = ED_NEC77_IRQ12;
127964777Snyan		break;
128064777Snyan	case 13:
128164777Snyan		tmp = ED_NEC77_IRQ13;
128264777Snyan		break;
128364777Snyan	default:
128464777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
128564777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
128664777Snyan		return (ENXIO);
128764777Snyan	}
128864777Snyan	ed_asic_outb(sc, ED_NEC77_IRQ, tmp);
128964777Snyan
129064777Snyan	return (0);
129164777Snyan}
129264777Snyan
129364777Snyan/*
129464777Snyan * Probe and vendor-specific initialization routine for EC/EP-98X boards
129564777Snyan */
129664777Snyanstatic int
1297141550Simped_probe_NW98X(device_t dev, int port_rid, int flags)
129864777Snyan{
129964777Snyan	struct ed_softc *sc = device_get_softc(dev);
130064777Snyan	int error;
130164777Snyan	u_char tmp;
130264777Snyan	u_long conf_irq, junk;
130364777Snyan
130464777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1305141552Simp	if (error)
130664777Snyan		return (error);
130764777Snyan
130864777Snyan	/* Networld 98X3 does not need IRQ setting. */
1309141552Simp	if (ED_TYPE98SUB(flags) == 0)
131064777Snyan		return (0);
131164777Snyan
131264777Snyan	/*
131364777Snyan	 * Set IRQ. EC/EP-98X only allows a choice of irq 3,5,6,12,13.
131464777Snyan	 */
1315141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1316141552Simp	if (error)
131764777Snyan		return (error);
131864777Snyan
131964777Snyan	switch (conf_irq) {
132064777Snyan	case 3:
132164777Snyan		tmp = ED_NW98X_IRQ3;
132264777Snyan		break;
132364777Snyan	case 5:
132464777Snyan		tmp = ED_NW98X_IRQ5;
132564777Snyan		break;
132664777Snyan	case 6:
132764777Snyan		tmp = ED_NW98X_IRQ6;
132864777Snyan		break;
132964777Snyan	case 12:
133064777Snyan		tmp = ED_NW98X_IRQ12;
133164777Snyan		break;
133264777Snyan	case 13:
133364777Snyan		tmp = ED_NW98X_IRQ13;
133464777Snyan		break;
133564777Snyan	default:
133664777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
133764777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
133864777Snyan		return (ENXIO);
133964777Snyan	}
134064777Snyan	ed_asic_outb(sc, ED_NW98X_IRQ, tmp);
134164777Snyan
134264777Snyan	return (0);
134364777Snyan}
134464777Snyan
134564777Snyan/*
134664777Snyan * Read SB-9801 station address from Serial Two-Wire EEPROM
134764777Snyan */
134864777Snyanstatic void
1349141550Simped_get_SB98(struct ed_softc *sc)
135064777Snyan{
135164777Snyan	int i, j;
135264777Snyan	u_char mask, val;
135364777Snyan
135464777Snyan        /* enable EEPROM acceess */
135564777Snyan        ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_ENABLE);
135664777Snyan
135764777Snyan	/* output start command */
135864777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
135964777Snyan	DELAY(ED_SB98_EEP_DELAY);
136064777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
136164777Snyan	DELAY(ED_SB98_EEP_DELAY);
136264777Snyan
136364777Snyan       	/* output address (7bit) */
136464777Snyan	for (mask = 0x40; mask != 0; mask >>= 1) {
136564777Snyan		val = 0;
136664777Snyan		if (ED_SB98_ADDRESS & mask)
136764777Snyan			val = ED_SB98_EEP_SDA;
136864777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val);
136964777Snyan		DELAY(ED_SB98_EEP_DELAY);
137064777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val | ED_SB98_EEP_SCL);
137164777Snyan		DELAY(ED_SB98_EEP_DELAY);
137264777Snyan	}
137364777Snyan
137464777Snyan	/* output READ command */
137564777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ);
137664777Snyan	DELAY(ED_SB98_EEP_DELAY);
137764777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ | ED_SB98_EEP_SCL);
137864777Snyan	DELAY(ED_SB98_EEP_DELAY);
137964777Snyan
138064777Snyan	/* read station address */
138164777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
138264777Snyan		/* output ACK */
138364777Snyan		ed_asic_outb(sc, ED_SB98_EEP, 0);
138464777Snyan		DELAY(ED_SB98_EEP_DELAY);
138564777Snyan		ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
138664777Snyan		DELAY(ED_SB98_EEP_DELAY);
138764777Snyan
138864777Snyan		val = 0;
138964777Snyan		for (j = 0; j < 8; j++) {
139064777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
139164777Snyan			DELAY(ED_SB98_EEP_DELAY);
139264777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
139364777Snyan			DELAY(ED_SB98_EEP_DELAY);
139464777Snyan			val <<= 1;
139564777Snyan			val |= (ed_asic_inb(sc, ED_SB98_EEP) & ED_SB98_EEP_SDA);
139664777Snyan			DELAY(ED_SB98_EEP_DELAY);
139764777Snyan	  	}
1398147256Sbrooks		sc->enaddr[i] = val;
139964777Snyan	}
140064777Snyan
140164777Snyan	/* output Last ACK */
140264777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
140364777Snyan        DELAY(ED_SB98_EEP_DELAY);
140464777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
140564777Snyan        DELAY(ED_SB98_EEP_DELAY);
140664777Snyan
140764777Snyan	/* output stop command */
140864777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
140964777Snyan	DELAY(ED_SB98_EEP_DELAY);
141064777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
141164777Snyan	DELAY(ED_SB98_EEP_DELAY);
141264777Snyan
141364777Snyan	/* disable EEPROM access */
141464777Snyan	ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_DISABLE);
141564777Snyan}
141664777Snyan
141764777Snyan/*
141864777Snyan * Probe and vendor-specific initialization routine for SB-9801 boards
141964777Snyan */
142064777Snyanstatic int
1421141550Simped_probe_SB98(device_t dev, int port_rid, int flags)
142264777Snyan{
142364777Snyan	struct ed_softc *sc = device_get_softc(dev);
142464777Snyan	int error;
142564777Snyan	u_char tmp;
142664777Snyan	u_long conf_irq, junk;
142764777Snyan
142864777Snyan	error = ed98_alloc_port(dev, port_rid);
1429141552Simp	if (error)
143064777Snyan		return (error);
143164777Snyan
143264777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
143364777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
143464777Snyan
143564777Snyan	/* Check I/O address. 00d[02468ace] are allowed. */
143664777Snyan	if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
143764777Snyan#ifdef DIAGNOSTIC
1438111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
1439141552Simp		    "must be %s for %s\n", rman_get_start(sc->port_res),
1440141552Simp		    "0xd?", "SB9801");
144164777Snyan#endif
144264777Snyan		return (ENXIO);
144364777Snyan	}
144464777Snyan
144564777Snyan	/* Write I/O port address and read 4 times */
144664777Snyan	outb(ED_SB98_IO_INHIBIT, rman_get_start(sc->port_res) & 0xff);
144764777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144864777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
144964777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145064777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145164777Snyan
145264777Snyan	/*
145364777Snyan	 * Check IRQ. Soliton SB-9801 only allows a choice of
145464777Snyan	 * irq 3,5,6,12
145564777Snyan	 */
1456141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1457141552Simp	if (error)
145864777Snyan		return (error);
145964777Snyan
146064777Snyan	switch (conf_irq) {
146164777Snyan	case 3:
146264777Snyan		tmp = ED_SB98_CFG_IRQ3;
146364777Snyan		break;
146464777Snyan	case 5:
146564777Snyan		tmp = ED_SB98_CFG_IRQ5;
146664777Snyan		break;
146764777Snyan	case 6:
146864777Snyan		tmp = ED_SB98_CFG_IRQ6;
146964777Snyan		break;
147064777Snyan	case 12:
147164777Snyan		tmp = ED_SB98_CFG_IRQ12;
147264777Snyan		break;
147364777Snyan	default:
147464777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
147564777Snyan			"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
147664777Snyan		return (ENXIO);
147764777Snyan	}
147864777Snyan
1479141552Simp	if (flags & ED_FLAGS_DISABLE_TRANCEIVER)
148064777Snyan		tmp |= ED_SB98_CFG_ALTPORT;
148164777Snyan	ed_asic_outb(sc, ED_SB98_CFG, ED_SB98_CFG_ENABLE | tmp);
148264777Snyan	ed_asic_outb(sc, ED_SB98_POLARITY, 0x01);
148364777Snyan
148464777Snyan	/* Reset the board. */
148564777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x7a);
148664777Snyan	DELAY(300);
148764777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x79);
148864777Snyan	DELAY(300);
148964777Snyan
149064777Snyan	/*
149164777Snyan	 * This is needed because some NE clones apparently don't reset the
149264777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
149364777Snyan	 * - this makes the probe invasive! ...Done against my better
149464777Snyan	 * judgement. -DLG
149564777Snyan	 */
149664777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
149764777Snyan	DELAY(5000);
149864777Snyan
149964777Snyan	/* Make sure that we really have an 8390 based board */
1500141552Simp	if (!ed98_probe_generic8390(sc))
150164777Snyan		return (ENXIO);
150264777Snyan
150364777Snyan	/* Test memory via PIO */
150464777Snyan	sc->cr_proto = ED_CR_RD2;
1505154924Simp	if (!ed_pio_testmem(sc, 16384, 1, flags))
150664777Snyan		return (ENXIO);
150764777Snyan
150864777Snyan	/* This looks like an SB9801 board. */
150964777Snyan	sc->type_str = "SB9801";
151064777Snyan
151164777Snyan	/* Get station address */
151264777Snyan	ed_get_SB98(sc);
151364777Snyan
151464777Snyan	/* clear any pending interrupts that might have occurred above */
151564777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
151664777Snyan
1517154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
151864777Snyan	return (0);
151964777Snyan}
152064777Snyan
152164777Snyan/*
152264777Snyan * Test the ability to read and write to the NIC memory.
152364777Snyan */
152464777Snyanstatic int
1525141550Simped_pio_testmem(struct ed_softc *sc, int page_offset, int isa16bit, int flags)
152664777Snyan{
152764777Snyan	u_long memsize;
152864777Snyan	static char test_pattern[32] = "THIS is A memory TEST pattern";
152964777Snyan	char test_buffer[32];
153064777Snyan#ifdef DIAGNOSTIC
153164777Snyan	int page_end;
153264777Snyan#endif
153364777Snyan
153464777Snyan	sc->vendor = ED_VENDOR_NOVELL;
153564777Snyan	sc->mem_shared = 0;
153664777Snyan	sc->isa16bit = isa16bit;
153764777Snyan
153864777Snyan	/* 8k of memory plus an additional 8k if 16bit */
153964777Snyan	memsize = (isa16bit ? 16384 : 8192);
154064777Snyan
154164777Snyan	/*
154264777Snyan	 * This prevents packets from being stored in the NIC memory when the
154364777Snyan	 * readmem routine turns on the start bit in the CR.
154464777Snyan	 */
154564777Snyan	ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON);
154664777Snyan
154764777Snyan	/* Initialize DCR for byte/word operations */
1548141550Simp	if (isa16bit)
154964777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
1550141550Simp	else
155164777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
155264777Snyan	ed_nic_outb(sc, ED_P0_PSTART, page_offset / ED_PAGE_SIZE);
155364777Snyan	ed_nic_outb(sc, ED_P0_PSTOP, (page_offset + memsize) / ED_PAGE_SIZE);
155464777Snyan#ifdef ED_DEBUG
1555137531Snyan	printf("ed?: ed_pio_testmem: page start=%x, end=%lx",
1556141552Simp	    page_offset, page_offset + memsize);
155764777Snyan#endif
155864777Snyan
155964777Snyan	/*
156064777Snyan	 * Write a test pattern. If this fails, then we don't know
156164777Snyan	 * what this board is.
156264777Snyan	 */
156364777Snyan	ed_pio_writemem(sc, test_pattern, page_offset, sizeof(test_pattern));
156464777Snyan	ed_pio_readmem(sc, page_offset, test_buffer, sizeof(test_pattern));
156564777Snyan
156664777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
156764777Snyan#ifdef ED_DEBUG
1568141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_offset);
156964777Snyan#endif
157064777Snyan		return (0);
157164777Snyan	}
157264777Snyan
157364777Snyan#ifdef DIAGNOSTIC
157464777Snyan	/* Check the bottom. */
157564777Snyan	page_end = page_offset + memsize - ED_PAGE_SIZE;
157664777Snyan	ed_pio_writemem(sc, test_pattern, page_end, sizeof(test_pattern));
157764777Snyan	ed_pio_readmem(sc, page_end, test_buffer, sizeof(test_pattern));
157864777Snyan
157964777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
158064777Snyan#ifdef ED_DEBUG
1581141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_end);
158264777Snyan#endif
158364777Snyan		return (0);
158464777Snyan	}
158564777Snyan#endif
158664777Snyan	sc->mem_size = memsize;
1587149558Simp	sc->mem_start = page_offset;
158864777Snyan	sc->mem_end   = sc->mem_start + memsize;
158964777Snyan	sc->tx_page_start = page_offset / ED_PAGE_SIZE;
159064777Snyan
159164777Snyan	/*
159264777Snyan	 * Use one xmit buffer if < 16k, two buffers otherwise (if not told
159364777Snyan	 * otherwise).
159464777Snyan	 */
1595141552Simp	if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
159664777Snyan		sc->txb_cnt = 1;
1597141552Simp	else
159864777Snyan		sc->txb_cnt = 2;
159964777Snyan
160064777Snyan	sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
160164777Snyan	sc->rec_page_stop  = sc->tx_page_start + memsize / ED_PAGE_SIZE;
160264777Snyan
160364777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
160464777Snyan
160564777Snyan	return (1);
160664777Snyan}
160770355Simp
1608141550Simpstatic device_method_t ed_cbus_methods[] = {
160970355Simp	/* Device interface */
1610141550Simp	DEVMETHOD(device_probe,		ed_cbus_probe),
1611141550Simp	DEVMETHOD(device_attach,	ed_cbus_attach),
1612150136Sru	DEVMETHOD(device_detach,	ed_detach),
161370355Simp
161470355Simp	{ 0, 0 }
161570355Simp};
161670355Simp
1617141550Simpstatic driver_t ed_cbus_driver = {
161870355Simp	"ed",
1619141550Simp	ed_cbus_methods,
162070355Simp	sizeof(struct ed_softc)
162170355Simp};
162270355Simp
1623141550SimpDRIVER_MODULE(ed, isa, ed_cbus_driver, ed_devclass, 0, 0);
1624113506SmdoddMODULE_DEPEND(ed, isa, 1, 1, 1);
1625113506SmdoddMODULE_DEPEND(ed, ether, 1, 1, 1);
1626