]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ie/if_ie_isa.c
Merge OpenSSL 1.0.1k.
[FreeBSD/FreeBSD.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/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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }