5438559d22914acb646b1ab4890fb7adb2ecbc49
[dragonfly.git] / sys / dev / netif / ex / if_ex_isa.c
1 /*-
2  * Copyright (c) 2000 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  *      $FreeBSD: src/sys/dev/ex/if_ex_isa.c,v 1.3.2.1 2001/03/05 05:33:20 imp Exp $
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/interrupt.h>
33 #include <sys/socket.h>
34 #include <sys/module.h>
35 #include <sys/bus.h>
36 #include <sys/rman.h>
37 #include <sys/serialize.h>
38
39 #include <machine/clock.h>
40
41 #include <net/if.h>
42 #include <net/if_arp.h>
43 #include <net/if_media.h> 
44
45 #include <bus/isa/isavar.h>
46 #include <bus/isa/pnpvar.h>
47
48 #include "if_exreg.h"
49 #include "if_exvar.h"
50
51 /* Bus Front End Functions */
52 static int      ex_isa_identify (driver_t *, device_t);
53 static int      ex_isa_probe    (device_t);
54 static int      ex_isa_attach   (device_t);
55
56 /*
57  * We need an identify function to 'probe' the ISA bus.
58  */
59 static device_method_t ex_methods[] = {
60         /* Device interface */
61         DEVMETHOD(device_identify,      ex_isa_identify),
62         DEVMETHOD(device_probe,         ex_isa_probe),
63         DEVMETHOD(device_attach,        ex_isa_attach),
64
65         { 0, 0 }
66 };
67
68 static driver_t ex_driver = {
69         "ex",
70         ex_methods,
71         sizeof(struct ex_softc),
72 };
73
74 devclass_t ex_devclass;
75
76 DRIVER_MODULE(if_ex, isa, ex_driver, ex_devclass, NULL, NULL);
77
78 static struct isa_pnp_id ex_ids[] = {
79         { 0x3110d425,   NULL }, /* INT1031 */
80         { 0x3010d425,   NULL }, /* INT1030 */
81         { 0,            NULL },
82 };
83
84 /*
85  * Non-destructive identify.
86  */
87 static int
88 ex_isa_identify (driver_t *driver, device_t parent)
89 {
90         device_t        child;
91         u_int32_t       ioport;
92         u_char          enaddr[6];
93         u_int           irq;
94         int             tmp;
95         int             count;
96         const char *    desc;
97
98         /*
99          * Rescanning ISA I/O ports is not supported.
100          */
101         if (device_get_state(parent) == DS_ATTACHED)
102                 return (0);
103
104         if (bootverbose)
105                 kprintf("ex_isa_identify()\n");
106
107         count = 0;
108         for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) {
109
110                 /* No board found at address */
111                 if (!look_for_card(ioport)) {
112                         continue;
113                 }
114
115                 if (bootverbose)
116                         kprintf("ex: Found card at 0x%03x!\n", ioport);
117
118                 /* Board in PnP mode */
119                 if (eeprom_read(ioport, EE_W0) & EE_W0_PNP) {
120                         /* Reset the card. */
121                         outb(ioport + CMD_REG, Reset_CMD);
122                         DELAY(500);
123                         if (bootverbose)
124                                 kprintf("ex: card at 0x%03x in PnP mode!\n", ioport);
125                         continue;
126                 }
127
128                 bzero(enaddr, sizeof(enaddr));
129
130                 /* Reset the card. */
131                 outb(ioport + CMD_REG, Reset_CMD);
132                 DELAY(400);
133
134                 ex_get_address(ioport, enaddr);
135                 tmp = eeprom_read(ioport, EE_W1) & EE_W1_INT_SEL;
136
137                 /* work out which set of irq <-> internal tables to use */
138                 if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) {
139                         irq  = plus_ee2irqmap[tmp];
140                         desc = "Intel Pro/10+";
141                 } else {
142                         irq = ee2irqmap[tmp];
143                         desc = "Intel Pro/10";
144                 }
145
146                 child = BUS_ADD_CHILD(parent, parent,
147                                       ISA_ORDER_SPECULATIVE, "ex", -1);
148                 device_set_desc_copy(child, desc);
149                 device_set_driver(child, driver);
150                 bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
151                 bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE);
152                 ++count;
153
154                 if (bootverbose)
155                         kprintf("ex: Adding board at 0x%03x, irq %d\n", ioport, irq);
156         }
157         return (count ? 0 : ENXIO);
158 }
159
160 static int
161 ex_isa_probe(device_t dev)
162 {
163         u_int           iobase;
164         u_int           irq;
165         u_char *        ee2irq;
166         u_char          enaddr[6];
167         int             tmp;
168         int             error;
169
170         /* Check isapnp ids */
171         error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids);
172
173         /* If the card had a PnP ID that didn't match any we know about */
174         if (error == ENXIO) {
175                 return(error);
176         }
177
178         /* If we had some other problem. */
179         if (!(error == 0 || error == ENOENT)) {
180                 return(error);
181         }
182
183         iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
184         if (!iobase) {
185                 kprintf("ex: no iobase?\n");
186                 return(ENXIO);
187         }
188
189         if (!look_for_card(iobase)) {
190                 kprintf("ex: no card found at 0x%03x\n", iobase);
191                 return(ENXIO);
192         }
193
194         if (bootverbose)
195                 kprintf("ex: ex_isa_probe() found card at 0x%03x\n", iobase);
196
197         /*
198          * Reset the card.
199          */
200         outb(iobase + CMD_REG, Reset_CMD);
201         DELAY(800);
202
203         ex_get_address(iobase, enaddr);
204
205         /* work out which set of irq <-> internal tables to use */
206         if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS)
207                 ee2irq = plus_ee2irqmap;
208         else
209                 ee2irq = ee2irqmap;
210
211         tmp = eeprom_read(iobase, EE_W1) & EE_W1_INT_SEL;
212         irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0);
213
214         if (irq > 0) {
215                 /* This will happen if board is in PnP mode. */
216                 if (ee2irq[tmp] != irq) {
217                         kprintf("ex: WARNING: board's EEPROM is configured"
218                                 " for IRQ %d, using %d\n",
219                                 ee2irq[tmp], irq);
220                 }
221         } else {
222                 irq = ee2irq[tmp];
223                 bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
224         }
225
226         if (irq == 0) {
227                 kprintf("ex: invalid IRQ.\n");
228                 return(ENXIO);
229         }
230
231         return(0);
232 }
233
234 static int
235 ex_isa_attach(device_t dev)
236 {
237         struct ex_softc *       sc = device_get_softc(dev);
238         struct ifnet *          ifp = &sc->arpcom.ac_if;
239         int                     error = 0;
240         u_int16_t               temp;
241
242         sc->dev = dev;
243         sc->ioport_rid = 0;
244         sc->irq_rid = 0;
245
246         if ((error = ex_alloc_resources(dev)) != 0) {
247                 device_printf(dev, "ex_alloc_resources() failed!\n");
248                 goto bad;
249         }
250
251         /*
252          * Fill in several fields of the softc structure:
253          *      - I/O base address.
254          *      - Hardware Ethernet address.
255          *      - IRQ number (if not supplied in config file, read it from EEPROM).
256          *      - Connector type.
257          */
258         sc->iobase = rman_get_start(sc->ioport);
259         sc->irq_no = rman_get_start(sc->irq);
260
261         ex_get_address(sc->iobase, sc->arpcom.ac_enaddr);
262
263         temp = eeprom_read(sc->iobase, EE_W0);
264         device_printf(sc->dev, "%s config, %s bus, ",
265                 (temp & EE_W0_PNP) ? "PnP" : "Manual",
266                 (temp & EE_W0_BUS16) ? "16-bit" : "8-bit");
267
268         temp = eeprom_read(sc->iobase, EE_W6);
269         kprintf("board id 0x%03x, stepping 0x%01x\n",
270                 (temp & EE_W6_BOARD_MASK) >> EE_W6_BOARD_SHIFT,
271                 temp & EE_W6_STEP_MASK);
272
273         if ((error = ex_attach(dev)) != 0) {
274                 device_printf(dev, "ex_attach() failed!\n");
275                 goto bad;
276         }
277
278         error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE,
279                                 ex_intr, (void *)sc, &sc->ih, 
280                                 ifp->if_serializer);
281         if (error) {
282                 device_printf(dev, "bus_setup_intr() failed!\n");
283                 goto bad;
284         }
285
286         ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->irq));
287         KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
288
289         return(0);
290 bad:
291         ex_release_resources(dev);
292         return (error);
293 }