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$
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
4164777Snyan#include <net/ethernet.h>
4264777Snyan#include <net/if.h>
4364777Snyan#include <net/if_arp.h>
44149609Simp#include <net/if_media.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_CNET98(device_t, int, int);
57141550Simpstatic int ed_probe_CNET98EL(device_t, int, int);
58154924Simpstatic int ed_probe_EZ98(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);
62154924Simpstatic int ed_probe_SIC98(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)
236191299Simp			ed_alloc_port(dev, 0, sc->port_used);
237141552Simp		else
238191299Simp			ed98_alloc_port(dev, 0);
23964777Snyan	}
24064777Snyan	if (sc->mem_used)
241191299Simp		ed_alloc_memory(dev, 0, sc->mem_used);
24264777Snyan
243191299Simp	ed_alloc_irq(dev, 0, 0);
24464777Snyan
245191234Simp	if (sc->sc_media_ioctl == NULL)
246191234Simp		ed_gen_ifmedia_init(sc);
247191234Simp	error = ed_attach(dev);
24864777Snyan	if (error) {
24964777Snyan		ed_release_resources(dev);
25064777Snyan		return (error);
25164777Snyan	}
252191234Simp	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE,
253191234Simp	    NULL, edintr, sc, &sc->irq_handle);
254191234Simp	if (error)
255191234Simp		ed_release_resources(dev);
256191234Simp	return (error);
25764777Snyan}
25864777Snyan
25964777Snyan/*
26064777Snyan * Interrupt conversion table for EtherEZ98
26164777Snyan */
262141495Simpstatic uint16_t ed_EZ98_intr_val[] = {
26364777Snyan	0,
26464777Snyan	3,
26564777Snyan	5,
26664777Snyan	6,
26764777Snyan	0,
26864777Snyan	9,
26964777Snyan	12,
27064777Snyan	13
27164777Snyan};
27264777Snyan
27364777Snyanstatic int
274141550Simped_probe_EZ98(device_t dev, int port_rid, int flags)
27564777Snyan{
27664777Snyan	struct ed_softc *sc = device_get_softc(dev);
27764777Snyan	int error;
27864777Snyan	static unsigned short *intr_vals[] = {NULL, ed_EZ98_intr_val};
27964777Snyan
28064777Snyan	error = ed_alloc_port(dev, port_rid, ED_EZ98_IO_PORTS);
28164777Snyan	if (error) {
28264777Snyan		return (error);
28364777Snyan	}
28464777Snyan
28564777Snyan	sc->asic_offset = ED_EZ98_ASIC_OFFSET;
28664777Snyan	sc->nic_offset  = ED_EZ98_NIC_OFFSET;
28764777Snyan
28864777Snyan	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
28964777Snyan}
29064777Snyan
29164777Snyan/*
29264777Snyan * I/O conversion tables
29364777Snyan */
29464777Snyan
29564777Snyan/* LGY-98, ICM, C-NET(98)E/L */
29664777Snyanstatic	bus_addr_t ed98_ioaddr_generic[] = {
29764777Snyan	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
29864777Snyan};
29964777Snyan
30064777Snyan/*
30164777Snyan *		Definitions for Contec C-NET(98)E/L
30264777Snyan */
30364777Snyan#define	ED_CNET98EL_ICR         2	/* Interrupt Configuration Register */
30464777Snyan
30564777Snyan#define	ED_CNET98EL_ICR_IRQ3	0x01
30664777Snyan#define	ED_CNET98EL_ICR_IRQ5	0x02
30764777Snyan#define	ED_CNET98EL_ICR_IRQ6	0x04
30864777Snyan#define	ED_CNET98EL_ICR_IRQ12	0x20
30964777Snyan
31064777Snyan#define	ED_CNET98EL_IMR         4	/* Interrupt Mask Register	*/
31164777Snyan#define	ED_CNET98EL_ISR         5	/* Interrupt Status Register	*/
31264777Snyan
31364777Snyan/* EGY-98 */
31464777Snyanstatic	bus_addr_t ed98_ioaddr_egy98[] = {
31564777Snyan	0,     0x02,  0x04,  0x06,  0x08,  0x0a,  0x0c,  0x0e,
31664777Snyan	0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e
31764777Snyan};
31864777Snyan
31964777Snyan/* SIC-98 */
32064777Snyanstatic	bus_addr_t ed98_ioaddr_sic98[] = {
32164777Snyan	0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00,
32264777Snyan	0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00
32364777Snyan};
32464777Snyan
32564777Snyan/* LA/T-98, LD-BDN, PC-9801-77, SB-9801 */
32664777Snyanstatic	bus_addr_t ed98_ioaddr_la98[] = {
32764777Snyan	0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000,
32864777Snyan	0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000,
32964777Snyan	0x0100	/* for NEC 77(see below) */
33064777Snyan};
33164777Snyan
33264777Snyan/*
33364777Snyan *		Definitions for NEC PC-9801-77
33464777Snyan */
33564777Snyan#define	ED_NEC77_IRQ		16	/* Interrupt Configuration Register */
33664777Snyan
33764777Snyan#define	ED_NEC77_IRQ3		0x04
33864777Snyan#define	ED_NEC77_IRQ5		0x06
33964777Snyan#define	ED_NEC77_IRQ6		0x08
34064777Snyan#define	ED_NEC77_IRQ12		0x0a
34164777Snyan#define	ED_NEC77_IRQ13		0x02
34264777Snyan
34364777Snyan/*
34464777Snyan *		Definitions for Soliton SB-9801
34564777Snyan */
34664777Snyan#define	ED_SB98_CFG		1	/* Board configuration		*/
34764777Snyan
34864777Snyan#define	ED_SB98_CFG_IRQ3	0x00
34964777Snyan#define	ED_SB98_CFG_IRQ5	0x04
35064777Snyan#define	ED_SB98_CFG_IRQ6	0x08
35164777Snyan#define	ED_SB98_CFG_IRQ12	0x0c
35264777Snyan#define	ED_SB98_CFG_ALTPORT	0x40		/* use EXTERNAL media	*/
35364777Snyan#define	ED_SB98_CFG_ENABLE	0xa0		/* enable configuration	*/
35464777Snyan
35564777Snyan#define	ED_SB98_EEPENA		2	/* EEPROM access enable		*/
35664777Snyan
35764777Snyan#define	ED_SB98_EEPENA_DISABLE	0x00
35864777Snyan#define	ED_SB98_EEPENA_ENABLE	0x01
35964777Snyan
36064777Snyan#define	ED_SB98_EEP		3	/* EEPROM access		*/
36164777Snyan
36264777Snyan#define	ED_SB98_EEP_SDA		0x01		/* Serial Data	*/
36364777Snyan#define	ED_SB98_EEP_SCL		0x02		/* Serial Clock	*/
36464777Snyan#define	ED_SB98_EEP_READ	0x01		/* Read Command	*/
36564777Snyan
36664777Snyan#define	ED_SB98_EEP_DELAY	300
36764777Snyan
36864777Snyan#define	ED_SB98_ADDRESS		0x01		/* Station Address(1-6)	*/
36964777Snyan
37064777Snyan#define	ED_SB98_POLARITY	4	/* Polarity			*/
37164777Snyan
37264777Snyan/* PC-9801-108 */
37364777Snyanstatic	bus_addr_t ed98_ioaddr_nec108[] = {
37464777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
37564777Snyan	0x1000, 0x1002, 0x1004, 0x1006, 0x1008, 0x100a, 0x100c, 0x100e
37664777Snyan};
37764777Snyan
37864777Snyan/* C-NET(98) */
37964777Snyanstatic	bus_addr_t ed98_ioaddr_cnet98[] = {
38064777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
38164777Snyan	0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e
38264777Snyan};
38364777Snyan
38464777Snyan/*
38564777Snyan *		Definitions for Contec C-NET(98)
38664777Snyan */
38764777Snyan#define	ED_CNET98_MAP_REG0L	0	/* MAPPING register0 Low	*/
38864777Snyan#define	ED_CNET98_MAP_REG1L	1	/* MAPPING register1 Low	*/
38964777Snyan#define	ED_CNET98_MAP_REG2L	2	/* MAPPING register2 Low	*/
39064777Snyan#define	ED_CNET98_MAP_REG3L	3	/* MAPPING register3 Low	*/
39164777Snyan#define	ED_CNET98_MAP_REG0H	4	/* MAPPING register0 Hi		*/
39264777Snyan#define	ED_CNET98_MAP_REG1H	5	/* MAPPING register1 Hi		*/
39364777Snyan#define	ED_CNET98_MAP_REG2H	6	/* MAPPING register2 Hi		*/
39464777Snyan#define	ED_CNET98_MAP_REG3H	7	/* MAPPING register3 Hi		*/
39564777Snyan#define	ED_CNET98_WIN_REG	8	/* Window register		*/
39664777Snyan#define	ED_CNET98_INT_LEV	9	/* Init level register		*/
39764777Snyan
39864777Snyan#define	ED_CNET98_INT_IRQ3	0x01		/* INT 0 */
39964777Snyan#define	ED_CNET98_INT_IRQ5	0x02		/* INT 1 */
40064777Snyan#define	ED_CNET98_INT_IRQ6	0x04		/* INT 2 */
40164777Snyan#define	ED_CNET98_INT_IRQ9	0x08		/* INT 3 */
40264777Snyan#define	ED_CNET98_INT_IRQ12	0x20		/* INT 5 */
40364777Snyan#define	ED_CNET98_INT_IRQ13	0x40		/* INT 6 */
40464777Snyan
40564777Snyan#define	ED_CNET98_INT_REQ	10	/* Init request register	*/
40664777Snyan#define	ED_CNET98_INT_MASK	11	/* Init mask register		*/
40764777Snyan#define	ED_CNET98_INT_STAT	12	/* Init status register		*/
40864777Snyan#define	ED_CNET98_INT_CLR	12	/* Init clear register		*/
40964777Snyan#define	ED_CNET98_RESERVE1	13
41064777Snyan#define	ED_CNET98_RESERVE2	14
41164777Snyan#define	ED_CNET98_RESERVE3	15
41264777Snyan
41364777Snyan/* EC/EP-98X, NC5098 */
41464777Snyanstatic	bus_addr_t ed98_ioaddr_nw98x[] = {
41564777Snyan	0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
41664777Snyan	0x0800, 0x0900, 0x0a00, 0x0b00, 0x0c00, 0x0d00, 0x0e00, 0x0f00,
41764777Snyan	0x1000	/* for EC/EP-98X(see below) */
41864777Snyan};
41964777Snyan
42064777Snyan/*
42164777Snyan *		Definitions for Networld EC/EP-98X
42264777Snyan */
42364777Snyan#define	ED_NW98X_IRQ            16	/* Interrupt Configuration Register */
42464777Snyan
42564777Snyan#define	ED_NW98X_IRQ3           0x04
42664777Snyan#define	ED_NW98X_IRQ5           0x06
42764777Snyan#define	ED_NW98X_IRQ6           0x08
42864777Snyan#define	ED_NW98X_IRQ12          0x0a
42964777Snyan#define	ED_NW98X_IRQ13          0x02
43064777Snyan
43164777Snyan/* NC5098 ASIC */
43264777Snyanstatic bus_addr_t ed98_asic_nc5098[] = {
43364777Snyan/*	DATA    ENADDR						RESET	*/
43464777Snyan	0x0000, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x4000,
43564777Snyan	     0,      0,      0,      0,      0,      0,      0,      0
43664777Snyan};
43764777Snyan
43864777Snyan/*
43964777Snyan *		Definitions for NextCom NC5098
44064777Snyan */
44164777Snyan#define	ED_NC5098_ENADDR	1	/* Station Address(1-6)		*/
44264777Snyan
44364777Snyan/*
44464777Snyan * Allocate a port resource with the given resource id.
44564777Snyan */
44664777Snyanstatic int
447141550Simped98_alloc_port(device_t dev, int rid)
44864777Snyan{
44964777Snyan	struct ed_softc *sc = device_get_softc(dev);
45064777Snyan	struct resource *res;
45164777Snyan	int error;
45264777Snyan	bus_addr_t *io_nic, *io_asic, adj;
45364777Snyan	static bus_addr_t io_res[ED_NOVELL_IO_PORTS + 1];
45464777Snyan	int i, n;
45564777Snyan	int offset, reset, data;
45664777Snyan
45764777Snyan	/* Set i/o table for resource manager */
45864777Snyan	io_nic = io_asic = ed98_ioaddr_generic;
45964777Snyan	offset = ED_NOVELL_ASIC_OFFSET;
46064777Snyan	reset = ED_NOVELL_RESET;
46164777Snyan	data  = ED_NOVELL_DATA;
46264777Snyan	n = ED_NOVELL_IO_PORTS;
46364777Snyan
46464777Snyan	switch (sc->type) {
46564777Snyan	case ED_TYPE98_LGY:
46664777Snyan		io_asic = ed98_ioaddr_egy98; /* XXX - Yes, we use egy98 */
46764777Snyan		offset = 0x0200;
46864777Snyan		reset = 8;
46964777Snyan		break;
47064777Snyan
47164777Snyan	case ED_TYPE98_EGY:
47264777Snyan		io_nic = io_asic = ed98_ioaddr_egy98;
47364777Snyan		offset = 0x0200;
47464777Snyan		reset = 8;
47564777Snyan		break;
47664777Snyan
47764777Snyan	case ED_TYPE98_ICM:
47864777Snyan		offset = 0x0100;
47964777Snyan		break;
48064777Snyan
48164777Snyan	case ED_TYPE98_BDN:
48264777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
48364777Snyan		offset = 0x0100;
48464777Snyan		reset = 0x0c;
48564777Snyan		break;
48664777Snyan
48764777Snyan	case ED_TYPE98_SIC:
48864777Snyan		io_nic = io_asic = ed98_ioaddr_sic98;
48964777Snyan		offset = 0x2000;
49064777Snyan		n = 16+1;
49164777Snyan		break;
49264777Snyan
49364777Snyan	case ED_TYPE98_108:
49464777Snyan		io_nic = io_asic = ed98_ioaddr_nec108;
49564777Snyan		offset = 0x0888;	/* XXX - overwritten after */
49664777Snyan		reset = 1;
49764777Snyan		n = 16;	/* XXX - does not set ASIC i/o here */
49864777Snyan		break;
49964777Snyan
50064777Snyan	case ED_TYPE98_LA98:
50164777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
50264777Snyan		offset = 0x0100;
50364777Snyan		break;
50464777Snyan
50564777Snyan	case ED_TYPE98_CNET98EL:
50664777Snyan		offset = 0x0400;
50764777Snyan		data = 0x0e;
50864777Snyan		break;
50964777Snyan
51064777Snyan	case ED_TYPE98_CNET98:
51164777Snyan		/* XXX - Yes, we use generic i/o here */
51264777Snyan		offset = 0x0400;
51364777Snyan		break;
51464777Snyan
51564777Snyan	case ED_TYPE98_NW98X:
51664777Snyan		io_nic = io_asic = ed98_ioaddr_nw98x;
51764777Snyan		offset = 0x1000;
51864777Snyan		break;
51964777Snyan
52064777Snyan	case ED_TYPE98_SB98:
52164777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
52264777Snyan		offset = 0x0400;
52364777Snyan		reset = 7;
52464777Snyan		break;
52564777Snyan
52664777Snyan	case ED_TYPE98_NC5098:
52764777Snyan		io_nic  = ed98_ioaddr_nw98x;
52864777Snyan		io_asic = ed98_asic_nc5098;
52964777Snyan		offset = 0x2000;
53064777Snyan		reset = 7;
53164777Snyan		n = 16+8;	/* XXX */
53264777Snyan		break;
53364777Snyan	}
53464777Snyan
53564777Snyan	bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
536141552Simp	for (i = ED_NOVELL_ASIC_OFFSET; i < ED_NOVELL_IO_PORTS; i++)
53764777Snyan		io_res[i] = io_asic[i - ED_NOVELL_ASIC_OFFSET] + offset;
53864777Snyan
539141552Simp	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, io_res, n,
540141552Simp	    RF_ACTIVE);
541141552Simp	if (!res)
54264777Snyan		return (ENOENT);
54364777Snyan
54464777Snyan	sc->port_res = res;
54564777Snyan	sc->port_used = n;
546155874Snyan	sc->port_bst = rman_get_bustag(res);
547155874Snyan	sc->port_bsh = rman_get_bushandle(res);
54864777Snyan
54964777Snyan	/* Re-map i/o table if needed */
55064777Snyan	switch (sc->type) {
55164777Snyan	case ED_TYPE98_LA98:
55264777Snyan	case ED_TYPE98_NW98X:
55364777Snyan		io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
55464777Snyan		n++;
55564777Snyan		break;
55664777Snyan
55764777Snyan	case ED_TYPE98_108:
55864777Snyan		adj = (rman_get_start(res) & 0xf000) / 2;
55964777Snyan		offset = (offset | adj) - rman_get_start(res);
56064777Snyan
561141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
56264777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
56364777Snyan		break;
56464777Snyan
56564777Snyan	case ED_TYPE98_CNET98:
56664777Snyan		io_nic = io_asic = ed98_ioaddr_cnet98;
56764777Snyan		offset = 1;
56864777Snyan
56964777Snyan		bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
570141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
57164777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
57264777Snyan		break;
57364777Snyan
57464777Snyan	case ED_TYPE98_NC5098:
57564777Snyan		n = ED_NOVELL_IO_PORTS;
57664777Snyan		break;
57764777Snyan	}
57864777Snyan
579141552Simp	if (reset != ED_NOVELL_RESET)
58064777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_RESET] =
58164777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + reset];
58264777Snyan	if (data  != ED_NOVELL_DATA) {
58364777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA] =
58464777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data];
58564777Snyan#if 0
58664777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA + 1] =
58764777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data + 1];
58864777Snyan#endif
58964777Snyan	}
59064777Snyan
59164777Snyan	error = isa_load_resourcev(res, io_res, n);
592141552Simp	if (error != 0)
59364777Snyan		return (ENOENT);
59464777Snyan#ifdef ED_DEBUG
59564777Snyan	device_printf(dev, "ed98_alloc_port: i/o ports = %d\n", n);
596141552Simp	for (i = 0; i < n; i++)
59764777Snyan		printf("%x,", io_res[i]);
59864777Snyan	printf("\n");
59964777Snyan#endif
60064777Snyan	return (0);
60164777Snyan}
60264777Snyan
60364777Snyanstatic int
60464777Snyaned98_alloc_memory(dev, rid)
60564777Snyan	device_t dev;
60664777Snyan	int rid;
60764777Snyan{
60864777Snyan	struct ed_softc *sc = device_get_softc(dev);
60964777Snyan	int error;
610294883Sjhibbits	rman_res_t conf_maddr, conf_msize;
61164777Snyan
612141552Simp	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &conf_maddr,
613141552Simp	    &conf_msize);
614141552Simp	if (error)
61564777Snyan		return (error);
61664777Snyan
617141552Simp	if ((conf_maddr == 0) || (conf_msize == 0))
61864777Snyan		return (ENXIO);
61964777Snyan
62064777Snyan	error = ed_alloc_memory(dev, rid, (int) conf_msize);
621141552Simp	if (error)
62264777Snyan		return (error);
62364777Snyan
624149558Simp	sc->mem_start = 0;
62564777Snyan	sc->mem_size  = conf_msize;
62664777Snyan
62764777Snyan	return (0);
62864777Snyan}
62964777Snyan
63064777Snyan/*
63164777Snyan * Generic probe routine for testing for the existance of a DS8390.
63264777Snyan *	Must be called after the NIC has just been reset. This routine
63364777Snyan *	works by looking at certain register values that are guaranteed
63464777Snyan *	to be initialized a certain way after power-up or reset. Seems
63564777Snyan *	not to currently work on the 83C690.
63664777Snyan *
63764777Snyan * Specifically:
63864777Snyan *
63964777Snyan *	Register			reset bits	set bits
64064777Snyan *	Command Register (CR)		TXP, STA	RD2, STP
64164777Snyan *	Interrupt Status (ISR)				RST
64264777Snyan *	Interrupt Mask (IMR)		All bits
64364777Snyan *	Data Control (DCR)				LAS
64464777Snyan *	Transmit Config. (TCR)		LB1, LB0
64564777Snyan *
64664777Snyan * XXX - We only check the CR register.
64764777Snyan *
64864777Snyan * Return 1 if 8390 was found, 0 if not.
64964777Snyan */
65064777Snyan
65164777Snyanstatic int
652141550Simped98_probe_generic8390(struct ed_softc *sc)
65364777Snyan{
65464777Snyan	u_char tmp = ed_nic_inb(sc, ED_P0_CR);
65564777Snyan#ifdef DIAGNOSTIC
65664777Snyan	printf("ed?: inb(ED_P0_CR)=%x\n", tmp);
65764777Snyan#endif
65864777Snyan	if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
659141552Simp	    (ED_CR_RD2 | ED_CR_STP))
66064777Snyan		return (0);
66164777Snyan
66264777Snyan	(void) ed_nic_inb(sc, ED_P0_ISR);
66364777Snyan
66464777Snyan	return (1);
66564777Snyan}
66664777Snyan
66764777Snyanstatic int
668141550Simped98_probe_Novell(device_t dev, int port_rid, int flags)
66964777Snyan{
67064777Snyan	struct ed_softc *sc = device_get_softc(dev);
67164777Snyan	int error;
67264777Snyan	int n;
67364777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
67464777Snyan
67564777Snyan#ifdef ED_DEBUG
67664777Snyan	device_printf(dev, "ed98_probe_Novell: start\n");
67764777Snyan#endif
67864777Snyan	error = ed98_alloc_port(dev, port_rid);
679141552Simp	if (error)
68064777Snyan		return (error);
68164777Snyan
68264777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
68364777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
68464777Snyan
68564777Snyan	/* Reset the board */
68664777Snyan#ifdef ED_DEBUG
68764777Snyan	device_printf(dev, "ed98_probe_Novell: reset\n");
68864777Snyan#endif
68964777Snyan	switch (sc->type) {
69064777Snyan#if 1	/* XXX - I'm not sure this is really necessary... */
69164777Snyan	case ED_TYPE98_BDN:
69264777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
69364777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, (tmp & 0xf0) | 0x08);
69464777Snyan		ed_nic_outb(sc, 0x04, tmp);
69564777Snyan		(void) ed_asic_inb(sc, 0x08);
69664777Snyan		ed_asic_outb(sc, 0x08, tmp);
69764777Snyan		ed_asic_outb(sc, 0x08, tmp & 0x7f);
69864777Snyan		break;
69964777Snyan#endif
70064777Snyan	case ED_TYPE98_NC5098:
70164777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x00);
70264777Snyan		DELAY(5000);
70364777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x01);
70464777Snyan		break;
70564777Snyan
70664777Snyan	default:
70764777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
70864777Snyan
70964777Snyan	/*
71064777Snyan	 * I don't know if this is necessary; probably cruft leftover from
71164777Snyan	 * Clarkson packet driver code. Doesn't do a thing on the boards I've
712108533Sschweikh	 * tested. -DG [note that an outb(0x84, 0) seems to work here, and is
71364777Snyan	 * non-invasive...but some boards don't seem to reset and I don't have
71464777Snyan	 * complete documentation on what the 'right' thing to do is...so we
71564777Snyan	 * do the invasive thing for now. Yuck.]
71664777Snyan	 */
71764777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
71864777Snyan		break;
71964777Snyan	}
72064777Snyan	DELAY(5000);
72164777Snyan
72264777Snyan	/*
72364777Snyan	 * This is needed because some NE clones apparently don't reset the
72464777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
72564777Snyan	 * - this makes the probe invasive! ...Done against my better
72664777Snyan	 * judgement. -DLG
72764777Snyan	 */
72864777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
72964777Snyan	DELAY(5000);
73064777Snyan
73164777Snyan	/* Make sure that we really have an 8390 based board */
732141552Simp	if (!ed98_probe_generic8390(sc))
73364777Snyan		return (ENXIO);
73464777Snyan
73564777Snyan	/* Test memory via PIO */
73664777Snyan#ifdef ED_DEBUG
73764777Snyan	device_printf(dev, "ed98_probe_Novell: test memory\n");
73864777Snyan#endif
73964777Snyan	sc->cr_proto = ED_CR_RD2;
740141552Simp	if (!ed_pio_testmem(sc,  8192, 0, flags) &&
741141552Simp	    !ed_pio_testmem(sc, 16384, 1, flags))
74264777Snyan		return (ENXIO);
74364777Snyan
74464777Snyan	/* Setup the board type */
74564777Snyan#ifdef ED_DEBUG
74664777Snyan	device_printf(dev, "ed98_probe_Novell: board type\n");
74764777Snyan#endif
74864777Snyan	switch (sc->type) {
74964777Snyan	case ED_TYPE98_BDN:
75064777Snyan		sc->type_str = "LD-BDN";
75164777Snyan		break;
75264777Snyan	case ED_TYPE98_EGY:
75364777Snyan		sc->type_str = "EGY-98";
75464777Snyan		break;
75564777Snyan	case ED_TYPE98_LGY:
75664777Snyan		sc->type_str = "LGY-98";
75764777Snyan		break;
75864777Snyan	case ED_TYPE98_ICM:
75964777Snyan		sc->type_str = "ICM";
76064777Snyan		break;
76164777Snyan	case ED_TYPE98_108:
76264777Snyan		sc->type_str = "PC-9801-108";
76364777Snyan		break;
76464777Snyan	case ED_TYPE98_LA98:
76564777Snyan		sc->type_str = "LA-98";
76664777Snyan		break;
76764777Snyan	case ED_TYPE98_NW98X:
76864777Snyan		sc->type_str = "NW98X";
76964777Snyan		break;
77064777Snyan	case ED_TYPE98_NC5098:
77164777Snyan		sc->type_str = "NC5098";
77264777Snyan		break;
77364777Snyan	default:
77464777Snyan		sc->type_str = NULL;
77564777Snyan		break;
77664777Snyan	}
77764777Snyan
77864777Snyan	/* Get station address */
77964777Snyan	switch (sc->type) {
78064777Snyan	case ED_TYPE98_NC5098:
781141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
782147256Sbrooks			sc->enaddr[n] = ed_asic_inb(sc, ED_NC5098_ENADDR + n);
78364777Snyan		break;
78464777Snyan
78564777Snyan	default:
78664777Snyan		ed_pio_readmem(sc, 0, romdata, sizeof(romdata));
787141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
788147256Sbrooks			sc->enaddr[n] = romdata[n * (sc->isa16bit + 1)];
78964777Snyan		break;
79064777Snyan	}
79164777Snyan
79264777Snyan	/* clear any pending interrupts that might have occurred above */
79364777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
79464777Snyan
795154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
79664777Snyan	return (0);
79764777Snyan}
79864777Snyan
79964777Snyan/*
80064777Snyan * Probe and vendor-specific initialization routine for SIC-98 boards
80164777Snyan */
80264777Snyanstatic int
803141550Simped_probe_SIC98(device_t dev, int port_rid, int flags)
80464777Snyan{
80564777Snyan	struct ed_softc *sc = device_get_softc(dev);
80664777Snyan	int error;
80764777Snyan	int i;
80864777Snyan	u_char sum;
80964777Snyan
81064777Snyan	/*
81164777Snyan	 * Setup card RAM and I/O address
81264777Snyan	 * Kernel Virtual to segment C0000-DFFFF????
81364777Snyan	 */
81464777Snyan	error = ed98_alloc_port(dev, port_rid);
815141552Simp	if (error)
81664777Snyan		return (error);
81764777Snyan
818121118Sshiba	sc->asic_offset = ED_SIC_ASIC_OFFSET;
819121118Sshiba	sc->nic_offset  = ED_SIC_NIC_OFFSET;
82064777Snyan
82164777Snyan	error = ed98_alloc_memory(dev, 0);
822141552Simp	if (error)
82364777Snyan		return (error);
82464777Snyan
82564777Snyan	/* Reset card to force it into a known state. */
82664777Snyan	ed_asic_outb(sc, 0, 0x00);
82764777Snyan	DELAY(100);
82864777Snyan	if (ED_TYPE98SUB(flags) == 0) {
82964777Snyan		/* SIC-98/SIU-98 */
83064777Snyan		ed_asic_outb(sc, 0, 0x94);
83164777Snyan		DELAY(100);
83264777Snyan		ed_asic_outb(sc, 0, 0x94);
83364777Snyan	} else {
83464777Snyan		/* SIU-98-D */
83564777Snyan		ed_asic_outb(sc, 0, 0x80);
83664777Snyan		DELAY(100);
83764777Snyan		ed_asic_outb(sc, 0, 0x94);
83864777Snyan		DELAY(100);
83964777Snyan		ed_asic_outb(sc, 0, 0x9e);
84064777Snyan	}
84164777Snyan	DELAY(100);
84264777Snyan
84364777Snyan	/*
84464777Snyan	 * Here we check the card ROM, if the checksum passes, and the
84564777Snyan	 * type code and ethernet address check out, then we know we have
84664777Snyan	 * an SIC card.
84764777Snyan	 */
848149558Simp	sum = bus_space_read_1(sc->mem_bst, sc->mem_bsh, 6 * 2);
849141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
850149558Simp		sum ^= (sc->enaddr[i] =
851149558Simp		    bus_space_read_1(sc->mem_bst, sc->mem_bsh, i * 2));
85264777Snyan#ifdef ED_DEBUG
85364777Snyan	device_printf(dev, "ed_probe_sic98: got address %6D\n",
854147256Sbrooks		      sc->enaddr, ":");
85564777Snyan#endif
856141552Simp	if (sum != 0)
85764777Snyan		return (ENXIO);
858147256Sbrooks	if ((sc->enaddr[0] | sc->enaddr[1] | sc->enaddr[2]) == 0)
85964777Snyan		return (ENXIO);
86064777Snyan
861121118Sshiba	sc->vendor   = ED_VENDOR_SIC;
86264777Snyan	sc->type_str = "SIC98";
86364777Snyan	sc->isa16bit = 1;
86464777Snyan	sc->cr_proto = 0;
86564777Snyan
86664777Snyan	/*
86764777Snyan	 * SIC RAM page 0x0000-0x3fff(or 0x7fff)
86864777Snyan	 */
869141552Simp	if (ED_TYPE98SUB(flags) == 0)
87064777Snyan		ed_asic_outb(sc, 0, 0x90);
871141552Simp	else
87264777Snyan		ed_asic_outb(sc, 0, 0x8e);
87364777Snyan	DELAY(100);
87464777Snyan
875141550Simp	error = ed_clear_memory(dev);
876141550Simp	if (error)
877141550Simp		return (error);
87864777Snyan
87964777Snyan	sc->mem_shared = 1;
88064777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
88164777Snyan
88264777Snyan	/*
88364777Snyan	 * allocate one xmit buffer if < 16k, two buffers otherwise
88464777Snyan	 */
885141552Simp	if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
88664777Snyan		sc->txb_cnt = 1;
887141552Simp	else
88864777Snyan		sc->txb_cnt = 2;
88964777Snyan	sc->tx_page_start = 0;
89064777Snyan
89164777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt;
89264777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
89364777Snyan
89464777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
89564777Snyan
896154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
89764777Snyan	return (0);
89864777Snyan}
89964777Snyan
90064777Snyan/*
90164777Snyan * Contec C-NET(98) series support routines
90264777Snyan */
90364777Snyanstatic void
904141550Simped_reset_CNET98(struct ed_softc *sc, int flags)
90564777Snyan{
906118557Sbde	u_int init_addr = ED_CNET98_INIT;
90764777Snyan	u_char tmp;
90864777Snyan
90964777Snyan	/* Choose initial register address */
91064777Snyan	if (ED_TYPE98SUB(flags) != 0) {
91164777Snyan		init_addr = ED_CNET98_INIT2;
91264777Snyan	}
91364777Snyan#ifdef ED_DEBUG
91464777Snyan	printf("ed?: initial register=%x\n", init_addr);
91564777Snyan#endif
91664777Snyan	/*
91764777Snyan	 * Reset the board to force it into a known state.
91864777Snyan	 */
91964777Snyan	outb(init_addr, 0x00);	/* request */
92064777Snyan	DELAY(5000);
92164777Snyan	outb(init_addr, 0x01);	/* cancel */
92264777Snyan	DELAY(5000);
92364777Snyan
92464777Snyan	/*
92564777Snyan	 * Set I/O address(A15-12) and cpu type
92664777Snyan	 *
92764777Snyan	 *   AAAAIXXC(8bit)
92864777Snyan	 *   AAAA: A15-A12,  I: I/O enable, XX: reserved, C: CPU type
92964777Snyan	 *
93064777Snyan	 * CPU type is 1:80286 or higher, 0:not.
93164777Snyan	 * But FreeBSD runs under i386 or higher, thus it must be 1.
93264777Snyan	 */
93364777Snyan	tmp = (rman_get_start(sc->port_res) & 0xf000) >> 8;
93464777Snyan	tmp |= (0x08 | 0x01);
93564777Snyan#ifdef ED_DEBUG
93664777Snyan	printf("ed?: outb(%x, %x)\n", init_addr + 2, tmp);
93764777Snyan#endif
93864777Snyan	outb(init_addr + 2, tmp);
93964777Snyan	DELAY(5000);
94064777Snyan
94164777Snyan	/*
94264777Snyan	 * This is needed because some NE clones apparently don't reset the
94364777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
94464777Snyan	 * - this makes the probe invasive! ...Done against my better
94564777Snyan	 * judgement. -DLG
94664777Snyan	 */
94764777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
94864777Snyan	DELAY(5000);
94964777Snyan}
95064777Snyan
95164777Snyanstatic void
952141550Simped_winsel_CNET98(struct ed_softc *sc, u_short bank)
95364777Snyan{
954141550Simp	u_char mem = (rman_get_start(sc->mem_res) >> 12) & 0xff;
95564777Snyan
95664777Snyan	/*
95764777Snyan	 * Disable window memory
95864777Snyan	 *    bit7 is 0:disable
95964777Snyan	 */
96064777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem & 0x7f);
96164777Snyan	DELAY(10);
96264777Snyan
96364777Snyan	/*
96464777Snyan	 * Select window address
96564777Snyan	 *    FreeBSD address 0xf00xxxxx
96664777Snyan	 */
96764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0L, bank & 0xff);
96864777Snyan	DELAY(10);
96964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0H, (bank >> 8) & 0xff);
97064777Snyan	DELAY(10);
97164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1L, 0x00);
97264777Snyan	DELAY(10);
97364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1H, 0x41);
97464777Snyan	DELAY(10);
97564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2L, 0x00);
97664777Snyan	DELAY(10);
97764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2H, 0x42);
97864777Snyan	DELAY(10);
97964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3L, 0x00);
98064777Snyan	DELAY(10);
98164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3H, 0x43);
98264777Snyan	DELAY(10);
98364777Snyan
98464777Snyan	/*
98564777Snyan	 * Enable window memory(16Kbyte)
98664777Snyan	 *    bit7 is 1:enable
98764777Snyan	 */
98864777Snyan#ifdef ED_DEBUG
98964777Snyan	printf("ed?: window start address=%x\n", mem);
99064777Snyan#endif
99164777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem);
99264777Snyan	DELAY(10);
99364777Snyan}
99464777Snyan
99564777Snyan/*
99664777Snyan * Probe and vendor-specific initialization routine for C-NET(98) boards
99764777Snyan */
99864777Snyanstatic int
999141550Simped_probe_CNET98(device_t dev, int port_rid, int flags)
100064777Snyan{
100164777Snyan	struct ed_softc *sc = device_get_softc(dev);
100264777Snyan	int error;
100364777Snyan	u_char tmp;
1004294883Sjhibbits	rman_res_t conf_irq, junk;
100564777Snyan#ifdef DIAGNOSTIC
100664777Snyan	u_char tmp_s;
100764777Snyan#endif
100864777Snyan
100964777Snyan	error = ed98_alloc_port(dev, port_rid);
1010141552Simp	if (error)
101164777Snyan		return (error);
101264777Snyan
101364777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
101464777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
101564777Snyan
101664777Snyan	error = ed98_alloc_memory(dev, 0);
1017141552Simp	if (error)
101864777Snyan		return (error);
101964777Snyan
102064777Snyan	/* Check I/O address. 0x[a-f]3d0 are allowed. */
102164777Snyan	if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
102264777Snyan	||  ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
102364777Snyan#ifdef DIAGNOSTIC
1024297000Sjhibbits		device_printf(dev, "Invalid i/o port configuration (0x%jx) "
102564777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
102664777Snyan			"0x[a-f]3d0", "CNET98");
102764777Snyan#endif
102864777Snyan		return (ENXIO);
102964777Snyan	}
103064777Snyan
103164777Snyan#ifdef DIAGNOSTIC
103264777Snyan	/* Check window area address */
1033141550Simp	tmp_s = rman_get_start(sc->mem_res) >> 12;
103464777Snyan	if (tmp_s < 0x80) {
1035297000Sjhibbits		device_printf(dev, "Please change window address(0x%jx)\n",
1036141550Simp		    rman_get_start(sc->mem_res));
103764777Snyan		return (ENXIO);
103864777Snyan	}
103964777Snyan
104064777Snyan	tmp_s &= 0x0f;
104164777Snyan	tmp    = rman_get_start(sc->port_res) >> 12;
104264777Snyan	if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
1043297000Sjhibbits		device_printf(dev, "Please change iobase address(0x%jx) "
1044297000Sjhibbits		    "or window address(0x%jx)\n",
1045141550Simp		    rman_get_start(sc->port_res),
1046141550Simp		    rman_get_start(sc->mem_res));
104764777Snyan		return (ENXIO);
104864777Snyan	}
104964777Snyan#endif
105064777Snyan	/* Reset the board */
105164777Snyan	ed_reset_CNET98(sc, flags);
105264777Snyan
105364777Snyan	/*
105464777Snyan	 * This is needed because some NE clones apparently don't reset the
105564777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
105664777Snyan	 * - this makes the probe invasive! ...Done against my better
105764777Snyan	 * judgement. -DLG
105864777Snyan	 */
105964777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
106064777Snyan	DELAY(5000);
106164777Snyan
106264777Snyan	/* Make sure that we really have an 8390 based board */
1063141552Simp	if (!ed98_probe_generic8390(sc))
106464777Snyan		return (ENXIO);
106564777Snyan
106664777Snyan	/*
106764777Snyan	 *  Set window ethernet address area
106864777Snyan	 *    board memory base 0x480000  data 256byte
106964777Snyan	 */
107064777Snyan	ed_winsel_CNET98(sc, 0x4800);
107164777Snyan
107264777Snyan	/*
107364777Snyan	 * Get station address from on-board ROM
107464777Snyan	 */
1075149558Simp	bus_space_read_region_1(sc->mem_bst, sc->mem_bsh, sc->mem_start,
1076149558Simp	    sc->enaddr, ETHER_ADDR_LEN);
107764777Snyan
107864777Snyan	sc->vendor    = ED_VENDOR_MISC;
107964777Snyan	sc->type_str  = "CNET98";
108064777Snyan	sc->isa16bit  = 0;
108164777Snyan	sc->cr_proto  = ED_CR_RD2;
108264777Snyan
108364777Snyan	/*
108464777Snyan	 * Set window buffer memory area
108564777Snyan	 *    board memory base 0x400000  data 16kbyte
108664777Snyan	 */
108764777Snyan	ed_winsel_CNET98(sc, 0x4000);
108864777Snyan
1089141550Simp	error = ed_clear_memory(dev);
1090141550Simp	if (error)
1091141550Simp		return (error);
109264777Snyan
109364777Snyan	sc->mem_shared = 1;
109464777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
109564777Snyan
109664777Snyan	sc->txb_cnt = 1;	/* XXX */
109764777Snyan	sc->tx_page_start = 0;
109864777Snyan
109964777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
110064777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
110164777Snyan
110264777Snyan	sc->mem_ring = sc->mem_start + ED_PAGE_SIZE * ED_TXBUF_SIZE;
110364777Snyan
110464777Snyan	/*
110564777Snyan	 *   Set interrupt level
110664777Snyan	 */
1107141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
110864777Snyan	if (error)
110964777Snyan		return (error);
111064777Snyan
111164777Snyan	switch (conf_irq) {
111264777Snyan	case 3:
111364777Snyan		tmp = ED_CNET98_INT_IRQ3;
111464777Snyan		break;
111564777Snyan	case 5:
111664777Snyan		tmp = ED_CNET98_INT_IRQ5;
111764777Snyan		break;
111864777Snyan	case 6:
111964777Snyan		tmp = ED_CNET98_INT_IRQ6;
112064777Snyan		break;
112164777Snyan	case 9:
112264777Snyan		tmp = ED_CNET98_INT_IRQ9;
112364777Snyan		break;
112464777Snyan	case 12:
112564777Snyan		tmp = ED_CNET98_INT_IRQ12;
112664777Snyan		break;
112764777Snyan	case 13:
112864777Snyan		tmp = ED_CNET98_INT_IRQ13;
112964777Snyan		break;
113064777Snyan	default:
1131297000Sjhibbits		device_printf(dev, "Invalid irq configuration (%jd) must be "
113264777Snyan			"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
113364777Snyan		return (ENXIO);
113464777Snyan	}
113564777Snyan	ed_asic_outb(sc, ED_CNET98_INT_LEV, tmp);
113664777Snyan	DELAY(1000);
113764777Snyan	/*
113864777Snyan	 *   Set interrupt mask.
113964777Snyan	 *     bit7:1 all interrupt mask
114064777Snyan	 *     bit1:1 timer interrupt mask
114164777Snyan	 *     bit0:0 NS controler interrupt enable
114264777Snyan	 */
114364777Snyan	ed_asic_outb(sc, ED_CNET98_INT_MASK, 0x7e);
114464777Snyan	DELAY(1000);
114564777Snyan
1146154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
114764777Snyan	return (0);
114864777Snyan}
114964777Snyan
115064777Snyan/*
115164777Snyan * Probe and vendor-specific initialization routine for C-NET(98)E/L boards
115264777Snyan */
115364777Snyanstatic int
1154141550Simped_probe_CNET98EL(device_t dev, int port_rid, int flags)
115564777Snyan{
115664777Snyan	struct ed_softc *sc = device_get_softc(dev);
115764777Snyan	int error;
115864777Snyan	int i;
115964777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
1160294883Sjhibbits	rman_res_t conf_irq, junk;
116164777Snyan
116264777Snyan	error = ed98_alloc_port(dev, port_rid);
1163141552Simp	if (error)
116464777Snyan		return (error);
116564777Snyan
116664777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
116764777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
116864777Snyan
116964777Snyan	/* Check I/O address. 0x[0-f]3d0 are allowed. */
117064777Snyan	if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
117164777Snyan#ifdef DIAGNOSTIC
1172297000Sjhibbits		device_printf(dev, "Invalid i/o port configuration (0x%jx) "
117364777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
117464777Snyan			"0x?3d0", "CNET98E/L");
117564777Snyan#endif
117664777Snyan		return (ENXIO);
117764777Snyan	}
117864777Snyan
117964777Snyan	/* Reset the board */
118064777Snyan	ed_reset_CNET98(sc, flags);
118164777Snyan
118264777Snyan	/*
118364777Snyan	 * This is needed because some NE clones apparently don't reset the
118464777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
118564777Snyan	 * - this makes the probe invasive! ...Done against my better
118664777Snyan	 * judgement. -DLG
118764777Snyan	 */
118864777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
118964777Snyan	DELAY(5000);
119064777Snyan
119164777Snyan	/* Make sure that we really have an 8390 based board */
1192141552Simp	if (!ed98_probe_generic8390(sc))
119364777Snyan		return (ENXIO);
119464777Snyan
119564777Snyan	/* Test memory via PIO */
119664777Snyan	sc->cr_proto = ED_CR_RD2;
1197141552Simp	if (!ed_pio_testmem(sc, ED_CNET98EL_PAGE_OFFSET, 1, flags))
119864777Snyan		return (ENXIO);
119964777Snyan
120064777Snyan	/* This looks like a C-NET(98)E/L board. */
120164777Snyan	sc->type_str = "CNET98E/L";
120264777Snyan
120364777Snyan	/*
120464777Snyan	 * Set IRQ. C-NET(98)E/L only allows a choice of irq 3,5,6.
120564777Snyan	 */
1206141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1207141552Simp	if (error)
120864777Snyan		return (error);
120964777Snyan
121064777Snyan	switch (conf_irq) {
121164777Snyan	case 3:
121264777Snyan		tmp = ED_CNET98EL_ICR_IRQ3;
121364777Snyan		break;
121464777Snyan	case 5:
121564777Snyan		tmp = ED_CNET98EL_ICR_IRQ5;
121664777Snyan		break;
121764777Snyan	case 6:
121864777Snyan		tmp = ED_CNET98EL_ICR_IRQ6;
121964777Snyan		break;
122064777Snyan#if 0
122164777Snyan	case 12:
122264777Snyan		tmp = ED_CNET98EL_ICR_IRQ12;
122364777Snyan		break;
122464777Snyan#endif
122564777Snyan	default:
1226297000Sjhibbits		device_printf(dev, "Invalid irq configuration (%jd) must be "
122764777Snyan			"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
122864777Snyan		return (ENXIO);
122964777Snyan	}
123064777Snyan	ed_asic_outb(sc, ED_CNET98EL_ICR, tmp);
123164777Snyan	ed_asic_outb(sc, ED_CNET98EL_IMR, 0x7e);
123264777Snyan
123364777Snyan	/* Get station address from on-board ROM */
123464777Snyan	ed_pio_readmem(sc, 16384, romdata, sizeof(romdata));
1235141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
1236147256Sbrooks		sc->enaddr[i] = romdata[i * 2];
123764777Snyan
123864777Snyan	/* clear any pending interrupts that might have occurred above */
123964777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
124064777Snyan
1241154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
124264777Snyan	return (0);
124364777Snyan}
124464777Snyan
124564777Snyan/*
124664777Snyan * Probe and vendor-specific initialization routine for PC-9801-77 boards
124764777Snyan */
124864777Snyanstatic int
1249141550Simped_probe_NEC77(device_t dev, int port_rid, int flags)
125064777Snyan{
125164777Snyan	struct ed_softc *sc = device_get_softc(dev);
125264777Snyan	int error;
125364777Snyan	u_char tmp;
1254294883Sjhibbits	rman_res_t conf_irq, junk;
125564777Snyan
125664777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1257141552Simp	if (error)
125864777Snyan		return (error);
125964777Snyan
126064777Snyan	/* LA/T-98 does not need IRQ setting. */
1261141552Simp	if (ED_TYPE98SUB(flags) == 0)
126264777Snyan		return (0);
126364777Snyan
126464777Snyan	/*
126564777Snyan	 * Set IRQ. PC-9801-77 only allows a choice of irq 3,5,6,12,13.
126664777Snyan	 */
1267141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1268141552Simp	if (error)
126964777Snyan		return (error);
127064777Snyan
127164777Snyan	switch (conf_irq) {
127264777Snyan	case 3:
127364777Snyan		tmp = ED_NEC77_IRQ3;
127464777Snyan		break;
127564777Snyan	case 5:
127664777Snyan		tmp = ED_NEC77_IRQ5;
127764777Snyan		break;
127864777Snyan	case 6:
127964777Snyan		tmp = ED_NEC77_IRQ6;
128064777Snyan		break;
128164777Snyan	case 12:
128264777Snyan		tmp = ED_NEC77_IRQ12;
128364777Snyan		break;
128464777Snyan	case 13:
128564777Snyan		tmp = ED_NEC77_IRQ13;
128664777Snyan		break;
128764777Snyan	default:
1288297000Sjhibbits		device_printf(dev, "Invalid irq configuration (%jd) must be "
128964777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
129064777Snyan		return (ENXIO);
129164777Snyan	}
129264777Snyan	ed_asic_outb(sc, ED_NEC77_IRQ, tmp);
129364777Snyan
129464777Snyan	return (0);
129564777Snyan}
129664777Snyan
129764777Snyan/*
129864777Snyan * Probe and vendor-specific initialization routine for EC/EP-98X boards
129964777Snyan */
130064777Snyanstatic int
1301141550Simped_probe_NW98X(device_t dev, int port_rid, int flags)
130264777Snyan{
130364777Snyan	struct ed_softc *sc = device_get_softc(dev);
130464777Snyan	int error;
130564777Snyan	u_char tmp;
1306294883Sjhibbits	rman_res_t conf_irq, junk;
130764777Snyan
130864777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1309141552Simp	if (error)
131064777Snyan		return (error);
131164777Snyan
131264777Snyan	/* Networld 98X3 does not need IRQ setting. */
1313141552Simp	if (ED_TYPE98SUB(flags) == 0)
131464777Snyan		return (0);
131564777Snyan
131664777Snyan	/*
131764777Snyan	 * Set IRQ. EC/EP-98X only allows a choice of irq 3,5,6,12,13.
131864777Snyan	 */
1319141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1320141552Simp	if (error)
132164777Snyan		return (error);
132264777Snyan
132364777Snyan	switch (conf_irq) {
132464777Snyan	case 3:
132564777Snyan		tmp = ED_NW98X_IRQ3;
132664777Snyan		break;
132764777Snyan	case 5:
132864777Snyan		tmp = ED_NW98X_IRQ5;
132964777Snyan		break;
133064777Snyan	case 6:
133164777Snyan		tmp = ED_NW98X_IRQ6;
133264777Snyan		break;
133364777Snyan	case 12:
133464777Snyan		tmp = ED_NW98X_IRQ12;
133564777Snyan		break;
133664777Snyan	case 13:
133764777Snyan		tmp = ED_NW98X_IRQ13;
133864777Snyan		break;
133964777Snyan	default:
1340297000Sjhibbits		device_printf(dev, "Invalid irq configuration (%jd) must be "
134164777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
134264777Snyan		return (ENXIO);
134364777Snyan	}
134464777Snyan	ed_asic_outb(sc, ED_NW98X_IRQ, tmp);
134564777Snyan
134664777Snyan	return (0);
134764777Snyan}
134864777Snyan
134964777Snyan/*
135064777Snyan * Read SB-9801 station address from Serial Two-Wire EEPROM
135164777Snyan */
135264777Snyanstatic void
1353141550Simped_get_SB98(struct ed_softc *sc)
135464777Snyan{
135564777Snyan	int i, j;
135664777Snyan	u_char mask, val;
135764777Snyan
135864777Snyan        /* enable EEPROM acceess */
135964777Snyan        ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_ENABLE);
136064777Snyan
136164777Snyan	/* output start command */
136264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
136364777Snyan	DELAY(ED_SB98_EEP_DELAY);
136464777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
136564777Snyan	DELAY(ED_SB98_EEP_DELAY);
136664777Snyan
136764777Snyan       	/* output address (7bit) */
136864777Snyan	for (mask = 0x40; mask != 0; mask >>= 1) {
136964777Snyan		val = 0;
137064777Snyan		if (ED_SB98_ADDRESS & mask)
137164777Snyan			val = ED_SB98_EEP_SDA;
137264777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val);
137364777Snyan		DELAY(ED_SB98_EEP_DELAY);
137464777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val | ED_SB98_EEP_SCL);
137564777Snyan		DELAY(ED_SB98_EEP_DELAY);
137664777Snyan	}
137764777Snyan
137864777Snyan	/* output READ command */
137964777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ);
138064777Snyan	DELAY(ED_SB98_EEP_DELAY);
138164777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ | ED_SB98_EEP_SCL);
138264777Snyan	DELAY(ED_SB98_EEP_DELAY);
138364777Snyan
138464777Snyan	/* read station address */
138564777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
138664777Snyan		/* output ACK */
138764777Snyan		ed_asic_outb(sc, ED_SB98_EEP, 0);
138864777Snyan		DELAY(ED_SB98_EEP_DELAY);
138964777Snyan		ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
139064777Snyan		DELAY(ED_SB98_EEP_DELAY);
139164777Snyan
139264777Snyan		val = 0;
139364777Snyan		for (j = 0; j < 8; j++) {
139464777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
139564777Snyan			DELAY(ED_SB98_EEP_DELAY);
139664777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
139764777Snyan			DELAY(ED_SB98_EEP_DELAY);
139864777Snyan			val <<= 1;
139964777Snyan			val |= (ed_asic_inb(sc, ED_SB98_EEP) & ED_SB98_EEP_SDA);
140064777Snyan			DELAY(ED_SB98_EEP_DELAY);
140164777Snyan	  	}
1402147256Sbrooks		sc->enaddr[i] = val;
140364777Snyan	}
140464777Snyan
140564777Snyan	/* output Last ACK */
140664777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
140764777Snyan        DELAY(ED_SB98_EEP_DELAY);
140864777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
140964777Snyan        DELAY(ED_SB98_EEP_DELAY);
141064777Snyan
141164777Snyan	/* output stop command */
141264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
141364777Snyan	DELAY(ED_SB98_EEP_DELAY);
141464777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
141564777Snyan	DELAY(ED_SB98_EEP_DELAY);
141664777Snyan
141764777Snyan	/* disable EEPROM access */
141864777Snyan	ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_DISABLE);
141964777Snyan}
142064777Snyan
142164777Snyan/*
142264777Snyan * Probe and vendor-specific initialization routine for SB-9801 boards
142364777Snyan */
142464777Snyanstatic int
1425141550Simped_probe_SB98(device_t dev, int port_rid, int flags)
142664777Snyan{
142764777Snyan	struct ed_softc *sc = device_get_softc(dev);
142864777Snyan	int error;
142964777Snyan	u_char tmp;
1430294883Sjhibbits	rman_res_t conf_irq, junk;
143164777Snyan
143264777Snyan	error = ed98_alloc_port(dev, port_rid);
1433141552Simp	if (error)
143464777Snyan		return (error);
143564777Snyan
143664777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
143764777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
143864777Snyan
143964777Snyan	/* Check I/O address. 00d[02468ace] are allowed. */
144064777Snyan	if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
144164777Snyan#ifdef DIAGNOSTIC
1442297000Sjhibbits		device_printf(dev, "Invalid i/o port configuration (0x%jx) "
1443141552Simp		    "must be %s for %s\n", rman_get_start(sc->port_res),
1444141552Simp		    "0xd?", "SB9801");
144564777Snyan#endif
144664777Snyan		return (ENXIO);
144764777Snyan	}
144864777Snyan
144964777Snyan	/* Write I/O port address and read 4 times */
145064777Snyan	outb(ED_SB98_IO_INHIBIT, rman_get_start(sc->port_res) & 0xff);
145164777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145264777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145364777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145464777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145564777Snyan
145664777Snyan	/*
145764777Snyan	 * Check IRQ. Soliton SB-9801 only allows a choice of
145864777Snyan	 * irq 3,5,6,12
145964777Snyan	 */
1460141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1461141552Simp	if (error)
146264777Snyan		return (error);
146364777Snyan
146464777Snyan	switch (conf_irq) {
146564777Snyan	case 3:
146664777Snyan		tmp = ED_SB98_CFG_IRQ3;
146764777Snyan		break;
146864777Snyan	case 5:
146964777Snyan		tmp = ED_SB98_CFG_IRQ5;
147064777Snyan		break;
147164777Snyan	case 6:
147264777Snyan		tmp = ED_SB98_CFG_IRQ6;
147364777Snyan		break;
147464777Snyan	case 12:
147564777Snyan		tmp = ED_SB98_CFG_IRQ12;
147664777Snyan		break;
147764777Snyan	default:
1478297000Sjhibbits		device_printf(dev, "Invalid irq configuration (%jd) must be "
147964777Snyan			"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
148064777Snyan		return (ENXIO);
148164777Snyan	}
148264777Snyan
1483141552Simp	if (flags & ED_FLAGS_DISABLE_TRANCEIVER)
148464777Snyan		tmp |= ED_SB98_CFG_ALTPORT;
148564777Snyan	ed_asic_outb(sc, ED_SB98_CFG, ED_SB98_CFG_ENABLE | tmp);
148664777Snyan	ed_asic_outb(sc, ED_SB98_POLARITY, 0x01);
148764777Snyan
148864777Snyan	/* Reset the board. */
148964777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x7a);
149064777Snyan	DELAY(300);
149164777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x79);
149264777Snyan	DELAY(300);
149364777Snyan
149464777Snyan	/*
149564777Snyan	 * This is needed because some NE clones apparently don't reset the
149664777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
149764777Snyan	 * - this makes the probe invasive! ...Done against my better
149864777Snyan	 * judgement. -DLG
149964777Snyan	 */
150064777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
150164777Snyan	DELAY(5000);
150264777Snyan
150364777Snyan	/* Make sure that we really have an 8390 based board */
1504141552Simp	if (!ed98_probe_generic8390(sc))
150564777Snyan		return (ENXIO);
150664777Snyan
150764777Snyan	/* Test memory via PIO */
150864777Snyan	sc->cr_proto = ED_CR_RD2;
1509154924Simp	if (!ed_pio_testmem(sc, 16384, 1, flags))
151064777Snyan		return (ENXIO);
151164777Snyan
151264777Snyan	/* This looks like an SB9801 board. */
151364777Snyan	sc->type_str = "SB9801";
151464777Snyan
151564777Snyan	/* Get station address */
151664777Snyan	ed_get_SB98(sc);
151764777Snyan
151864777Snyan	/* clear any pending interrupts that might have occurred above */
151964777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
152064777Snyan
1521154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
152264777Snyan	return (0);
152364777Snyan}
152464777Snyan
152564777Snyan/*
152664777Snyan * Test the ability to read and write to the NIC memory.
152764777Snyan */
152864777Snyanstatic int
1529141550Simped_pio_testmem(struct ed_softc *sc, int page_offset, int isa16bit, int flags)
153064777Snyan{
153164777Snyan	u_long memsize;
153264777Snyan	static char test_pattern[32] = "THIS is A memory TEST pattern";
153364777Snyan	char test_buffer[32];
153464777Snyan#ifdef DIAGNOSTIC
153564777Snyan	int page_end;
153664777Snyan#endif
153764777Snyan
153864777Snyan	sc->vendor = ED_VENDOR_NOVELL;
153964777Snyan	sc->mem_shared = 0;
154064777Snyan	sc->isa16bit = isa16bit;
154164777Snyan
154264777Snyan	/* 8k of memory plus an additional 8k if 16bit */
154364777Snyan	memsize = (isa16bit ? 16384 : 8192);
154464777Snyan
154564777Snyan	/*
154664777Snyan	 * This prevents packets from being stored in the NIC memory when the
154764777Snyan	 * readmem routine turns on the start bit in the CR.
154864777Snyan	 */
154964777Snyan	ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON);
155064777Snyan
155164777Snyan	/* Initialize DCR for byte/word operations */
1552141550Simp	if (isa16bit)
155364777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
1554141550Simp	else
155564777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
155664777Snyan	ed_nic_outb(sc, ED_P0_PSTART, page_offset / ED_PAGE_SIZE);
155764777Snyan	ed_nic_outb(sc, ED_P0_PSTOP, (page_offset + memsize) / ED_PAGE_SIZE);
155864777Snyan#ifdef ED_DEBUG
1559137531Snyan	printf("ed?: ed_pio_testmem: page start=%x, end=%lx",
1560141552Simp	    page_offset, page_offset + memsize);
156164777Snyan#endif
156264777Snyan
156364777Snyan	/*
156464777Snyan	 * Write a test pattern. If this fails, then we don't know
156564777Snyan	 * what this board is.
156664777Snyan	 */
156764777Snyan	ed_pio_writemem(sc, test_pattern, page_offset, sizeof(test_pattern));
156864777Snyan	ed_pio_readmem(sc, page_offset, test_buffer, sizeof(test_pattern));
156964777Snyan
157064777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
157164777Snyan#ifdef ED_DEBUG
1572141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_offset);
157364777Snyan#endif
157464777Snyan		return (0);
157564777Snyan	}
157664777Snyan
157764777Snyan#ifdef DIAGNOSTIC
157864777Snyan	/* Check the bottom. */
157964777Snyan	page_end = page_offset + memsize - ED_PAGE_SIZE;
158064777Snyan	ed_pio_writemem(sc, test_pattern, page_end, sizeof(test_pattern));
158164777Snyan	ed_pio_readmem(sc, page_end, test_buffer, sizeof(test_pattern));
158264777Snyan
158364777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
158464777Snyan#ifdef ED_DEBUG
1585141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_end);
158664777Snyan#endif
158764777Snyan		return (0);
158864777Snyan	}
158964777Snyan#endif
159064777Snyan	sc->mem_size = memsize;
1591149558Simp	sc->mem_start = page_offset;
159264777Snyan	sc->mem_end   = sc->mem_start + memsize;
159364777Snyan	sc->tx_page_start = page_offset / ED_PAGE_SIZE;
159464777Snyan
159564777Snyan	/*
159664777Snyan	 * Use one xmit buffer if < 16k, two buffers otherwise (if not told
159764777Snyan	 * otherwise).
159864777Snyan	 */
1599141552Simp	if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
160064777Snyan		sc->txb_cnt = 1;
1601141552Simp	else
160264777Snyan		sc->txb_cnt = 2;
160364777Snyan
160464777Snyan	sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
160564777Snyan	sc->rec_page_stop  = sc->tx_page_start + memsize / ED_PAGE_SIZE;
160664777Snyan
160764777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
160864777Snyan
160964777Snyan	return (1);
161064777Snyan}
161170355Simp
1612141550Simpstatic device_method_t ed_cbus_methods[] = {
161370355Simp	/* Device interface */
1614141550Simp	DEVMETHOD(device_probe,		ed_cbus_probe),
1615141550Simp	DEVMETHOD(device_attach,	ed_cbus_attach),
1616150136Sru	DEVMETHOD(device_detach,	ed_detach),
161770355Simp
161870355Simp	{ 0, 0 }
161970355Simp};
162070355Simp
1621141550Simpstatic driver_t ed_cbus_driver = {
162270355Simp	"ed",
1623141550Simp	ed_cbus_methods,
162470355Simp	sizeof(struct ed_softc)
162570355Simp};
162670355Simp
1627141550SimpDRIVER_MODULE(ed, isa, ed_cbus_driver, ed_devclass, 0, 0);
1628113506SmdoddMODULE_DEPEND(ed, isa, 1, 1, 1);
1629113506SmdoddMODULE_DEPEND(ed, ether, 1, 1, 1);
1630