1139749Simp/*-
214258Sgibbs * Product specific probe and attach routines for:
314258Sgibbs * 	3COM 3C579 and 3C509(in eisa config mode) ethernet controllers
414258Sgibbs *
514258Sgibbs * Copyright (c) 1996 Justin T. Gibbs
614258Sgibbs * All rights reserved.
714258Sgibbs *
814258Sgibbs * Redistribution and use in source and binary forms, with or without
914258Sgibbs * modification, are permitted provided that the following conditions
1014258Sgibbs * are met:
1114258Sgibbs * 1. Redistributions of source code must retain the above copyright
1214258Sgibbs *    notice immediately at the beginning of the file, without modification,
1314258Sgibbs *    this list of conditions, and the following disclaimer.
1414258Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1514258Sgibbs *    notice, this list of conditions and the following disclaimer in the
1614258Sgibbs *    documentation and/or other materials provided with the distribution.
1714258Sgibbs * 3. Absolutely no warranty of function or purpose is made by the author
1814258Sgibbs *    Justin T. Gibbs.
1914258Sgibbs * 4. Modifications may be freely made to this file if the above conditions
2014258Sgibbs *    are met.
2114258Sgibbs */
2214258Sgibbs
23117700Smarkm#include <sys/cdefs.h>
24117700Smarkm__FBSDID("$FreeBSD$");
25117700Smarkm
2614258Sgibbs#include <sys/param.h>
2714258Sgibbs#include <sys/systm.h>
2814258Sgibbs#include <sys/kernel.h>
2918892Sbde#include <sys/socket.h>
3045791Speter#include <sys/module.h>
3145791Speter#include <sys/bus.h>
3214258Sgibbs
3345791Speter#include <machine/bus.h>
3445791Speter#include <machine/resource.h>
35117700Smarkm#include <sys/rman.h>
3614258Sgibbs
3714258Sgibbs#include <net/if.h>
3852549Smdodd#include <net/if_arp.h>
39117700Smarkm#include <net/if_media.h>
4014258Sgibbs
41112845Smdodd#include <dev/eisa/eisaconf.h>
42112845Smdodd
4351879Smdodd#include <dev/ep/if_epreg.h>
4451879Smdodd#include <dev/ep/if_epvar.h>
4551879Smdodd
4614258Sgibbs#define EISA_DEVICE_ID_3COM_3C509_TP	0x506d5090
4714258Sgibbs#define EISA_DEVICE_ID_3COM_3C509_BNC	0x506d5091
4814258Sgibbs#define EISA_DEVICE_ID_3COM_3C579_TP	0x506d5092
4914258Sgibbs#define EISA_DEVICE_ID_3COM_3C579_BNC	0x506d5093
5014258Sgibbs#define EISA_DEVICE_ID_3COM_3C509_COMBO	0x506d5094
5114258Sgibbs#define EISA_DEVICE_ID_3COM_3C509_TPO	0x506d5095
5214258Sgibbs
5314258Sgibbs#define	EP_EISA_SLOT_OFFSET		0x0c80
5414258Sgibbs#define	EP_EISA_IOSIZE			0x000a
5514258Sgibbs
5614258Sgibbs#define EISA_IOCONF			0x0008
5714258Sgibbs#define		IRQ_CHANNEL		0xf000
5814258Sgibbs#define			INT_3		0x3000
5914258Sgibbs#define			INT_5		0x5000
6014258Sgibbs#define			INT_7		0x7000
6114258Sgibbs#define			INT_9		0x9000
6214258Sgibbs#define			INT_10		0xa000
6314258Sgibbs#define			INT_11		0xb000
6414258Sgibbs#define			INT_12		0xc000
6514258Sgibbs#define			INT_15		0xf000
6614258Sgibbs#define EISA_BPROM_MEDIA_CONF		0x0006
6714258Sgibbs#define		TRANS_TYPE		0xc000
6814258Sgibbs#define			TRANS_TP	0x0000
6914258Sgibbs#define			TRANS_AUI	0x4000
7014258Sgibbs#define			TRANS_BNC	0xc000
7114258Sgibbs
7292739Salfredstatic const char *ep_match(eisa_id_t type);
7314258Sgibbs
74117700Smarkmstatic const char *
7545791Speterep_match(eisa_id_t type)
7614258Sgibbs{
77117700Smarkm	switch (type) {
78117700Smarkm	case EISA_DEVICE_ID_3COM_3C509_TP:
79149559Simp		return ("3Com 3C509-TP");
80117700Smarkm	case EISA_DEVICE_ID_3COM_3C509_BNC:
81149559Simp		return ("3Com 3C509-BNC");
82117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_TP:
83149559Simp		return ("3Com 3C579-TP");
84117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_BNC:
85149559Simp		return ("3Com 3C579-BNC");
86117700Smarkm	case EISA_DEVICE_ID_3COM_3C509_COMBO:
87149559Simp		return ("3Com 3C509-Combo");
88117700Smarkm	case EISA_DEVICE_ID_3COM_3C509_TPO:
89149559Simp		return ("3Com 3C509-TPO");
90117700Smarkm	default:
91117700Smarkm		return (NULL);
9214258Sgibbs	}
9314258Sgibbs}
9414258Sgibbs
9514258Sgibbsstatic int
9645791Speterep_eisa_probe(device_t dev)
9714258Sgibbs{
9845791Speter	const char *desc;
9914258Sgibbs	u_long iobase;
10045791Speter	u_short conf;
10145791Speter	u_long port;
10245791Speter	int irq;
10352549Smdodd	int int_trig;
10414258Sgibbs
10545791Speter	desc = ep_match(eisa_get_id(dev));
10645791Speter	if (!desc)
10745791Speter		return (ENXIO);
10845791Speter	device_set_desc(dev, desc);
10914258Sgibbs
11045791Speter	port = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
11145791Speter	iobase = port + EP_EISA_SLOT_OFFSET;
11214258Sgibbs
11345791Speter	/* We must be in EISA configuration mode */
11445791Speter	if ((inw(iobase + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
115132518Simp		return (ENXIO);
11614258Sgibbs
117112845Smdodd	eisa_add_iospace(dev, iobase, EP_EISA_IOSIZE, RESVADDR_NONE);
118112845Smdodd	eisa_add_iospace(dev, port, EP_IOSIZE, RESVADDR_NONE);
11914258Sgibbs
12045791Speter	conf = inw(iobase + EISA_IOCONF);
12145791Speter	/* Determine our IRQ */
12245791Speter	switch (conf & IRQ_CHANNEL) {
12345791Speter	case INT_3:
124117700Smarkm		irq = 3;
125117700Smarkm		break;
12645791Speter	case INT_5:
127117700Smarkm		irq = 5;
128117700Smarkm		break;
12945791Speter	case INT_7:
130117700Smarkm		irq = 7;
131117700Smarkm		break;
13245791Speter	case INT_9:
133117700Smarkm		irq = 9;
134117700Smarkm		break;
13545791Speter	case INT_10:
136117700Smarkm		irq = 10;
137117700Smarkm		break;
13845791Speter	case INT_11:
139117700Smarkm		irq = 11;
140117700Smarkm		break;
14145791Speter	case INT_12:
142117700Smarkm		irq = 12;
143117700Smarkm		break;
14445791Speter	case INT_15:
145117700Smarkm		irq = 15;
146117700Smarkm		break;
14745791Speter	default:
148117700Smarkm		/* Disabled */
149117700Smarkm		printf("ep: 3COM Network Adapter at "
150117700Smarkm		    "slot %d has its IRQ disabled. "
151117700Smarkm		    "Probe failed.\n",
152117700Smarkm		    eisa_get_slot(dev));
153117700Smarkm		return (ENXIO);
15414258Sgibbs	}
15545791Speter
156117700Smarkm	switch (eisa_get_id(dev)) {
157117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_BNC:
158117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_TP:
159117700Smarkm		int_trig = EISA_TRIGGER_LEVEL;
160117700Smarkm		break;
161117700Smarkm	default:
162117700Smarkm		int_trig = EISA_TRIGGER_EDGE;
163117700Smarkm		break;
16452549Smdodd	}
165117700Smarkm
166112845Smdodd	eisa_add_intr(dev, irq, int_trig);
16752549Smdodd
168117700Smarkm	return (0);
16914258Sgibbs}
17014258Sgibbs
17114258Sgibbsstatic int
17245791Speterep_eisa_attach(device_t dev)
17314258Sgibbs{
174117700Smarkm	struct ep_softc *sc = device_get_softc(dev);
175117700Smarkm	struct resource *eisa_io = NULL;
176140523Simp	uint32_t eisa_iobase;
177117700Smarkm	int irq;
178117700Smarkm	int error = 0;
179117700Smarkm	int rid;
18014258Sgibbs
18145791Speter	rid = 1;
182127135Snjl	eisa_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
18345791Speter	if (!eisa_io) {
18445791Speter		device_printf(dev, "No I/O space?!\n");
18552549Smdodd		error = ENXIO;
18645791Speter		goto bad;
18745791Speter	}
18852549Smdodd	eisa_iobase = rman_get_start(eisa_io);
18914258Sgibbs
19052549Smdodd	/* Reset and Enable the card */
19152549Smdodd	outb(eisa_iobase + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER);
192117700Smarkm	DELAY(1000);		/* we must wait at least 1 ms */
19352549Smdodd	outb(eisa_iobase + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER);
19452549Smdodd	/* Now the registers are availible through the lower ioport */
19514258Sgibbs
19652549Smdodd	if ((error = ep_alloc(dev))) {
19752549Smdodd		device_printf(dev, "ep_alloc() failed! (%d)\n", error);
19845791Speter		goto bad;
19952549Smdodd	}
200117700Smarkm	switch (eisa_get_id(dev)) {
201117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_BNC:
202117700Smarkm	case EISA_DEVICE_ID_3COM_3C579_TP:
203117700Smarkm		sc->stat = F_ACCESS_32_BITS;
204117700Smarkm		break;
20514258Sgibbs	}
20614258Sgibbs
20752549Smdodd	ep_get_media(sc);
20814258Sgibbs
20952549Smdodd	irq = rman_get_start(sc->irq);
21052549Smdodd	if (irq == 9)
21152549Smdodd		irq = 2;
21214258Sgibbs
213121588Simp	GO_WINDOW(sc, 0);
214121225Sbms	SET_IRQ(sc, irq);
21514258Sgibbs
21652549Smdodd	if ((error = ep_attach(sc))) {
21752549Smdodd		device_printf(dev, "ep_attach() failed! (%d)\n", error);
21852549Smdodd		goto bad;
21952549Smdodd	}
220166901Spiso	if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
221166901Spiso	    NULL, ep_intr, sc, &sc->ep_intrhand))) {
22252549Smdodd		device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
22352549Smdodd		goto bad;
22452549Smdodd	}
22552549Smdodd	return (0);
22614258Sgibbs
227117700Smarkmbad:
22845791Speter	if (eisa_io)
22945791Speter		bus_release_resource(dev, SYS_RES_IOPORT, 0, eisa_io);
23052549Smdodd
23152549Smdodd	ep_free(dev);
23252549Smdodd	return (error);
23314258Sgibbs}
23414258Sgibbs
23545791Speterstatic device_method_t ep_eisa_methods[] = {
23645791Speter	/* Device interface */
237117700Smarkm	DEVMETHOD(device_probe, ep_eisa_probe),
238117700Smarkm	DEVMETHOD(device_attach, ep_eisa_attach),
239117700Smarkm	DEVMETHOD(device_detach, ep_detach),
24045791Speter
241246128Ssbz	DEVMETHOD_END
24245791Speter};
24345791Speter
24445791Speterstatic driver_t ep_eisa_driver = {
24545791Speter	"ep",
24645791Speter	ep_eisa_methods,
24752549Smdodd	sizeof(struct ep_softc),
24845791Speter};
24945791Speter
25052472Simpextern devclass_t ep_devclass;
25145791Speter
25245791SpeterDRIVER_MODULE(ep, eisa, ep_eisa_driver, ep_devclass, 0, 0);
253