]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/ie/if_ie_isa.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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_ee16_port_check      (u_int32_t port);
82 static u_int16_t        ie_ee16_hw_read_eeprom  (u_int32_t port, int loc);
83
84 static int              ie_isa_sl_probe         (device_t);
85 static int              ie_isa_sl_attach        (device_t);
86 static enum ie_hardware ie_isa_sl_get_hard_type (u_int32_t);
87
88 /*
89  * 3Com 3C507 Etherlink 16
90  */
91 #define IE_3C507_IOBASE_LOW     0x200
92 #define IE_3C507_IOBASE_HIGH    0x3e0
93 #define IE_3C507_IOSIZE         16
94
95 #define IE_3C507_IRQ_MASK       0x0f
96
97 #define IE_3C507_MADDR_HIGH     0x20
98 #define IE_3C507_MADDR_MASK     0x1c
99 #define IE_3C507_MADDR_BASE     0xc0000
100 #define IE_3C507_MADDR_SHIFT    12
101
102 #define IE_3C507_MSIZE_MASK     3
103 #define IE_3C507_MSIZE_SHIFT    14
104
105 static void
106 ie_isa_3C507_identify (driver_t *driver, device_t parent)
107 {
108         char *          desc = "3Com 3C507 Etherlink 16";
109         device_t        child;
110         u_int32_t       port, maddr, msize;
111         u_int8_t        irq, data;
112         int             error;
113
114         /* Reset and put card in CONFIG state without changing address. */
115         elink_reset();
116         elink_idseq(ELINK_507_POLY);
117         elink_idseq(ELINK_507_POLY);
118         outb(ELINK_ID_PORT, 0xff);
119
120         for (port = IE_3C507_IOBASE_LOW;
121              port <= IE_3C507_IOBASE_HIGH;
122              port += IE_3C507_IOSIZE) {
123
124                 if (ie_3C507_port_check(port)) {
125 #ifdef DEBUG 
126                         if (bootverbose) {
127                                 device_printf(parent,
128                                         "(if_ie) (3C507) not found at port %#x\n",
129                                         port);
130                         }
131 #endif
132                         continue;
133                 }
134
135                 outb(port + IE507_CTRL, EL_CTRL_NRST);
136
137                 data = inb(port + IE507_IRQ);
138                 irq = data & IE_3C507_IRQ_MASK;
139
140                 data = inb(port + IE507_MADDR);
141
142                 if (data & IE_3C507_MADDR_HIGH) {
143                         if (bootverbose) {
144                                 device_printf(parent,
145                                         "(if_ie) can't map 3C507 RAM in high memory\n");
146                         }
147                         continue;
148                 }
149
150                 maddr = IE_3C507_MADDR_BASE +
151                         ((data & IE_3C507_MADDR_MASK)
152                         << IE_3C507_MADDR_SHIFT);
153                 msize = ((data & IE_3C507_MSIZE_MASK) + 1)
154                         << IE_3C507_MSIZE_SHIFT;
155
156                 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
157                 device_set_desc_copy(child, desc);
158                 device_set_driver(child, driver);
159
160                 error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
161                 if (error) {
162                         device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
163                                         irq);
164                         error = device_delete_child(parent, child);
165                         continue;
166                 }
167
168                 error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_3C507_IOSIZE);
169                 if (error) {
170                         device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
171                                         port, port+IE_3C507_IOSIZE);
172                         error = device_delete_child(parent, child);
173                         continue;
174                 }
175
176                 error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
177                 if (error) {
178                         device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
179                                         maddr, maddr+msize);
180                         error = device_delete_child(parent, child);
181                         continue;
182                 }
183
184                 if (bootverbose) {
185                         device_printf(parent,
186                                 "(if_ie) <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
187                                 desc,
188                                 port, (port + IE_3C507_IOSIZE) - 1,
189                                 irq,
190                                 (u_long)maddr, (u_long)(maddr + msize) - 1,
191                                 (msize / 1024));
192                 }
193         }
194
195         /* go to RUN state */
196         outb(ELINK_ID_PORT, 0x00);
197         elink_idseq(ELINK_507_POLY);
198         outb(ELINK_ID_PORT, 0x00);
199
200         return;
201 }
202
203 static int
204 ie_isa_3C507_probe (device_t dev)
205 {
206         u_int32_t       iobase;
207
208         /* No ISA-PnP support */
209         if (isa_get_vendorid(dev)) {
210                 return (ENXIO);
211         }
212
213         /* No ISA-HINT support */
214         if (!device_get_desc(dev)) {
215                 return (EBUSY);
216         }
217
218         /* Have we at least an ioport? */
219         if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) {
220                 return (ENXIO);
221         }
222
223         /* Is this thing really a 3c507? */
224         if (ie_3C507_port_check(iobase)) {
225                 return (ENXIO);
226         }
227
228         return (0);
229 }
230
231 static int
232 ie_isa_3C507_attach (device_t dev)
233 {
234         struct ie_softc *       sc;
235         int                     error;
236
237         sc = device_get_softc(dev);
238
239         sc->io_rid = 0;
240         sc->irq_rid = 0;
241         sc->mem_rid = 0;
242
243         error = ie_alloc_resources(dev);
244         if (error) {
245                 goto bad;
246         }
247
248         sc->bus_use = 0;
249         sc->ie_reset_586 = el_reset_586;
250         sc->ie_chan_attn = el_chan_attn;
251         sc->hard_type = IE_3C507;
252         sc->hard_vers = 0;
253
254         outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL);
255
256         if (!check_ie_present(sc)) {
257                 error = ENXIO;
258                 goto bad;
259         }
260
261         sl_read_ether(sc, sc->enaddr);
262
263         /* Clear the interrupt latch just in case. */
264         outb(PORT(sc) + IE507_ICTRL, 1);
265
266         error = ie_attach(dev);
267         if (error) {
268                 device_printf(dev, "ie_attach() failed.\n");
269                 goto bad;
270         }
271
272         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
273                                 NULL, ie_intr, sc, &sc->irq_ih);
274         if (error) {
275                 device_printf(dev, "Unable to register interrupt handler\n"); 
276                 goto bad;
277         }
278
279         return (0);
280 bad:
281         ie_release_resources(dev);
282
283         return (error);
284 }
285
286 /*
287  * If a 3c507 is present, return 0
288  * else, return 1.
289  */
290 static int
291 ie_3C507_port_check (u_int32_t port)
292 {
293         u_char *        signature = "*3COM*";
294         int             i;
295
296         for (i = 0; i < 6; i++)
297                 if (inb(port + i) != signature[i])
298                         return (ENXIO);
299
300         return (0);
301 }
302
303 /*
304  * Intel EtherExpress 16
305  */
306 #define IE_EE16_ID_PORT                 0x0f
307 #define IE_EE16_ID                      0xbaba
308 #define IE_EE16_EEPROM_CONFIG1          0x00
309 #define IE_EE16_EEPROM_IRQ_MASK         0xe000
310 #define IE_EE16_EEPROM_IRQ_SHIFT        13
311 #define IE_EE16_EEPROM_MEMCFG           0x06
312 #define IE_EE16_IOSIZE                  16
313
314 /*
315  * TODO:
316  *              Test for 8/16 bit mode.
317  *              Test for invalid mem sizes.
318  */
319 static void
320 ie_isa_ee16_identify (driver_t *driver, device_t parent)
321 {
322         char *          desc = "Intel EtherExpress 16";
323         device_t        child;
324         u_int16_t       ports[] = {
325                                 0x300, 0x310, 0x320, 0x330,
326                                 0x340, 0x350, 0x360, 0x370,
327                                 0x200, 0x210, 0x220, 0x230,
328                                 0x240, 0x250, 0x260, 0x270,
329                                 0
330                         };
331         u_int16_t       irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 };
332         u_int32_t       port, maddr, msize;
333         u_int8_t        irq;
334         u_int16_t       data;
335         int             i, error;
336
337         for (i = 0; ports[i]; i++) {
338                 port = ports[i];
339
340                 if (ie_ee16_port_check(port)) {
341 #ifdef DEBUG
342                         if (bootverbose) {
343                                 device_printf(parent,
344                                         "if_ie: (EE16) not found at port %#x\n",
345                                         port);
346                         }
347 #endif
348                         continue;
349                 }
350
351                 /* reset any ee16 at the current iobase */
352                 outb(port + IEE16_ECTRL, IEE16_RESET_ASIC);
353                 outb(port + IEE16_ECTRL, 0);
354                 DELAY(240);
355
356                 data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1);
357                 irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK)
358                            >> IE_EE16_EEPROM_IRQ_SHIFT)];
359
360                 data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG);
361                 maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000);
362                 msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1)))
363                         * 0x4000;
364
365                 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
366                 device_set_desc_copy(child, desc);
367                 device_set_driver(child, driver);
368
369                 error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
370                 if (error) {
371                         device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
372                                         irq);
373                         error = device_delete_child(parent, child);
374                         continue;
375                 }
376
377                 error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE);
378                 if (error) {
379                         device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
380                                         port, port+IE_EE16_IOSIZE);
381                         error = device_delete_child(parent, child);
382                         continue;
383                 }
384
385                 error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
386                 if (error) {
387                         device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
388                                         maddr, maddr+msize);
389                         error = device_delete_child(parent, child);
390                         continue;
391                 }
392
393                 if (bootverbose) {
394                         device_printf(parent,
395                                 "if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
396                                 desc,
397                                 port, (port + IE_EE16_IOSIZE) - 1,
398                                 irq,
399                                 (u_long)maddr, (u_long)(maddr + msize) - 1,
400                                 (msize / 1024));
401                 }
402         }
403
404         return;
405 }
406
407 static int
408 ie_isa_ee16_probe (device_t dev)
409 {
410         u_int32_t       iobase;
411
412         /* No ISA-PnP support */
413         if (isa_get_vendorid(dev))
414                 return (ENXIO);
415
416         /* No ISA-HINT support */
417         if (!device_get_desc(dev))
418                 return (EBUSY);
419
420         /* Have we at least an ioport? */
421         if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
422                 return (ENXIO);
423
424         /* Is this really an EE16? */
425         if (ie_ee16_port_check(iobase))
426                 return (ENXIO);
427
428         return (0);
429 }
430
431 static int
432 ie_isa_ee16_attach (device_t dev)
433 {
434         struct ie_softc *       sc;
435         int                     i, error;
436         u_int16_t               checksum;
437         u_short                 eaddrtemp, pg, adjust, decode, edecode;
438         u_char                  bart_config;
439         
440         sc = device_get_softc(dev);
441
442         sc->io_rid = 0;
443         sc->irq_rid = 0;
444         sc->mem_rid = 0;
445
446         error = ie_alloc_resources(dev);
447         if (error) {
448                 goto bad;
449         }
450
451         sc->bus_use = 0;
452         sc->ie_reset_586 = ee16_reset_586;
453         sc->ie_chan_attn = ee16_chan_attn;
454         sc->hard_type = IE_EE16;
455         sc->hard_vers = 0;
456         sc->iomem = 0;
457
458         /* reset any ee16 at the current iobase */
459         outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC);
460         outb(PORT(sc) + IEE16_ECTRL, 0);
461         DELAY(240);
462
463         /* Is this really an EE16? */
464         if (ie_ee16_port_check(PORT(sc))) {
465                 device_printf(dev, "ie_ee16_port_check() failed\n");
466                 error = ENXIO;
467                 goto bad;
468         }
469
470         /* need to put the 586 in RESET while we access the eeprom. */
471         outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
472
473         /* read the eeprom and checksum it, should == IE_E16_ID */
474         checksum = 0;
475         for (i = 0; i < 0x40; i++)
476                 checksum += ie_ee16_hw_read_eeprom(PORT(sc), i);
477
478         if (checksum != IE_EE16_ID) {
479                 device_printf(dev, "invalid eeprom checksum: %x\n", checksum);
480                 error = ENXIO;
481                 goto bad;
482         }
483
484         if ((kvtop(sc->iomembot) < 0xC0000) ||
485              (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) {
486                 device_printf(sc->dev, "mapped memory location %p out of range\n",
487                         (void *)sc->iomembot);
488                 error = ENXIO;
489                 goto bad;
490         }
491
492         pg = ((kvtop(sc->iomembot)) & 0x3C000) >> 14;
493         adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2;
494         decode = ((1 << (sc->iosize / 16384)) - 1) << pg;
495         edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
496
497         /* ZZZ This should be checked against eeprom location 6, low byte */
498         outb(PORT(sc) + IEE16_MEMDEC, decode & 0xFF);
499         /* ZZZ This should be checked against eeprom location 1, low byte */
500         outb(PORT(sc) + IEE16_MCTRL, adjust);
501         /* ZZZ Now if I could find this one I would have it made */
502         outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
503         /* ZZZ I think this is location 6, high byte */
504         outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */
505
506 #if 0
507         (void) kvtop(sc->iomembot);
508 #endif
509
510         /*
511          * first prime the stupid bart DRAM controller so that it works,
512          * then zero out all of memory.
513          */
514         bzero(sc->iomembot, 32);
515         bzero(sc->iomembot, sc->iosize);
516
517         /* Get the encoded interrupt number from the EEPROM */
518         sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc),
519                                                  IE_EE16_EEPROM_CONFIG1);
520         sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >>
521                            IE_EE16_EEPROM_IRQ_SHIFT;
522
523         /*
524          * Get the hardware ethernet address from the EEPROM and save it in
525          * the softc for use by the 586 setup code.
526          */
527         eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH);
528         sc->enaddr[1] = eaddrtemp & 0xFF;
529         sc->enaddr[0] = eaddrtemp >> 8;
530         eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID);
531         sc->enaddr[3] = eaddrtemp & 0xFF;
532         sc->enaddr[2] = eaddrtemp >> 8;
533         eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_LOW);
534         sc->enaddr[5] = eaddrtemp & 0xFF;
535         sc->enaddr[4] = eaddrtemp >> 8;
536
537         /* disable the board interrupts */
538         outb(PORT(sc) + IEE16_IRQ, sc->irq_encoded);
539
540         /* enable loopback to keep bad packets off the wire */
541         bart_config = inb(PORT(sc) + IEE16_CONFIG);
542         bart_config |= IEE16_BART_LOOPBACK;
543         bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
544         outb(PORT(sc) + IEE16_CONFIG, bart_config);
545         bart_config = inb(PORT(sc) + IEE16_CONFIG);
546
547         /* take the board out of reset state */
548         outb(PORT(sc) + IEE16_ECTRL, 0);
549         DELAY(100);
550
551         if (!check_ie_present(sc)) {
552                 device_printf(dev, "check_ie_present() returned false.\n");
553                 error = ENXIO;
554                 goto bad;
555         }
556
557         error = ie_attach(dev);
558         if (error) {
559                 device_printf(dev, "ie_attach() failed.\n");
560                 goto bad;
561         }
562
563         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
564                                 NULL, ie_intr, sc, &sc->irq_ih);
565         if (error) {
566                 device_printf(dev, "Unable to register interrupt handler\n"); 
567                 goto bad;
568         }
569
570         return (0);
571 bad:
572         ie_release_resources(dev);
573
574         return (error);
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         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
776                                 NULL, ie_intr, sc, &sc->irq_ih);
777         if (error) {
778                 device_printf(dev, "Unable to register interrupt handler\n"); 
779                 goto bad;
780         }
781
782         return (0);
783 bad:
784         ie_release_resources(dev);
785
786         return (error);
787 }
788
789 static enum ie_hardware
790 ie_isa_sl_get_hard_type (u_int32_t port)
791 {
792         u_char                  c;
793         enum ie_hardware        retval;
794
795         c = inb(port + IEATT_REVISION);
796         switch (SL_BOARD(c)) {
797                 case SL1_BOARD:
798                         if (inb(port + IEATT_ATTRIB) != NI5210_BOARD)
799                                 retval = IE_NONE;
800                         retval = IE_NI5210;
801                         break;
802                 case SL10_BOARD:
803                         retval = IE_STARLAN10;
804                         break;
805                 case EN100_BOARD:
806                         retval = IE_EN100;
807                         break;
808                 case SLFIBER_BOARD:
809                         retval = IE_SLFIBER;
810                         break;
811                 default:
812                         retval = IE_NONE;
813         }
814         return (retval);
815 }
816
817 static devclass_t ie_devclass;
818
819 static device_method_t ie_isa_3C507_methods[] = {
820         DEVMETHOD(device_identify,      ie_isa_3C507_identify),
821         DEVMETHOD(device_probe,         ie_isa_3C507_probe),
822         DEVMETHOD(device_attach,        ie_isa_3C507_attach),
823         DEVMETHOD(device_detach,        ie_detach),
824         { 0, 0 }
825 };
826 static driver_t ie_isa_3C507_driver = {
827         "ie",
828         ie_isa_3C507_methods,
829         sizeof(struct ie_softc), 
830 };
831 DRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
832 MODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
833
834 static device_method_t ie_isa_ee16_methods[] = {
835         DEVMETHOD(device_identify,      ie_isa_ee16_identify),
836         DEVMETHOD(device_probe,         ie_isa_ee16_probe),
837         DEVMETHOD(device_attach,        ie_isa_ee16_attach),
838         DEVMETHOD(device_detach,        ie_detach),
839         { 0, 0 }
840 };
841 static driver_t ie_isa_ee16_driver = {
842         "ie",
843         ie_isa_ee16_methods,
844         sizeof(struct ie_softc), 
845 };
846 DRIVER_MODULE(ie_EE16, 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 static driver_t ie_isa_sl_driver = {
855         "ie",
856         ie_isa_sl_methods,
857         sizeof(struct ie_softc), 
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                 break;
879         default:
880                 break;
881         };
882
883         return (0);
884 }