]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/ie/if_ie_isa.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / ie / if_ie_isa.c
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
71 static int              ie_modevent             (module_t, int, void *);
72
73 static void             ie_isa_3C507_identify   (driver_t *, device_t);
74 static int              ie_isa_3C507_probe      (device_t);
75 static int              ie_isa_3C507_attach     (device_t);
76 static int              ie_3C507_port_check     (u_int32_t);
77
78 static void             ie_isa_ee16_identify    (driver_t *, device_t);
79 static int              ie_isa_ee16_probe       (device_t);
80 static int              ie_isa_ee16_attach      (device_t);
81 static int              ie_isa_ee16_shutdown    (device_t);
82 static int              ie_ee16_port_check      (u_int32_t port);
83 static u_int16_t        ie_ee16_hw_read_eeprom  (u_int32_t port, int loc);
84
85 static int              ie_isa_sl_probe         (device_t);
86 static int              ie_isa_sl_attach        (device_t);
87 static 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
106 static void
107 ie_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
204 static int
205 ie_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
232 static int
233 ie_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);
274 bad:
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  */
284 static int
285 ie_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  */
313 static void
314 ie_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
401 static int
402 ie_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
425 static int
426 ie_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);
558 bad:
559         ie_release_resources(dev);
560
561         return (error);
562 }
563
564 static int
565 ie_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  */
581 static int
582 ie_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
600 static void
601 ie_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
615 static void
616 ie_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
641 static u_int16_t
642 ie_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
663 static u_int16_t
664 ie_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
692 static int
693 ie_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
716 static int
717 ie_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);
776 bad:
777         ie_release_resources(dev);
778
779         return (error);
780 }
781
782 static enum ie_hardware
783 ie_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
810 static devclass_t ie_devclass;
811
812 static 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
820 static driver_t ie_isa_3C507_driver = {
821         "ie",
822         ie_isa_3C507_methods,
823         sizeof(struct ie_softc), 
824 };
825
826 DRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
827 MODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
828
829 static 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
838 static driver_t ie_isa_ee16_driver = {
839         "ie",
840         ie_isa_ee16_methods,
841         sizeof(struct ie_softc), 
842 };
843
844 DRIVER_MODULE(ie, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0);
845
846 static 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
853 static driver_t ie_isa_sl_driver = {
854         "ie",
855         ie_isa_sl_methods,
856         sizeof(struct ie_softc), 
857 };
858
859 DRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0);
860
861 static int
862 ie_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 }