if_ed_cbus.c revision 155874
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 155874 2006-02-21 12:01:39Z nyan $
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;
544155874Snyan	sc->port_bst = rman_get_bustag(res);
545155874Snyan	sc->port_bsh = rman_get_bushandle(res);
54664777Snyan
54764777Snyan	/* Re-map i/o table if needed */
54864777Snyan	switch (sc->type) {
54964777Snyan	case ED_TYPE98_LA98:
55064777Snyan	case ED_TYPE98_NW98X:
55164777Snyan		io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
55264777Snyan		n++;
55364777Snyan		break;
55464777Snyan
55564777Snyan	case ED_TYPE98_108:
55664777Snyan		adj = (rman_get_start(res) & 0xf000) / 2;
55764777Snyan		offset = (offset | adj) - rman_get_start(res);
55864777Snyan
559141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
56064777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
56164777Snyan		break;
56264777Snyan
56364777Snyan	case ED_TYPE98_CNET98:
56464777Snyan		io_nic = io_asic = ed98_ioaddr_cnet98;
56564777Snyan		offset = 1;
56664777Snyan
56764777Snyan		bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
568141552Simp		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++)
56964777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
57064777Snyan		break;
57164777Snyan
57264777Snyan	case ED_TYPE98_NC5098:
57364777Snyan		n = ED_NOVELL_IO_PORTS;
57464777Snyan		break;
57564777Snyan	}
57664777Snyan
577141552Simp	if (reset != ED_NOVELL_RESET)
57864777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_RESET] =
57964777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + reset];
58064777Snyan	if (data  != ED_NOVELL_DATA) {
58164777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA] =
58264777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data];
58364777Snyan#if 0
58464777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA + 1] =
58564777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data + 1];
58664777Snyan#endif
58764777Snyan	}
58864777Snyan
58964777Snyan	error = isa_load_resourcev(res, io_res, n);
590141552Simp	if (error != 0)
59164777Snyan		return (ENOENT);
59264777Snyan#ifdef ED_DEBUG
59364777Snyan	device_printf(dev, "ed98_alloc_port: i/o ports = %d\n", n);
594141552Simp	for (i = 0; i < n; i++)
59564777Snyan		printf("%x,", io_res[i]);
59664777Snyan	printf("\n");
59764777Snyan#endif
59864777Snyan	return (0);
59964777Snyan}
60064777Snyan
60164777Snyanstatic int
60264777Snyaned98_alloc_memory(dev, rid)
60364777Snyan	device_t dev;
60464777Snyan	int rid;
60564777Snyan{
60664777Snyan	struct ed_softc *sc = device_get_softc(dev);
60764777Snyan	int error;
60864777Snyan	u_long conf_maddr, conf_msize;
60964777Snyan
610141552Simp	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &conf_maddr,
611141552Simp	    &conf_msize);
612141552Simp	if (error)
61364777Snyan		return (error);
61464777Snyan
615141552Simp	if ((conf_maddr == 0) || (conf_msize == 0))
61664777Snyan		return (ENXIO);
61764777Snyan
61864777Snyan	error = ed_alloc_memory(dev, rid, (int) conf_msize);
619141552Simp	if (error)
62064777Snyan		return (error);
62164777Snyan
622149558Simp	sc->mem_start = 0;
62364777Snyan	sc->mem_size  = conf_msize;
62464777Snyan
62564777Snyan	return (0);
62664777Snyan}
62764777Snyan
62864777Snyan/*
62964777Snyan * Generic probe routine for testing for the existance of a DS8390.
63064777Snyan *	Must be called after the NIC has just been reset. This routine
63164777Snyan *	works by looking at certain register values that are guaranteed
63264777Snyan *	to be initialized a certain way after power-up or reset. Seems
63364777Snyan *	not to currently work on the 83C690.
63464777Snyan *
63564777Snyan * Specifically:
63664777Snyan *
63764777Snyan *	Register			reset bits	set bits
63864777Snyan *	Command Register (CR)		TXP, STA	RD2, STP
63964777Snyan *	Interrupt Status (ISR)				RST
64064777Snyan *	Interrupt Mask (IMR)		All bits
64164777Snyan *	Data Control (DCR)				LAS
64264777Snyan *	Transmit Config. (TCR)		LB1, LB0
64364777Snyan *
64464777Snyan * XXX - We only check the CR register.
64564777Snyan *
64664777Snyan * Return 1 if 8390 was found, 0 if not.
64764777Snyan */
64864777Snyan
64964777Snyanstatic int
650141550Simped98_probe_generic8390(struct ed_softc *sc)
65164777Snyan{
65264777Snyan	u_char tmp = ed_nic_inb(sc, ED_P0_CR);
65364777Snyan#ifdef DIAGNOSTIC
65464777Snyan	printf("ed?: inb(ED_P0_CR)=%x\n", tmp);
65564777Snyan#endif
65664777Snyan	if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
657141552Simp	    (ED_CR_RD2 | ED_CR_STP))
65864777Snyan		return (0);
65964777Snyan
66064777Snyan	(void) ed_nic_inb(sc, ED_P0_ISR);
66164777Snyan
66264777Snyan	return (1);
66364777Snyan}
66464777Snyan
66564777Snyanstatic int
666141550Simped98_probe_Novell(device_t dev, int port_rid, int flags)
66764777Snyan{
66864777Snyan	struct ed_softc *sc = device_get_softc(dev);
66964777Snyan	int error;
67064777Snyan	int n;
67164777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
67264777Snyan
67364777Snyan#ifdef ED_DEBUG
67464777Snyan	device_printf(dev, "ed98_probe_Novell: start\n");
67564777Snyan#endif
67664777Snyan	error = ed98_alloc_port(dev, port_rid);
677141552Simp	if (error)
67864777Snyan		return (error);
67964777Snyan
68064777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
68164777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
68264777Snyan
68364777Snyan	/* Reset the board */
68464777Snyan#ifdef ED_DEBUG
68564777Snyan	device_printf(dev, "ed98_probe_Novell: reset\n");
68664777Snyan#endif
68764777Snyan	switch (sc->type) {
68864777Snyan#if 1	/* XXX - I'm not sure this is really necessary... */
68964777Snyan	case ED_TYPE98_BDN:
69064777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
69164777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, (tmp & 0xf0) | 0x08);
69264777Snyan		ed_nic_outb(sc, 0x04, tmp);
69364777Snyan		(void) ed_asic_inb(sc, 0x08);
69464777Snyan		ed_asic_outb(sc, 0x08, tmp);
69564777Snyan		ed_asic_outb(sc, 0x08, tmp & 0x7f);
69664777Snyan		break;
69764777Snyan#endif
69864777Snyan	case ED_TYPE98_NC5098:
69964777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x00);
70064777Snyan		DELAY(5000);
70164777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x01);
70264777Snyan		break;
70364777Snyan
70464777Snyan	default:
70564777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
70664777Snyan
70764777Snyan	/*
70864777Snyan	 * I don't know if this is necessary; probably cruft leftover from
70964777Snyan	 * Clarkson packet driver code. Doesn't do a thing on the boards I've
710108533Sschweikh	 * tested. -DG [note that an outb(0x84, 0) seems to work here, and is
71164777Snyan	 * non-invasive...but some boards don't seem to reset and I don't have
71264777Snyan	 * complete documentation on what the 'right' thing to do is...so we
71364777Snyan	 * do the invasive thing for now. Yuck.]
71464777Snyan	 */
71564777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
71664777Snyan		break;
71764777Snyan	}
71864777Snyan	DELAY(5000);
71964777Snyan
72064777Snyan	/*
72164777Snyan	 * This is needed because some NE clones apparently don't reset the
72264777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
72364777Snyan	 * - this makes the probe invasive! ...Done against my better
72464777Snyan	 * judgement. -DLG
72564777Snyan	 */
72664777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
72764777Snyan	DELAY(5000);
72864777Snyan
72964777Snyan	/* Make sure that we really have an 8390 based board */
730141552Simp	if (!ed98_probe_generic8390(sc))
73164777Snyan		return (ENXIO);
73264777Snyan
73364777Snyan	/* Test memory via PIO */
73464777Snyan#ifdef ED_DEBUG
73564777Snyan	device_printf(dev, "ed98_probe_Novell: test memory\n");
73664777Snyan#endif
73764777Snyan	sc->cr_proto = ED_CR_RD2;
738141552Simp	if (!ed_pio_testmem(sc,  8192, 0, flags) &&
739141552Simp	    !ed_pio_testmem(sc, 16384, 1, flags))
74064777Snyan		return (ENXIO);
74164777Snyan
74264777Snyan	/* Setup the board type */
74364777Snyan#ifdef ED_DEBUG
74464777Snyan	device_printf(dev, "ed98_probe_Novell: board type\n");
74564777Snyan#endif
74664777Snyan	switch (sc->type) {
74764777Snyan	case ED_TYPE98_BDN:
74864777Snyan		sc->type_str = "LD-BDN";
74964777Snyan		break;
75064777Snyan	case ED_TYPE98_EGY:
75164777Snyan		sc->type_str = "EGY-98";
75264777Snyan		break;
75364777Snyan	case ED_TYPE98_LGY:
75464777Snyan		sc->type_str = "LGY-98";
75564777Snyan		break;
75664777Snyan	case ED_TYPE98_ICM:
75764777Snyan		sc->type_str = "ICM";
75864777Snyan		break;
75964777Snyan	case ED_TYPE98_108:
76064777Snyan		sc->type_str = "PC-9801-108";
76164777Snyan		break;
76264777Snyan	case ED_TYPE98_LA98:
76364777Snyan		sc->type_str = "LA-98";
76464777Snyan		break;
76564777Snyan	case ED_TYPE98_NW98X:
76664777Snyan		sc->type_str = "NW98X";
76764777Snyan		break;
76864777Snyan	case ED_TYPE98_NC5098:
76964777Snyan		sc->type_str = "NC5098";
77064777Snyan		break;
77164777Snyan	default:
77264777Snyan		sc->type_str = NULL;
77364777Snyan		break;
77464777Snyan	}
77564777Snyan
77664777Snyan	/* Get station address */
77764777Snyan	switch (sc->type) {
77864777Snyan	case ED_TYPE98_NC5098:
779141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
780147256Sbrooks			sc->enaddr[n] = ed_asic_inb(sc, ED_NC5098_ENADDR + n);
78164777Snyan		break;
78264777Snyan
78364777Snyan	default:
78464777Snyan		ed_pio_readmem(sc, 0, romdata, sizeof(romdata));
785141552Simp		for (n = 0; n < ETHER_ADDR_LEN; n++)
786147256Sbrooks			sc->enaddr[n] = romdata[n * (sc->isa16bit + 1)];
78764777Snyan		break;
78864777Snyan	}
78964777Snyan
79064777Snyan	/* clear any pending interrupts that might have occurred above */
79164777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
79264777Snyan
793154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
79464777Snyan	return (0);
79564777Snyan}
79664777Snyan
79764777Snyan/*
79864777Snyan * Probe and vendor-specific initialization routine for SIC-98 boards
79964777Snyan */
80064777Snyanstatic int
801141550Simped_probe_SIC98(device_t dev, int port_rid, int flags)
80264777Snyan{
80364777Snyan	struct ed_softc *sc = device_get_softc(dev);
80464777Snyan	int error;
80564777Snyan	int i;
80664777Snyan	u_char sum;
80764777Snyan
80864777Snyan	/*
80964777Snyan	 * Setup card RAM and I/O address
81064777Snyan	 * Kernel Virtual to segment C0000-DFFFF????
81164777Snyan	 */
81264777Snyan	error = ed98_alloc_port(dev, port_rid);
813141552Simp	if (error)
81464777Snyan		return (error);
81564777Snyan
816121118Sshiba	sc->asic_offset = ED_SIC_ASIC_OFFSET;
817121118Sshiba	sc->nic_offset  = ED_SIC_NIC_OFFSET;
81864777Snyan
81964777Snyan	error = ed98_alloc_memory(dev, 0);
820141552Simp	if (error)
82164777Snyan		return (error);
82264777Snyan
82364777Snyan	/* Reset card to force it into a known state. */
82464777Snyan	ed_asic_outb(sc, 0, 0x00);
82564777Snyan	DELAY(100);
82664777Snyan	if (ED_TYPE98SUB(flags) == 0) {
82764777Snyan		/* SIC-98/SIU-98 */
82864777Snyan		ed_asic_outb(sc, 0, 0x94);
82964777Snyan		DELAY(100);
83064777Snyan		ed_asic_outb(sc, 0, 0x94);
83164777Snyan	} else {
83264777Snyan		/* SIU-98-D */
83364777Snyan		ed_asic_outb(sc, 0, 0x80);
83464777Snyan		DELAY(100);
83564777Snyan		ed_asic_outb(sc, 0, 0x94);
83664777Snyan		DELAY(100);
83764777Snyan		ed_asic_outb(sc, 0, 0x9e);
83864777Snyan	}
83964777Snyan	DELAY(100);
84064777Snyan
84164777Snyan	/*
84264777Snyan	 * Here we check the card ROM, if the checksum passes, and the
84364777Snyan	 * type code and ethernet address check out, then we know we have
84464777Snyan	 * an SIC card.
84564777Snyan	 */
846149558Simp	sum = bus_space_read_1(sc->mem_bst, sc->mem_bsh, 6 * 2);
847141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
848149558Simp		sum ^= (sc->enaddr[i] =
849149558Simp		    bus_space_read_1(sc->mem_bst, sc->mem_bsh, i * 2));
85064777Snyan#ifdef ED_DEBUG
85164777Snyan	device_printf(dev, "ed_probe_sic98: got address %6D\n",
852147256Sbrooks		      sc->enaddr, ":");
85364777Snyan#endif
854141552Simp	if (sum != 0)
85564777Snyan		return (ENXIO);
856147256Sbrooks	if ((sc->enaddr[0] | sc->enaddr[1] | sc->enaddr[2]) == 0)
85764777Snyan		return (ENXIO);
85864777Snyan
859121118Sshiba	sc->vendor   = ED_VENDOR_SIC;
86064777Snyan	sc->type_str = "SIC98";
86164777Snyan	sc->isa16bit = 1;
86264777Snyan	sc->cr_proto = 0;
86364777Snyan
86464777Snyan	/*
86564777Snyan	 * SIC RAM page 0x0000-0x3fff(or 0x7fff)
86664777Snyan	 */
867141552Simp	if (ED_TYPE98SUB(flags) == 0)
86864777Snyan		ed_asic_outb(sc, 0, 0x90);
869141552Simp	else
87064777Snyan		ed_asic_outb(sc, 0, 0x8e);
87164777Snyan	DELAY(100);
87264777Snyan
873141550Simp	error = ed_clear_memory(dev);
874141550Simp	if (error)
875141550Simp		return (error);
87664777Snyan
87764777Snyan	sc->mem_shared = 1;
87864777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
87964777Snyan
88064777Snyan	/*
88164777Snyan	 * allocate one xmit buffer if < 16k, two buffers otherwise
88264777Snyan	 */
883141552Simp	if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
88464777Snyan		sc->txb_cnt = 1;
885141552Simp	else
88664777Snyan		sc->txb_cnt = 2;
88764777Snyan	sc->tx_page_start = 0;
88864777Snyan
88964777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt;
89064777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
89164777Snyan
89264777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
89364777Snyan
894154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
89564777Snyan	return (0);
89664777Snyan}
89764777Snyan
89864777Snyan/*
89964777Snyan * Contec C-NET(98) series support routines
90064777Snyan */
90164777Snyanstatic void
902141550Simped_reset_CNET98(struct ed_softc *sc, int flags)
90364777Snyan{
904118557Sbde	u_int init_addr = ED_CNET98_INIT;
90564777Snyan	u_char tmp;
90664777Snyan
90764777Snyan	/* Choose initial register address */
90864777Snyan	if (ED_TYPE98SUB(flags) != 0) {
90964777Snyan		init_addr = ED_CNET98_INIT2;
91064777Snyan	}
91164777Snyan#ifdef ED_DEBUG
91264777Snyan	printf("ed?: initial register=%x\n", init_addr);
91364777Snyan#endif
91464777Snyan	/*
91564777Snyan	 * Reset the board to force it into a known state.
91664777Snyan	 */
91764777Snyan	outb(init_addr, 0x00);	/* request */
91864777Snyan	DELAY(5000);
91964777Snyan	outb(init_addr, 0x01);	/* cancel */
92064777Snyan	DELAY(5000);
92164777Snyan
92264777Snyan	/*
92364777Snyan	 * Set I/O address(A15-12) and cpu type
92464777Snyan	 *
92564777Snyan	 *   AAAAIXXC(8bit)
92664777Snyan	 *   AAAA: A15-A12,  I: I/O enable, XX: reserved, C: CPU type
92764777Snyan	 *
92864777Snyan	 * CPU type is 1:80286 or higher, 0:not.
92964777Snyan	 * But FreeBSD runs under i386 or higher, thus it must be 1.
93064777Snyan	 */
93164777Snyan	tmp = (rman_get_start(sc->port_res) & 0xf000) >> 8;
93264777Snyan	tmp |= (0x08 | 0x01);
93364777Snyan#ifdef ED_DEBUG
93464777Snyan	printf("ed?: outb(%x, %x)\n", init_addr + 2, tmp);
93564777Snyan#endif
93664777Snyan	outb(init_addr + 2, tmp);
93764777Snyan	DELAY(5000);
93864777Snyan
93964777Snyan	/*
94064777Snyan	 * This is needed because some NE clones apparently don't reset the
94164777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
94264777Snyan	 * - this makes the probe invasive! ...Done against my better
94364777Snyan	 * judgement. -DLG
94464777Snyan	 */
94564777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
94664777Snyan	DELAY(5000);
94764777Snyan}
94864777Snyan
94964777Snyanstatic void
950141550Simped_winsel_CNET98(struct ed_softc *sc, u_short bank)
95164777Snyan{
952141550Simp	u_char mem = (rman_get_start(sc->mem_res) >> 12) & 0xff;
95364777Snyan
95464777Snyan	/*
95564777Snyan	 * Disable window memory
95664777Snyan	 *    bit7 is 0:disable
95764777Snyan	 */
95864777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem & 0x7f);
95964777Snyan	DELAY(10);
96064777Snyan
96164777Snyan	/*
96264777Snyan	 * Select window address
96364777Snyan	 *    FreeBSD address 0xf00xxxxx
96464777Snyan	 */
96564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0L, bank & 0xff);
96664777Snyan	DELAY(10);
96764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0H, (bank >> 8) & 0xff);
96864777Snyan	DELAY(10);
96964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1L, 0x00);
97064777Snyan	DELAY(10);
97164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1H, 0x41);
97264777Snyan	DELAY(10);
97364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2L, 0x00);
97464777Snyan	DELAY(10);
97564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2H, 0x42);
97664777Snyan	DELAY(10);
97764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3L, 0x00);
97864777Snyan	DELAY(10);
97964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3H, 0x43);
98064777Snyan	DELAY(10);
98164777Snyan
98264777Snyan	/*
98364777Snyan	 * Enable window memory(16Kbyte)
98464777Snyan	 *    bit7 is 1:enable
98564777Snyan	 */
98664777Snyan#ifdef ED_DEBUG
98764777Snyan	printf("ed?: window start address=%x\n", mem);
98864777Snyan#endif
98964777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem);
99064777Snyan	DELAY(10);
99164777Snyan}
99264777Snyan
99364777Snyan/*
99464777Snyan * Probe and vendor-specific initialization routine for C-NET(98) boards
99564777Snyan */
99664777Snyanstatic int
997141550Simped_probe_CNET98(device_t dev, int port_rid, int flags)
99864777Snyan{
99964777Snyan	struct ed_softc *sc = device_get_softc(dev);
100064777Snyan	int error;
100164777Snyan	u_char tmp;
100264777Snyan	u_long conf_irq, junk;
100364777Snyan#ifdef DIAGNOSTIC
100464777Snyan	u_char tmp_s;
100564777Snyan#endif
100664777Snyan
100764777Snyan	error = ed98_alloc_port(dev, port_rid);
1008141552Simp	if (error)
100964777Snyan		return (error);
101064777Snyan
101164777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
101264777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
101364777Snyan
101464777Snyan	error = ed98_alloc_memory(dev, 0);
1015141552Simp	if (error)
101664777Snyan		return (error);
101764777Snyan
101864777Snyan	/* Check I/O address. 0x[a-f]3d0 are allowed. */
101964777Snyan	if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
102064777Snyan	||  ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
102164777Snyan#ifdef DIAGNOSTIC
1022111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
102364777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
102464777Snyan			"0x[a-f]3d0", "CNET98");
102564777Snyan#endif
102664777Snyan		return (ENXIO);
102764777Snyan	}
102864777Snyan
102964777Snyan#ifdef DIAGNOSTIC
103064777Snyan	/* Check window area address */
1031141550Simp	tmp_s = rman_get_start(sc->mem_res) >> 12;
103264777Snyan	if (tmp_s < 0x80) {
1033141550Simp		device_printf(dev, "Please change window address(0x%lx)\n",
1034141550Simp		    rman_get_start(sc->mem_res));
103564777Snyan		return (ENXIO);
103664777Snyan	}
103764777Snyan
103864777Snyan	tmp_s &= 0x0f;
103964777Snyan	tmp    = rman_get_start(sc->port_res) >> 12;
104064777Snyan	if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
1041111427Snyan		device_printf(dev, "Please change iobase address(0x%lx) "
1042141550Simp		    "or window address(0x%lx)\n",
1043141550Simp		    rman_get_start(sc->port_res),
1044141550Simp		    rman_get_start(sc->mem_res));
104564777Snyan		return (ENXIO);
104664777Snyan	}
104764777Snyan#endif
104864777Snyan	/* Reset the board */
104964777Snyan	ed_reset_CNET98(sc, flags);
105064777Snyan
105164777Snyan	/*
105264777Snyan	 * This is needed because some NE clones apparently don't reset the
105364777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
105464777Snyan	 * - this makes the probe invasive! ...Done against my better
105564777Snyan	 * judgement. -DLG
105664777Snyan	 */
105764777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
105864777Snyan	DELAY(5000);
105964777Snyan
106064777Snyan	/* Make sure that we really have an 8390 based board */
1061141552Simp	if (!ed98_probe_generic8390(sc))
106264777Snyan		return (ENXIO);
106364777Snyan
106464777Snyan	/*
106564777Snyan	 *  Set window ethernet address area
106664777Snyan	 *    board memory base 0x480000  data 256byte
106764777Snyan	 */
106864777Snyan	ed_winsel_CNET98(sc, 0x4800);
106964777Snyan
107064777Snyan	/*
107164777Snyan	 * Get station address from on-board ROM
107264777Snyan	 */
1073149558Simp	bus_space_read_region_1(sc->mem_bst, sc->mem_bsh, sc->mem_start,
1074149558Simp	    sc->enaddr, ETHER_ADDR_LEN);
107564777Snyan
107664777Snyan	sc->vendor    = ED_VENDOR_MISC;
107764777Snyan	sc->type_str  = "CNET98";
107864777Snyan	sc->isa16bit  = 0;
107964777Snyan	sc->cr_proto  = ED_CR_RD2;
108064777Snyan
108164777Snyan	/*
108264777Snyan	 * Set window buffer memory area
108364777Snyan	 *    board memory base 0x400000  data 16kbyte
108464777Snyan	 */
108564777Snyan	ed_winsel_CNET98(sc, 0x4000);
108664777Snyan
1087141550Simp	error = ed_clear_memory(dev);
1088141550Simp	if (error)
1089141550Simp		return (error);
109064777Snyan
109164777Snyan	sc->mem_shared = 1;
109264777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
109364777Snyan
109464777Snyan	sc->txb_cnt = 1;	/* XXX */
109564777Snyan	sc->tx_page_start = 0;
109664777Snyan
109764777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
109864777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
109964777Snyan
110064777Snyan	sc->mem_ring = sc->mem_start + ED_PAGE_SIZE * ED_TXBUF_SIZE;
110164777Snyan
110264777Snyan	/*
110364777Snyan	 *   Set interrupt level
110464777Snyan	 */
1105141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
110664777Snyan	if (error)
110764777Snyan		return (error);
110864777Snyan
110964777Snyan	switch (conf_irq) {
111064777Snyan	case 3:
111164777Snyan		tmp = ED_CNET98_INT_IRQ3;
111264777Snyan		break;
111364777Snyan	case 5:
111464777Snyan		tmp = ED_CNET98_INT_IRQ5;
111564777Snyan		break;
111664777Snyan	case 6:
111764777Snyan		tmp = ED_CNET98_INT_IRQ6;
111864777Snyan		break;
111964777Snyan	case 9:
112064777Snyan		tmp = ED_CNET98_INT_IRQ9;
112164777Snyan		break;
112264777Snyan	case 12:
112364777Snyan		tmp = ED_CNET98_INT_IRQ12;
112464777Snyan		break;
112564777Snyan	case 13:
112664777Snyan		tmp = ED_CNET98_INT_IRQ13;
112764777Snyan		break;
112864777Snyan	default:
112964777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
113064777Snyan			"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
113164777Snyan		return (ENXIO);
113264777Snyan	}
113364777Snyan	ed_asic_outb(sc, ED_CNET98_INT_LEV, tmp);
113464777Snyan	DELAY(1000);
113564777Snyan	/*
113664777Snyan	 *   Set interrupt mask.
113764777Snyan	 *     bit7:1 all interrupt mask
113864777Snyan	 *     bit1:1 timer interrupt mask
113964777Snyan	 *     bit0:0 NS controler interrupt enable
114064777Snyan	 */
114164777Snyan	ed_asic_outb(sc, ED_CNET98_INT_MASK, 0x7e);
114264777Snyan	DELAY(1000);
114364777Snyan
1144154924Simp	sc->sc_write_mbufs = ed_shmem_write_mbufs;
114564777Snyan	return (0);
114664777Snyan}
114764777Snyan
114864777Snyan/*
114964777Snyan * Probe and vendor-specific initialization routine for C-NET(98)E/L boards
115064777Snyan */
115164777Snyanstatic int
1152141550Simped_probe_CNET98EL(device_t dev, int port_rid, int flags)
115364777Snyan{
115464777Snyan	struct ed_softc *sc = device_get_softc(dev);
115564777Snyan	int error;
115664777Snyan	int i;
115764777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
115864777Snyan	u_long conf_irq, junk;
115964777Snyan
116064777Snyan	error = ed98_alloc_port(dev, port_rid);
1161141552Simp	if (error)
116264777Snyan		return (error);
116364777Snyan
116464777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
116564777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
116664777Snyan
116764777Snyan	/* Check I/O address. 0x[0-f]3d0 are allowed. */
116864777Snyan	if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
116964777Snyan#ifdef DIAGNOSTIC
1170111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
117164777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
117264777Snyan			"0x?3d0", "CNET98E/L");
117364777Snyan#endif
117464777Snyan		return (ENXIO);
117564777Snyan	}
117664777Snyan
117764777Snyan	/* Reset the board */
117864777Snyan	ed_reset_CNET98(sc, flags);
117964777Snyan
118064777Snyan	/*
118164777Snyan	 * This is needed because some NE clones apparently don't reset the
118264777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
118364777Snyan	 * - this makes the probe invasive! ...Done against my better
118464777Snyan	 * judgement. -DLG
118564777Snyan	 */
118664777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
118764777Snyan	DELAY(5000);
118864777Snyan
118964777Snyan	/* Make sure that we really have an 8390 based board */
1190141552Simp	if (!ed98_probe_generic8390(sc))
119164777Snyan		return (ENXIO);
119264777Snyan
119364777Snyan	/* Test memory via PIO */
119464777Snyan	sc->cr_proto = ED_CR_RD2;
1195141552Simp	if (!ed_pio_testmem(sc, ED_CNET98EL_PAGE_OFFSET, 1, flags))
119664777Snyan		return (ENXIO);
119764777Snyan
119864777Snyan	/* This looks like a C-NET(98)E/L board. */
119964777Snyan	sc->type_str = "CNET98E/L";
120064777Snyan
120164777Snyan	/*
120264777Snyan	 * Set IRQ. C-NET(98)E/L only allows a choice of irq 3,5,6.
120364777Snyan	 */
1204141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1205141552Simp	if (error)
120664777Snyan		return (error);
120764777Snyan
120864777Snyan	switch (conf_irq) {
120964777Snyan	case 3:
121064777Snyan		tmp = ED_CNET98EL_ICR_IRQ3;
121164777Snyan		break;
121264777Snyan	case 5:
121364777Snyan		tmp = ED_CNET98EL_ICR_IRQ5;
121464777Snyan		break;
121564777Snyan	case 6:
121664777Snyan		tmp = ED_CNET98EL_ICR_IRQ6;
121764777Snyan		break;
121864777Snyan#if 0
121964777Snyan	case 12:
122064777Snyan		tmp = ED_CNET98EL_ICR_IRQ12;
122164777Snyan		break;
122264777Snyan#endif
122364777Snyan	default:
122464777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
122564777Snyan			"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
122664777Snyan		return (ENXIO);
122764777Snyan	}
122864777Snyan	ed_asic_outb(sc, ED_CNET98EL_ICR, tmp);
122964777Snyan	ed_asic_outb(sc, ED_CNET98EL_IMR, 0x7e);
123064777Snyan
123164777Snyan	/* Get station address from on-board ROM */
123264777Snyan	ed_pio_readmem(sc, 16384, romdata, sizeof(romdata));
1233141552Simp	for (i = 0; i < ETHER_ADDR_LEN; i++)
1234147256Sbrooks		sc->enaddr[i] = romdata[i * 2];
123564777Snyan
123664777Snyan	/* clear any pending interrupts that might have occurred above */
123764777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
123864777Snyan
1239154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
124064777Snyan	return (0);
124164777Snyan}
124264777Snyan
124364777Snyan/*
124464777Snyan * Probe and vendor-specific initialization routine for PC-9801-77 boards
124564777Snyan */
124664777Snyanstatic int
1247141550Simped_probe_NEC77(device_t dev, int port_rid, int flags)
124864777Snyan{
124964777Snyan	struct ed_softc *sc = device_get_softc(dev);
125064777Snyan	int error;
125164777Snyan	u_char tmp;
125264777Snyan	u_long conf_irq, junk;
125364777Snyan
125464777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1255141552Simp	if (error)
125664777Snyan		return (error);
125764777Snyan
125864777Snyan	/* LA/T-98 does not need IRQ setting. */
1259141552Simp	if (ED_TYPE98SUB(flags) == 0)
126064777Snyan		return (0);
126164777Snyan
126264777Snyan	/*
126364777Snyan	 * Set IRQ. PC-9801-77 only allows a choice of irq 3,5,6,12,13.
126464777Snyan	 */
1265141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1266141552Simp	if (error)
126764777Snyan		return (error);
126864777Snyan
126964777Snyan	switch (conf_irq) {
127064777Snyan	case 3:
127164777Snyan		tmp = ED_NEC77_IRQ3;
127264777Snyan		break;
127364777Snyan	case 5:
127464777Snyan		tmp = ED_NEC77_IRQ5;
127564777Snyan		break;
127664777Snyan	case 6:
127764777Snyan		tmp = ED_NEC77_IRQ6;
127864777Snyan		break;
127964777Snyan	case 12:
128064777Snyan		tmp = ED_NEC77_IRQ12;
128164777Snyan		break;
128264777Snyan	case 13:
128364777Snyan		tmp = ED_NEC77_IRQ13;
128464777Snyan		break;
128564777Snyan	default:
128664777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
128764777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
128864777Snyan		return (ENXIO);
128964777Snyan	}
129064777Snyan	ed_asic_outb(sc, ED_NEC77_IRQ, tmp);
129164777Snyan
129264777Snyan	return (0);
129364777Snyan}
129464777Snyan
129564777Snyan/*
129664777Snyan * Probe and vendor-specific initialization routine for EC/EP-98X boards
129764777Snyan */
129864777Snyanstatic int
1299141550Simped_probe_NW98X(device_t dev, int port_rid, int flags)
130064777Snyan{
130164777Snyan	struct ed_softc *sc = device_get_softc(dev);
130264777Snyan	int error;
130364777Snyan	u_char tmp;
130464777Snyan	u_long conf_irq, junk;
130564777Snyan
130664777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
1307141552Simp	if (error)
130864777Snyan		return (error);
130964777Snyan
131064777Snyan	/* Networld 98X3 does not need IRQ setting. */
1311141552Simp	if (ED_TYPE98SUB(flags) == 0)
131264777Snyan		return (0);
131364777Snyan
131464777Snyan	/*
131564777Snyan	 * Set IRQ. EC/EP-98X only allows a choice of irq 3,5,6,12,13.
131664777Snyan	 */
1317141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1318141552Simp	if (error)
131964777Snyan		return (error);
132064777Snyan
132164777Snyan	switch (conf_irq) {
132264777Snyan	case 3:
132364777Snyan		tmp = ED_NW98X_IRQ3;
132464777Snyan		break;
132564777Snyan	case 5:
132664777Snyan		tmp = ED_NW98X_IRQ5;
132764777Snyan		break;
132864777Snyan	case 6:
132964777Snyan		tmp = ED_NW98X_IRQ6;
133064777Snyan		break;
133164777Snyan	case 12:
133264777Snyan		tmp = ED_NW98X_IRQ12;
133364777Snyan		break;
133464777Snyan	case 13:
133564777Snyan		tmp = ED_NW98X_IRQ13;
133664777Snyan		break;
133764777Snyan	default:
133864777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
133964777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
134064777Snyan		return (ENXIO);
134164777Snyan	}
134264777Snyan	ed_asic_outb(sc, ED_NW98X_IRQ, tmp);
134364777Snyan
134464777Snyan	return (0);
134564777Snyan}
134664777Snyan
134764777Snyan/*
134864777Snyan * Read SB-9801 station address from Serial Two-Wire EEPROM
134964777Snyan */
135064777Snyanstatic void
1351141550Simped_get_SB98(struct ed_softc *sc)
135264777Snyan{
135364777Snyan	int i, j;
135464777Snyan	u_char mask, val;
135564777Snyan
135664777Snyan        /* enable EEPROM acceess */
135764777Snyan        ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_ENABLE);
135864777Snyan
135964777Snyan	/* output start command */
136064777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
136164777Snyan	DELAY(ED_SB98_EEP_DELAY);
136264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
136364777Snyan	DELAY(ED_SB98_EEP_DELAY);
136464777Snyan
136564777Snyan       	/* output address (7bit) */
136664777Snyan	for (mask = 0x40; mask != 0; mask >>= 1) {
136764777Snyan		val = 0;
136864777Snyan		if (ED_SB98_ADDRESS & mask)
136964777Snyan			val = ED_SB98_EEP_SDA;
137064777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val);
137164777Snyan		DELAY(ED_SB98_EEP_DELAY);
137264777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val | ED_SB98_EEP_SCL);
137364777Snyan		DELAY(ED_SB98_EEP_DELAY);
137464777Snyan	}
137564777Snyan
137664777Snyan	/* output READ command */
137764777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ);
137864777Snyan	DELAY(ED_SB98_EEP_DELAY);
137964777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ | ED_SB98_EEP_SCL);
138064777Snyan	DELAY(ED_SB98_EEP_DELAY);
138164777Snyan
138264777Snyan	/* read station address */
138364777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
138464777Snyan		/* output ACK */
138564777Snyan		ed_asic_outb(sc, ED_SB98_EEP, 0);
138664777Snyan		DELAY(ED_SB98_EEP_DELAY);
138764777Snyan		ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
138864777Snyan		DELAY(ED_SB98_EEP_DELAY);
138964777Snyan
139064777Snyan		val = 0;
139164777Snyan		for (j = 0; j < 8; j++) {
139264777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
139364777Snyan			DELAY(ED_SB98_EEP_DELAY);
139464777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
139564777Snyan			DELAY(ED_SB98_EEP_DELAY);
139664777Snyan			val <<= 1;
139764777Snyan			val |= (ed_asic_inb(sc, ED_SB98_EEP) & ED_SB98_EEP_SDA);
139864777Snyan			DELAY(ED_SB98_EEP_DELAY);
139964777Snyan	  	}
1400147256Sbrooks		sc->enaddr[i] = val;
140164777Snyan	}
140264777Snyan
140364777Snyan	/* output Last ACK */
140464777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
140564777Snyan        DELAY(ED_SB98_EEP_DELAY);
140664777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
140764777Snyan        DELAY(ED_SB98_EEP_DELAY);
140864777Snyan
140964777Snyan	/* output stop command */
141064777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
141164777Snyan	DELAY(ED_SB98_EEP_DELAY);
141264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
141364777Snyan	DELAY(ED_SB98_EEP_DELAY);
141464777Snyan
141564777Snyan	/* disable EEPROM access */
141664777Snyan	ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_DISABLE);
141764777Snyan}
141864777Snyan
141964777Snyan/*
142064777Snyan * Probe and vendor-specific initialization routine for SB-9801 boards
142164777Snyan */
142264777Snyanstatic int
1423141550Simped_probe_SB98(device_t dev, int port_rid, int flags)
142464777Snyan{
142564777Snyan	struct ed_softc *sc = device_get_softc(dev);
142664777Snyan	int error;
142764777Snyan	u_char tmp;
142864777Snyan	u_long conf_irq, junk;
142964777Snyan
143064777Snyan	error = ed98_alloc_port(dev, port_rid);
1431141552Simp	if (error)
143264777Snyan		return (error);
143364777Snyan
143464777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
143564777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
143664777Snyan
143764777Snyan	/* Check I/O address. 00d[02468ace] are allowed. */
143864777Snyan	if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
143964777Snyan#ifdef DIAGNOSTIC
1440111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
1441141552Simp		    "must be %s for %s\n", rman_get_start(sc->port_res),
1442141552Simp		    "0xd?", "SB9801");
144364777Snyan#endif
144464777Snyan		return (ENXIO);
144564777Snyan	}
144664777Snyan
144764777Snyan	/* Write I/O port address and read 4 times */
144864777Snyan	outb(ED_SB98_IO_INHIBIT, rman_get_start(sc->port_res) & 0xff);
144964777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145064777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145164777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145264777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
145364777Snyan
145464777Snyan	/*
145564777Snyan	 * Check IRQ. Soliton SB-9801 only allows a choice of
145664777Snyan	 * irq 3,5,6,12
145764777Snyan	 */
1458141552Simp	error = bus_get_resource(dev, SYS_RES_IRQ, 0, &conf_irq, &junk);
1459141552Simp	if (error)
146064777Snyan		return (error);
146164777Snyan
146264777Snyan	switch (conf_irq) {
146364777Snyan	case 3:
146464777Snyan		tmp = ED_SB98_CFG_IRQ3;
146564777Snyan		break;
146664777Snyan	case 5:
146764777Snyan		tmp = ED_SB98_CFG_IRQ5;
146864777Snyan		break;
146964777Snyan	case 6:
147064777Snyan		tmp = ED_SB98_CFG_IRQ6;
147164777Snyan		break;
147264777Snyan	case 12:
147364777Snyan		tmp = ED_SB98_CFG_IRQ12;
147464777Snyan		break;
147564777Snyan	default:
147664777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
147764777Snyan			"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
147864777Snyan		return (ENXIO);
147964777Snyan	}
148064777Snyan
1481141552Simp	if (flags & ED_FLAGS_DISABLE_TRANCEIVER)
148264777Snyan		tmp |= ED_SB98_CFG_ALTPORT;
148364777Snyan	ed_asic_outb(sc, ED_SB98_CFG, ED_SB98_CFG_ENABLE | tmp);
148464777Snyan	ed_asic_outb(sc, ED_SB98_POLARITY, 0x01);
148564777Snyan
148664777Snyan	/* Reset the board. */
148764777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x7a);
148864777Snyan	DELAY(300);
148964777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x79);
149064777Snyan	DELAY(300);
149164777Snyan
149264777Snyan	/*
149364777Snyan	 * This is needed because some NE clones apparently don't reset the
149464777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
149564777Snyan	 * - this makes the probe invasive! ...Done against my better
149664777Snyan	 * judgement. -DLG
149764777Snyan	 */
149864777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
149964777Snyan	DELAY(5000);
150064777Snyan
150164777Snyan	/* Make sure that we really have an 8390 based board */
1502141552Simp	if (!ed98_probe_generic8390(sc))
150364777Snyan		return (ENXIO);
150464777Snyan
150564777Snyan	/* Test memory via PIO */
150664777Snyan	sc->cr_proto = ED_CR_RD2;
1507154924Simp	if (!ed_pio_testmem(sc, 16384, 1, flags))
150864777Snyan		return (ENXIO);
150964777Snyan
151064777Snyan	/* This looks like an SB9801 board. */
151164777Snyan	sc->type_str = "SB9801";
151264777Snyan
151364777Snyan	/* Get station address */
151464777Snyan	ed_get_SB98(sc);
151564777Snyan
151664777Snyan	/* clear any pending interrupts that might have occurred above */
151764777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
151864777Snyan
1519154924Simp	sc->sc_write_mbufs = ed_pio_write_mbufs;
152064777Snyan	return (0);
152164777Snyan}
152264777Snyan
152364777Snyan/*
152464777Snyan * Test the ability to read and write to the NIC memory.
152564777Snyan */
152664777Snyanstatic int
1527141550Simped_pio_testmem(struct ed_softc *sc, int page_offset, int isa16bit, int flags)
152864777Snyan{
152964777Snyan	u_long memsize;
153064777Snyan	static char test_pattern[32] = "THIS is A memory TEST pattern";
153164777Snyan	char test_buffer[32];
153264777Snyan#ifdef DIAGNOSTIC
153364777Snyan	int page_end;
153464777Snyan#endif
153564777Snyan
153664777Snyan	sc->vendor = ED_VENDOR_NOVELL;
153764777Snyan	sc->mem_shared = 0;
153864777Snyan	sc->isa16bit = isa16bit;
153964777Snyan
154064777Snyan	/* 8k of memory plus an additional 8k if 16bit */
154164777Snyan	memsize = (isa16bit ? 16384 : 8192);
154264777Snyan
154364777Snyan	/*
154464777Snyan	 * This prevents packets from being stored in the NIC memory when the
154564777Snyan	 * readmem routine turns on the start bit in the CR.
154664777Snyan	 */
154764777Snyan	ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON);
154864777Snyan
154964777Snyan	/* Initialize DCR for byte/word operations */
1550141550Simp	if (isa16bit)
155164777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
1552141550Simp	else
155364777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
155464777Snyan	ed_nic_outb(sc, ED_P0_PSTART, page_offset / ED_PAGE_SIZE);
155564777Snyan	ed_nic_outb(sc, ED_P0_PSTOP, (page_offset + memsize) / ED_PAGE_SIZE);
155664777Snyan#ifdef ED_DEBUG
1557137531Snyan	printf("ed?: ed_pio_testmem: page start=%x, end=%lx",
1558141552Simp	    page_offset, page_offset + memsize);
155964777Snyan#endif
156064777Snyan
156164777Snyan	/*
156264777Snyan	 * Write a test pattern. If this fails, then we don't know
156364777Snyan	 * what this board is.
156464777Snyan	 */
156564777Snyan	ed_pio_writemem(sc, test_pattern, page_offset, sizeof(test_pattern));
156664777Snyan	ed_pio_readmem(sc, page_offset, test_buffer, sizeof(test_pattern));
156764777Snyan
156864777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
156964777Snyan#ifdef ED_DEBUG
1570141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_offset);
157164777Snyan#endif
157264777Snyan		return (0);
157364777Snyan	}
157464777Snyan
157564777Snyan#ifdef DIAGNOSTIC
157664777Snyan	/* Check the bottom. */
157764777Snyan	page_end = page_offset + memsize - ED_PAGE_SIZE;
157864777Snyan	ed_pio_writemem(sc, test_pattern, page_end, sizeof(test_pattern));
157964777Snyan	ed_pio_readmem(sc, page_end, test_buffer, sizeof(test_pattern));
158064777Snyan
158164777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
158264777Snyan#ifdef ED_DEBUG
1583141552Simp		printf("ed?: ed_pio_testmem: bcmp(page %x) NG", page_end);
158464777Snyan#endif
158564777Snyan		return (0);
158664777Snyan	}
158764777Snyan#endif
158864777Snyan	sc->mem_size = memsize;
1589149558Simp	sc->mem_start = page_offset;
159064777Snyan	sc->mem_end   = sc->mem_start + memsize;
159164777Snyan	sc->tx_page_start = page_offset / ED_PAGE_SIZE;
159264777Snyan
159364777Snyan	/*
159464777Snyan	 * Use one xmit buffer if < 16k, two buffers otherwise (if not told
159564777Snyan	 * otherwise).
159664777Snyan	 */
1597141552Simp	if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING))
159864777Snyan		sc->txb_cnt = 1;
1599141552Simp	else
160064777Snyan		sc->txb_cnt = 2;
160164777Snyan
160264777Snyan	sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
160364777Snyan	sc->rec_page_stop  = sc->tx_page_start + memsize / ED_PAGE_SIZE;
160464777Snyan
160564777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
160664777Snyan
160764777Snyan	return (1);
160864777Snyan}
160970355Simp
1610141550Simpstatic device_method_t ed_cbus_methods[] = {
161170355Simp	/* Device interface */
1612141550Simp	DEVMETHOD(device_probe,		ed_cbus_probe),
1613141550Simp	DEVMETHOD(device_attach,	ed_cbus_attach),
1614150136Sru	DEVMETHOD(device_detach,	ed_detach),
161570355Simp
161670355Simp	{ 0, 0 }
161770355Simp};
161870355Simp
1619141550Simpstatic driver_t ed_cbus_driver = {
162070355Simp	"ed",
1621141550Simp	ed_cbus_methods,
162270355Simp	sizeof(struct ed_softc)
162370355Simp};
162470355Simp
1625141550SimpDRIVER_MODULE(ed, isa, ed_cbus_driver, ed_devclass, 0, 0);
1626113506SmdoddMODULE_DEPEND(ed, isa, 1, 1, 1);
1627113506SmdoddMODULE_DEPEND(ed, ether, 1, 1, 1);
1628