if_ie_isa.c revision 153110
1/*-
2 * Copyright (c) 2003 Matthew N. Dodd
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * Portions:
27 * Copyright (c) 1992, 1993, University of Vermont and State
28 *  Agricultural College.
29 * Copyright (c) 1992, 1993, Garrett A. Wollman.
30 * Copyright (c) 1990, 1991, William F. Jolitz
31 * Copyright (c) 1990, The Regents of the University of California
32 * Copyright (c) 1993, 1994, Charles M. Hannum
33 * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes
34 * Copyright (c) 1997, Aaron C. Smith
35 *
36 * See if_ie.c for applicable license.
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/dev/ie/if_ie_isa.c 153110 2005-12-05 11:58:35Z ru $");
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/kernel.h>
45#include <sys/socket.h>
46
47#include <sys/module.h>
48#include <sys/bus.h>
49
50#include <machine/bus.h>
51#include <machine/resource.h>
52#include <sys/rman.h>
53
54#include <machine/clock.h>
55#include <machine/md_var.h>
56
57#include <net/if.h>
58#include <net/if_arp.h>
59#include <net/if_media.h>
60
61#include <isa/isavar.h>
62#include <isa/pnpvar.h>
63
64#include <i386/isa/elink.h>
65
66#include <dev/ic/i82586.h>
67#include <dev/ie/if_ie507.h>
68#include <dev/ie/if_iee16.h>
69#include <dev/ie/if_iereg.h>
70#include <dev/ie/if_ievar.h>
71
72static int		ie_modevent		(module_t, int, void *);
73
74static void		ie_isa_3C507_identify	(driver_t *, device_t);
75static int		ie_isa_3C507_probe	(device_t);
76static int		ie_isa_3C507_attach	(device_t);
77static int		ie_3C507_port_check	(u_int32_t);
78
79static void		ie_isa_ee16_identify	(driver_t *, device_t);
80static int		ie_isa_ee16_probe	(device_t);
81static int		ie_isa_ee16_attach	(device_t);
82static int		ie_ee16_port_check	(u_int32_t port);
83static u_int16_t	ie_ee16_hw_read_eeprom	(u_int32_t port, int loc);
84
85static int		ie_isa_sl_probe		(device_t);
86static int		ie_isa_sl_attach	(device_t);
87static enum ie_hardware	ie_isa_sl_get_hard_type	(u_int32_t);
88
89/*
90 * 3Com 3C507 Etherlink 16
91 */
92#define IE_3C507_IOBASE_LOW	0x200
93#define IE_3C507_IOBASE_HIGH	0x3e0
94#define IE_3C507_IOSIZE		16
95
96#define IE_3C507_IRQ_MASK	0x0f
97
98#define IE_3C507_MADDR_HIGH	0x20
99#define IE_3C507_MADDR_MASK	0x1c
100#define IE_3C507_MADDR_BASE	0xc0000
101#define IE_3C507_MADDR_SHIFT	12
102
103#define IE_3C507_MSIZE_MASK	3
104#define IE_3C507_MSIZE_SHIFT	14
105
106static void
107ie_isa_3C507_identify (driver_t *driver, device_t parent)
108{
109	char *		desc = "3Com 3C507 Etherlink 16";
110	device_t	child;
111	u_int32_t	port, maddr, msize;
112	u_int8_t	irq, data;
113	int		error;
114
115	/* Reset and put card in CONFIG state without changing address. */
116	elink_reset();
117	elink_idseq(ELINK_507_POLY);
118	elink_idseq(ELINK_507_POLY);
119	outb(ELINK_ID_PORT, 0xff);
120
121	for (port = IE_3C507_IOBASE_LOW;
122	     port <= IE_3C507_IOBASE_HIGH;
123	     port += IE_3C507_IOSIZE) {
124
125		if (ie_3C507_port_check(port)) {
126#ifdef DEBUG
127			if (bootverbose) {
128				device_printf(parent,
129					"(if_ie) (3C507) not found at port %#x\n",
130					port);
131			}
132#endif
133			continue;
134		}
135
136		outb(port + IE507_CTRL, EL_CTRL_NRST);
137
138		data = inb(port + IE507_IRQ);
139		irq = data & IE_3C507_IRQ_MASK;
140
141		data = inb(port + IE507_MADDR);
142
143		if (data & IE_3C507_MADDR_HIGH) {
144			if (bootverbose) {
145				device_printf(parent,
146					"(if_ie) can't map 3C507 RAM in high memory\n");
147			}
148			continue;
149		}
150
151		maddr = IE_3C507_MADDR_BASE +
152			((data & IE_3C507_MADDR_MASK)
153			<< IE_3C507_MADDR_SHIFT);
154		msize = ((data & IE_3C507_MSIZE_MASK) + 1)
155			<< IE_3C507_MSIZE_SHIFT;
156
157		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
158		device_set_desc_copy(child, desc);
159		device_set_driver(child, driver);
160
161		error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
162		if (error) {
163			device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
164					irq);
165			error = device_delete_child(parent, child);
166			continue;
167		}
168
169		error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_3C507_IOSIZE);
170		if (error) {
171			device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
172					port, port+IE_3C507_IOSIZE);
173			error = device_delete_child(parent, child);
174			continue;
175		}
176
177		error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
178		if (error) {
179			device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
180					maddr, maddr+msize);
181			error = device_delete_child(parent, child);
182			continue;
183		}
184
185		if (bootverbose) {
186			device_printf(parent,
187				"(if_ie) <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
188				desc,
189				port, (port + IE_3C507_IOSIZE) - 1,
190				irq,
191				(u_long)maddr, (u_long)(maddr + msize) - 1,
192				(msize / 1024));
193		}
194	}
195
196	/* go to RUN state */
197	outb(ELINK_ID_PORT, 0x00);
198	elink_idseq(ELINK_507_POLY);
199	outb(ELINK_ID_PORT, 0x00);
200
201	return;
202}
203
204static int
205ie_isa_3C507_probe (device_t dev)
206{
207	u_int32_t	iobase;
208
209	/* No ISA-PnP support */
210	if (isa_get_vendorid(dev)) {
211		return (ENXIO);
212	}
213
214	/* No ISA-HINT support */
215	if (!device_get_desc(dev)) {
216		return (EBUSY);
217	}
218
219	/* Have we at least an ioport? */
220	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) {
221		return (ENXIO);
222	}
223
224	/* Is this thing really a 3c507? */
225	if (ie_3C507_port_check(iobase)) {
226		return (ENXIO);
227	}
228
229	return (0);
230}
231
232static int
233ie_isa_3C507_attach (device_t dev)
234{
235	struct ie_softc *	sc;
236	int			error;
237
238	sc = device_get_softc(dev);
239
240	sc->io_rid = 0;
241	sc->irq_rid = 0;
242	sc->mem_rid = 0;
243
244	error = ie_alloc_resources(dev);
245	if (error) {
246		goto bad;
247	}
248
249	sc->bus_use = 0;
250	sc->ie_reset_586 = el_reset_586;
251	sc->ie_chan_attn = el_chan_attn;
252	sc->hard_type = IE_3C507;
253	sc->hard_vers = 0;
254
255	outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL);
256
257	if (!check_ie_present(sc)) {
258		error = ENXIO;
259		goto bad;
260	}
261
262	sl_read_ether(sc, sc->enaddr);
263
264	/* Clear the interrupt latch just in case. */
265	outb(PORT(sc) + IE507_ICTRL, 1);
266
267	error = ie_attach(dev);
268	if (error) {
269		device_printf(dev, "ie_attach() failed.\n");
270		goto bad;
271	}
272
273	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
274				ie_intr, sc, &sc->irq_ih);
275	if (error) {
276		device_printf(dev, "Unable to register interrupt handler\n");
277		goto bad;
278	}
279
280	return (0);
281bad:
282	ie_release_resources(dev);
283
284	return (error);
285}
286
287/*
288 * If a 3c507 is present, return 0
289 * else, return 1.
290 */
291static int
292ie_3C507_port_check (u_int32_t port)
293{
294	u_char *	signature = "*3COM*";
295	int		i;
296
297	for (i = 0; i < 6; i++)
298		if (inb(port + i) != signature[i])
299			return (ENXIO);
300
301	return (0);
302}
303
304/*
305 * Intel EtherExpress 16
306 */
307#define IE_EE16_ID_PORT			0x0f
308#define IE_EE16_ID			0xbaba
309#define IE_EE16_EEPROM_CONFIG1		0x00
310#define IE_EE16_EEPROM_IRQ_MASK		0xe000
311#define IE_EE16_EEPROM_IRQ_SHIFT	13
312#define IE_EE16_EEPROM_MEMCFG		0x06
313#define IE_EE16_IOSIZE			16
314
315/*
316 * TODO:
317 *		Test for 8/16 bit mode.
318 *		Test for invalid mem sizes.
319 */
320static void
321ie_isa_ee16_identify (driver_t *driver, device_t parent)
322{
323	char *		desc = "Intel EtherExpress 16";
324	device_t	child;
325	u_int16_t	ports[] = {
326				0x300, 0x310, 0x320, 0x330,
327				0x340, 0x350, 0x360, 0x370,
328				0x200, 0x210, 0x220, 0x230,
329				0x240, 0x250, 0x260, 0x270,
330				0
331			};
332	u_int16_t	irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 };
333	u_int32_t	port, maddr, msize;
334	u_int8_t	irq;
335	u_int16_t	data;
336	int		i, error;
337
338	for (i = 0; ports[i]; i++) {
339		port = ports[i];
340
341		if (ie_ee16_port_check(port)) {
342#ifdef DEBUG
343			if (bootverbose) {
344				device_printf(parent,
345					"if_ie: (EE16) not found at port %#x\n",
346					port);
347			}
348#endif
349			continue;
350		}
351
352		/* reset any ee16 at the current iobase */
353		outb(port + IEE16_ECTRL, IEE16_RESET_ASIC);
354		outb(port + IEE16_ECTRL, 0);
355		DELAY(240);
356
357		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1);
358		irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK)
359			   >> IE_EE16_EEPROM_IRQ_SHIFT)];
360
361		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG);
362		maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000);
363		msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1)))
364			* 0x4000;
365
366		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
367		device_set_desc_copy(child, desc);
368		device_set_driver(child, driver);
369
370		error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
371		if (error) {
372			device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
373					irq);
374			error = device_delete_child(parent, child);
375			continue;
376		}
377
378		error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE);
379		if (error) {
380			device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
381					port, port+IE_EE16_IOSIZE);
382			error = device_delete_child(parent, child);
383			continue;
384		}
385
386		error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
387		if (error) {
388			device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
389					maddr, maddr+msize);
390			error = device_delete_child(parent, child);
391			continue;
392		}
393
394		if (bootverbose) {
395			device_printf(parent,
396				"if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
397				desc,
398				port, (port + IE_EE16_IOSIZE) - 1,
399				irq,
400				(u_long)maddr, (u_long)(maddr + msize) - 1,
401				(msize / 1024));
402		}
403	}
404
405	return;
406}
407
408static int
409ie_isa_ee16_probe (device_t dev)
410{
411	u_int32_t	iobase;
412
413	/* No ISA-PnP support */
414	if (isa_get_vendorid(dev))
415		return (ENXIO);
416
417	/* No ISA-HINT support */
418	if (!device_get_desc(dev))
419		return (EBUSY);
420
421	/* Have we at least an ioport? */
422	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
423		return (ENXIO);
424
425	/* Is this really an EE16? */
426	if (ie_ee16_port_check(iobase))
427		return (ENXIO);
428
429	return (0);
430}
431
432static int
433ie_isa_ee16_attach (device_t dev)
434{
435	struct ie_softc *	sc;
436	int			i, error;
437	u_int16_t		checksum;
438	u_short			eaddrtemp, pg, adjust, decode, edecode;
439	u_char			bart_config;
440
441	sc = device_get_softc(dev);
442
443	sc->io_rid = 0;
444	sc->irq_rid = 0;
445	sc->mem_rid = 0;
446
447	error = ie_alloc_resources(dev);
448	if (error) {
449		goto bad;
450	}
451
452	sc->bus_use = 0;
453	sc->ie_reset_586 = ee16_reset_586;
454	sc->ie_chan_attn = ee16_chan_attn;
455	sc->hard_type = IE_EE16;
456	sc->hard_vers = 0;
457	sc->iomem = 0;
458
459	/* reset any ee16 at the current iobase */
460	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC);
461	outb(PORT(sc) + IEE16_ECTRL, 0);
462	DELAY(240);
463
464	/* Is this really an EE16? */
465	if (ie_ee16_port_check(PORT(sc))) {
466		device_printf(dev, "ie_ee16_port_check() failed\n");
467		error = ENXIO;
468		goto bad;
469	}
470
471	/* need to put the 586 in RESET while we access the eeprom. */
472	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
473
474	/* read the eeprom and checksum it, should == IE_E16_ID */
475	checksum = 0;
476	for (i = 0; i < 0x40; i++)
477		checksum += ie_ee16_hw_read_eeprom(PORT(sc), i);
478
479	if (checksum != IE_EE16_ID) {
480		device_printf(dev, "invalid eeprom checksum: %x\n", checksum);
481		error = ENXIO;
482		goto bad;
483	}
484
485	if ((kvtop(sc->iomembot) < 0xC0000) ||
486	     (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) {
487		device_printf(sc->dev, "mapped memory location %p out of range\n",
488			(void *)sc->iomembot);
489		error = ENXIO;
490		goto bad;
491	}
492
493	pg = ((kvtop(sc->iomembot)) & 0x3C000) >> 14;
494	adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2;
495	decode = ((1 << (sc->iosize / 16384)) - 1) << pg;
496	edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
497
498	/* ZZZ This should be checked against eeprom location 6, low byte */
499	outb(PORT(sc) + IEE16_MEMDEC, decode & 0xFF);
500	/* ZZZ This should be checked against eeprom location 1, low byte */
501	outb(PORT(sc) + IEE16_MCTRL, adjust);
502	/* ZZZ Now if I could find this one I would have it made */
503	outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
504	/* ZZZ I think this is location 6, high byte */
505	outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */
506
507#if 0
508	(void) kvtop(sc->iomembot);
509#endif
510
511	/*
512	 * first prime the stupid bart DRAM controller so that it works,
513	 * then zero out all of memory.
514	 */
515	bzero(sc->iomembot, 32);
516	bzero(sc->iomembot, sc->iosize);
517
518	/* Get the encoded interrupt number from the EEPROM */
519	sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc),
520						 IE_EE16_EEPROM_CONFIG1);
521	sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >>
522			   IE_EE16_EEPROM_IRQ_SHIFT;
523
524	/*
525	 * Get the hardware ethernet address from the EEPROM and save it in
526	 * the softc for use by the 586 setup code.
527	 */
528	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH);
529	sc->enaddr[1] = eaddrtemp & 0xFF;
530	sc->enaddr[0] = eaddrtemp >> 8;
531	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID);
532	sc->enaddr[3] = eaddrtemp & 0xFF;
533	sc->enaddr[2] = eaddrtemp >> 8;
534	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_LOW);
535	sc->enaddr[5] = eaddrtemp & 0xFF;
536	sc->enaddr[4] = eaddrtemp >> 8;
537
538	/* disable the board interrupts */
539	outb(PORT(sc) + IEE16_IRQ, sc->irq_encoded);
540
541	/* enable loopback to keep bad packets off the wire */
542	bart_config = inb(PORT(sc) + IEE16_CONFIG);
543	bart_config |= IEE16_BART_LOOPBACK;
544	bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
545	outb(PORT(sc) + IEE16_CONFIG, bart_config);
546	bart_config = inb(PORT(sc) + IEE16_CONFIG);
547
548	/* take the board out of reset state */
549	outb(PORT(sc) + IEE16_ECTRL, 0);
550	DELAY(100);
551
552	if (!check_ie_present(sc)) {
553		device_printf(dev, "check_ie_present() returned false.\n");
554		error = ENXIO;
555		goto bad;
556	}
557
558	error = ie_attach(dev);
559	if (error) {
560		device_printf(dev, "ie_attach() failed.\n");
561		goto bad;
562	}
563
564	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
565				ie_intr, sc, &sc->irq_ih);
566	if (error) {
567		device_printf(dev, "Unable to register interrupt handler\n");
568		goto bad;
569	}
570
571	return (0);
572bad:
573	ie_release_resources(dev);
574
575	return (error);
576}
577
578/*
579 * If an EE16 is present, return 0
580 * else, return 1.
581 */
582static int
583ie_ee16_port_check (u_int32_t port)
584{
585	int		i;
586	u_int16_t	board_id;
587	u_int8_t	data;
588
589	board_id = 0;
590	for (i = 0; i < 4; i++) {
591		data = inb(port + IE_EE16_ID_PORT);
592		board_id |= ((data >> 4) << ((data & 0x03) << 2));
593	}
594
595	if (board_id != IE_EE16_ID)
596		return (1);
597
598	return (0);
599}
600
601static void
602ie_ee16_hw_eeprom_clock (u_int32_t port, int state)
603{
604	u_int8_t	ectrl;
605
606	ectrl = inb(port + IEE16_ECTRL);
607	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK);
608
609	if (state) {
610		ectrl |= IEE16_ECTRL_EESK;
611	}
612	outb(port + IEE16_ECTRL, ectrl);
613	DELAY(9);		/* EESK must be stable for 8.38 uSec */
614}
615
616static void
617ie_ee16_hw_eeprom_out (u_int32_t port, u_int16_t edata, int count)
618{
619	u_int8_t	ectrl;
620	int		i;
621
622	ectrl = inb(port + IEE16_ECTRL);
623	ectrl &= ~IEE16_RESET_ASIC;
624
625	for (i = count - 1; i >= 0; i--) {
626		ectrl &= ~IEE16_ECTRL_EEDI;
627		if (edata & (1 << i)) {
628			ectrl |= IEE16_ECTRL_EEDI;
629		}
630		outb(port + IEE16_ECTRL, ectrl);
631		DELAY(1);       /* eeprom data must be setup for 0.4 uSec */
632		ie_ee16_hw_eeprom_clock(port, 1);
633		ie_ee16_hw_eeprom_clock(port, 0);
634	}
635	ectrl &= ~IEE16_ECTRL_EEDI;
636	outb(port + IEE16_ECTRL, ectrl);
637	DELAY(1);               /* eeprom data must be held for 0.4 uSec */
638
639	return;
640}
641
642static u_int16_t
643ie_ee16_hw_eeprom_in (u_int32_t port)
644{
645	u_int8_t	ectrl;
646	u_int16_t	edata;
647	int		i;
648
649	ectrl = inb(port + IEE16_ECTRL);
650	ectrl &= ~IEE16_RESET_ASIC;
651
652	for (edata = 0, i = 0; i < 16; i++) {
653		edata = edata << 1;
654		ie_ee16_hw_eeprom_clock(port, 1);
655		ectrl = inb(port + IEE16_ECTRL);
656		if (ectrl & IEE16_ECTRL_EEDO) {
657			edata |= 1;
658		}
659		ie_ee16_hw_eeprom_clock(port, 0);
660	}
661	return (edata);
662}
663
664static u_int16_t
665ie_ee16_hw_read_eeprom (u_int32_t port, int loc)
666{
667	u_int8_t	ectrl;
668	u_int16_t	edata;
669
670	ectrl = inb(port + IEE16_ECTRL);
671	ectrl &= IEE16_ECTRL_MASK;
672	ectrl |= IEE16_ECTRL_EECS;
673	outb(port + IEE16_ECTRL, ectrl);
674
675	ie_ee16_hw_eeprom_out(port, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1);
676	ie_ee16_hw_eeprom_out(port, loc, IEE16_EEPROM_ADDR_SIZE);
677	edata = ie_ee16_hw_eeprom_in(port);
678
679	ectrl = inb(port + IEE16_ECTRL);
680	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS);
681	outb(port + IEE16_ECTRL, ectrl);
682
683	ie_ee16_hw_eeprom_clock(port, 1);
684	ie_ee16_hw_eeprom_clock(port, 0);
685
686	return (edata);
687}
688
689/*
690 * AT&T StarLan/
691 */
692
693static int
694ie_isa_sl_probe (device_t dev)
695{
696	u_int32_t	iobase;
697
698	/* No ISA-PnP support */
699	if (isa_get_vendorid(dev))
700		return (ENXIO);
701
702	/* ISA-HINT support only! */
703	if (device_get_desc(dev))
704		return (EBUSY);
705
706	/* Have we at least an ioport? */
707	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
708		return (ENXIO);
709
710	/* Is this really an SL board? */
711	if (ie_isa_sl_get_hard_type(iobase) == IE_NONE)
712		return (ENXIO);
713
714	return (ENXIO);
715}
716
717static int
718ie_isa_sl_attach (device_t dev)
719{
720	struct ie_softc *	sc;
721	int			error;
722
723	sc = device_get_softc(dev);
724
725	sc->io_rid = 0;
726	sc->irq_rid = 0;
727	sc->mem_rid = 0;
728
729	error = ie_alloc_resources(dev);
730	if (error) {
731		goto bad;
732	}
733
734	/* Is this really an SL board? */
735	if ((sc->hard_type = ie_isa_sl_get_hard_type(PORT(sc))) == IE_NONE) {
736		error = ENXIO;
737		goto bad;
738	}
739
740	sc->hard_vers = SL_REV(inb(PORT(sc) + IEATT_REVISION));
741	if (sc->hard_type == IE_NI5210) {
742		sc->bus_use = 1;
743	} else {
744		sc->bus_use = 0;
745	}
746
747	sc->ie_reset_586 = sl_reset_586;
748	sc->ie_chan_attn = sl_chan_attn;
749
750	if (!check_ie_present(sc)) {
751		error = ENXIO;
752		goto bad;
753	}
754
755	switch (sc->hard_type) {
756		case IE_EN100:
757		case IE_STARLAN10:
758		case IE_SLFIBER:
759		case IE_NI5210:
760			sl_read_ether(sc, sc->enaddr);
761			break;
762		default:
763			if (bootverbose)
764				device_printf(sc->dev, "unknown AT&T board type code %d\n", sc->hard_type);
765			error = ENXIO;
766			goto bad;
767			break;
768	}
769
770	error = ie_attach(dev);
771	if (error) {
772		device_printf(dev, "ie_attach() failed.\n");
773		goto bad;
774	}
775
776	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
777				ie_intr, sc, &sc->irq_ih);
778	if (error) {
779		device_printf(dev, "Unable to register interrupt handler\n");
780		goto bad;
781	}
782
783	return (0);
784bad:
785	ie_release_resources(dev);
786
787	return (error);
788}
789
790static enum ie_hardware
791ie_isa_sl_get_hard_type (u_int32_t port)
792{
793	u_char			c;
794	enum ie_hardware	retval;
795
796	c = inb(port + IEATT_REVISION);
797	switch (SL_BOARD(c)) {
798		case SL1_BOARD:
799			if (inb(port + IEATT_ATTRIB) != NI5210_BOARD)
800				retval = IE_NONE;
801			retval = IE_NI5210;
802			break;
803		case SL10_BOARD:
804			retval = IE_STARLAN10;
805			break;
806		case EN100_BOARD:
807			retval = IE_EN100;
808			break;
809		case SLFIBER_BOARD:
810			retval = IE_SLFIBER;
811			break;
812		default:
813			retval = IE_NONE;
814	}
815	return (retval);
816}
817
818static devclass_t ie_devclass;
819
820static device_method_t ie_isa_3C507_methods[] = {
821	DEVMETHOD(device_identify,	ie_isa_3C507_identify),
822	DEVMETHOD(device_probe,		ie_isa_3C507_probe),
823	DEVMETHOD(device_attach,	ie_isa_3C507_attach),
824	DEVMETHOD(device_detach,	ie_detach),
825	{ 0, 0 }
826};
827static driver_t ie_isa_3C507_driver = {
828	"ie",
829	ie_isa_3C507_methods,
830	sizeof(struct ie_softc),
831};
832DRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
833MODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
834
835static device_method_t ie_isa_ee16_methods[] = {
836	DEVMETHOD(device_identify,	ie_isa_ee16_identify),
837	DEVMETHOD(device_probe,		ie_isa_ee16_probe),
838	DEVMETHOD(device_attach,	ie_isa_ee16_attach),
839	DEVMETHOD(device_detach,	ie_detach),
840	{ 0, 0 }
841};
842static driver_t ie_isa_ee16_driver = {
843	"ie",
844	ie_isa_ee16_methods,
845	sizeof(struct ie_softc),
846};
847DRIVER_MODULE(ie_EE16, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0);
848
849static device_method_t ie_isa_sl_methods[] = {
850	DEVMETHOD(device_probe,		ie_isa_sl_probe),
851	DEVMETHOD(device_attach,	ie_isa_sl_attach),
852	DEVMETHOD(device_detach,	ie_detach),
853	{ 0, 0 }
854};
855static driver_t ie_isa_sl_driver = {
856	"ie",
857	ie_isa_sl_methods,
858	sizeof(struct ie_softc),
859};
860DRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0);
861
862static int
863ie_modevent (mod, what, arg)
864	module_t	mod;
865	int		what;
866	void *		arg;
867{
868	device_t *	devs;
869	int		count;
870	int		i;
871
872	switch (what) {
873	case MOD_LOAD:
874		break;
875	case MOD_UNLOAD:
876		devclass_get_devices(ie_devclass, &devs, &count);
877		for (i = 0; i < count; i++)
878			device_delete_child(device_get_parent(devs[i]), devs[i]);
879		break;
880	default:
881		break;
882	};
883
884	return (0);
885}
886