159816Smdodd/*-
259816Smdodd * Copyright (c) 2000 Matthew N. Dodd
359816Smdodd * All rights reserved.
459816Smdodd *
559816Smdodd * Redistribution and use in source and binary forms, with or without
659816Smdodd * modification, are permitted provided that the following conditions
759816Smdodd * are met:
859816Smdodd * 1. Redistributions of source code must retain the above copyright
959816Smdodd *    notice, this list of conditions and the following disclaimer.
1059816Smdodd * 2. Redistributions in binary form must reproduce the above copyright
1159816Smdodd *    notice, this list of conditions and the following disclaimer in the
1259816Smdodd *    documentation and/or other materials provided with the distribution.
1359816Smdodd *
1459816Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1559816Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1659816Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1759816Smdodd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1859816Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1959816Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2059816Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2159816Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2259816Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2359816Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2459816Smdodd * SUCH DAMAGE.
2559816Smdodd *
2659816Smdodd */
2759816Smdodd
28119418Sobrien#include <sys/cdefs.h>
29119418Sobrien__FBSDID("$FreeBSD$");
30119418Sobrien
3159816Smdodd#include <sys/param.h>
3259816Smdodd#include <sys/systm.h>
3359816Smdodd#include <sys/kernel.h>
3459816Smdodd#include <sys/socket.h>
3559816Smdodd
3659816Smdodd#include <sys/module.h>
3759816Smdodd#include <sys/bus.h>
3859816Smdodd
3959816Smdodd#include <machine/bus.h>
4059816Smdodd#include <machine/resource.h>
4159816Smdodd#include <sys/rman.h>
4259816Smdodd
4359816Smdodd#include <net/if.h>
4459816Smdodd#include <net/if_arp.h>
4559816Smdodd#include <net/if_media.h>
4659816Smdodd
4759816Smdodd
4859816Smdodd#include <isa/isavar.h>
4959816Smdodd#include <isa/pnpvar.h>
5059816Smdodd
5159816Smdodd#include <dev/ex/if_exreg.h>
5259816Smdodd#include <dev/ex/if_exvar.h>
5359816Smdodd
5459816Smdodd/* Bus Front End Functions */
55131192Simpstatic void	ex_isa_identify(driver_t *, device_t);
56131192Simpstatic int	ex_isa_probe(device_t);
57131192Simpstatic int	ex_isa_attach(device_t);
5859816Smdodd
59131192Simpstatic int	ex_look_for_card(struct ex_softc *);
60131192Simp
6159816Smdodd#if 0
62131192Simpstatic	void	ex_pnp_wakeup(void *);
6359816Smdodd
6459816SmdoddSYSINIT(ex_pnpwakeup, SI_SUB_CPU, SI_ORDER_ANY, ex_pnp_wakeup, NULL);
6559816Smdodd#endif
6659816Smdodd
67112801Smdoddstatic device_method_t ex_isa_methods[] = {
6859816Smdodd	/* Device interface */
6959816Smdodd	DEVMETHOD(device_identify,	ex_isa_identify),
7059816Smdodd	DEVMETHOD(device_probe,		ex_isa_probe),
7159816Smdodd	DEVMETHOD(device_attach,	ex_isa_attach),
72112800Smdodd	DEVMETHOD(device_detach,	ex_detach),
7359816Smdodd
7459816Smdodd	{ 0, 0 }
7559816Smdodd};
7659816Smdodd
77112801Smdoddstatic driver_t ex_isa_driver = {
7859816Smdodd	"ex",
79112801Smdodd	ex_isa_methods,
8059816Smdodd	sizeof(struct ex_softc),
8159816Smdodd};
8259816Smdodd
83112801SmdoddDRIVER_MODULE(ex, isa, ex_isa_driver, ex_devclass, 0, 0);
8459816Smdodd
8559816Smdoddstatic struct isa_pnp_id ex_ids[] = {
8659816Smdodd	{ 0x3110d425,	NULL },	/* INT1031 */
8759816Smdodd	{ 0x3010d425,	NULL },	/* INT1030 */
8859816Smdodd	{ 0,		NULL },
8959816Smdodd};
9059816Smdodd
9159816Smdodd#if 0
9259816Smdodd#define EX_PNP_WAKE		0x279
9359816Smdodd
94131192Simpstatic uint8_t ex_pnp_wake_seq[] =
9559816Smdodd			{ 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
9659816Smdodd			  0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
9759816Smdodd			  0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
9859816Smdodd			  0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43 };
9959816Smdodd
10059816Smdoddstatic void
10159816Smdoddex_pnp_wakeup (void * dummy)
10259816Smdodd{
10359816Smdodd	int	tmp;
10459816Smdodd
10559816Smdodd	if (bootverbose)
10659816Smdodd		printf("ex_pnp_wakeup()\n");
10759816Smdodd
10859816Smdodd	outb(EX_PNP_WAKE, 0);
10959816Smdodd	outb(EX_PNP_WAKE, 0);
11059816Smdodd	for (tmp = 0; tmp < 32; tmp++) {
11159816Smdodd		outb(EX_PNP_WAKE, ex_pnp_wake_seq[tmp]);
11259816Smdodd	}
11359816Smdodd}
11459816Smdodd#endif
11559816Smdodd
11659816Smdodd/*
11759816Smdodd * Non-destructive identify.
11859816Smdodd */
11959816Smdoddstatic void
120131192Simpex_isa_identify(driver_t *driver, device_t parent)
12159816Smdodd{
12259816Smdodd	device_t	child;
123131192Simp	bus_addr_t	ioport;
12459816Smdodd	u_char 		enaddr[6];
12559816Smdodd	u_int		irq;
12659816Smdodd	int		tmp;
12759816Smdodd	const char *	desc;
128131192Simp	struct ex_softc sc;
129131192Simp	int		rid;
13059816Smdodd
13159816Smdodd	if (bootverbose)
13259816Smdodd		printf("ex_isa_identify()\n");
13359816Smdodd
13459816Smdodd	for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) {
135131192Simp		rid = 0;
136179775Sjhb		sc.ioport = bus_alloc_resource(parent, SYS_RES_IOPORT, &rid,
137131192Simp		    ioport, ioport, 0x10, RF_ACTIVE);
138179775Sjhb		if (sc.ioport == NULL)
139131192Simp			continue;
14059816Smdodd
14159816Smdodd		/* No board found at address */
142131192Simp		if (!ex_look_for_card(&sc)) {
143179775Sjhb			bus_release_resource(parent, SYS_RES_IOPORT, rid,
144179775Sjhb			    sc.ioport);
14559816Smdodd			continue;
14659816Smdodd		}
14759816Smdodd
14859816Smdodd		if (bootverbose)
149131247Simp			printf("ex: Found card at 0x%03lx!\n", (unsigned long)ioport);
15059816Smdodd
15159816Smdodd		/* Board in PnP mode */
152131192Simp		if (ex_eeprom_read(&sc, EE_W0) & EE_W0_PNP) {
15359816Smdodd			/* Reset the card. */
154131192Simp			CSR_WRITE_1(&sc, CMD_REG, Reset_CMD);
15559816Smdodd			DELAY(500);
15659816Smdodd			if (bootverbose)
157131247Simp				printf("ex: card at 0x%03lx in PnP mode!\n", (unsigned long)ioport);
158179775Sjhb			bus_release_resource(parent, SYS_RES_IOPORT, rid,
159179775Sjhb			    sc.ioport);
16059816Smdodd			continue;
16159816Smdodd		}
16259816Smdodd
16359816Smdodd		bzero(enaddr, sizeof(enaddr));
16459816Smdodd
16559816Smdodd		/* Reset the card. */
166131192Simp		CSR_WRITE_1(&sc, CMD_REG, Reset_CMD);
16759816Smdodd		DELAY(400);
16859816Smdodd
169131192Simp		ex_get_address(&sc, enaddr);
170131192Simp		tmp = ex_eeprom_read(&sc, EE_W1) & EE_W1_INT_SEL;
17159816Smdodd
17259816Smdodd		/* work out which set of irq <-> internal tables to use */
17359816Smdodd		if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
17459816Smdodd			irq  = plus_ee2irqmap[tmp];
17559816Smdodd			desc = "Intel Pro/10+";
17659816Smdodd		} else {
17759816Smdodd			irq = ee2irqmap[tmp];
17859816Smdodd			desc = "Intel Pro/10";
17959816Smdodd		}
18059816Smdodd
181179775Sjhb		bus_release_resource(parent, SYS_RES_IOPORT, rid, sc.ioport);
18259816Smdodd		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1);
18359816Smdodd		device_set_desc_copy(child, desc);
18459816Smdodd		device_set_driver(child, driver);
18559816Smdodd		bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
18659816Smdodd		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE);
18759816Smdodd		if (bootverbose)
188131248Simp			printf("ex: Adding board at 0x%03lx, irq %d\n",
189131248Simp			   (unsigned long)ioport, irq);
19059816Smdodd	}
19159816Smdodd
19259816Smdodd	return;
19359816Smdodd}
19459816Smdodd
19559816Smdoddstatic int
19659816Smdoddex_isa_probe(device_t dev)
19759816Smdodd{
198131192Simp	bus_addr_t	iobase;
19959816Smdodd	u_int		irq;
20059816Smdodd	char *		irq2ee;
20159816Smdodd	u_char *	ee2irq;
20259816Smdodd	u_char 		enaddr[6];
20359816Smdodd	int		tmp;
20459816Smdodd	int		error;
205131192Simp	struct ex_softc *sc = device_get_softc(dev);
20659816Smdodd
20759816Smdodd	/* Check isapnp ids */
20859816Smdodd	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids);
20959816Smdodd
21059816Smdodd	/* If the card had a PnP ID that didn't match any we know about */
211131192Simp	if (error == ENXIO)
21259816Smdodd		return(error);
21359816Smdodd
21459816Smdodd	/* If we had some other problem. */
215131192Simp	if (!(error == 0 || error == ENOENT))
21659816Smdodd		return(error);
21759816Smdodd
218131192Simp	error = ex_alloc_resources(dev);
219131192Simp	if (error != 0)
220131192Simp		goto bad;
22159816Smdodd	iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
222131192Simp	if (!ex_look_for_card(sc)) {
223131192Simp		if (bootverbose)
224131247Simp			printf("ex: no card found at 0x%03lx.\n", (unsigned long)iobase);
225131192Simp		error = ENXIO;
226131192Simp		goto bad;
22759816Smdodd	}
22859816Smdodd	if (bootverbose)
229131247Simp		printf("ex: ex_isa_probe() found card at 0x%03lx\n", (unsigned long)iobase);
23059816Smdodd
23159816Smdodd	/*
23259816Smdodd	 * Reset the card.
23359816Smdodd	 */
234131192Simp	CSR_WRITE_1(sc, CMD_REG, Reset_CMD);
23559816Smdodd	DELAY(800);
23659816Smdodd
237131192Simp	ex_get_address(sc, enaddr);
23859816Smdodd
23959816Smdodd	/* work out which set of irq <-> internal tables to use */
24059816Smdodd	if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
24159816Smdodd		irq2ee = plus_irq2eemap;
24259816Smdodd		ee2irq = plus_ee2irqmap;
24359816Smdodd	} else {
24459816Smdodd		irq2ee = irq2eemap;
24559816Smdodd		ee2irq = ee2irqmap;
24659816Smdodd	}
24759816Smdodd
248131192Simp	tmp = ex_eeprom_read(sc, EE_W1) & EE_W1_INT_SEL;
24959816Smdodd	irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
25059816Smdodd	if (irq > 0) {
25159816Smdodd		/* This will happen if board is in PnP mode. */
25259816Smdodd		if (ee2irq[tmp] != irq) {
253182088Simp			device_printf(dev,
254182088Simp			    "WARNING: IRQ mismatch: EEPROM %d, using %d\n",
25559816Smdodd				ee2irq[tmp], irq);
25659816Smdodd		}
25759816Smdodd	} else {
25859816Smdodd		irq = ee2irq[tmp];
25959816Smdodd		bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
26059816Smdodd	}
26159816Smdodd
26259816Smdodd	if (irq == 0) {
26359816Smdodd		printf("ex: invalid IRQ.\n");
264131192Simp		error = ENXIO;
26559816Smdodd	}
26659816Smdodd
267131192Simpbad:;
268131192Simp	ex_release_resources(dev);
269182088Simp	return (error);
27059816Smdodd}
27159816Smdodd
27259816Smdoddstatic int
27359816Smdoddex_isa_attach(device_t dev)
27459816Smdodd{
27559816Smdodd	struct ex_softc *	sc = device_get_softc(dev);
27659816Smdodd	int			error = 0;
277131192Simp	uint16_t		temp;
27859816Smdodd
27959816Smdodd	sc->dev = dev;
28059816Smdodd	sc->ioport_rid = 0;
28159816Smdodd	sc->irq_rid = 0;
282182088Simp	sc->flags |= HAS_INT_NO_REG;
28359816Smdodd
28459816Smdodd	if ((error = ex_alloc_resources(dev)) != 0) {
28559816Smdodd		device_printf(dev, "ex_alloc_resources() failed!\n");
28659816Smdodd		goto bad;
28759816Smdodd	}
28859816Smdodd
28959816Smdodd	/*
29059816Smdodd	 * Fill in several fields of the softc structure:
29159816Smdodd	 *	- I/O base address.
29259816Smdodd	 *	- Hardware Ethernet address.
29359816Smdodd	 *	- IRQ number (if not supplied in config file, read it from EEPROM).
29459816Smdodd	 *	- Connector type.
29559816Smdodd	 */
29659816Smdodd	sc->irq_no = rman_get_start(sc->irq);
29759816Smdodd
298147256Sbrooks	ex_get_address(sc, sc->enaddr);
29959816Smdodd
300131192Simp	temp = ex_eeprom_read(sc, EE_W0);
30159816Smdodd	device_printf(sc->dev, "%s config, %s bus, ",
30259816Smdodd		(temp & EE_W0_PNP) ? "PnP" : "Manual",
30359816Smdodd		(temp & EE_W0_BUS16) ? "16-bit" : "8-bit");
30459816Smdodd
305131192Simp	temp = ex_eeprom_read(sc, EE_W6);
30659816Smdodd	printf("board id 0x%03x, stepping 0x%01x\n",
30759816Smdodd		(temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT,
30859816Smdodd		temp & EE_W6_STEP_MASK);
30959816Smdodd
31059816Smdodd	if ((error = ex_attach(dev)) != 0) {
31159816Smdodd		device_printf(dev, "ex_attach() failed!\n");
31259816Smdodd		goto bad;
31359816Smdodd	}
31459816Smdodd
31559816Smdodd	return(0);
31659816Smdoddbad:
31759816Smdodd	ex_release_resources(dev);
31859816Smdodd	return (error);
31959816Smdodd}
320131192Simp
321131192Simpstatic int
322131192Simpex_look_for_card(struct ex_softc *sc)
323131192Simp{
324131192Simp	int count1, count2;
325131192Simp
326131192Simp	/*
327131192Simp	 * Check for the i82595 signature, and check that the round robin
328131192Simp	 * counter actually advances.
329131192Simp	 */
330131192Simp	if (((count1 = CSR_READ_1(sc, ID_REG)) & Id_Mask) != Id_Sig)
331131192Simp		return(0);
332131192Simp	count2 = CSR_READ_1(sc, ID_REG);
333131192Simp	count2 = CSR_READ_1(sc, ID_REG);
334131192Simp	count2 = CSR_READ_1(sc, ID_REG);
335131192Simp
336131192Simp	return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits));
337131192Simp}
338