if_ep_eisa.c revision 52472
1/*
2 * Product specific probe and attach routines for:
3 * 	3COM 3C579 and 3C509(in eisa config mode) ethernet controllers
4 *
5 * Copyright (c) 1996 Justin T. Gibbs
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice immediately at the beginning of the file, without modification,
13 *    this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Absolutely no warranty of function or purpose is made by the author
18 *    Justin T. Gibbs.
19 * 4. Modifications may be freely made to this file if the above conditions
20 *    are met.
21 *
22 * $FreeBSD: head/sys/dev/ep/if_ep_eisa.c 52472 1999-10-25 02:52:16Z imp $
23 */
24
25#include "eisa.h"
26#if NEISA > 0
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/kernel.h>
31#include <sys/socket.h>
32#include <sys/module.h>
33#include <sys/bus.h>
34
35#include <machine/clock.h>
36#include <machine/bus.h>
37#include <machine/resource.h>
38#include <sys/rman.h>
39
40#include <net/if.h>
41
42#include <netinet/in.h>
43#include <netinet/if_ether.h>
44
45#include <i386/eisa/eisaconf.h>
46
47#include <dev/ep/if_epreg.h>
48#include <dev/ep/if_epvar.h>
49
50#define EISA_DEVICE_ID_3COM_3C509_TP	0x506d5090
51#define EISA_DEVICE_ID_3COM_3C509_BNC	0x506d5091
52#define EISA_DEVICE_ID_3COM_3C579_TP	0x506d5092
53#define EISA_DEVICE_ID_3COM_3C579_BNC	0x506d5093
54#define EISA_DEVICE_ID_3COM_3C509_COMBO	0x506d5094
55#define EISA_DEVICE_ID_3COM_3C509_TPO	0x506d5095
56
57#define	EP_EISA_SLOT_OFFSET		0x0c80
58#define	EP_EISA_IOSIZE			0x000a
59
60#define EISA_IOCONF			0x0008
61#define		IRQ_CHANNEL		0xf000
62#define			INT_3		0x3000
63#define			INT_5		0x5000
64#define			INT_7		0x7000
65#define			INT_9		0x9000
66#define			INT_10		0xa000
67#define			INT_11		0xb000
68#define			INT_12		0xc000
69#define			INT_15		0xf000
70#define EISA_BPROM_MEDIA_CONF		0x0006
71#define		TRANS_TYPE		0xc000
72#define			TRANS_TP	0x0000
73#define			TRANS_AUI	0x4000
74#define			TRANS_BNC	0xc000
75
76static const char *ep_match __P((eisa_id_t type));
77
78static const char*
79ep_match(eisa_id_t type)
80{
81	switch(type) {
82		case EISA_DEVICE_ID_3COM_3C509_TP:
83			return "3Com 3C509-TP Network Adapter";
84			break;
85		case EISA_DEVICE_ID_3COM_3C509_BNC:
86			return "3Com 3C509-BNC Network Adapter";
87			break;
88		case EISA_DEVICE_ID_3COM_3C579_TP:
89			return "3Com 3C579-TP EISA Network Adapter";
90			break;
91		case EISA_DEVICE_ID_3COM_3C579_BNC:
92			return "3Com 3C579-BNC EISA Network Adapter";
93			break;
94		case EISA_DEVICE_ID_3COM_3C509_COMBO:
95			return "3Com 3C509-Combo Network Adapter";
96			break;
97		case EISA_DEVICE_ID_3COM_3C509_TPO:
98			return "3Com 3C509-TPO Network Adapter";
99			break;
100		default:
101			break;
102	}
103	return (NULL);
104}
105
106static int
107ep_eisa_probe(device_t dev)
108{
109	const char *desc;
110	u_long iobase;
111	u_short conf;
112	u_long port;
113	int irq;
114
115	desc = ep_match(eisa_get_id(dev));
116	if (!desc)
117		return (ENXIO);
118	device_set_desc(dev, desc);
119
120	port = (eisa_get_slot(dev) * EISA_SLOT_SIZE);
121	iobase = port + EP_EISA_SLOT_OFFSET;
122
123	/* We must be in EISA configuration mode */
124	if ((inw(iobase + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
125	    return ENXIO;
126
127	eisa_add_iospace(dev, iobase, EP_EISA_IOSIZE, RESVADDR_NONE);
128	eisa_add_iospace(dev, port, EP_IOSIZE, RESVADDR_NONE);
129
130	conf = inw(iobase + EISA_IOCONF);
131	/* Determine our IRQ */
132	switch (conf & IRQ_CHANNEL) {
133	case INT_3:
134	    irq = 3;
135	    break;
136	case INT_5:
137	    irq = 5;
138	    break;
139	case INT_7:
140	    irq = 7;
141	    break;
142	case INT_9:
143	    irq = 9;
144	    break;
145	case INT_10:
146	    irq = 10;
147	    break;
148	case INT_11:
149	    irq = 11;
150	    break;
151	case INT_12:
152	    irq = 12;
153	    break;
154	case INT_15:
155	    irq = 15;
156	    break;
157	default:
158				/* Disabled */
159	    printf("ep: 3COM Network Adapter at "
160		   "slot %d has its IRQ disabled. "
161		   "Probe failed.\n",
162		   eisa_get_slot(dev));
163	    return ENXIO;
164	}
165	eisa_add_intr(dev, irq, EISA_TRIGGER_EDGE);
166
167	return 0;
168}
169
170static int
171ep_eisa_attach(device_t dev)
172{
173	struct ep_softc *sc;
174	struct ep_board *epb;
175	struct resource *io = 0;
176	struct resource *eisa_io = 0;
177	struct resource *irq = 0;
178	int unit = device_get_unit(dev);
179	u_char level_intr;
180	int i, rid, shared;
181	void *ih;
182
183	/*
184	 * The addresses are sorted in increasing order
185	 * so we know the port to pass to the core ep
186	 * driver comes first.
187	 */
188	rid = 0;
189	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
190				0, ~0, 1, RF_ACTIVE);
191	if (!io) {
192		device_printf(dev, "No I/O space?!\n");
193		goto bad;
194	}
195
196	rid = 1;
197	eisa_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
198				     0, ~0, 1, RF_ACTIVE);
199	if (!eisa_io) {
200		device_printf(dev, "No I/O space?!\n");
201		goto bad;
202	}
203
204	epb = &ep_board[ep_boards];
205
206	epb->epb_addr = rman_get_start(io);
207	epb->epb_used = 1;
208
209	if(!(sc = ep_alloc(unit, epb)))
210		goto bad;
211
212	ep_boards++;
213
214	sc->stat = 0;
215	level_intr = FALSE;
216	switch(eisa_get_id(dev)) {
217		case EISA_DEVICE_ID_3COM_3C509_TP:
218			sc->ep_connectors = UTP|AUI;
219			break;
220		case EISA_DEVICE_ID_3COM_3C509_BNC:
221			sc->ep_connectors = BNC|AUI;
222			break;
223		case EISA_DEVICE_ID_3COM_3C579_TP:
224			sc->ep_connectors = UTP|AUI;
225			sc->stat = F_ACCESS_32_BITS;
226			level_intr = TRUE;
227			break;
228		case EISA_DEVICE_ID_3COM_3C579_BNC:
229			sc->ep_connectors = BNC|AUI;
230			sc->stat = F_ACCESS_32_BITS;
231			level_intr = TRUE;
232			break;
233		case EISA_DEVICE_ID_3COM_3C509_COMBO:
234			sc->ep_connectors = UTP|BNC|AUI;
235			break;
236		case EISA_DEVICE_ID_3COM_3C509_TPO:
237			sc->ep_connectors = UTP;
238			break;
239		default:
240			break;
241        }
242	/*
243	 * Set the eisa config selected media type
244	 */
245	sc->ep_connector = inw(rman_get_start(eisa_io) + EISA_BPROM_MEDIA_CONF)
246			   >> ACF_CONNECTOR_BITS;
247
248	shared = level_intr ? RF_SHAREABLE : 0;
249	rid = 0;
250	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
251				 0, ~0, 1, shared | RF_ACTIVE);
252	if (!irq) {
253		device_printf(dev, "No irq?!\n");
254		goto bad;
255	}
256
257	/* Reset and Enable the card */
258	outb(rman_get_start(eisa_io) + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER);
259	DELAY(1000); /* we must wait at least 1 ms */
260	outb(rman_get_start(eisa_io) + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER);
261
262	/* Now the registers are availible through the lower ioport */
263
264	/*
265	 * Retrieve our ethernet address
266	 */
267	GO_WINDOW(0);
268	for(i = 0; i < 3; i++)
269		sc->epb->eth_addr[i] = get_e(sc, i);
270
271        /* Even we get irq number from board, we should tell him..
272            Otherwise we never get a H/W interrupt anymore...*/
273        if ( rman_get_start(irq) == 9 )
274               rman_get_start(irq) = 2;
275        SET_IRQ(rman_get_start(eisa_io), rman_get_start(irq));
276
277	ep_attach(sc);
278
279	bus_setup_intr(dev, irq, INTR_TYPE_NET, ep_intr, sc, &ih);
280
281	return 0;
282
283 bad:
284	if (io)
285		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
286	if (eisa_io)
287		bus_release_resource(dev, SYS_RES_IOPORT, 0, eisa_io);
288	if (irq)
289		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
290	return -1;
291}
292
293static device_method_t ep_eisa_methods[] = {
294	/* Device interface */
295	DEVMETHOD(device_probe,		ep_eisa_probe),
296	DEVMETHOD(device_attach,	ep_eisa_attach),
297
298	{ 0, 0 }
299};
300
301static driver_t ep_eisa_driver = {
302	"ep",
303	ep_eisa_methods,
304	1,			/* unused */
305};
306
307extern devclass_t ep_devclass;
308
309DRIVER_MODULE(ep, eisa, ep_eisa_driver, ep_devclass, 0, 0);
310
311#endif /* NEISA > 0 */
312