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