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/clock.h>
62 #include <machine/md_var.h>
63 #include <vm/vm.h>
64 #include <vm/pmap.h>
65 #include <vm/vm_param.h>
66
67 #include <dev/arl/if_arlreg.h>
68
69 static void arl_isa_identify(driver_t *, device_t);
70 static int arl_isa_probe (device_t);
71 static int arl_isa_attach (device_t);
72 static int arl_isa_detach (device_t);
73 static char* arl_make_desc (u_int8_t, u_int8_t);
74
75 #define ARL_MAX_ATYPE_LEN 10
76 static struct arl_type {
77 u_int8_t type;
78 char* desc;
79 }
80 arl_type_list[] = {
81 { 0, "450" },
82 { 1, "650" },
83 { 0xb, "670" },
84 { 0xc, "670E" },
85 { 0xd, "650E" },
86 { 0xe, "440LT" },
87 { 0x2e, "655" },
88 { 0x6b, "IC2200" },
89 { 0, 0 }
90 };
91
92 #define ARL_MAX_RTYPE_LEN 10
93 struct radio_type {
94 u_int8_t type;
95 char* desc;
96 } radio_type_list [] = {
97 { 1, "092/094" },
98 { 2, "020" },
99 { 3, "092A" },
100 { 4, "020B" },
101 { 5, "095" },
102 { 6, "024" },
103 { 7, "025B" },
104 { 8, "024B" },
105 { 9, "024C" },
106 {10, "025C" },
107 {11, "024-1A" },
108 {12, "025-1A" },
109 };
110
111
112 static char*
113 arl_make_desc(hw_type, radio_mod)
114 u_int8_t hw_type;
115 u_int8_t radio_mod;
116 {
117 static char desc[80];
118 char atype[ARL_MAX_ATYPE_LEN], rtype[ARL_MAX_RTYPE_LEN];
119 int i;
120
121 *atype = *rtype = 0;
122
123 /* arl type */
124 for(i = 0; arl_type_list[i].desc; i++) {
125 if (arl_type_list[i].type == hw_type)
126 break;
127 }
128
129 if (arl_type_list[i].desc)
130 strncpy(atype, arl_type_list[i].desc, ARL_MAX_ATYPE_LEN);
131 else
132 snprintf(atype, ARL_MAX_ATYPE_LEN, "(0x%x)", hw_type);
133
134 /* radio type */
135 for(i = 0; radio_type_list[i].desc; i++)
136 if (radio_type_list[i].type == radio_mod)
137 break;
138
139 if (radio_type_list[i].desc)
140 strncpy(rtype, radio_type_list[i].desc, ARL_MAX_RTYPE_LEN);
141 else
142 snprintf(rtype, ARL_MAX_RTYPE_LEN, "(0x%x)", radio_mod);
143
144 snprintf(desc, 80, "ArLan type %s, radio module %s", atype, rtype);
145
146 return desc;
147 }
148
149 #define ARL_ADDR2VEC(addr) (1 << ((addr - ARL_BASE_START) / ARL_BASE_STEP))
150
151 static void
152 arl_isa_identify (driver_t *driver, device_t parent)
153 {
154 device_t child;
155 struct arl_softc *sc;
156 int chunk, found, i;
157 u_int16_t free_mem = 0xFFFF;
158
159 if (bootverbose)
160 printf("arl: in identify\n");
161
162 /* Try avoid already added devices */
163 for (i = 0; (child = device_find_child(parent, "arl", i)) != NULL; i++) {
164 chunk = bus_get_resource_start(child, SYS_RES_MEMORY, 0);
165 if (bootverbose)
166 device_printf(child, "found at iomem = 0x%0x\n", chunk);
167 if (chunk >= ARL_BASE_START && chunk <= ARL_BASE_END)
168 free_mem ^= ARL_ADDR2VEC(chunk);
169 }
170
171 if (bootverbose)
172 printf("arl: free mem vector = 0x%x\n", free_mem);
173
174 for (chunk = ARL_BASE_START; chunk <= ARL_BASE_END; chunk += ARL_BASE_STEP) {
175 /* If device 'arl' with this chunk was found early - skip it */
176 if ( !(free_mem & ARL_ADDR2VEC(chunk)) )
177 continue;
178
179 found = 0;
180 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "arl", -1);
181 device_set_driver(child, driver);
182 sc = device_get_softc(child);
183 bzero(sc, sizeof(*sc));
184
185 bus_set_resource(child, SYS_RES_MEMORY, sc->mem_rid, chunk,
186 ARL_BASE_STEP);
187
188 if (arl_alloc_memory(child, sc->mem_rid, ARL_BASE_STEP) == 0) {
189 ar = (struct arl_private *) rman_get_virtual(sc->mem_res);
190 if (!bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1))
191 found++;
192 }
193
194 if (bootverbose)
195 device_printf(child, "%sfound at 0x%x\n",
196 !found ? "not " : "", chunk);
197
198 arl_release_resources(child);
199 if (!found) {
200 bus_delete_resource(child, SYS_RES_MEMORY, sc->mem_rid);
201 device_delete_child(parent, child);
202 }
203
204 }
205 }
206
207 static int
208 arl_isa_probe (device_t dev)
209 {
210 struct arl_softc *sc = device_get_softc(dev);
211 int error;
212 u_char *ptr;
213 u_int8_t irq;
214
215 if (isa_get_vendorid(dev))
216 return (ENXIO);
217
218 if (bootverbose)
219 device_printf(dev, "in probe\n");
220
221 bzero(sc, sizeof(struct arl_softc));
222
223 sc->arl_unit = device_get_unit(dev);
224
225 error = arl_alloc_memory(dev, 0, ARL_BASE_STEP);
226 if (error) {
227 if (bootverbose)
228 device_printf(dev, "Error allocating memory (%d)\n", error);
229 return (error);
230 }
231
232 ar = (struct arl_private *) rman_get_virtual(sc->mem_res);
233 if (bcmp(ar->textRegion, ARLAN_SIGN, sizeof(ARLAN_SIGN) - 1)) {
234 if (bootverbose)
235 device_printf(dev, "not found\n");
236 error = ENOENT;
237 goto bad;
238 }
239
240 irq = ar->irqLevel;
241 if (irq == 2)
242 irq = 9;
243
244 error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
245 if (error)
246 goto bad;
247
248 error = arl_alloc_irq(dev, 0, 0);
249 if (error) {
250 if (bootverbose)
251 device_printf(dev, "Can't allocate IRQ %d\n", irq);
252 goto bad;
253 }
254
255 ar->controlRegister = 1; /* freeze board */
256
257 /* Memory test */
258 for (ptr = (u_char *) ar;
259 ptr < ((u_char *) ar + ARL_BASE_STEP - 1); ptr++) {
260 u_char c;
261
262 c = *ptr; *ptr = ~(*ptr);
263 if (*ptr != (u_char)~c) {
264 device_printf(dev, "board memory failed at [%lx]\n",
265 rman_get_start(sc->mem_res) + (ptr - (u_char *)ar));
266 break; /* skip memory test */
267 }
268 }
269
270 bzero((void *) ar, ARL_BASE_STEP - 1); /* clear board ram */
271
272 if (arl_wait_reset(sc, 100, ARDELAY)) {
273 error = ENXIO;
274 goto bad;
275 }
276
277 if (ar->diagnosticInfo == 0xFF) {
278 device_set_desc_copy(dev, arl_make_desc(ar->hardwareType,
279 ar->radioModule));
280 error = 0;
281 } else {
282 if (bootverbose)
283 device_printf(dev, "board self-test failed (0x%x)!\n",
284 ar->diagnosticInfo);
285 error = ENXIO;
286 }
287
288 bad:
289 arl_release_resources(dev);
290
291 return (error);
292 }
293
294 static int
295 arl_isa_attach (device_t dev)
296 {
297 struct arl_softc *sc = device_get_softc(dev);
298 int error;
299
300 if (bootverbose)
301 device_printf(dev, "in attach\n");
302
303 arl_alloc_memory(dev, sc->mem_rid, ARL_BASE_STEP);
304 arl_alloc_irq(dev, sc->irq_rid, 0);
305
306 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
307 arl_intr, sc, &sc->irq_handle);
308 if (error) {
309 arl_release_resources(dev);
310 return (error);
311 }
312
313 #if __FreeBSD_version < 502108
314 device_printf(dev, "Ethernet address %6D\n", IFP2ENADDR(sc->arl_ifp), ":");
315 #endif
316
317 return arl_attach(dev);
318 }
319
320 static int
321 arl_isa_detach(device_t dev)
322 {
323 struct arl_softc *sc = device_get_softc(dev);
324
325 arl_stop(sc);
326 ifmedia_removeall(&sc->arl_ifmedia);
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 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
334 arl_release_resources(dev);
335
336 return (0);
337 }
338
339 static device_method_t arl_isa_methods[] = {
340 /* Device interface */
341 DEVMETHOD(device_identify, arl_isa_identify),
342 DEVMETHOD(device_probe, arl_isa_probe),
343 DEVMETHOD(device_attach, arl_isa_attach),
344 DEVMETHOD(device_detach, arl_isa_detach),
345
346 { 0, 0 }
347 };
348
349 static driver_t arl_isa_driver = {
350 "arl",
351 arl_isa_methods,
352 sizeof(struct arl_softc)
353 };
354
355 extern devclass_t arl_devclass;
356
357 DRIVER_MODULE(arl, isa, arl_isa_driver, arl_devclass, 0, 0);
358 MODULE_DEPEND(arl, isa, 1, 1, 1);
359 MODULE_DEPEND(arl, ether, 1, 1, 1);
Cache object: fda1feb197a1d8581042d81d5db525fa
|