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$");
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/md_var.h>
55
56#include <net/if.h>
57#include <net/if_arp.h>
58#include <net/if_media.h>
59
60#include <isa/isavar.h>
61#include <isa/pnpvar.h>
62
63#include <i386/isa/elink.h>
64
65#include <dev/ic/i82586.h>
66#include <dev/ie/if_ie507.h>
67#include <dev/ie/if_iee16.h>
68#include <dev/ie/if_iereg.h>
69#include <dev/ie/if_ievar.h>
70
71static int		ie_modevent		(module_t, int, void *);
72
73static void		ie_isa_3C507_identify	(driver_t *, device_t);
74static int		ie_isa_3C507_probe	(device_t);
75static int		ie_isa_3C507_attach	(device_t);
76static int		ie_3C507_port_check	(u_int32_t);
77
78static void		ie_isa_ee16_identify	(driver_t *, device_t);
79static int		ie_isa_ee16_probe	(device_t);
80static int		ie_isa_ee16_attach	(device_t);
81static int		ie_isa_ee16_shutdown	(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	return (0);
274bad:
275	ie_release_resources(dev);
276
277	return (error);
278}
279
280/*
281 * If a 3c507 is present, return 0
282 * else, return 1.
283 */
284static int
285ie_3C507_port_check (u_int32_t port)
286{
287	u_char *	signature = "*3COM*";
288	int		i;
289
290	for (i = 0; i < 6; i++)
291		if (inb(port + i) != signature[i])
292			return (ENXIO);
293
294	return (0);
295}
296
297/*
298 * Intel EtherExpress 16
299 */
300#define IE_EE16_ID_PORT			0x0f
301#define IE_EE16_ID			0xbaba
302#define IE_EE16_EEPROM_CONFIG1		0x00
303#define IE_EE16_EEPROM_IRQ_MASK		0xe000
304#define IE_EE16_EEPROM_IRQ_SHIFT	13
305#define IE_EE16_EEPROM_MEMCFG		0x06
306#define IE_EE16_IOSIZE			16
307
308/*
309 * TODO:
310 *		Test for 8/16 bit mode.
311 *		Test for invalid mem sizes.
312 */
313static void
314ie_isa_ee16_identify (driver_t *driver, device_t parent)
315{
316	char *		desc = "Intel EtherExpress 16";
317	device_t	child;
318	u_int16_t	ports[] = {
319				0x300, 0x310, 0x320, 0x330,
320				0x340, 0x350, 0x360, 0x370,
321				0x200, 0x210, 0x220, 0x230,
322				0x240, 0x250, 0x260, 0x270,
323				0
324			};
325	u_int16_t	irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 };
326	u_int32_t	port, maddr, msize;
327	u_int8_t	irq;
328	u_int16_t	data;
329	int		i, error;
330
331	for (i = 0; ports[i]; i++) {
332		port = ports[i];
333
334		if (ie_ee16_port_check(port)) {
335#ifdef DEBUG
336			if (bootverbose) {
337				device_printf(parent,
338					"if_ie: (EE16) not found at port %#x\n",
339					port);
340			}
341#endif
342			continue;
343		}
344
345		/* reset any ee16 at the current iobase */
346		outb(port + IEE16_ECTRL, IEE16_RESET_ASIC);
347		outb(port + IEE16_ECTRL, 0);
348		DELAY(240);
349
350		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1);
351		irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK)
352			   >> IE_EE16_EEPROM_IRQ_SHIFT)];
353
354		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG);
355		maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000);
356		msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1)))
357			* 0x4000;
358
359		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
360		device_set_desc_copy(child, desc);
361		device_set_driver(child, driver);
362
363		error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
364		if (error) {
365			device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
366					irq);
367			error = device_delete_child(parent, child);
368			continue;
369		}
370
371		error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE);
372		if (error) {
373			device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
374					port, port+IE_EE16_IOSIZE);
375			error = device_delete_child(parent, child);
376			continue;
377		}
378
379		error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
380		if (error) {
381			device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
382					maddr, maddr+msize);
383			error = device_delete_child(parent, child);
384			continue;
385		}
386
387		if (bootverbose) {
388			device_printf(parent,
389				"if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
390				desc,
391				port, (port + IE_EE16_IOSIZE) - 1,
392				irq,
393				(u_long)maddr, (u_long)(maddr + msize) - 1,
394				(msize / 1024));
395		}
396	}
397
398	return;
399}
400
401static int
402ie_isa_ee16_probe (device_t dev)
403{
404	u_int32_t	iobase;
405
406	/* No ISA-PnP support */
407	if (isa_get_vendorid(dev))
408		return (ENXIO);
409
410	/* No ISA-HINT support */
411	if (!device_get_desc(dev))
412		return (EBUSY);
413
414	/* Have we at least an ioport? */
415	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
416		return (ENXIO);
417
418	/* Is this really an EE16? */
419	if (ie_ee16_port_check(iobase))
420		return (ENXIO);
421
422	return (0);
423}
424
425static int
426ie_isa_ee16_attach (device_t dev)
427{
428	struct ie_softc *	sc;
429	int			i, error;
430	u_int16_t		checksum;
431	u_short			eaddrtemp, pg, adjust, decode, edecode;
432	u_char			bart_config;
433
434	sc = device_get_softc(dev);
435
436	sc->io_rid = 0;
437	sc->irq_rid = 0;
438	sc->mem_rid = 0;
439
440	error = ie_alloc_resources(dev);
441	if (error) {
442		goto bad;
443	}
444
445	sc->bus_use = 0;
446	sc->ie_reset_586 = ee16_reset_586;
447	sc->ie_chan_attn = ee16_chan_attn;
448	sc->hard_type = IE_EE16;
449	sc->hard_vers = 0;
450	sc->iomem = 0;
451
452	/* reset any ee16 at the current iobase */
453	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC);
454	outb(PORT(sc) + IEE16_ECTRL, 0);
455	DELAY(240);
456
457	/* Is this really an EE16? */
458	if (ie_ee16_port_check(PORT(sc))) {
459		device_printf(dev, "ie_ee16_port_check() failed\n");
460		error = ENXIO;
461		goto bad;
462	}
463
464	/* need to put the 586 in RESET while we access the eeprom. */
465	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
466
467	/* read the eeprom and checksum it, should == IE_E16_ID */
468	checksum = 0;
469	for (i = 0; i < 0x40; i++)
470		checksum += ie_ee16_hw_read_eeprom(PORT(sc), i);
471
472	if (checksum != IE_EE16_ID) {
473		device_printf(dev, "invalid eeprom checksum: %x\n", checksum);
474		error = ENXIO;
475		goto bad;
476	}
477
478	if ((kvtop(sc->iomembot) < 0xC0000) ||
479	     (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) {
480		device_printf(sc->dev, "mapped memory location %p out of range\n",
481			(void *)sc->iomembot);
482		error = ENXIO;
483		goto bad;
484	}
485
486	pg = ((kvtop(sc->iomembot)) & 0x3C000) >> 14;
487	adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2;
488	decode = ((1 << (sc->iosize / 16384)) - 1) << pg;
489	edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
490
491	/* ZZZ This should be checked against eeprom location 6, low byte */
492	outb(PORT(sc) + IEE16_MEMDEC, decode & 0xFF);
493	/* ZZZ This should be checked against eeprom location 1, low byte */
494	outb(PORT(sc) + IEE16_MCTRL, adjust);
495	/* ZZZ Now if I could find this one I would have it made */
496	outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
497	/* ZZZ I think this is location 6, high byte */
498	outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */
499
500#if 0
501	(void) kvtop(sc->iomembot);
502#endif
503
504	/*
505	 * first prime the stupid bart DRAM controller so that it works,
506	 * then zero out all of memory.
507	 */
508	bzero(sc->iomembot, 32);
509	bzero(sc->iomembot, sc->iosize);
510
511	/* Get the encoded interrupt number from the EEPROM */
512	sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc),
513						 IE_EE16_EEPROM_CONFIG1);
514	sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >>
515			   IE_EE16_EEPROM_IRQ_SHIFT;
516
517	/*
518	 * Get the hardware ethernet address from the EEPROM and save it in
519	 * the softc for use by the 586 setup code.
520	 */
521	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH);
522	sc->enaddr[1] = eaddrtemp & 0xFF;
523	sc->enaddr[0] = eaddrtemp >> 8;
524	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID);
525	sc->enaddr[3] = eaddrtemp & 0xFF;
526	sc->enaddr[2] = eaddrtemp >> 8;
527	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_LOW);
528	sc->enaddr[5] = eaddrtemp & 0xFF;
529	sc->enaddr[4] = eaddrtemp >> 8;
530
531	/* disable the board interrupts */
532	outb(PORT(sc) + IEE16_IRQ, sc->irq_encoded);
533
534	/* enable loopback to keep bad packets off the wire */
535	bart_config = inb(PORT(sc) + IEE16_CONFIG);
536	bart_config |= IEE16_BART_LOOPBACK;
537	bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
538	outb(PORT(sc) + IEE16_CONFIG, bart_config);
539	bart_config = inb(PORT(sc) + IEE16_CONFIG);
540
541	/* take the board out of reset state */
542	outb(PORT(sc) + IEE16_ECTRL, 0);
543	DELAY(100);
544
545	if (!check_ie_present(sc)) {
546		device_printf(dev, "check_ie_present() returned false.\n");
547		error = ENXIO;
548		goto bad;
549	}
550
551	error = ie_attach(dev);
552	if (error) {
553		device_printf(dev, "ie_attach() failed.\n");
554		goto bad;
555	}
556
557	return (0);
558bad:
559	ie_release_resources(dev);
560
561	return (error);
562}
563
564static int
565ie_isa_ee16_shutdown(device_t dev)
566{
567	struct ie_softc *	sc;
568
569	sc = device_get_softc(dev);
570	IE_LOCK(sc);
571	ee16_shutdown(sc);
572	IE_UNLOCK(sc);
573
574	return (0);
575}
576
577/*
578 * If an EE16 is present, return 0
579 * else, return 1.
580 */
581static int
582ie_ee16_port_check (u_int32_t port)
583{
584	int		i;
585	u_int16_t	board_id;
586	u_int8_t	data;
587
588	board_id = 0;
589	for (i = 0; i < 4; i++) {
590		data = inb(port + IE_EE16_ID_PORT);
591		board_id |= ((data >> 4) << ((data & 0x03) << 2));
592	}
593
594	if (board_id != IE_EE16_ID)
595		return (1);
596
597	return (0);
598}
599
600static void
601ie_ee16_hw_eeprom_clock (u_int32_t port, int state)
602{
603	u_int8_t	ectrl;
604
605	ectrl = inb(port + IEE16_ECTRL);
606	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK);
607
608	if (state) {
609		ectrl |= IEE16_ECTRL_EESK;
610	}
611	outb(port + IEE16_ECTRL, ectrl);
612	DELAY(9);		/* EESK must be stable for 8.38 uSec */
613}
614
615static void
616ie_ee16_hw_eeprom_out (u_int32_t port, u_int16_t edata, int count)
617{
618	u_int8_t	ectrl;
619	int		i;
620
621	ectrl = inb(port + IEE16_ECTRL);
622	ectrl &= ~IEE16_RESET_ASIC;
623
624	for (i = count - 1; i >= 0; i--) {
625		ectrl &= ~IEE16_ECTRL_EEDI;
626		if (edata & (1 << i)) {
627			ectrl |= IEE16_ECTRL_EEDI;
628		}
629		outb(port + IEE16_ECTRL, ectrl);
630		DELAY(1);       /* eeprom data must be setup for 0.4 uSec */
631		ie_ee16_hw_eeprom_clock(port, 1);
632		ie_ee16_hw_eeprom_clock(port, 0);
633	}
634	ectrl &= ~IEE16_ECTRL_EEDI;
635	outb(port + IEE16_ECTRL, ectrl);
636	DELAY(1);               /* eeprom data must be held for 0.4 uSec */
637
638	return;
639}
640
641static u_int16_t
642ie_ee16_hw_eeprom_in (u_int32_t port)
643{
644	u_int8_t	ectrl;
645	u_int16_t	edata;
646	int		i;
647
648	ectrl = inb(port + IEE16_ECTRL);
649	ectrl &= ~IEE16_RESET_ASIC;
650
651	for (edata = 0, i = 0; i < 16; i++) {
652		edata = edata << 1;
653		ie_ee16_hw_eeprom_clock(port, 1);
654		ectrl = inb(port + IEE16_ECTRL);
655		if (ectrl & IEE16_ECTRL_EEDO) {
656			edata |= 1;
657		}
658		ie_ee16_hw_eeprom_clock(port, 0);
659	}
660	return (edata);
661}
662
663static u_int16_t
664ie_ee16_hw_read_eeprom (u_int32_t port, int loc)
665{
666	u_int8_t	ectrl;
667	u_int16_t	edata;
668
669	ectrl = inb(port + IEE16_ECTRL);
670	ectrl &= IEE16_ECTRL_MASK;
671	ectrl |= IEE16_ECTRL_EECS;
672	outb(port + IEE16_ECTRL, ectrl);
673
674	ie_ee16_hw_eeprom_out(port, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1);
675	ie_ee16_hw_eeprom_out(port, loc, IEE16_EEPROM_ADDR_SIZE);
676	edata = ie_ee16_hw_eeprom_in(port);
677
678	ectrl = inb(port + IEE16_ECTRL);
679	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS);
680	outb(port + IEE16_ECTRL, ectrl);
681
682	ie_ee16_hw_eeprom_clock(port, 1);
683	ie_ee16_hw_eeprom_clock(port, 0);
684
685	return (edata);
686}
687
688/*
689 * AT&T StarLan/
690 */
691
692static int
693ie_isa_sl_probe (device_t dev)
694{
695	u_int32_t	iobase;
696
697	/* No ISA-PnP support */
698	if (isa_get_vendorid(dev))
699		return (ENXIO);
700
701	/* ISA-HINT support only! */
702	if (device_get_desc(dev))
703		return (EBUSY);
704
705	/* Have we at least an ioport? */
706	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
707		return (ENXIO);
708
709	/* Is this really an SL board? */
710	if (ie_isa_sl_get_hard_type(iobase) == IE_NONE)
711		return (ENXIO);
712
713	return (ENXIO);
714}
715
716static int
717ie_isa_sl_attach (device_t dev)
718{
719	struct ie_softc *	sc;
720	int			error;
721
722	sc = device_get_softc(dev);
723
724	sc->io_rid = 0;
725	sc->irq_rid = 0;
726	sc->mem_rid = 0;
727
728	error = ie_alloc_resources(dev);
729	if (error) {
730		goto bad;
731	}
732
733	/* Is this really an SL board? */
734	if ((sc->hard_type = ie_isa_sl_get_hard_type(PORT(sc))) == IE_NONE) {
735		error = ENXIO;
736		goto bad;
737	}
738
739	sc->hard_vers = SL_REV(inb(PORT(sc) + IEATT_REVISION));
740	if (sc->hard_type == IE_NI5210) {
741		sc->bus_use = 1;
742	} else {
743		sc->bus_use = 0;
744	}
745
746	sc->ie_reset_586 = sl_reset_586;
747	sc->ie_chan_attn = sl_chan_attn;
748
749	if (!check_ie_present(sc)) {
750		error = ENXIO;
751		goto bad;
752	}
753
754	switch (sc->hard_type) {
755		case IE_EN100:
756		case IE_STARLAN10:
757		case IE_SLFIBER:
758		case IE_NI5210:
759			sl_read_ether(sc, sc->enaddr);
760			break;
761		default:
762			if (bootverbose)
763				device_printf(sc->dev, "unknown AT&T board type code %d\n", sc->hard_type);
764			error = ENXIO;
765			goto bad;
766			break;
767	}
768
769	error = ie_attach(dev);
770	if (error) {
771		device_printf(dev, "ie_attach() failed.\n");
772		goto bad;
773	}
774
775	return (0);
776bad:
777	ie_release_resources(dev);
778
779	return (error);
780}
781
782static enum ie_hardware
783ie_isa_sl_get_hard_type (u_int32_t port)
784{
785	u_char			c;
786	enum ie_hardware	retval;
787
788	c = inb(port + IEATT_REVISION);
789	switch (SL_BOARD(c)) {
790		case SL1_BOARD:
791			if (inb(port + IEATT_ATTRIB) != NI5210_BOARD)
792				retval = IE_NONE;
793			retval = IE_NI5210;
794			break;
795		case SL10_BOARD:
796			retval = IE_STARLAN10;
797			break;
798		case EN100_BOARD:
799			retval = IE_EN100;
800			break;
801		case SLFIBER_BOARD:
802			retval = IE_SLFIBER;
803			break;
804		default:
805			retval = IE_NONE;
806	}
807	return (retval);
808}
809
810static devclass_t ie_devclass;
811
812static device_method_t ie_isa_3C507_methods[] = {
813	DEVMETHOD(device_identify,	ie_isa_3C507_identify),
814	DEVMETHOD(device_probe,		ie_isa_3C507_probe),
815	DEVMETHOD(device_attach,	ie_isa_3C507_attach),
816	DEVMETHOD(device_detach,	ie_detach),
817	{ 0, 0 }
818};
819
820static driver_t ie_isa_3C507_driver = {
821	"ie",
822	ie_isa_3C507_methods,
823	sizeof(struct ie_softc),
824};
825
826DRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
827MODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
828
829static device_method_t ie_isa_ee16_methods[] = {
830	DEVMETHOD(device_identify,	ie_isa_ee16_identify),
831	DEVMETHOD(device_probe,		ie_isa_ee16_probe),
832	DEVMETHOD(device_attach,	ie_isa_ee16_attach),
833	DEVMETHOD(device_shutdown,	ie_isa_ee16_shutdown),
834	DEVMETHOD(device_detach,	ie_detach),
835	{ 0, 0 }
836};
837
838static driver_t ie_isa_ee16_driver = {
839	"ie",
840	ie_isa_ee16_methods,
841	sizeof(struct ie_softc),
842};
843
844DRIVER_MODULE(ie, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0);
845
846static device_method_t ie_isa_sl_methods[] = {
847	DEVMETHOD(device_probe,		ie_isa_sl_probe),
848	DEVMETHOD(device_attach,	ie_isa_sl_attach),
849	DEVMETHOD(device_detach,	ie_detach),
850	{ 0, 0 }
851};
852
853static driver_t ie_isa_sl_driver = {
854	"ie",
855	ie_isa_sl_methods,
856	sizeof(struct ie_softc),
857};
858
859DRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0);
860
861static int
862ie_modevent (mod, what, arg)
863	module_t	mod;
864	int		what;
865	void *		arg;
866{
867	device_t *	devs;
868	int		count;
869	int		i;
870
871	switch (what) {
872	case MOD_LOAD:
873		break;
874	case MOD_UNLOAD:
875		devclass_get_devices(ie_devclass, &devs, &count);
876		for (i = 0; i < count; i++)
877			device_delete_child(device_get_parent(devs[i]), devs[i]);
878		free(devs, M_TEMP);
879		break;
880	default:
881		break;
882	};
883
884	return (0);
885}
886