]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/arl/if_arl_isa.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / arl / if_arl_isa.c
1 /*-
2  * Copyright (c) 1999-2001, Ivan Sharov, Vitaly Belekhov.
3  * Copyright (c) 2004 Stanislav Svirid.
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  * 
27  * $RISS: if_arl/dev/arl/if_arl_isa.c,v 1.7 2004/03/16 05:30:38 count Exp $
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_inet.h"
34
35 #ifdef INET
36 #define ARLCACHE
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44
45 #include <sys/module.h>
46 #include <sys/bus.h>
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <sys/rman.h>
50
51 #include <net/ethernet.h>
52 #include <net/if.h>
53 #include <net/if_arp.h>
54 #include <net/if_mib.h>
55 #include <net/if_media.h>
56
57 #include <isa/isavar.h>
58 #include <isa/pnpvar.h>
59 #include <isa/isa_common.h>
60
61 #include <machine/md_var.h>
62 #include <vm/vm.h>
63 #include <vm/pmap.h>
64 #include <vm/vm_param.h>
65
66 #include <dev/arl/if_arlreg.h>
67
68 static void     arl_isa_identify(driver_t *, device_t);
69 static int      arl_isa_probe   (device_t);
70 static int      arl_isa_attach  (device_t);
71 static int      arl_isa_detach  (device_t);
72 static char*    arl_make_desc   (u_int8_t, u_int8_t);
73
74 #define ARL_MAX_ATYPE_LEN       10
75 static struct arl_type {
76         u_int8_t        type;
77         char*           desc;
78 }
79 arl_type_list[] = {
80         { 0, "450" },
81         { 1, "650" },
82         { 0xb, "670" },
83         { 0xc, "670E" },
84         { 0xd, "650E" },
85         { 0xe, "440LT" },
86         { 0x2e, "655" },
87         { 0x6b, "IC2200" },
88         { 0, 0 }
89 };
90
91 #define ARL_MAX_RTYPE_LEN       10
92 struct radio_type {
93         u_int8_t        type;
94         char*           desc;
95 } radio_type_list []  = {
96         { 1, "092/094"  },
97         { 2, "020"      },
98         { 3, "092A"     },
99         { 4, "020B"     },
100         { 5, "095"      },
101         { 6, "024"      },
102         { 7, "025B"     },
103         { 8, "024B"     },
104         { 9, "024C"     },
105         {10, "025C"     },
106         {11, "024-1A"   },
107         {12, "025-1A"   },
108 };
109
110
111 static char*
112 arl_make_desc(hw_type, radio_mod)
113         u_int8_t hw_type;
114         u_int8_t radio_mod;
115 {
116         static char desc[80];
117         char atype[ARL_MAX_ATYPE_LEN], rtype[ARL_MAX_RTYPE_LEN];
118         int i;
119
120         *atype = *rtype = 0;
121
122         /* arl type */
123         for(i = 0; arl_type_list[i].desc; i++) {
124                 if (arl_type_list[i].type == hw_type)
125                         break;
126         }
127
128         if (arl_type_list[i].desc)
129                 strncpy(atype, arl_type_list[i].desc, ARL_MAX_ATYPE_LEN);
130         else
131                 snprintf(atype, ARL_MAX_ATYPE_LEN, "(0x%x)", hw_type);
132
133         /* radio type */
134         for(i = 0; radio_type_list[i].desc; i++)
135                 if (radio_type_list[i].type == radio_mod)
136                         break;
137
138         if (radio_type_list[i].desc)
139                 strncpy(rtype, radio_type_list[i].desc, ARL_MAX_RTYPE_LEN);
140         else
141                 snprintf(rtype, ARL_MAX_RTYPE_LEN, "(0x%x)", radio_mod);
142
143         snprintf(desc, 80, "ArLan type %s, radio module %s", atype, rtype);
144
145         return desc;
146 }
147
148 #define ARL_ADDR2VEC(addr) (1 << ((addr - ARL_BASE_START) / ARL_BASE_STEP))
149
150 static void
151 arl_isa_identify (driver_t *driver, device_t parent)
152 {
153         device_t        child;
154         struct  arl_softc       *sc;
155         int             chunk, found, i;
156         u_int16_t       free_mem = 0xFFFF;
157
158         if (bootverbose)
159                 printf("arl: in identify\n");
160
161         /* Try avoid already added devices */
162         for (i = 0; (child = device_find_child(parent, "arl", i)) != NULL; i++) {
163                 chunk = bus_get_resource_start(child, SYS_RES_MEMORY, 0);
164                 if (bootverbose)
165                         device_printf(child, "found at iomem = 0x%0x\n", chunk);
166                 if (chunk >= ARL_BASE_START && chunk <= ARL_BASE_END)
167                         free_mem ^= ARL_ADDR2VEC(chunk);
168         }
169
170         if (bootverbose)
171                 printf("arl: free mem vector = 0x%x\n", free_mem);
172
173         for (chunk = ARL_BASE_START; chunk <= ARL_BASE_END; chunk += ARL_BASE_STEP) {
174                 /* If device 'arl' with this chunk was found early - skip it */
175                 if ( !(free_mem & ARL_ADDR2VEC(chunk)) )
176                         continue;
177
178                 found = 0;
179                 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "arl", -1);
180                 device_set_driver(child, driver);
181                 sc = device_get_softc(child);
182                 bzero(sc, sizeof(*sc));
183
184                 bus_set_resource(child, SYS_RES_MEMORY, sc->mem_rid, chunk,
185                         ARL_BASE_STEP);
186
187                 if (arl_alloc_memory(child, sc->mem_rid, ARL_BASE_STEP) == 0) {
188                         ar = (struct arl_private *) rman_get_virtual(sc->mem_res);
189                         if (!bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1))
190                                 found++;
191                 }
192
193                 if (bootverbose)
194                         device_printf(child, "%sfound at 0x%x\n",
195                                         !found ? "not " : "", chunk);
196
197                 arl_release_resources(child);
198                 if (!found) {
199                         bus_delete_resource(child, SYS_RES_MEMORY, sc->mem_rid);
200                         device_delete_child(parent, child);
201                 }
202
203         }
204 }
205
206 static int
207 arl_isa_probe (device_t dev)
208 {
209         struct arl_softc *sc = device_get_softc(dev);
210         int error;
211         u_char *ptr;
212         u_int8_t irq;
213
214         if (isa_get_vendorid(dev))
215                 return (ENXIO);
216
217         if (bootverbose)
218                 device_printf(dev, "in probe\n");
219
220         bzero(sc, sizeof(struct arl_softc));
221
222         sc->arl_unit = device_get_unit(dev);
223
224         error = arl_alloc_memory(dev, 0, ARL_BASE_STEP);
225         if (error) {
226                 if (bootverbose)
227                         device_printf(dev, "Error allocating memory (%d)\n", error);
228                 return (error);
229         }
230
231         ar = (struct arl_private *) rman_get_virtual(sc->mem_res);
232         if (bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) {
233                 if (bootverbose)
234                         device_printf(dev, "not found\n");
235                 error = ENOENT;
236                 goto bad;
237         }
238
239         irq = ar->irqLevel;
240         if (irq == 2)
241                 irq = 9;
242
243         error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
244         if (error)
245                 goto bad;
246
247         error = arl_alloc_irq(dev, 0, 0);
248         if (error) {
249                 if (bootverbose)
250                         device_printf(dev, "Can't allocate IRQ %d\n", irq);
251                 goto bad;
252         }
253
254         ar->controlRegister = 1;        /* freeze board */
255
256         /* Memory test */
257         for (ptr = (u_char *) ar;
258              ptr < ((u_char *) ar + ARL_BASE_STEP - 1); ptr++) {
259                 u_char c;
260
261                 c = *ptr; *ptr = ~(*ptr);
262                 if (*ptr != (u_char)~c) {
263                         device_printf(dev, "board memory failed at [%lx]\n",
264                             rman_get_start(sc->mem_res) + (ptr - (u_char *)ar));
265                         break; /* skip memory test */
266                 }
267         }
268
269         bzero((void *) ar,  ARL_BASE_STEP - 1); /* clear board ram */
270
271         if (arl_wait_reset(sc, 100, ARDELAY)) {
272                 error = ENXIO;
273                 goto bad;
274         }
275
276         if (ar->diagnosticInfo == 0xFF) {
277                 device_set_desc_copy(dev, arl_make_desc(ar->hardwareType,
278                         ar->radioModule));
279                 error = 0;
280         } else {
281                 if (bootverbose)
282                         device_printf(dev, "board self-test failed (0x%x)!\n",
283                                ar->diagnosticInfo);
284                 error = ENXIO;
285         }
286
287 bad:
288         arl_release_resources(dev);
289
290         return (error);
291 }
292
293 static int
294 arl_isa_attach (device_t dev)
295 {
296         struct arl_softc *sc = device_get_softc(dev);
297         int error;
298
299         if (bootverbose)
300                 device_printf(dev, "in attach\n");
301
302         arl_alloc_memory(dev, sc->mem_rid, ARL_BASE_STEP);
303         arl_alloc_irq(dev, sc->irq_rid, 0);
304
305         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
306                                NULL, arl_intr, sc, &sc->irq_handle);
307         if (error) {
308                 arl_release_resources(dev);
309                 return (error);
310         }
311
312 #if __FreeBSD_version < 502108
313         device_printf(dev, "Ethernet address %6D\n", IFP2ENADDR(sc->arl_ifp), ":");
314 #endif
315
316         return arl_attach(dev);
317 }
318
319 static int
320 arl_isa_detach(device_t dev)
321 {
322         struct arl_softc *sc = device_get_softc(dev);
323
324         arl_stop(sc);
325         ifmedia_removeall(&sc->arl_ifmedia);
326         bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
327 #if __FreeBSD_version < 500100
328         ether_ifdetach(sc->arl_ifp, ETHER_BPF_SUPPORTED);
329 #else
330         ether_ifdetach(sc->arl_ifp);
331         if_free(sc->arl_ifp);
332 #endif
333         arl_release_resources(dev);
334
335         return (0);
336 }
337
338 static device_method_t arl_isa_methods[] = {
339         /* Device interface */
340         DEVMETHOD(device_identify,      arl_isa_identify),
341         DEVMETHOD(device_probe,         arl_isa_probe),
342         DEVMETHOD(device_attach,        arl_isa_attach),
343         DEVMETHOD(device_detach,        arl_isa_detach),
344
345         { 0, 0 }
346 };
347
348 static driver_t arl_isa_driver = {
349         "arl",
350         arl_isa_methods,
351         sizeof(struct arl_softc)
352 };
353
354 extern devclass_t arl_devclass;
355
356 DRIVER_MODULE(arl, isa, arl_isa_driver, arl_devclass, 0, 0);
357 MODULE_DEPEND(arl, isa, 1, 1, 1);
358 MODULE_DEPEND(arl, ether, 1, 1, 1);