if_ed_cbus.c revision 113506
164777Snyan/*
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 113506 2003-04-15 06:37:30Z mdodd $
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#ifdef PC98
3964777Snyan#include <sys/rman.h>
4064777Snyan#include <machine/resource.h>
4164777Snyan#include <machine/clock.h>
4264777Snyan#include <machine/md_var.h>
4364777Snyan#endif
4464777Snyan
4564777Snyan#include <net/ethernet.h>
4664777Snyan#include <net/if.h>
4764777Snyan#include <net/if_arp.h>
4864777Snyan#include <net/if_mib.h>
4964777Snyan
5064777Snyan#include <isa/isavar.h>
5164777Snyan
5264777Snyan#include <dev/ed/if_edvar.h>
5364777Snyan#ifdef PC98
5464777Snyan#include <dev/ed/if_edreg.h>
5564777Snyan#include <dev/ed/if_ed98.h>
5664777Snyan
5792739Salfredstatic int ed98_alloc_port	(device_t, int);
5892739Salfredstatic int ed98_alloc_memory	(device_t, int);
5992739Salfredstatic int ed_pio_testmem	(struct ed_softc *, int, int, int);
6092739Salfredstatic int ed_probe_SIC98	(device_t, int, int);
6192739Salfredstatic int ed_probe_CNET98	(device_t, int, int);
6292739Salfredstatic int ed_probe_CNET98EL	(device_t, int, int);
6392739Salfredstatic int ed_probe_NEC77	(device_t, int, int);
6492739Salfredstatic int ed_probe_NW98X	(device_t, int, int);
6592739Salfredstatic int ed_probe_SB98	(device_t, int, int);
6692739Salfredstatic int ed_probe_EZ98	(device_t, int, int);
6792739Salfredstatic int ed98_probe_Novell	(device_t, int, int);
6892739Salfredstatic int ed98_probe_generic8390	(struct ed_softc *);
6992739Salfredstatic void ed_reset_CNET98	(struct ed_softc *, int);
7092739Salfredstatic void ed_winsel_CNET98	(struct ed_softc *, u_short);
7192739Salfredstatic void ed_get_SB98		(struct ed_softc *);
7264777Snyan#endif
7364777Snyan
7492739Salfredstatic int ed_isa_probe		(device_t);
7592739Salfredstatic int ed_isa_attach	(device_t);
7664777Snyan
7764777Snyanstatic struct isa_pnp_id ed_ids[] = {
7864777Snyan#ifdef PC98
7964777Snyan/* TODO - list up PnP boards for PC-98 */
8064777Snyan	{ 0,		NULL }
8164777Snyan#endif
8264777Snyan};
8364777Snyan
8464777Snyanstatic int
8564777Snyaned_isa_probe(dev)
8664777Snyan	device_t dev;
8764777Snyan{
8864777Snyan	struct ed_softc *sc = device_get_softc(dev);
8964777Snyan	int flags = device_get_flags(dev);
9064777Snyan	int error = 0;
9164777Snyan
9264777Snyan	bzero(sc, sizeof(struct ed_softc));
9364777Snyan#ifdef PC98
9464777Snyan	sc->type = ED_TYPE98(flags);
9564777Snyan#ifdef ED_DEBUG
9664777Snyan	device_printf(dev, "ed_isa_probe: sc->type=%x\n", sc->type);
9764777Snyan#endif
9864777Snyan#endif
9964777Snyan
10064777Snyan	/* Check isapnp ids */
10164777Snyan	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ed_ids);
10264777Snyan#ifdef ED_DEBUG
10364777Snyan	device_printf(dev, "ed_isa_probe: ISA_PNP_PROBE returns %d\n", error);
10464777Snyan#endif
10564777Snyan
10664777Snyan	/* If the card had a PnP ID that didn't match any we know about */
10764777Snyan	if (error == ENXIO) {
10864777Snyan		goto end;
10964777Snyan	}
11064777Snyan
11164777Snyan	/* If we had some other problem. */
11264777Snyan	if (!(error == 0 || error == ENOENT)) {
11364777Snyan		goto end;
11464777Snyan	}
11564777Snyan
11664777Snyan	/* Heuristic probes */
11764777Snyan#ifdef ED_DEBUG
11864777Snyan	device_printf(dev, "ed_isa_probe: Heuristic probes start\n");
11964777Snyan#endif
12064777Snyan#ifdef PC98
12164777Snyan	switch (sc->type) {
12264777Snyan	case ED_TYPE98_GENERIC:
12364777Snyan		/*
12464777Snyan		 * CAUTION!
12564777Snyan		 * sc->type of these boards are overwritten by PC/AT's value.
12664777Snyan		 */
12764777Snyan
12864777Snyan		/*
12964777Snyan		 * SMC EtherEZ98
13064777Snyan		 */
13164777Snyan		error = ed_probe_EZ98(dev, 0, flags);
13264777Snyan		if (error == 0) {
13364777Snyan			goto end;
13464777Snyan		}
13564777Snyan
13664777Snyan		ed_release_resources(dev);
13764777Snyan
13864777Snyan		/*
13964777Snyan		 * Allied Telesis CenterCom LA-98-T
14064777Snyan		 */
14164777Snyan		error = ed_probe_Novell(dev, 0, flags);
14264777Snyan		if (error == 0) {
14364777Snyan			goto end;
14464777Snyan		}
14564777Snyan
14664777Snyan		break;
14764777Snyan
14864777Snyan	/*
14964777Snyan	 * NE2000-like boards probe routine
15064777Snyan	 */
15164777Snyan	case ED_TYPE98_BDN:
15264777Snyan		/*
15364777Snyan		 * ELECOM LANEED LD-BDN
15464777Snyan		 * PLANET SMART COM 98 EN-2298
15564777Snyan		 */
15664777Snyan	case ED_TYPE98_LGY:
15764777Snyan		/*
15864777Snyan		 * MELCO LGY-98, IND-SP, IND-SS
15964777Snyan		 * MACNICA NE2098
16064777Snyan		 */
16164777Snyan	case ED_TYPE98_ICM:
16264777Snyan		/*
16364777Snyan		 * ICM DT-ET-25, DT-ET-T5, IF-2766ET, IF-2771ET
16464777Snyan		 * D-Link DE-298P, DE-298
16564777Snyan		 */
16664777Snyan	case ED_TYPE98_EGY:
16764777Snyan		/*
16864777Snyan		 * MELCO EGY-98
16964777Snyan		 * Contec C-NET(98)E-A, C-NET(98)L-A
17064777Snyan		 */
17164777Snyan	case ED_TYPE98_108:
17264777Snyan		/*
17364777Snyan		 * NEC PC-9801-107,108
17464777Snyan		 */
17564777Snyan	case ED_TYPE98_NC5098:
17664777Snyan		/*
17764777Snyan		 * NextCom NC5098
17864777Snyan		 */
17964777Snyan
18064777Snyan		error = ed98_probe_Novell(dev, 0, flags);
18164777Snyan
18264777Snyan		break;
18364777Snyan
18464777Snyan	/*
18564777Snyan	 * other boards with special probe routine
18664777Snyan	 */
18764777Snyan	case ED_TYPE98_SIC:
18864777Snyan		/*
18964777Snyan		 * Allied Telesis SIC-98
19064777Snyan		 */
19164777Snyan		error = ed_probe_SIC98(dev, 0, flags);
19264777Snyan
19364777Snyan		break;
19464777Snyan
19564777Snyan	case ED_TYPE98_CNET98EL:
19664777Snyan		/*
19764777Snyan		 * Contec C-NET(98)E/L
19864777Snyan		 */
19964777Snyan		error = ed_probe_CNET98EL(dev, 0, flags);
20064777Snyan
20164777Snyan		break;
20264777Snyan
20364777Snyan	case ED_TYPE98_CNET98:
20464777Snyan		/*
20564777Snyan		 * Contec C-NET(98)
20664777Snyan		 */
20764777Snyan		error = ed_probe_CNET98(dev, 0, flags);
20864777Snyan
20964777Snyan		break;
21064777Snyan
21164777Snyan	case ED_TYPE98_LA98:
21264777Snyan		/*
21364777Snyan		 * IO-DATA LA/T-98
21464777Snyan		 * NEC PC-9801-77,78
21564777Snyan		 */
21664777Snyan		error = ed_probe_NEC77(dev, 0, flags);
21764777Snyan
21864777Snyan		break;
21964777Snyan
22064777Snyan	case ED_TYPE98_NW98X:
22164777Snyan		/*
22264777Snyan		 * Networld EC/EP-98X
22364777Snyan		 */
22464777Snyan		error = ed_probe_NW98X(dev, 0, flags);
22564777Snyan
22664777Snyan		break;
22764777Snyan
22864777Snyan	case ED_TYPE98_SB98:
22964777Snyan		/*
23064777Snyan		 * Soliton SB-9801
23164777Snyan		 * Fujikura FN-9801
23264777Snyan		 */
23364777Snyan
23464777Snyan		error = ed_probe_SB98(dev, 0, flags);
23564777Snyan
23664777Snyan		break;
23764777Snyan	}
23864777Snyan#endif
23964777Snyan
24064777Snyanend:
24164777Snyan#ifdef ED_DEBUG
24264777Snyan	device_printf(dev, "ed_isa_probe: end, error=%d\n", error);
24364777Snyan#endif
24464777Snyan	if (error == 0)
24564777Snyan		error = ed_alloc_irq(dev, 0, 0);
24664777Snyan
24764777Snyan	ed_release_resources(dev);
24864777Snyan	return (error);
24964777Snyan}
25064777Snyan
25164777Snyanstatic int
25264777Snyaned_isa_attach(dev)
25364777Snyan	device_t dev;
25464777Snyan{
25564777Snyan	struct ed_softc *sc = device_get_softc(dev);
25664777Snyan	int flags = device_get_flags(dev);
25764777Snyan	int error;
25864777Snyan
25964777Snyan	if (sc->port_used > 0) {
26064777Snyan#ifdef PC98
26164777Snyan		if (ED_TYPE98(flags) == ED_TYPE98_GENERIC) {
26264777Snyan			ed_alloc_port(dev, sc->port_rid, sc->port_used);
26364777Snyan		} else {
26464777Snyan			ed98_alloc_port(dev, sc->port_rid);
26564777Snyan		}
26664777Snyan#endif
26764777Snyan	}
26864777Snyan	if (sc->mem_used)
26964777Snyan		ed_alloc_memory(dev, sc->mem_rid, sc->mem_used);
27064777Snyan
27164777Snyan	ed_alloc_irq(dev, sc->irq_rid, 0);
27264777Snyan
27364777Snyan	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
27464777Snyan			       edintr, sc, &sc->irq_handle);
27564777Snyan	if (error) {
27664777Snyan		ed_release_resources(dev);
27764777Snyan		return (error);
27864777Snyan	}
27964777Snyan
28064777Snyan	return ed_attach(sc, device_get_unit(dev), flags);
28164777Snyan}
28264777Snyan
28364777Snyan#ifdef PC98
28464777Snyan/*
28564777Snyan * Interrupt conversion table for EtherEZ98
28664777Snyan */
28764777Snyanstatic unsigned short ed_EZ98_intr_val[] = {
28864777Snyan	0,
28964777Snyan	3,
29064777Snyan	5,
29164777Snyan	6,
29264777Snyan	0,
29364777Snyan	9,
29464777Snyan	12,
29564777Snyan	13
29664777Snyan};
29764777Snyan
29864777Snyanstatic int
29964777Snyaned_probe_EZ98(dev, port_rid, flags)
30064777Snyan	device_t dev;
30164777Snyan	int port_rid;
30264777Snyan	int flags;
30364777Snyan{
30464777Snyan	struct ed_softc *sc = device_get_softc(dev);
30564777Snyan	int error;
30664777Snyan	static unsigned short *intr_vals[] = {NULL, ed_EZ98_intr_val};
30764777Snyan
30864777Snyan	error = ed_alloc_port(dev, port_rid, ED_EZ98_IO_PORTS);
30964777Snyan	if (error) {
31064777Snyan		return (error);
31164777Snyan	}
31264777Snyan
31364777Snyan	sc->asic_offset = ED_EZ98_ASIC_OFFSET;
31464777Snyan	sc->nic_offset  = ED_EZ98_NIC_OFFSET;
31564777Snyan
31664777Snyan	return ed_probe_WD80x3_generic(dev, flags, intr_vals);
31764777Snyan}
31864777Snyan
31964777Snyan/*
32064777Snyan * I/O conversion tables
32164777Snyan */
32264777Snyan
32364777Snyan/* LGY-98, ICM, C-NET(98)E/L */
32464777Snyanstatic	bus_addr_t ed98_ioaddr_generic[] = {
32564777Snyan	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
32664777Snyan};
32764777Snyan
32864777Snyan/*
32964777Snyan *		Definitions for Contec C-NET(98)E/L
33064777Snyan */
33164777Snyan#define	ED_CNET98EL_ICR         2	/* Interrupt Configuration Register */
33264777Snyan
33364777Snyan#define	ED_CNET98EL_ICR_IRQ3	0x01
33464777Snyan#define	ED_CNET98EL_ICR_IRQ5	0x02
33564777Snyan#define	ED_CNET98EL_ICR_IRQ6	0x04
33664777Snyan#define	ED_CNET98EL_ICR_IRQ12	0x20
33764777Snyan
33864777Snyan#define	ED_CNET98EL_IMR         4	/* Interrupt Mask Register	*/
33964777Snyan#define	ED_CNET98EL_ISR         5	/* Interrupt Status Register	*/
34064777Snyan
34164777Snyan/* EGY-98 */
34264777Snyanstatic	bus_addr_t ed98_ioaddr_egy98[] = {
34364777Snyan	0,     0x02,  0x04,  0x06,  0x08,  0x0a,  0x0c,  0x0e,
34464777Snyan	0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e
34564777Snyan};
34664777Snyan
34764777Snyan/* SIC-98 */
34864777Snyanstatic	bus_addr_t ed98_ioaddr_sic98[] = {
34964777Snyan	0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00,
35064777Snyan	0x1000, 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00
35164777Snyan};
35264777Snyan
35364777Snyan/* LA/T-98, LD-BDN, PC-9801-77, SB-9801 */
35464777Snyanstatic	bus_addr_t ed98_ioaddr_la98[] = {
35564777Snyan	0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000,
35664777Snyan	0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000,
35764777Snyan	0x0100	/* for NEC 77(see below) */
35864777Snyan};
35964777Snyan
36064777Snyan/*
36164777Snyan *		Definitions for NEC PC-9801-77
36264777Snyan */
36364777Snyan#define	ED_NEC77_IRQ		16	/* Interrupt Configuration Register */
36464777Snyan
36564777Snyan#define	ED_NEC77_IRQ3		0x04
36664777Snyan#define	ED_NEC77_IRQ5		0x06
36764777Snyan#define	ED_NEC77_IRQ6		0x08
36864777Snyan#define	ED_NEC77_IRQ12		0x0a
36964777Snyan#define	ED_NEC77_IRQ13		0x02
37064777Snyan
37164777Snyan/*
37264777Snyan *		Definitions for Soliton SB-9801
37364777Snyan */
37464777Snyan#define	ED_SB98_CFG		1	/* Board configuration		*/
37564777Snyan
37664777Snyan#define	ED_SB98_CFG_IRQ3	0x00
37764777Snyan#define	ED_SB98_CFG_IRQ5	0x04
37864777Snyan#define	ED_SB98_CFG_IRQ6	0x08
37964777Snyan#define	ED_SB98_CFG_IRQ12	0x0c
38064777Snyan#define	ED_SB98_CFG_ALTPORT	0x40		/* use EXTERNAL media	*/
38164777Snyan#define	ED_SB98_CFG_ENABLE	0xa0		/* enable configuration	*/
38264777Snyan
38364777Snyan#define	ED_SB98_EEPENA		2	/* EEPROM access enable		*/
38464777Snyan
38564777Snyan#define	ED_SB98_EEPENA_DISABLE	0x00
38664777Snyan#define	ED_SB98_EEPENA_ENABLE	0x01
38764777Snyan
38864777Snyan#define	ED_SB98_EEP		3	/* EEPROM access		*/
38964777Snyan
39064777Snyan#define	ED_SB98_EEP_SDA		0x01		/* Serial Data	*/
39164777Snyan#define	ED_SB98_EEP_SCL		0x02		/* Serial Clock	*/
39264777Snyan#define	ED_SB98_EEP_READ	0x01		/* Read Command	*/
39364777Snyan
39464777Snyan#define	ED_SB98_EEP_DELAY	300
39564777Snyan
39664777Snyan#define	ED_SB98_ADDRESS		0x01		/* Station Address(1-6)	*/
39764777Snyan
39864777Snyan#define	ED_SB98_POLARITY	4	/* Polarity			*/
39964777Snyan
40064777Snyan/* PC-9801-108 */
40164777Snyanstatic	bus_addr_t ed98_ioaddr_nec108[] = {
40264777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
40364777Snyan	0x1000, 0x1002, 0x1004, 0x1006, 0x1008, 0x100a, 0x100c, 0x100e
40464777Snyan};
40564777Snyan
40664777Snyan/* C-NET(98) */
40764777Snyanstatic	bus_addr_t ed98_ioaddr_cnet98[] = {
40864777Snyan	0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e,
40964777Snyan	0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e
41064777Snyan};
41164777Snyan
41264777Snyan/*
41364777Snyan *		Definitions for Contec C-NET(98)
41464777Snyan */
41564777Snyan#define	ED_CNET98_MAP_REG0L	0	/* MAPPING register0 Low	*/
41664777Snyan#define	ED_CNET98_MAP_REG1L	1	/* MAPPING register1 Low	*/
41764777Snyan#define	ED_CNET98_MAP_REG2L	2	/* MAPPING register2 Low	*/
41864777Snyan#define	ED_CNET98_MAP_REG3L	3	/* MAPPING register3 Low	*/
41964777Snyan#define	ED_CNET98_MAP_REG0H	4	/* MAPPING register0 Hi		*/
42064777Snyan#define	ED_CNET98_MAP_REG1H	5	/* MAPPING register1 Hi		*/
42164777Snyan#define	ED_CNET98_MAP_REG2H	6	/* MAPPING register2 Hi		*/
42264777Snyan#define	ED_CNET98_MAP_REG3H	7	/* MAPPING register3 Hi		*/
42364777Snyan#define	ED_CNET98_WIN_REG	8	/* Window register		*/
42464777Snyan#define	ED_CNET98_INT_LEV	9	/* Init level register		*/
42564777Snyan
42664777Snyan#define	ED_CNET98_INT_IRQ3	0x01		/* INT 0 */
42764777Snyan#define	ED_CNET98_INT_IRQ5	0x02		/* INT 1 */
42864777Snyan#define	ED_CNET98_INT_IRQ6	0x04		/* INT 2 */
42964777Snyan#define	ED_CNET98_INT_IRQ9	0x08		/* INT 3 */
43064777Snyan#define	ED_CNET98_INT_IRQ12	0x20		/* INT 5 */
43164777Snyan#define	ED_CNET98_INT_IRQ13	0x40		/* INT 6 */
43264777Snyan
43364777Snyan#define	ED_CNET98_INT_REQ	10	/* Init request register	*/
43464777Snyan#define	ED_CNET98_INT_MASK	11	/* Init mask register		*/
43564777Snyan#define	ED_CNET98_INT_STAT	12	/* Init status register		*/
43664777Snyan#define	ED_CNET98_INT_CLR	12	/* Init clear register		*/
43764777Snyan#define	ED_CNET98_RESERVE1	13
43864777Snyan#define	ED_CNET98_RESERVE2	14
43964777Snyan#define	ED_CNET98_RESERVE3	15
44064777Snyan
44164777Snyan/* EC/EP-98X, NC5098 */
44264777Snyanstatic	bus_addr_t ed98_ioaddr_nw98x[] = {
44364777Snyan	0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,
44464777Snyan	0x0800, 0x0900, 0x0a00, 0x0b00, 0x0c00, 0x0d00, 0x0e00, 0x0f00,
44564777Snyan	0x1000	/* for EC/EP-98X(see below) */
44664777Snyan};
44764777Snyan
44864777Snyan/*
44964777Snyan *		Definitions for Networld EC/EP-98X
45064777Snyan */
45164777Snyan#define	ED_NW98X_IRQ            16	/* Interrupt Configuration Register */
45264777Snyan
45364777Snyan#define	ED_NW98X_IRQ3           0x04
45464777Snyan#define	ED_NW98X_IRQ5           0x06
45564777Snyan#define	ED_NW98X_IRQ6           0x08
45664777Snyan#define	ED_NW98X_IRQ12          0x0a
45764777Snyan#define	ED_NW98X_IRQ13          0x02
45864777Snyan
45964777Snyan/* NC5098 ASIC */
46064777Snyanstatic bus_addr_t ed98_asic_nc5098[] = {
46164777Snyan/*	DATA    ENADDR						RESET	*/
46264777Snyan	0x0000, 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x4000,
46364777Snyan	     0,      0,      0,      0,      0,      0,      0,      0
46464777Snyan};
46564777Snyan
46664777Snyan/*
46764777Snyan *		Definitions for NextCom NC5098
46864777Snyan */
46964777Snyan#define	ED_NC5098_ENADDR	1	/* Station Address(1-6)		*/
47064777Snyan
47164777Snyan/*
47264777Snyan * Allocate a port resource with the given resource id.
47364777Snyan */
47464777Snyanstatic int
47564777Snyaned98_alloc_port(dev, rid)
47664777Snyan	device_t dev;
47764777Snyan	int rid;
47864777Snyan{
47964777Snyan	struct ed_softc *sc = device_get_softc(dev);
48064777Snyan	struct resource *res;
48164777Snyan	int error;
48264777Snyan	bus_addr_t *io_nic, *io_asic, adj;
48364777Snyan	static bus_addr_t io_res[ED_NOVELL_IO_PORTS + 1];
48464777Snyan	int i, n;
48564777Snyan	int offset, reset, data;
48664777Snyan
48764777Snyan	/* Set i/o table for resource manager */
48864777Snyan	io_nic = io_asic = ed98_ioaddr_generic;
48964777Snyan	offset = ED_NOVELL_ASIC_OFFSET;
49064777Snyan	reset = ED_NOVELL_RESET;
49164777Snyan	data  = ED_NOVELL_DATA;
49264777Snyan	n = ED_NOVELL_IO_PORTS;
49364777Snyan
49464777Snyan	switch (sc->type) {
49564777Snyan	case ED_TYPE98_LGY:
49664777Snyan		io_asic = ed98_ioaddr_egy98; /* XXX - Yes, we use egy98 */
49764777Snyan		offset = 0x0200;
49864777Snyan		reset = 8;
49964777Snyan		break;
50064777Snyan
50164777Snyan	case ED_TYPE98_EGY:
50264777Snyan		io_nic = io_asic = ed98_ioaddr_egy98;
50364777Snyan		offset = 0x0200;
50464777Snyan		reset = 8;
50564777Snyan		break;
50664777Snyan
50764777Snyan	case ED_TYPE98_ICM:
50864777Snyan		offset = 0x0100;
50964777Snyan		break;
51064777Snyan
51164777Snyan	case ED_TYPE98_BDN:
51264777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
51364777Snyan		offset = 0x0100;
51464777Snyan		reset = 0x0c;
51564777Snyan		break;
51664777Snyan
51764777Snyan	case ED_TYPE98_SIC:
51864777Snyan		io_nic = io_asic = ed98_ioaddr_sic98;
51964777Snyan		offset = 0x2000;
52064777Snyan		n = 16+1;
52164777Snyan		break;
52264777Snyan
52364777Snyan	case ED_TYPE98_108:
52464777Snyan		io_nic = io_asic = ed98_ioaddr_nec108;
52564777Snyan		offset = 0x0888;	/* XXX - overwritten after */
52664777Snyan		reset = 1;
52764777Snyan		n = 16;	/* XXX - does not set ASIC i/o here */
52864777Snyan		break;
52964777Snyan
53064777Snyan	case ED_TYPE98_LA98:
53164777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
53264777Snyan		offset = 0x0100;
53364777Snyan		break;
53464777Snyan
53564777Snyan	case ED_TYPE98_CNET98EL:
53664777Snyan		offset = 0x0400;
53764777Snyan		data = 0x0e;
53864777Snyan		break;
53964777Snyan
54064777Snyan	case ED_TYPE98_CNET98:
54164777Snyan		/* XXX - Yes, we use generic i/o here */
54264777Snyan		offset = 0x0400;
54364777Snyan		break;
54464777Snyan
54564777Snyan	case ED_TYPE98_NW98X:
54664777Snyan		io_nic = io_asic = ed98_ioaddr_nw98x;
54764777Snyan		offset = 0x1000;
54864777Snyan		break;
54964777Snyan
55064777Snyan	case ED_TYPE98_SB98:
55164777Snyan		io_nic = io_asic = ed98_ioaddr_la98;
55264777Snyan		offset = 0x0400;
55364777Snyan		reset = 7;
55464777Snyan		break;
55564777Snyan
55664777Snyan	case ED_TYPE98_NC5098:
55764777Snyan		io_nic  = ed98_ioaddr_nw98x;
55864777Snyan		io_asic = ed98_asic_nc5098;
55964777Snyan		offset = 0x2000;
56064777Snyan		reset = 7;
56164777Snyan		n = 16+8;	/* XXX */
56264777Snyan		break;
56364777Snyan	}
56464777Snyan
56564777Snyan	bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
56664777Snyan	for (i = ED_NOVELL_ASIC_OFFSET; i < ED_NOVELL_IO_PORTS; i++) {
56764777Snyan		io_res[i] = io_asic[i - ED_NOVELL_ASIC_OFFSET] + offset;
56864777Snyan	}
56964777Snyan
57064777Snyan	res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
57164777Snyan				  io_res, n, RF_ACTIVE);
57264777Snyan	if (!res) {
57364777Snyan		return (ENOENT);
57464777Snyan	}
57564777Snyan
57664777Snyan	sc->port_rid = rid;
57764777Snyan	sc->port_res = res;
57864777Snyan	sc->port_used = n;
57964777Snyan
58064777Snyan	/* Re-map i/o table if needed */
58164777Snyan	switch (sc->type) {
58264777Snyan	case ED_TYPE98_LA98:
58364777Snyan	case ED_TYPE98_NW98X:
58464777Snyan		io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
58564777Snyan		n++;
58664777Snyan		break;
58764777Snyan
58864777Snyan	case ED_TYPE98_108:
58964777Snyan		adj = (rman_get_start(res) & 0xf000) / 2;
59064777Snyan		offset = (offset | adj) - rman_get_start(res);
59164777Snyan
59264777Snyan		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++) {
59364777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
59464777Snyan		}
59564777Snyan		break;
59664777Snyan
59764777Snyan	case ED_TYPE98_CNET98:
59864777Snyan		io_nic = io_asic = ed98_ioaddr_cnet98;
59964777Snyan		offset = 1;
60064777Snyan
60164777Snyan		bcopy(io_nic, io_res, sizeof(io_nic[0]) * ED_NOVELL_ASIC_OFFSET);
60264777Snyan		for (n = ED_NOVELL_ASIC_OFFSET; n < ED_NOVELL_IO_PORTS; n++) {
60364777Snyan			io_res[n] = io_asic[n - ED_NOVELL_ASIC_OFFSET] + offset;
60464777Snyan		}
60564777Snyan		break;
60664777Snyan
60764777Snyan	case ED_TYPE98_NC5098:
60864777Snyan		n = ED_NOVELL_IO_PORTS;
60964777Snyan		break;
61064777Snyan	}
61164777Snyan
61264777Snyan	if (reset != ED_NOVELL_RESET) {
61364777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_RESET] =
61464777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + reset];
61564777Snyan	}
61664777Snyan	if (data  != ED_NOVELL_DATA) {
61764777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA] =
61864777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data];
61964777Snyan#if 0
62064777Snyan		io_res[ED_NOVELL_ASIC_OFFSET + ED_NOVELL_DATA + 1] =
62164777Snyan			io_res[ED_NOVELL_ASIC_OFFSET + data + 1];
62264777Snyan#endif
62364777Snyan	}
62464777Snyan
62564777Snyan	error = isa_load_resourcev(res, io_res, n);
62664777Snyan	if (error != 0) {
62764777Snyan		return (ENOENT);
62864777Snyan	}
62964777Snyan#ifdef ED_DEBUG
63064777Snyan	device_printf(dev, "ed98_alloc_port: i/o ports = %d\n", n);
63164777Snyan	for (i = 0; i < n; i++) {
63264777Snyan		printf("%x,", io_res[i]);
63364777Snyan	}
63464777Snyan	printf("\n");
63564777Snyan#endif
63664777Snyan	return (0);
63764777Snyan}
63864777Snyan
63964777Snyanstatic int
64064777Snyaned98_alloc_memory(dev, rid)
64164777Snyan	device_t dev;
64264777Snyan	int rid;
64364777Snyan{
64464777Snyan	struct ed_softc *sc = device_get_softc(dev);
64564777Snyan	int error;
64664777Snyan	u_long conf_maddr, conf_msize;
64764777Snyan
64864777Snyan	error = bus_get_resource(dev, SYS_RES_MEMORY, 0,
64964777Snyan				 &conf_maddr, &conf_msize);
65064777Snyan	if (error) {
65164777Snyan		return (error);
65264777Snyan	}
65364777Snyan
65464777Snyan	if ((conf_maddr == 0) || (conf_msize == 0)) {
65564777Snyan		return (ENXIO);
65664777Snyan	}
65764777Snyan
65864777Snyan	error = ed_alloc_memory(dev, rid, (int) conf_msize);
65964777Snyan	if (error) {
66064777Snyan		return (error);
66164777Snyan	}
66264777Snyan
66364777Snyan	sc->mem_start = (caddr_t) rman_get_virtual(sc->mem_res);
66464777Snyan	sc->mem_size  = conf_msize;
66564777Snyan
66664777Snyan	return (0);
66764777Snyan}
66864777Snyan
66964777Snyan/*
67064777Snyan * Generic probe routine for testing for the existance of a DS8390.
67164777Snyan *	Must be called after the NIC has just been reset. This routine
67264777Snyan *	works by looking at certain register values that are guaranteed
67364777Snyan *	to be initialized a certain way after power-up or reset. Seems
67464777Snyan *	not to currently work on the 83C690.
67564777Snyan *
67664777Snyan * Specifically:
67764777Snyan *
67864777Snyan *	Register			reset bits	set bits
67964777Snyan *	Command Register (CR)		TXP, STA	RD2, STP
68064777Snyan *	Interrupt Status (ISR)				RST
68164777Snyan *	Interrupt Mask (IMR)		All bits
68264777Snyan *	Data Control (DCR)				LAS
68364777Snyan *	Transmit Config. (TCR)		LB1, LB0
68464777Snyan *
68564777Snyan * XXX - We only check the CR register.
68664777Snyan *
68764777Snyan * Return 1 if 8390 was found, 0 if not.
68864777Snyan */
68964777Snyan
69064777Snyanstatic int
69164777Snyaned98_probe_generic8390(sc)
69264777Snyan	struct ed_softc *sc;
69364777Snyan{
69464777Snyan	u_char tmp = ed_nic_inb(sc, ED_P0_CR);
69564777Snyan#ifdef DIAGNOSTIC
69664777Snyan	printf("ed?: inb(ED_P0_CR)=%x\n", tmp);
69764777Snyan#endif
69864777Snyan	if ((tmp & (ED_CR_RD2 | ED_CR_TXP | ED_CR_STA | ED_CR_STP)) !=
69964777Snyan	    (ED_CR_RD2 | ED_CR_STP)) {
70064777Snyan		return (0);
70164777Snyan	}
70264777Snyan
70364777Snyan	(void) ed_nic_inb(sc, ED_P0_ISR);
70464777Snyan
70564777Snyan	return (1);
70664777Snyan}
70764777Snyan
70864777Snyanstatic int
70964777Snyaned98_probe_Novell(dev, port_rid, flags)
71064777Snyan	device_t dev;
71164777Snyan	int port_rid;
71264777Snyan	int flags;
71364777Snyan{
71464777Snyan	struct ed_softc *sc = device_get_softc(dev);
71564777Snyan	int error;
71664777Snyan	int n;
71764777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
71864777Snyan
71964777Snyan#ifdef ED_DEBUG
72064777Snyan	device_printf(dev, "ed98_probe_Novell: start\n");
72164777Snyan#endif
72264777Snyan	error = ed98_alloc_port(dev, port_rid);
72364777Snyan	if (error) {
72464777Snyan		return (error);
72564777Snyan	}
72664777Snyan
72764777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
72864777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
72964777Snyan
73064777Snyan	/* Reset the board */
73164777Snyan#ifdef ED_DEBUG
73264777Snyan	device_printf(dev, "ed98_probe_Novell: reset\n");
73364777Snyan#endif
73464777Snyan	switch (sc->type) {
73564777Snyan#if 1	/* XXX - I'm not sure this is really necessary... */
73664777Snyan	case ED_TYPE98_BDN:
73764777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
73864777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, (tmp & 0xf0) | 0x08);
73964777Snyan		ed_nic_outb(sc, 0x04, tmp);
74064777Snyan		(void) ed_asic_inb(sc, 0x08);
74164777Snyan		ed_asic_outb(sc, 0x08, tmp);
74264777Snyan		ed_asic_outb(sc, 0x08, tmp & 0x7f);
74364777Snyan		break;
74464777Snyan#endif
74564777Snyan	case ED_TYPE98_NC5098:
74664777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x00);
74764777Snyan		DELAY(5000);
74864777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, 0x01);
74964777Snyan		break;
75064777Snyan
75164777Snyan	default:
75264777Snyan		tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
75364777Snyan
75464777Snyan	/*
75564777Snyan	 * I don't know if this is necessary; probably cruft leftover from
75664777Snyan	 * Clarkson packet driver code. Doesn't do a thing on the boards I've
757108533Sschweikh	 * tested. -DG [note that an outb(0x84, 0) seems to work here, and is
75864777Snyan	 * non-invasive...but some boards don't seem to reset and I don't have
75964777Snyan	 * complete documentation on what the 'right' thing to do is...so we
76064777Snyan	 * do the invasive thing for now. Yuck.]
76164777Snyan	 */
76264777Snyan		ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
76364777Snyan		break;
76464777Snyan	}
76564777Snyan	DELAY(5000);
76664777Snyan
76764777Snyan	/*
76864777Snyan	 * This is needed because some NE clones apparently don't reset the
76964777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
77064777Snyan	 * - this makes the probe invasive! ...Done against my better
77164777Snyan	 * judgement. -DLG
77264777Snyan	 */
77364777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
77464777Snyan	DELAY(5000);
77564777Snyan
77664777Snyan	/* Make sure that we really have an 8390 based board */
77764777Snyan	if (!ed98_probe_generic8390(sc)) {
77864777Snyan		return (ENXIO);
77964777Snyan	}
78064777Snyan
78164777Snyan	/* Test memory via PIO */
78264777Snyan#ifdef ED_DEBUG
78364777Snyan	device_printf(dev, "ed98_probe_Novell: test memory\n");
78464777Snyan#endif
78564777Snyan	sc->cr_proto = ED_CR_RD2;
78664777Snyan	if (!ed_pio_testmem(sc,  8192, 0, flags)
78764777Snyan	&&  !ed_pio_testmem(sc, 16384, 1, flags)) {
78864777Snyan		return (ENXIO);
78964777Snyan	}
79064777Snyan
79164777Snyan	/* Setup the board type */
79264777Snyan#ifdef ED_DEBUG
79364777Snyan	device_printf(dev, "ed98_probe_Novell: board type\n");
79464777Snyan#endif
79564777Snyan	switch (sc->type) {
79664777Snyan	case ED_TYPE98_BDN:
79764777Snyan		sc->type_str = "LD-BDN";
79864777Snyan		break;
79964777Snyan	case ED_TYPE98_EGY:
80064777Snyan		sc->type_str = "EGY-98";
80164777Snyan		break;
80264777Snyan	case ED_TYPE98_LGY:
80364777Snyan		sc->type_str = "LGY-98";
80464777Snyan		break;
80564777Snyan	case ED_TYPE98_ICM:
80664777Snyan		sc->type_str = "ICM";
80764777Snyan		break;
80864777Snyan	case ED_TYPE98_108:
80964777Snyan		sc->type_str = "PC-9801-108";
81064777Snyan		break;
81164777Snyan	case ED_TYPE98_LA98:
81264777Snyan		sc->type_str = "LA-98";
81364777Snyan		break;
81464777Snyan	case ED_TYPE98_NW98X:
81564777Snyan		sc->type_str = "NW98X";
81664777Snyan		break;
81764777Snyan	case ED_TYPE98_NC5098:
81864777Snyan		sc->type_str = "NC5098";
81964777Snyan		break;
82064777Snyan	default:
82164777Snyan		sc->type_str = NULL;
82264777Snyan		break;
82364777Snyan	}
82464777Snyan
82564777Snyan	/* Get station address */
82664777Snyan	switch (sc->type) {
82764777Snyan	case ED_TYPE98_NC5098:
82864777Snyan		for (n = 0; n < ETHER_ADDR_LEN; n++) {
82964777Snyan			sc->arpcom.ac_enaddr[n] =
83064777Snyan				ed_asic_inb(sc, ED_NC5098_ENADDR + n);
83164777Snyan		}
83264777Snyan		break;
83364777Snyan
83464777Snyan	default:
83564777Snyan		ed_pio_readmem(sc, 0, romdata, sizeof(romdata));
83664777Snyan		for (n = 0; n < ETHER_ADDR_LEN; n++) {
83764777Snyan			sc->arpcom.ac_enaddr[n] =
83864777Snyan				romdata[n * (sc->isa16bit + 1)];
83964777Snyan		}
84064777Snyan		break;
84164777Snyan	}
84264777Snyan
84364777Snyan	/* clear any pending interrupts that might have occurred above */
84464777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
84564777Snyan
84664777Snyan	return (0);
84764777Snyan}
84864777Snyan
84964777Snyan/*
85064777Snyan * Probe and vendor-specific initialization routine for SIC-98 boards
85164777Snyan */
85264777Snyanstatic int
85364777Snyaned_probe_SIC98(dev, port_rid, flags)
85464777Snyan	device_t dev;
85564777Snyan	int port_rid;
85664777Snyan	int flags;
85764777Snyan{
85864777Snyan	struct ed_softc *sc = device_get_softc(dev);
85964777Snyan	int error;
86064777Snyan	int i;
86164777Snyan	u_char sum;
86264777Snyan
86364777Snyan	/*
86464777Snyan	 * Setup card RAM and I/O address
86564777Snyan	 * Kernel Virtual to segment C0000-DFFFF????
86664777Snyan	 */
86764777Snyan	error = ed98_alloc_port(dev, port_rid);
86864777Snyan	if (error) {
86964777Snyan		return (error);
87064777Snyan	}
87164777Snyan
87264777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
87364777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
87464777Snyan
87564777Snyan	error = ed98_alloc_memory(dev, 0);
87664777Snyan	if (error) {
87764777Snyan		return (error);
87864777Snyan	}
87964777Snyan
88064777Snyan	/* Reset card to force it into a known state. */
88164777Snyan	ed_asic_outb(sc, 0, 0x00);
88264777Snyan	DELAY(100);
88364777Snyan	if (ED_TYPE98SUB(flags) == 0) {
88464777Snyan		/* SIC-98/SIU-98 */
88564777Snyan		ed_asic_outb(sc, 0, 0x94);
88664777Snyan		DELAY(100);
88764777Snyan		ed_asic_outb(sc, 0, 0x94);
88864777Snyan	} else {
88964777Snyan		/* SIU-98-D */
89064777Snyan		ed_asic_outb(sc, 0, 0x80);
89164777Snyan		DELAY(100);
89264777Snyan		ed_asic_outb(sc, 0, 0x94);
89364777Snyan		DELAY(100);
89464777Snyan		ed_asic_outb(sc, 0, 0x9e);
89564777Snyan	}
89664777Snyan	DELAY(100);
89764777Snyan
89864777Snyan	/*
89964777Snyan	 * Here we check the card ROM, if the checksum passes, and the
90064777Snyan	 * type code and ethernet address check out, then we know we have
90164777Snyan	 * an SIC card.
90264777Snyan	 */
90364777Snyan	sum = sc->mem_start[6 * 2];
90464777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
90564777Snyan		sum ^= (sc->arpcom.ac_enaddr[i] = sc->mem_start[i * 2]);
90664777Snyan	}
90764777Snyan#ifdef ED_DEBUG
90864777Snyan	device_printf(dev, "ed_probe_sic98: got address %6D\n",
90964777Snyan		      sc->arpcom.ac_enaddr, ":");
91064777Snyan#endif
91164777Snyan	if (sum != 0) {
91264777Snyan		return (ENXIO);
91364777Snyan	}
91464777Snyan	if ((sc->arpcom.ac_enaddr[0] | sc->arpcom.ac_enaddr[1] |
91564777Snyan	     sc->arpcom.ac_enaddr[2]) == 0) {
91664777Snyan		return (ENXIO);
91764777Snyan	}
91864777Snyan
91964777Snyan	sc->vendor   = ED_VENDOR_MISC;
92064777Snyan	sc->type_str = "SIC98";
92164777Snyan	sc->isa16bit = 1;
92264777Snyan	sc->cr_proto = 0;
92364777Snyan
92464777Snyan	/*
92564777Snyan	 * SIC RAM page 0x0000-0x3fff(or 0x7fff)
92664777Snyan	 */
92764777Snyan	if (ED_TYPE98SUB(flags) == 0) {
92864777Snyan		ed_asic_outb(sc, 0, 0x90);
92964777Snyan	} else {
93064777Snyan		ed_asic_outb(sc, 0, 0x8e);
93164777Snyan	}
93264777Snyan	DELAY(100);
93364777Snyan
93464777Snyan	/*
93564777Snyan	 * clear interface memory, then sum to make sure its valid
93664777Snyan	 */
93764777Snyan	bzero(sc->mem_start, sc->mem_size);
93864777Snyan
93964777Snyan	for (i = 0; i < sc->mem_size; i++) {
94064777Snyan		if (sc->mem_start[i]) {
94164777Snyan			device_printf(dev, "failed to clear shared memory "
942112569Sjake				"at %x - check configuration\n",
94364777Snyan				kvtop(sc->mem_start + i));
94464777Snyan
94564777Snyan			return (ENXIO);
94664777Snyan		}
94764777Snyan	}
94864777Snyan
94964777Snyan	sc->mem_shared = 1;
95064777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
95164777Snyan
95264777Snyan	/*
95364777Snyan	 * allocate one xmit buffer if < 16k, two buffers otherwise
95464777Snyan	 */
95564777Snyan	if ((sc->mem_size < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) {
95664777Snyan		sc->txb_cnt = 1;
95764777Snyan	} else {
95864777Snyan		sc->txb_cnt = 2;
95964777Snyan	}
96064777Snyan	sc->tx_page_start = 0;
96164777Snyan
96264777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt;
96364777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
96464777Snyan
96564777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
96664777Snyan
96764777Snyan	return (0);
96864777Snyan}
96964777Snyan
97064777Snyan/*
97164777Snyan * Contec C-NET(98) series support routines
97264777Snyan */
97364777Snyanstatic void
97464777Snyaned_reset_CNET98(sc, flags)
97564777Snyan	struct ed_softc *sc;
97664777Snyan	int flags;
97764777Snyan{
97864777Snyan	u_short	init_addr = ED_CNET98_INIT;
97964777Snyan	u_char tmp;
98064777Snyan
98164777Snyan	/* Choose initial register address */
98264777Snyan	if (ED_TYPE98SUB(flags) != 0) {
98364777Snyan		init_addr = ED_CNET98_INIT2;
98464777Snyan	}
98564777Snyan#ifdef ED_DEBUG
98664777Snyan	printf("ed?: initial register=%x\n", init_addr);
98764777Snyan#endif
98864777Snyan	/*
98964777Snyan	 * Reset the board to force it into a known state.
99064777Snyan	 */
99164777Snyan	outb(init_addr, 0x00);	/* request */
99264777Snyan	DELAY(5000);
99364777Snyan	outb(init_addr, 0x01);	/* cancel */
99464777Snyan	DELAY(5000);
99564777Snyan
99664777Snyan	/*
99764777Snyan	 * Set I/O address(A15-12) and cpu type
99864777Snyan	 *
99964777Snyan	 *   AAAAIXXC(8bit)
100064777Snyan	 *   AAAA: A15-A12,  I: I/O enable, XX: reserved, C: CPU type
100164777Snyan	 *
100264777Snyan	 * CPU type is 1:80286 or higher, 0:not.
100364777Snyan	 * But FreeBSD runs under i386 or higher, thus it must be 1.
100464777Snyan	 */
100564777Snyan	tmp = (rman_get_start(sc->port_res) & 0xf000) >> 8;
100664777Snyan	tmp |= (0x08 | 0x01);
100764777Snyan#ifdef ED_DEBUG
100864777Snyan	printf("ed?: outb(%x, %x)\n", init_addr + 2, tmp);
100964777Snyan#endif
101064777Snyan	outb(init_addr + 2, tmp);
101164777Snyan	DELAY(5000);
101264777Snyan
101364777Snyan	/*
101464777Snyan	 * This is needed because some NE clones apparently don't reset the
101564777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
101664777Snyan	 * - this makes the probe invasive! ...Done against my better
101764777Snyan	 * judgement. -DLG
101864777Snyan	 */
101964777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
102064777Snyan	DELAY(5000);
102164777Snyan}
102264777Snyan
102364777Snyanstatic void
102464777Snyaned_winsel_CNET98(sc, bank)
102564777Snyan	struct ed_softc *sc;
102664777Snyan	u_short bank;
102764777Snyan{
102864777Snyan	u_char mem = (kvtop(sc->mem_start) >> 12) & 0xff;
102964777Snyan
103064777Snyan	/*
103164777Snyan	 * Disable window memory
103264777Snyan	 *    bit7 is 0:disable
103364777Snyan	 */
103464777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem & 0x7f);
103564777Snyan	DELAY(10);
103664777Snyan
103764777Snyan	/*
103864777Snyan	 * Select window address
103964777Snyan	 *    FreeBSD address 0xf00xxxxx
104064777Snyan	 */
104164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0L, bank & 0xff);
104264777Snyan	DELAY(10);
104364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG0H, (bank >> 8) & 0xff);
104464777Snyan	DELAY(10);
104564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1L, 0x00);
104664777Snyan	DELAY(10);
104764777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG1H, 0x41);
104864777Snyan	DELAY(10);
104964777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2L, 0x00);
105064777Snyan	DELAY(10);
105164777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG2H, 0x42);
105264777Snyan	DELAY(10);
105364777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3L, 0x00);
105464777Snyan	DELAY(10);
105564777Snyan	ed_asic_outb(sc, ED_CNET98_MAP_REG3H, 0x43);
105664777Snyan	DELAY(10);
105764777Snyan
105864777Snyan	/*
105964777Snyan	 * Enable window memory(16Kbyte)
106064777Snyan	 *    bit7 is 1:enable
106164777Snyan	 */
106264777Snyan#ifdef ED_DEBUG
106364777Snyan	printf("ed?: window start address=%x\n", mem);
106464777Snyan#endif
106564777Snyan	ed_asic_outb(sc, ED_CNET98_WIN_REG, mem);
106664777Snyan	DELAY(10);
106764777Snyan}
106864777Snyan
106964777Snyan/*
107064777Snyan * Probe and vendor-specific initialization routine for C-NET(98) boards
107164777Snyan */
107264777Snyanstatic int
107364777Snyaned_probe_CNET98(dev, port_rid, flags)
107464777Snyan	device_t dev;
107564777Snyan	int port_rid;
107664777Snyan	int flags;
107764777Snyan{
107864777Snyan	struct ed_softc *sc = device_get_softc(dev);
107964777Snyan	int error;
108064777Snyan	u_char tmp;
108164777Snyan	u_long conf_irq, junk;
108264777Snyan	int i;
108364777Snyan#ifdef DIAGNOSTIC
108464777Snyan	u_char tmp_s;
108564777Snyan#endif
108664777Snyan
108764777Snyan	error = ed98_alloc_port(dev, port_rid);
108864777Snyan	if (error) {
108964777Snyan		return (error);
109064777Snyan	}
109164777Snyan
109264777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
109364777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
109464777Snyan
109564777Snyan	error = ed98_alloc_memory(dev, 0);
109664777Snyan	if (error) {
109764777Snyan		return (error);
109864777Snyan	}
109964777Snyan
110064777Snyan	/* Check I/O address. 0x[a-f]3d0 are allowed. */
110164777Snyan	if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
110264777Snyan	||  ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
110364777Snyan#ifdef DIAGNOSTIC
1104111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
110564777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
110664777Snyan			"0x[a-f]3d0", "CNET98");
110764777Snyan#endif
110864777Snyan		return (ENXIO);
110964777Snyan	}
111064777Snyan
111164777Snyan#ifdef DIAGNOSTIC
111264777Snyan	/* Check window area address */
111364777Snyan	tmp_s = kvtop(sc->mem_start) >> 12;
111464777Snyan	if (tmp_s < 0x80) {
1115112569Sjake		device_printf(dev, "Please change window address(0x%x)\n",
111664777Snyan			kvtop(sc->mem_start));
111764777Snyan		return (ENXIO);
111864777Snyan	}
111964777Snyan
112064777Snyan	tmp_s &= 0x0f;
112164777Snyan	tmp    = rman_get_start(sc->port_res) >> 12;
112264777Snyan	if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
1123111427Snyan		device_printf(dev, "Please change iobase address(0x%lx) "
1124112569Sjake			"or window address(0x%x)\n",
112564777Snyan	   		rman_get_start(sc->port_res), kvtop(sc->mem_start));
112664777Snyan		return (ENXIO);
112764777Snyan	}
112864777Snyan#endif
112964777Snyan	/* Reset the board */
113064777Snyan	ed_reset_CNET98(sc, flags);
113164777Snyan
113264777Snyan	/*
113364777Snyan	 * This is needed because some NE clones apparently don't reset the
113464777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
113564777Snyan	 * - this makes the probe invasive! ...Done against my better
113664777Snyan	 * judgement. -DLG
113764777Snyan	 */
113864777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
113964777Snyan	DELAY(5000);
114064777Snyan
114164777Snyan	/* Make sure that we really have an 8390 based board */
114264777Snyan	if (!ed98_probe_generic8390(sc)) {
114364777Snyan		return (ENXIO);
114464777Snyan	}
114564777Snyan
114664777Snyan	/*
114764777Snyan	 *  Set window ethernet address area
114864777Snyan	 *    board memory base 0x480000  data 256byte
114964777Snyan	 */
115064777Snyan	ed_winsel_CNET98(sc, 0x4800);
115164777Snyan
115264777Snyan	/*
115364777Snyan	 * Get station address from on-board ROM
115464777Snyan	 */
115564777Snyan	bcopy(sc->mem_start, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
115664777Snyan
115764777Snyan	sc->vendor    = ED_VENDOR_MISC;
115864777Snyan	sc->type_str  = "CNET98";
115964777Snyan	sc->isa16bit  = 0;
116064777Snyan	sc->cr_proto  = ED_CR_RD2;
116164777Snyan
116264777Snyan	/*
116364777Snyan	 * Set window buffer memory area
116464777Snyan	 *    board memory base 0x400000  data 16kbyte
116564777Snyan	 */
116664777Snyan	ed_winsel_CNET98(sc, 0x4000);
116764777Snyan
116864777Snyan	/*
116964777Snyan	 * clear interface memory, then sum to make sure its valid
117064777Snyan	 */
117164777Snyan	bzero(sc->mem_start, sc->mem_size);
117264777Snyan
117364777Snyan	for (i = 0; i < sc->mem_size; i++) {
117464777Snyan		if (sc->mem_start[i]) {
117564777Snyan			device_printf(dev, "failed to clear shared memory "
1176112569Sjake				"at %x - check configuration\n",
117764777Snyan				kvtop(sc->mem_start + i));
117864777Snyan
117964777Snyan			return (ENXIO);
118064777Snyan		}
118164777Snyan	}
118264777Snyan
118364777Snyan	sc->mem_shared = 1;
118464777Snyan	sc->mem_end = sc->mem_start + sc->mem_size;
118564777Snyan
118664777Snyan	sc->txb_cnt = 1;	/* XXX */
118764777Snyan	sc->tx_page_start = 0;
118864777Snyan
118964777Snyan	sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
119064777Snyan	sc->rec_page_stop = sc->tx_page_start + sc->mem_size / ED_PAGE_SIZE;
119164777Snyan
119264777Snyan	sc->mem_ring = sc->mem_start + ED_PAGE_SIZE * ED_TXBUF_SIZE;
119364777Snyan
119464777Snyan	/*
119564777Snyan	 *   Set interrupt level
119664777Snyan	 */
119764777Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0,
119864777Snyan				 &conf_irq, &junk);
119964777Snyan	if (error)
120064777Snyan		return (error);
120164777Snyan
120264777Snyan	switch (conf_irq) {
120364777Snyan	case 3:
120464777Snyan		tmp = ED_CNET98_INT_IRQ3;
120564777Snyan		break;
120664777Snyan	case 5:
120764777Snyan		tmp = ED_CNET98_INT_IRQ5;
120864777Snyan		break;
120964777Snyan	case 6:
121064777Snyan		tmp = ED_CNET98_INT_IRQ6;
121164777Snyan		break;
121264777Snyan	case 9:
121364777Snyan		tmp = ED_CNET98_INT_IRQ9;
121464777Snyan		break;
121564777Snyan	case 12:
121664777Snyan		tmp = ED_CNET98_INT_IRQ12;
121764777Snyan		break;
121864777Snyan	case 13:
121964777Snyan		tmp = ED_CNET98_INT_IRQ13;
122064777Snyan		break;
122164777Snyan	default:
122264777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
122364777Snyan			"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
122464777Snyan		return (ENXIO);
122564777Snyan	}
122664777Snyan	ed_asic_outb(sc, ED_CNET98_INT_LEV, tmp);
122764777Snyan	DELAY(1000);
122864777Snyan	/*
122964777Snyan	 *   Set interrupt mask.
123064777Snyan	 *     bit7:1 all interrupt mask
123164777Snyan	 *     bit1:1 timer interrupt mask
123264777Snyan	 *     bit0:0 NS controler interrupt enable
123364777Snyan	 */
123464777Snyan	ed_asic_outb(sc, ED_CNET98_INT_MASK, 0x7e);
123564777Snyan	DELAY(1000);
123664777Snyan
123764777Snyan	return (0);
123864777Snyan}
123964777Snyan
124064777Snyan/*
124164777Snyan * Probe and vendor-specific initialization routine for C-NET(98)E/L boards
124264777Snyan */
124364777Snyanstatic int
124464777Snyaned_probe_CNET98EL(dev, port_rid, flags)
124564777Snyan	device_t dev;
124664777Snyan	int port_rid;
124764777Snyan	int flags;
124864777Snyan{
124964777Snyan	struct ed_softc *sc = device_get_softc(dev);
125064777Snyan	int error;
125164777Snyan	int i;
125264777Snyan	u_char romdata[ETHER_ADDR_LEN * 2], tmp;
125364777Snyan	u_long conf_irq, junk;
125464777Snyan
125564777Snyan	error = ed98_alloc_port(dev, port_rid);
125664777Snyan	if (error) {
125764777Snyan		return (error);
125864777Snyan	}
125964777Snyan
126064777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
126164777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
126264777Snyan
126364777Snyan	/* Check I/O address. 0x[0-f]3d0 are allowed. */
126464777Snyan	if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
126564777Snyan#ifdef DIAGNOSTIC
1266111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
126764777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
126864777Snyan			"0x?3d0", "CNET98E/L");
126964777Snyan#endif
127064777Snyan		return (ENXIO);
127164777Snyan	}
127264777Snyan
127364777Snyan	/* Reset the board */
127464777Snyan	ed_reset_CNET98(sc, flags);
127564777Snyan
127664777Snyan	/*
127764777Snyan	 * This is needed because some NE clones apparently don't reset the
127864777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
127964777Snyan	 * - this makes the probe invasive! ...Done against my better
128064777Snyan	 * judgement. -DLG
128164777Snyan	 */
128264777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
128364777Snyan	DELAY(5000);
128464777Snyan
128564777Snyan	/* Make sure that we really have an 8390 based board */
128664777Snyan	if (!ed98_probe_generic8390(sc)) {
128764777Snyan		return (ENXIO);
128864777Snyan	}
128964777Snyan
129064777Snyan	/* Test memory via PIO */
129164777Snyan	sc->cr_proto = ED_CR_RD2;
129264777Snyan	if (!ed_pio_testmem(sc, ED_CNET98EL_PAGE_OFFSET, 1, flags)) {
129364777Snyan		return (ENXIO);
129464777Snyan	}
129564777Snyan
129664777Snyan	/* This looks like a C-NET(98)E/L board. */
129764777Snyan	sc->type_str = "CNET98E/L";
129864777Snyan
129964777Snyan	/*
130064777Snyan	 * Set IRQ. C-NET(98)E/L only allows a choice of irq 3,5,6.
130164777Snyan	 */
130264777Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0,
130364777Snyan				 &conf_irq, &junk);
130464777Snyan	if (error) {
130564777Snyan		return (error);
130664777Snyan	}
130764777Snyan
130864777Snyan	switch (conf_irq) {
130964777Snyan	case 3:
131064777Snyan		tmp = ED_CNET98EL_ICR_IRQ3;
131164777Snyan		break;
131264777Snyan	case 5:
131364777Snyan		tmp = ED_CNET98EL_ICR_IRQ5;
131464777Snyan		break;
131564777Snyan	case 6:
131664777Snyan		tmp = ED_CNET98EL_ICR_IRQ6;
131764777Snyan		break;
131864777Snyan#if 0
131964777Snyan	case 12:
132064777Snyan		tmp = ED_CNET98EL_ICR_IRQ12;
132164777Snyan		break;
132264777Snyan#endif
132364777Snyan	default:
132464777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
132564777Snyan			"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
132664777Snyan		return (ENXIO);
132764777Snyan	}
132864777Snyan	ed_asic_outb(sc, ED_CNET98EL_ICR, tmp);
132964777Snyan	ed_asic_outb(sc, ED_CNET98EL_IMR, 0x7e);
133064777Snyan
133164777Snyan	/* Get station address from on-board ROM */
133264777Snyan	ed_pio_readmem(sc, 16384, romdata, sizeof(romdata));
133364777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
133464777Snyan		sc->arpcom.ac_enaddr[i] = romdata[i * 2];
133564777Snyan	}
133664777Snyan
133764777Snyan	/* clear any pending interrupts that might have occurred above */
133864777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
133964777Snyan
134064777Snyan	return (0);
134164777Snyan}
134264777Snyan
134364777Snyan/*
134464777Snyan * Probe and vendor-specific initialization routine for PC-9801-77 boards
134564777Snyan */
134664777Snyanstatic int
134764777Snyaned_probe_NEC77(dev, port_rid, flags)
134864777Snyan	device_t dev;
134964777Snyan	int port_rid;
135064777Snyan	int flags;
135164777Snyan{
135264777Snyan	struct ed_softc *sc = device_get_softc(dev);
135364777Snyan	int error;
135464777Snyan	u_char tmp;
135564777Snyan	u_long conf_irq, junk;
135664777Snyan
135764777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
135864777Snyan	if (error) {
135964777Snyan		return (error);
136064777Snyan	}
136164777Snyan
136264777Snyan	/* LA/T-98 does not need IRQ setting. */
136364777Snyan	if (ED_TYPE98SUB(flags) == 0) {
136464777Snyan		return (0);
136564777Snyan	}
136664777Snyan
136764777Snyan	/*
136864777Snyan	 * Set IRQ. PC-9801-77 only allows a choice of irq 3,5,6,12,13.
136964777Snyan	 */
137064777Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0,
137164777Snyan				 &conf_irq, &junk);
137264777Snyan	if (error) {
137364777Snyan		return (error);
137464777Snyan	}
137564777Snyan
137664777Snyan	switch (conf_irq) {
137764777Snyan	case 3:
137864777Snyan		tmp = ED_NEC77_IRQ3;
137964777Snyan		break;
138064777Snyan	case 5:
138164777Snyan		tmp = ED_NEC77_IRQ5;
138264777Snyan		break;
138364777Snyan	case 6:
138464777Snyan		tmp = ED_NEC77_IRQ6;
138564777Snyan		break;
138664777Snyan	case 12:
138764777Snyan		tmp = ED_NEC77_IRQ12;
138864777Snyan		break;
138964777Snyan	case 13:
139064777Snyan		tmp = ED_NEC77_IRQ13;
139164777Snyan		break;
139264777Snyan	default:
139364777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
139464777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
139564777Snyan		return (ENXIO);
139664777Snyan	}
139764777Snyan	ed_asic_outb(sc, ED_NEC77_IRQ, tmp);
139864777Snyan
139964777Snyan	return (0);
140064777Snyan}
140164777Snyan
140264777Snyan/*
140364777Snyan * Probe and vendor-specific initialization routine for EC/EP-98X boards
140464777Snyan */
140564777Snyanstatic int
140664777Snyaned_probe_NW98X(dev, port_rid, flags)
140764777Snyan	device_t dev;
140864777Snyan	int port_rid;
140964777Snyan	int flags;
141064777Snyan{
141164777Snyan	struct ed_softc *sc = device_get_softc(dev);
141264777Snyan	int error;
141364777Snyan	u_char tmp;
141464777Snyan	u_long conf_irq, junk;
141564777Snyan
141664777Snyan	error = ed98_probe_Novell(dev, port_rid, flags);
141764777Snyan	if (error) {
141864777Snyan		return (error);
141964777Snyan	}
142064777Snyan
142164777Snyan	/* Networld 98X3 does not need IRQ setting. */
142264777Snyan	if (ED_TYPE98SUB(flags) == 0) {
142364777Snyan		return (0);
142464777Snyan	}
142564777Snyan
142664777Snyan	/*
142764777Snyan	 * Set IRQ. EC/EP-98X only allows a choice of irq 3,5,6,12,13.
142864777Snyan	 */
142964777Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0,
143064777Snyan				 &conf_irq, &junk);
143164777Snyan	if (error) {
143264777Snyan		return (error);
143364777Snyan	}
143464777Snyan
143564777Snyan	switch (conf_irq) {
143664777Snyan	case 3:
143764777Snyan		tmp = ED_NW98X_IRQ3;
143864777Snyan		break;
143964777Snyan	case 5:
144064777Snyan		tmp = ED_NW98X_IRQ5;
144164777Snyan		break;
144264777Snyan	case 6:
144364777Snyan		tmp = ED_NW98X_IRQ6;
144464777Snyan		break;
144564777Snyan	case 12:
144664777Snyan		tmp = ED_NW98X_IRQ12;
144764777Snyan		break;
144864777Snyan	case 13:
144964777Snyan		tmp = ED_NW98X_IRQ13;
145064777Snyan		break;
145164777Snyan	default:
145264777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
145364777Snyan			"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
145464777Snyan		return (ENXIO);
145564777Snyan	}
145664777Snyan	ed_asic_outb(sc, ED_NW98X_IRQ, tmp);
145764777Snyan
145864777Snyan	return (0);
145964777Snyan}
146064777Snyan
146164777Snyan/*
146264777Snyan * Read SB-9801 station address from Serial Two-Wire EEPROM
146364777Snyan */
146464777Snyanstatic void
146564777Snyaned_get_SB98(sc)
146664777Snyan	struct ed_softc *sc;
146764777Snyan{
146864777Snyan	int i, j;
146964777Snyan	u_char mask, val;
147064777Snyan
147164777Snyan        /* enable EEPROM acceess */
147264777Snyan        ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_ENABLE);
147364777Snyan
147464777Snyan	/* output start command */
147564777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
147664777Snyan	DELAY(ED_SB98_EEP_DELAY);
147764777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
147864777Snyan	DELAY(ED_SB98_EEP_DELAY);
147964777Snyan
148064777Snyan       	/* output address (7bit) */
148164777Snyan	for (mask = 0x40; mask != 0; mask >>= 1) {
148264777Snyan		val = 0;
148364777Snyan		if (ED_SB98_ADDRESS & mask)
148464777Snyan			val = ED_SB98_EEP_SDA;
148564777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val);
148664777Snyan		DELAY(ED_SB98_EEP_DELAY);
148764777Snyan		ed_asic_outb(sc, ED_SB98_EEP, val | ED_SB98_EEP_SCL);
148864777Snyan		DELAY(ED_SB98_EEP_DELAY);
148964777Snyan	}
149064777Snyan
149164777Snyan	/* output READ command */
149264777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ);
149364777Snyan	DELAY(ED_SB98_EEP_DELAY);
149464777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_READ | ED_SB98_EEP_SCL);
149564777Snyan	DELAY(ED_SB98_EEP_DELAY);
149664777Snyan
149764777Snyan	/* read station address */
149864777Snyan	for (i = 0; i < ETHER_ADDR_LEN; i++) {
149964777Snyan		/* output ACK */
150064777Snyan		ed_asic_outb(sc, ED_SB98_EEP, 0);
150164777Snyan		DELAY(ED_SB98_EEP_DELAY);
150264777Snyan		ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
150364777Snyan		DELAY(ED_SB98_EEP_DELAY);
150464777Snyan
150564777Snyan		val = 0;
150664777Snyan		for (j = 0; j < 8; j++) {
150764777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
150864777Snyan			DELAY(ED_SB98_EEP_DELAY);
150964777Snyan			ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
151064777Snyan			DELAY(ED_SB98_EEP_DELAY);
151164777Snyan			val <<= 1;
151264777Snyan			val |= (ed_asic_inb(sc, ED_SB98_EEP) & ED_SB98_EEP_SDA);
151364777Snyan			DELAY(ED_SB98_EEP_DELAY);
151464777Snyan	  	}
151564777Snyan		sc->arpcom.ac_enaddr[i] = val;
151664777Snyan	}
151764777Snyan
151864777Snyan	/* output Last ACK */
151964777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA);
152064777Snyan        DELAY(ED_SB98_EEP_DELAY);
152164777Snyan        ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
152264777Snyan        DELAY(ED_SB98_EEP_DELAY);
152364777Snyan
152464777Snyan	/* output stop command */
152564777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SCL);
152664777Snyan	DELAY(ED_SB98_EEP_DELAY);
152764777Snyan	ed_asic_outb(sc, ED_SB98_EEP, ED_SB98_EEP_SDA | ED_SB98_EEP_SCL);
152864777Snyan	DELAY(ED_SB98_EEP_DELAY);
152964777Snyan
153064777Snyan	/* disable EEPROM access */
153164777Snyan	ed_asic_outb(sc, ED_SB98_EEPENA, ED_SB98_EEPENA_DISABLE);
153264777Snyan}
153364777Snyan
153464777Snyan/*
153564777Snyan * Probe and vendor-specific initialization routine for SB-9801 boards
153664777Snyan */
153764777Snyanstatic int
153864777Snyaned_probe_SB98(dev, port_rid, flags)
153964777Snyan	device_t dev;
154064777Snyan	int port_rid;
154164777Snyan	int flags;
154264777Snyan{
154364777Snyan	struct ed_softc *sc = device_get_softc(dev);
154464777Snyan	int error;
154564777Snyan	u_char tmp;
154664777Snyan	u_long conf_irq, junk;
154764777Snyan
154864777Snyan	error = ed98_alloc_port(dev, port_rid);
154964777Snyan	if (error) {
155064777Snyan		return (error);
155164777Snyan	}
155264777Snyan
155364777Snyan	sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
155464777Snyan	sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
155564777Snyan
155664777Snyan	/* Check I/O address. 00d[02468ace] are allowed. */
155764777Snyan	if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
155864777Snyan#ifdef DIAGNOSTIC
1559111427Snyan		device_printf(dev, "Invalid i/o port configuration (0x%lx) "
156064777Snyan			"must be %s for %s\n", rman_get_start(sc->port_res),
156164777Snyan			"0xd?", "SB9801");
156264777Snyan#endif
156364777Snyan		return (ENXIO);
156464777Snyan	}
156564777Snyan
156664777Snyan	/* Write I/O port address and read 4 times */
156764777Snyan	outb(ED_SB98_IO_INHIBIT, rman_get_start(sc->port_res) & 0xff);
156864777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
156964777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
157064777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
157164777Snyan	(void) inb(ED_SB98_IO_INHIBIT); DELAY(300);
157264777Snyan
157364777Snyan	/*
157464777Snyan	 * Check IRQ. Soliton SB-9801 only allows a choice of
157564777Snyan	 * irq 3,5,6,12
157664777Snyan	 */
157764777Snyan	error = bus_get_resource(dev, SYS_RES_IRQ, 0,
157864777Snyan				 &conf_irq, &junk);
157964777Snyan	if (error) {
158064777Snyan		return (error);
158164777Snyan	}
158264777Snyan
158364777Snyan	switch (conf_irq) {
158464777Snyan	case 3:
158564777Snyan		tmp = ED_SB98_CFG_IRQ3;
158664777Snyan		break;
158764777Snyan	case 5:
158864777Snyan		tmp = ED_SB98_CFG_IRQ5;
158964777Snyan		break;
159064777Snyan	case 6:
159164777Snyan		tmp = ED_SB98_CFG_IRQ6;
159264777Snyan		break;
159364777Snyan	case 12:
159464777Snyan		tmp = ED_SB98_CFG_IRQ12;
159564777Snyan		break;
159664777Snyan	default:
159764777Snyan		device_printf(dev, "Invalid irq configuration (%ld) must be "
159864777Snyan			"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
159964777Snyan		return (ENXIO);
160064777Snyan	}
160164777Snyan
160264777Snyan	if (flags & ED_FLAGS_DISABLE_TRANCEIVER) {
160364777Snyan		tmp |= ED_SB98_CFG_ALTPORT;
160464777Snyan	}
160564777Snyan	ed_asic_outb(sc, ED_SB98_CFG, ED_SB98_CFG_ENABLE | tmp);
160664777Snyan	ed_asic_outb(sc, ED_SB98_POLARITY, 0x01);
160764777Snyan
160864777Snyan	/* Reset the board. */
160964777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x7a);
161064777Snyan	DELAY(300);
161164777Snyan	ed_asic_outb(sc, ED_NOVELL_RESET, 0x79);
161264777Snyan	DELAY(300);
161364777Snyan
161464777Snyan	/*
161564777Snyan	 * This is needed because some NE clones apparently don't reset the
161664777Snyan	 * NIC properly (or the NIC chip doesn't reset fully on power-up) XXX
161764777Snyan	 * - this makes the probe invasive! ...Done against my better
161864777Snyan	 * judgement. -DLG
161964777Snyan	 */
162064777Snyan	ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
162164777Snyan	DELAY(5000);
162264777Snyan
162364777Snyan	/* Make sure that we really have an 8390 based board */
162464777Snyan	if (!ed98_probe_generic8390(sc)) {
162564777Snyan		return (ENXIO);
162664777Snyan	}
162764777Snyan
162864777Snyan	/* Test memory via PIO */
162964777Snyan	sc->cr_proto = ED_CR_RD2;
163064777Snyan	if (!ed_pio_testmem(sc, 16384, 1, flags)) {
163164777Snyan		return (ENXIO);
163264777Snyan	}
163364777Snyan
163464777Snyan	/* This looks like an SB9801 board. */
163564777Snyan	sc->type_str = "SB9801";
163664777Snyan
163764777Snyan	/* Get station address */
163864777Snyan	ed_get_SB98(sc);
163964777Snyan
164064777Snyan	/* clear any pending interrupts that might have occurred above */
164164777Snyan	ed_nic_outb(sc, ED_P0_ISR, 0xff);
164264777Snyan
164364777Snyan	return (0);
164464777Snyan}
164564777Snyan
164664777Snyan/*
164764777Snyan * Test the ability to read and write to the NIC memory.
164864777Snyan */
164964777Snyanstatic int
165064777Snyaned_pio_testmem(sc, page_offset, isa16bit, flags)
165164777Snyan	struct ed_softc *sc;
165264777Snyan	int page_offset;
165364777Snyan	int isa16bit;
165464777Snyan	int flags;
165564777Snyan{
165664777Snyan	u_long memsize;
165764777Snyan	static char test_pattern[32] = "THIS is A memory TEST pattern";
165864777Snyan	char test_buffer[32];
165964777Snyan#ifdef DIAGNOSTIC
166064777Snyan	int page_end;
166164777Snyan#endif
166264777Snyan
166364777Snyan	sc->vendor = ED_VENDOR_NOVELL;
166464777Snyan	sc->mem_shared = 0;
166564777Snyan	sc->isa16bit = isa16bit;
166664777Snyan
166764777Snyan	/* 8k of memory plus an additional 8k if 16bit */
166864777Snyan	memsize = (isa16bit ? 16384 : 8192);
166964777Snyan
167064777Snyan	/*
167164777Snyan	 * This prevents packets from being stored in the NIC memory when the
167264777Snyan	 * readmem routine turns on the start bit in the CR.
167364777Snyan	 */
167464777Snyan	ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON);
167564777Snyan
167664777Snyan	/* Initialize DCR for byte/word operations */
167764777Snyan	if (isa16bit) {
167864777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS);
167964777Snyan	} else {
168064777Snyan		ed_nic_outb(sc, ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
168164777Snyan	}
168264777Snyan	ed_nic_outb(sc, ED_P0_PSTART, page_offset / ED_PAGE_SIZE);
168364777Snyan	ed_nic_outb(sc, ED_P0_PSTOP, (page_offset + memsize) / ED_PAGE_SIZE);
168464777Snyan#ifdef ED_DEBUG
168564777Snyan	printf("ed?: ed_pio_testmem: page start=%x, end=%x",
168664777Snyan		      page_offset, page_offset + memsize);
168764777Snyan#endif
168864777Snyan
168964777Snyan	/*
169064777Snyan	 * Write a test pattern. If this fails, then we don't know
169164777Snyan	 * what this board is.
169264777Snyan	 */
169364777Snyan	ed_pio_writemem(sc, test_pattern, page_offset, sizeof(test_pattern));
169464777Snyan	ed_pio_readmem(sc, page_offset, test_buffer, sizeof(test_pattern));
169564777Snyan
169664777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
169764777Snyan#ifdef ED_DEBUG
169864777Snyan		printf("ed?: ed_pio_testmem: bcmp(page %x) NG",
169964777Snyan			      page_offset);
170064777Snyan#endif
170164777Snyan		return (0);
170264777Snyan	}
170364777Snyan
170464777Snyan#ifdef DIAGNOSTIC
170564777Snyan	/* Check the bottom. */
170664777Snyan	page_end = page_offset + memsize - ED_PAGE_SIZE;
170764777Snyan	ed_pio_writemem(sc, test_pattern, page_end, sizeof(test_pattern));
170864777Snyan	ed_pio_readmem(sc, page_end, test_buffer, sizeof(test_pattern));
170964777Snyan
171064777Snyan	if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
171164777Snyan#ifdef ED_DEBUG
171264777Snyan		printf("ed?: ed_pio_testmem: bcmp(page %x) NG",
171364777Snyan			      page_end);
171464777Snyan#endif
171564777Snyan		return (0);
171664777Snyan	}
171764777Snyan#endif
171864777Snyan	sc->mem_size = memsize;
171964777Snyan	sc->mem_start = (char *) page_offset;
172064777Snyan	sc->mem_end   = sc->mem_start + memsize;
172164777Snyan	sc->tx_page_start = page_offset / ED_PAGE_SIZE;
172264777Snyan
172364777Snyan	/*
172464777Snyan	 * Use one xmit buffer if < 16k, two buffers otherwise (if not told
172564777Snyan	 * otherwise).
172664777Snyan	 */
172764777Snyan	if ((memsize < 16384) || (flags & ED_FLAGS_NO_MULTI_BUFFERING)) {
172864777Snyan		sc->txb_cnt = 1;
172964777Snyan	} else {
173064777Snyan		sc->txb_cnt = 2;
173164777Snyan	}
173264777Snyan
173364777Snyan	sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
173464777Snyan	sc->rec_page_stop  = sc->tx_page_start + memsize / ED_PAGE_SIZE;
173564777Snyan
173664777Snyan	sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
173764777Snyan
173864777Snyan	return (1);
173964777Snyan}
174064777Snyan#endif	/* PC98 */
174170355Simp
174270355Simpstatic device_method_t ed_isa_methods[] = {
174370355Simp	/* Device interface */
174470355Simp	DEVMETHOD(device_probe,		ed_isa_probe),
174570355Simp	DEVMETHOD(device_attach,	ed_isa_attach),
174670355Simp
174770355Simp	{ 0, 0 }
174870355Simp};
174970355Simp
175070355Simpstatic driver_t ed_isa_driver = {
175170355Simp	"ed",
175270355Simp	ed_isa_methods,
175370355Simp	sizeof(struct ed_softc)
175470355Simp};
175570355Simp
1756113506SmdoddDRIVER_MODULE(ed, isa, ed_isa_driver, ed_devclass, 0, 0);
1757113506SmdoddMODULE_DEPEND(ed, isa, 1, 1, 1);
1758113506SmdoddMODULE_DEPEND(ed, ether, 1, 1, 1);
1759