if_ex_isa.c revision 119418
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: head/sys/dev/ex/if_ex_isa.c 119418 2003-08-24 17:55:58Z obrien $");
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 */
5592739Salfredstatic void	ex_isa_identify	(driver_t *, device_t);
5692739Salfredstatic int	ex_isa_probe	(device_t);
5792739Salfredstatic int	ex_isa_attach	(device_t);
5859816Smdodd
5959816Smdodd#if 0
6059816Smdoddstatic	void	ex_pnp_wakeup	(void *);
6159816Smdodd
6259816SmdoddSYSINIT(ex_pnpwakeup, SI_SUB_CPU, SI_ORDER_ANY, ex_pnp_wakeup, NULL);
6359816Smdodd#endif
6459816Smdodd
65112801Smdoddstatic device_method_t ex_isa_methods[] = {
6659816Smdodd	/* Device interface */
6759816Smdodd	DEVMETHOD(device_identify,	ex_isa_identify),
6859816Smdodd	DEVMETHOD(device_probe,		ex_isa_probe),
6959816Smdodd	DEVMETHOD(device_attach,	ex_isa_attach),
70112800Smdodd	DEVMETHOD(device_detach,	ex_detach),
7159816Smdodd
7259816Smdodd	{ 0, 0 }
7359816Smdodd};
7459816Smdodd
75112801Smdoddstatic driver_t ex_isa_driver = {
7659816Smdodd	"ex",
77112801Smdodd	ex_isa_methods,
7859816Smdodd	sizeof(struct ex_softc),
7959816Smdodd};
8059816Smdodd
81112801SmdoddDRIVER_MODULE(ex, isa, ex_isa_driver, ex_devclass, 0, 0);
8259816Smdodd
8359816Smdoddstatic struct isa_pnp_id ex_ids[] = {
8459816Smdodd	{ 0x3110d425,	NULL },	/* INT1031 */
8559816Smdodd	{ 0x3010d425,	NULL },	/* INT1030 */
8659816Smdodd	{ 0,		NULL },
8759816Smdodd};
8859816Smdodd
8959816Smdodd#if 0
9059816Smdodd#define EX_PNP_WAKE		0x279
9159816Smdodd
9259816Smdoddstatic u_int8_t ex_pnp_wake_seq[] =
9359816Smdodd			{ 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
9459816Smdodd			  0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
9559816Smdodd			  0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
9659816Smdodd			  0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43 };
9759816Smdodd
9859816Smdoddstatic void
9959816Smdoddex_pnp_wakeup (void * dummy)
10059816Smdodd{
10159816Smdodd	int	tmp;
10259816Smdodd
10359816Smdodd	if (bootverbose)
10459816Smdodd		printf("ex_pnp_wakeup()\n");
10559816Smdodd
10659816Smdodd	outb(EX_PNP_WAKE, 0);
10759816Smdodd	outb(EX_PNP_WAKE, 0);
10859816Smdodd	for (tmp = 0; tmp < 32; tmp++) {
10959816Smdodd		outb(EX_PNP_WAKE, ex_pnp_wake_seq[tmp]);
11059816Smdodd	}
11159816Smdodd}
11259816Smdodd#endif
11359816Smdodd
11459816Smdodd/*
11559816Smdodd * Non-destructive identify.
11659816Smdodd */
11759816Smdoddstatic void
11859816Smdoddex_isa_identify (driver_t *driver, device_t parent)
11959816Smdodd{
12059816Smdodd	device_t	child;
12159816Smdodd	u_int32_t	ioport;
12259816Smdodd	u_char 		enaddr[6];
12359816Smdodd	u_int		irq;
12459816Smdodd	int		tmp;
12559816Smdodd	const char *	desc;
12659816Smdodd
12759816Smdodd	if (bootverbose)
12859816Smdodd		printf("ex_isa_identify()\n");
12959816Smdodd
13059816Smdodd	for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) {
13159816Smdodd
13259816Smdodd		/* No board found at address */
13359816Smdodd		if (!look_for_card(ioport)) {
13459816Smdodd			continue;
13559816Smdodd		}
13659816Smdodd
13759816Smdodd		if (bootverbose)
13859816Smdodd			printf("ex: Found card at 0x%03x!\n", ioport);
13959816Smdodd
14059816Smdodd		/* Board in PnP mode */
14159816Smdodd		if (eeprom_read(ioport, EE_W0) & EE_W0_PNP) {
14259816Smdodd			/* Reset the card. */
14359816Smdodd			outb(ioport + CMD_REG, Reset_CMD);
14459816Smdodd			DELAY(500);
14559816Smdodd			if (bootverbose)
14659816Smdodd				printf("ex: card at 0x%03x in PnP mode!\n", ioport);
14759816Smdodd			continue;
14859816Smdodd		}
14959816Smdodd
15059816Smdodd		bzero(enaddr, sizeof(enaddr));
15159816Smdodd
15259816Smdodd		/* Reset the card. */
15359816Smdodd		outb(ioport + CMD_REG, Reset_CMD);
15459816Smdodd		DELAY(400);
15559816Smdodd
15659816Smdodd		ex_get_address(ioport, enaddr);
15759816Smdodd		tmp = eeprom_read(ioport, EE_W1) & EE_W1_INT_SEL;
15859816Smdodd
15959816Smdodd		/* work out which set of irq <-> internal tables to use */
16059816Smdodd		if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
16159816Smdodd			irq  = plus_ee2irqmap[tmp];
16259816Smdodd			desc = "Intel Pro/10+";
16359816Smdodd		} else {
16459816Smdodd			irq = ee2irqmap[tmp];
16559816Smdodd			desc = "Intel Pro/10";
16659816Smdodd		}
16759816Smdodd
16859816Smdodd		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1);
16959816Smdodd		device_set_desc_copy(child, desc);
17059816Smdodd		device_set_driver(child, driver);
17159816Smdodd		bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
17259816Smdodd		bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE);
17359816Smdodd
17459816Smdodd		if (bootverbose)
17559816Smdodd			printf("ex: Adding board at 0x%03x, irq %d\n", ioport, irq);
17659816Smdodd	}
17759816Smdodd
17859816Smdodd	return;
17959816Smdodd}
18059816Smdodd
18159816Smdoddstatic int
18259816Smdoddex_isa_probe(device_t dev)
18359816Smdodd{
18459816Smdodd	u_int		iobase;
18559816Smdodd	u_int		irq;
18659816Smdodd	char *		irq2ee;
18759816Smdodd	u_char *	ee2irq;
18859816Smdodd	u_char 		enaddr[6];
18959816Smdodd	int		tmp;
19059816Smdodd	int		error;
19159816Smdodd
19259816Smdodd	/* Check isapnp ids */
19359816Smdodd	error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids);
19459816Smdodd
19559816Smdodd	/* If the card had a PnP ID that didn't match any we know about */
19659816Smdodd	if (error == ENXIO) {
19759816Smdodd		return(error);
19859816Smdodd	}
19959816Smdodd
20059816Smdodd	/* If we had some other problem. */
20159816Smdodd	if (!(error == 0 || error == ENOENT)) {
20259816Smdodd		return(error);
20359816Smdodd	}
20459816Smdodd
20559816Smdodd	iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
20659816Smdodd	if (!iobase) {
20759816Smdodd		printf("ex: no iobase?\n");
20859816Smdodd		return(ENXIO);
20959816Smdodd	}
21059816Smdodd
21159816Smdodd	if (!look_for_card(iobase)) {
21259816Smdodd		printf("ex: no card found at 0x%03x\n", iobase);
21359816Smdodd		return(ENXIO);
21459816Smdodd	}
21559816Smdodd
21659816Smdodd	if (bootverbose)
21759816Smdodd		printf("ex: ex_isa_probe() found card at 0x%03x\n", iobase);
21859816Smdodd
21959816Smdodd	/*
22059816Smdodd	 * Reset the card.
22159816Smdodd	 */
22259816Smdodd	outb(iobase + CMD_REG, Reset_CMD);
22359816Smdodd	DELAY(800);
22459816Smdodd
22559816Smdodd	ex_get_address(iobase, enaddr);
22659816Smdodd
22759816Smdodd	/* work out which set of irq <-> internal tables to use */
22859816Smdodd	if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
22959816Smdodd		irq2ee = plus_irq2eemap;
23059816Smdodd		ee2irq = plus_ee2irqmap;
23159816Smdodd	} else {
23259816Smdodd		irq2ee = irq2eemap;
23359816Smdodd		ee2irq = ee2irqmap;
23459816Smdodd	}
23559816Smdodd
23659816Smdodd	tmp = eeprom_read(iobase, EE_W1) & EE_W1_INT_SEL;
23759816Smdodd	irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
23859816Smdodd
23959816Smdodd	if (irq > 0) {
24059816Smdodd		/* This will happen if board is in PnP mode. */
24159816Smdodd		if (ee2irq[tmp] != irq) {
24259816Smdodd			printf("ex: WARNING: board's EEPROM is configured"
24359816Smdodd				" for IRQ %d, using %d\n",
24459816Smdodd				ee2irq[tmp], irq);
24559816Smdodd		}
24659816Smdodd	} else {
24759816Smdodd		irq = ee2irq[tmp];
24859816Smdodd		bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
24959816Smdodd	}
25059816Smdodd
25159816Smdodd	if (irq == 0) {
25259816Smdodd		printf("ex: invalid IRQ.\n");
25359816Smdodd		return(ENXIO);
25459816Smdodd	}
25559816Smdodd
25659816Smdodd	return(0);
25759816Smdodd}
25859816Smdodd
25959816Smdoddstatic int
26059816Smdoddex_isa_attach(device_t dev)
26159816Smdodd{
26259816Smdodd	struct ex_softc *	sc = device_get_softc(dev);
26359816Smdodd	int			error = 0;
26459816Smdodd	u_int16_t		temp;
26559816Smdodd
26659816Smdodd	sc->dev = dev;
26759816Smdodd	sc->ioport_rid = 0;
26859816Smdodd	sc->irq_rid = 0;
26959816Smdodd
27059816Smdodd	if ((error = ex_alloc_resources(dev)) != 0) {
27159816Smdodd		device_printf(dev, "ex_alloc_resources() failed!\n");
27259816Smdodd		goto bad;
27359816Smdodd	}
27459816Smdodd
27559816Smdodd	/*
27659816Smdodd	 * Fill in several fields of the softc structure:
27759816Smdodd	 *	- I/O base address.
27859816Smdodd	 *	- Hardware Ethernet address.
27959816Smdodd	 *	- IRQ number (if not supplied in config file, read it from EEPROM).
28059816Smdodd	 *	- Connector type.
28159816Smdodd	 */
28259816Smdodd	sc->iobase = rman_get_start(sc->ioport);
28359816Smdodd	sc->irq_no = rman_get_start(sc->irq);
28459816Smdodd
28559816Smdodd	ex_get_address(sc->iobase, sc->arpcom.ac_enaddr);
28659816Smdodd
28759816Smdodd	temp = eeprom_read(sc->iobase, EE_W0);
28859816Smdodd	device_printf(sc->dev, "%s config, %s bus, ",
28959816Smdodd		(temp & EE_W0_PNP) ? "PnP" : "Manual",
29059816Smdodd		(temp & EE_W0_BUS16) ? "16-bit" : "8-bit");
29159816Smdodd
29259816Smdodd	temp = eeprom_read(sc->iobase, EE_W6);
29359816Smdodd	printf("board id 0x%03x, stepping 0x%01x\n",
29459816Smdodd		(temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT,
29559816Smdodd		temp & EE_W6_STEP_MASK);
29659816Smdodd
29759816Smdodd	if ((error = ex_attach(dev)) != 0) {
29859816Smdodd		device_printf(dev, "ex_attach() failed!\n");
29959816Smdodd		goto bad;
30059816Smdodd	}
30159816Smdodd
30259816Smdodd	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET,
30359816Smdodd				ex_intr, (void *)sc, &sc->ih);
30459816Smdodd	if (error) {
30559816Smdodd		device_printf(dev, "bus_setup_intr() failed!\n");
30659816Smdodd		goto bad;
30759816Smdodd	}
30859816Smdodd
30959816Smdodd	return(0);
31059816Smdoddbad:
31159816Smdodd	ex_release_resources(dev);
31259816Smdodd	return (error);
31359816Smdodd}
314