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