1 /*-
2 * EISA bus probe and attach routines
3 *
4 * Copyright (c) 1995, 1996 Justin T. Gibbs.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice immediately at the beginning of the file, without modification,
12 * this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/6.2/sys/dev/eisa/eisaconf.c 143759 2005-03-17 17:36:07Z imp $");
35
36 #include "opt_eisa.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/queue.h>
41 #include <sys/limits.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/bus.h>
46
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <sys/rman.h>
50
51 #include <dev/eisa/eisaconf.h>
52
53 typedef struct resvaddr {
54 u_long addr; /* start address */
55 u_long size; /* size of reserved area */
56 int flags;
57 struct resource *res; /* resource manager handle */
58 LIST_ENTRY(resvaddr) links; /* List links */
59 } resvaddr_t;
60
61 LIST_HEAD(resvlist, resvaddr);
62
63 struct irq_node {
64 int irq_no;
65 int irq_trigger;
66 void *idesc;
67 TAILQ_ENTRY(irq_node) links;
68 };
69
70 TAILQ_HEAD(irqlist, irq_node);
71
72 struct eisa_ioconf {
73 int slot;
74 struct resvlist ioaddrs; /* list of reserved I/O ranges */
75 struct resvlist maddrs; /* list of reserved memory ranges */
76 struct irqlist irqs; /* list of reserved irqs */
77 };
78
79 /* To be replaced by the "super device" generic device structure... */
80 struct eisa_device {
81 eisa_id_t id;
82 struct eisa_ioconf ioconf;
83 };
84
85
86 #define MAX_COL 79
87 #ifndef EISA_SLOTS
88 #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */
89 #endif
90 int num_eisa_slots = EISA_SLOTS;
91 TUNABLE_INT("hw.eisa_slots", &num_eisa_slots);
92
93 static devclass_t eisa_devclass;
94
95 static int eisa_probe_slot(int slot, eisa_id_t *eisa_id);
96 static void eisa_reg_print (device_t, char *, char *, int *);
97 static struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid);
98 static struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid);
99 static struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid);
100
101 static int
102 mainboard_probe(device_t dev)
103 {
104 char *idstring;
105 eisa_id_t id = eisa_get_id(dev);
106
107 if (eisa_get_slot(dev) != 0)
108 return (ENXIO);
109
110 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
111 M_DEVBUF, M_NOWAIT);
112 if (idstring == NULL)
113 panic("Eisa probe unable to malloc");
114 sprintf(idstring, "%c%c%c%03x%01x (System Board)",
115 EISA_MFCTR_CHAR0(id), EISA_MFCTR_CHAR1(id), EISA_MFCTR_CHAR2(id),
116 EISA_PRODUCT_ID(id), EISA_REVISION_ID(id));
117 device_set_desc(dev, idstring);
118
119 return (0);
120 }
121
122 static int
123 mainboard_attach(device_t dev)
124 {
125 return (0);
126 }
127
128 static device_method_t mainboard_methods[] = {
129 /* Device interface */
130 DEVMETHOD(device_probe, mainboard_probe),
131 DEVMETHOD(device_attach, mainboard_attach),
132
133 { 0, 0 }
134 };
135
136 static driver_t mainboard_driver = {
137 "mainboard",
138 mainboard_methods,
139 1,
140 };
141
142 static devclass_t mainboard_devclass;
143
144 DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0);
145
146 /*
147 ** probe for EISA devices
148 */
149 static int
150 eisa_probe(device_t dev)
151 {
152 int devices_found, slot;
153 struct eisa_device *e_dev;
154 device_t child;
155 eisa_id_t eisa_id;
156
157 device_set_desc(dev, "EISA bus");
158
159 devices_found = 0;
160 for (slot = 0; slot < num_eisa_slots; slot++) {
161 eisa_id = 0;
162 if (eisa_probe_slot(slot, &eisa_id)) {
163 /*
164 * If there's no card in the first slot (the
165 * mainboard), then the system doesn't have EISA.
166 * We abort the probe early in this case since
167 * continuing on causes a hang on some systems.
168 * Interestingly enough, the inb has been seen to
169 * cause the hang.
170 */
171 if (slot == 0)
172 break;
173 continue;
174 }
175
176 devices_found++;
177
178 /* Prepare an eisa_device_node for this slot */
179 e_dev = (struct eisa_device *)malloc(sizeof(*e_dev),
180 M_DEVBUF, M_NOWAIT|M_ZERO);
181 if (!e_dev) {
182 device_printf(dev, "cannot malloc eisa_device");
183 break; /* Try to attach what we have already */
184 }
185
186 e_dev->id = eisa_id;
187 e_dev->ioconf.slot = slot;
188
189 /* Initialize our lists of reserved addresses */
190 LIST_INIT(&(e_dev->ioconf.ioaddrs));
191 LIST_INIT(&(e_dev->ioconf.maddrs));
192 TAILQ_INIT(&(e_dev->ioconf.irqs));
193
194 child = device_add_child(dev, NULL, -1);
195 device_set_ivars(child, e_dev);
196 }
197
198 /*
199 * EISA busses themselves are not easily detectable, the easiest way
200 * to tell if there is an eisa bus is if we found something - there
201 * should be a motherboard "card" there somewhere.
202 */
203 return (devices_found ? 0 : ENXIO);
204 }
205
206 static int
207 eisa_probe_slot(int slot, eisa_id_t *eisa_id)
208 {
209 eisa_id_t probe_id;
210 int base, i, id_size;
211
212 probe_id = 0;
213 id_size = sizeof(probe_id);
214 base = 0x0c80 + (slot * 0x1000);
215
216 for (i = 0; i < id_size; i++)
217 probe_id |= inb(base + i) << ((id_size - i - 1) * CHAR_BIT);
218
219 /* If we found a card, return its EISA id. */
220 if ((probe_id & 0x80000000) == 0) {
221 *eisa_id = probe_id;
222 return (0);
223 }
224
225 return (ENXIO);
226 }
227
228 static void
229 eisa_probe_nomatch(device_t dev, device_t child)
230 {
231 u_int32_t eisa_id = eisa_get_id(child);
232 u_int8_t slot = eisa_get_slot(child);
233
234 device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n",
235 EISA_MFCTR_CHAR0(eisa_id), EISA_MFCTR_CHAR1(eisa_id),
236 EISA_MFCTR_CHAR2(eisa_id), EISA_PRODUCT_ID(eisa_id),
237 EISA_REVISION_ID(eisa_id), eisa_id, slot);
238 return;
239 }
240
241 static void
242 eisa_reg_print (device_t dev, char *string, char *separator, int *column)
243 {
244 int length = strlen(string);
245
246 length += (separator ? 2 : 1);
247
248 if (((*column) + length) >= MAX_COL) {
249 printf("\n");
250 (*column) = 0;
251 } else if ((*column) != 0) {
252 if (separator) {
253 printf("%c", *separator);
254 (*column)++;
255 }
256 printf(" ");
257 (*column)++;
258 }
259
260 if ((*column) == 0)
261 (*column) += device_printf(dev, "%s", string);
262 else
263 (*column) += printf("%s", string);
264
265 return;
266 }
267
268 static int
269 eisa_print_child(device_t dev, device_t child)
270 {
271 char buf[81];
272 struct eisa_device * e_dev = device_get_ivars(child);
273 int rid;
274 struct irq_node * irq;
275 struct resvaddr * resv;
276 char separator = ',';
277 int column = 0;
278 int retval = 0;
279
280 if (device_get_desc(child)) {
281 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
282 eisa_reg_print(child, buf, NULL, &column);
283 }
284
285 rid = 0;
286 while ((resv = eisa_find_ioaddr(e_dev, rid++))) {
287 if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK))
288 snprintf(buf, sizeof(buf), "%s%lx",
289 rid == 1 ? "at 0x" : "0x", resv->addr);
290 else
291 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
292 rid == 1 ? "at 0x" : "0x", resv->addr,
293 resv->addr + resv->size - 1);
294 eisa_reg_print(child, buf, rid == 2 ? &separator : NULL,
295 &column);
296 }
297
298 rid = 0;
299 while ((resv = eisa_find_maddr(e_dev, rid++))) {
300 if (resv->size == 1 || (resv->flags & RESVADDR_BITMASK))
301 snprintf(buf, sizeof(buf), "%s%lx",
302 rid == 1 ? "at 0x" : "0x", resv->addr);
303 else
304 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
305 rid == 1 ? "at 0x" : "0x",
306 resv->addr, resv->addr + resv->size - 1);
307 eisa_reg_print(child, buf, rid == 2 ? &separator : NULL,
308 &column);
309 }
310
311 rid = 0;
312 while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) {
313 snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no,
314 irq->irq_trigger ? "level" : "edge");
315 eisa_reg_print(child, buf, rid == 1 ? &separator : NULL,
316 &column);
317 }
318
319 snprintf(buf, sizeof(buf), "on %s slot %d\n",
320 device_get_nameunit(dev), eisa_get_slot(child));
321 eisa_reg_print(child, buf, NULL, &column);
322
323 return (retval);
324 }
325
326 static struct irq_node *
327 eisa_find_irq(struct eisa_device *e_dev, int rid)
328 {
329 int i;
330 struct irq_node *irq;
331
332 for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
333 i < rid && irq != NULL; i++, irq = TAILQ_NEXT(irq, links))
334 continue;
335
336 return (irq);
337 }
338
339 static struct resvaddr *
340 eisa_find_maddr(struct eisa_device *e_dev, int rid)
341 {
342 int i;
343 struct resvaddr *resv;
344
345 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs);
346 i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links))
347 continue;
348
349 return (resv);
350 }
351
352 static struct resvaddr *
353 eisa_find_ioaddr(struct eisa_device *e_dev, int rid)
354 {
355 int i;
356 struct resvaddr *resv;
357
358 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs);
359 i < rid && resv != NULL; i++, resv = LIST_NEXT(resv, links))
360 continue;
361
362 return (resv);
363 }
364
365 static int
366 eisa_read_ivar(device_t dev, device_t child, int which, u_long *result)
367 {
368 struct eisa_device *e_dev = device_get_ivars(child);
369 struct irq_node *irq;
370
371 switch (which) {
372 case EISA_IVAR_SLOT:
373 *result = e_dev->ioconf.slot;
374 break;
375
376 case EISA_IVAR_ID:
377 *result = e_dev->id;
378 break;
379
380 case EISA_IVAR_IRQ:
381 /* XXX only first irq */
382 if ((irq = eisa_find_irq(e_dev, 0)) != NULL)
383 *result = irq->irq_no;
384 else
385 *result = -1;
386 break;
387
388 default:
389 return (ENOENT);
390 }
391
392 return (0);
393 }
394
395 static int
396 eisa_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
397 {
398 return (EINVAL);
399 }
400
401 static struct resource *
402 eisa_alloc_resource(device_t dev, device_t child, int type, int *rid,
403 u_long start, u_long end, u_long count, u_int flags)
404 {
405 int isdefault;
406 struct eisa_device *e_dev = device_get_ivars(child);
407 struct resource *rv, **rvp = 0;
408
409 isdefault = (device_get_parent(child) == dev &&
410 start == 0UL && end == ~0UL && count == 1);
411
412 switch (type) {
413 case SYS_RES_IRQ:
414 if (isdefault) {
415 struct irq_node * irq = eisa_find_irq(e_dev, *rid);
416 if (irq == NULL)
417 return (NULL);
418 start = end = irq->irq_no;
419 count = 1;
420 if (irq->irq_trigger == EISA_TRIGGER_LEVEL)
421 flags |= RF_SHAREABLE;
422 else
423 flags &= ~RF_SHAREABLE;
424 }
425 break;
426
427 case SYS_RES_MEMORY:
428 if (isdefault) {
429 struct resvaddr *resv;
430
431 resv = eisa_find_maddr(e_dev, *rid);
432 if (resv == NULL)
433 return (NULL);
434
435 start = resv->addr;
436 end = resv->addr + (resv->size - 1);
437 count = resv->size;
438 rvp = &resv->res;
439 }
440 break;
441
442 case SYS_RES_IOPORT:
443 if (isdefault) {
444 struct resvaddr *resv;
445
446 resv = eisa_find_ioaddr(e_dev, *rid);
447 if (resv == NULL)
448 return (NULL);
449
450 start = resv->addr;
451 end = resv->addr + (resv->size - 1);
452 count = resv->size;
453 rvp = &resv->res;
454 }
455 break;
456
457 default:
458 return 0;
459 }
460
461 rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
462 type, rid, start, end, count, flags);
463 if (rvp)
464 *rvp = rv;
465
466 return (rv);
467 }
468
469 static int
470 eisa_release_resource(device_t dev, device_t child, int type, int rid,
471 struct resource *r)
472 {
473 int rv;
474 struct eisa_device *e_dev = device_get_ivars(child);
475 struct resvaddr *resv = 0;
476
477 switch (type) {
478 case SYS_RES_IRQ:
479 if (eisa_find_irq(e_dev, rid) == NULL)
480 return (EINVAL);
481 break;
482
483 case SYS_RES_MEMORY:
484 if (device_get_parent(child) == dev)
485 resv = eisa_find_maddr(e_dev, rid);
486 break;
487
488
489 case SYS_RES_IOPORT:
490 if (device_get_parent(child) == dev)
491 resv = eisa_find_ioaddr(e_dev, rid);
492 break;
493
494 default:
495 return (ENOENT);
496 }
497
498 rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
499
500 if (rv == 0) {
501 if (resv != NULL)
502 resv->res = 0;
503 }
504
505 return (rv);
506 }
507
508 static int
509 eisa_add_intr_m(device_t eisa, device_t dev, int irq, int trigger)
510 {
511 struct eisa_device *e_dev = device_get_ivars(dev);
512 struct irq_node *irq_info;
513
514 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
515 M_NOWAIT);
516 if (irq_info == NULL)
517 return (1);
518
519 irq_info->irq_no = irq;
520 irq_info->irq_trigger = trigger;
521 irq_info->idesc = NULL;
522 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
523 return (0);
524 }
525
526 static int
527 eisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base,
528 u_long size, int flags)
529 {
530 resvaddr_t *reservation;
531
532 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
533 M_DEVBUF, M_NOWAIT);
534 if(!reservation)
535 return (ENOMEM);
536
537 reservation->addr = base;
538 reservation->size = size;
539 reservation->flags = flags;
540
541 if (!LIST_FIRST(head)) {
542 LIST_INSERT_HEAD(head, reservation, links);
543 }
544 else {
545 resvaddr_t *node;
546 LIST_FOREACH(node, head, links) {
547 if (node->addr > reservation->addr) {
548 /*
549 * List is sorted in increasing
550 * address order.
551 */
552 LIST_INSERT_BEFORE(node, reservation, links);
553 break;
554 }
555
556 if (node->addr == reservation->addr) {
557 /*
558 * If the entry we want to add
559 * matches any already in here,
560 * fail.
561 */
562 free(reservation, M_DEVBUF);
563 return (EEXIST);
564 }
565
566 if (!LIST_NEXT(node, links)) {
567 LIST_INSERT_AFTER(node, reservation, links);
568 break;
569 }
570 }
571 }
572 return (0);
573 }
574
575 static int
576 eisa_add_mspace_m(device_t eisa, device_t dev, u_long mbase, u_long msize,
577 int flags)
578 {
579 struct eisa_device *e_dev = device_get_ivars(dev);
580
581 return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.maddrs), mbase, msize,
582 flags));
583 }
584
585 static int
586 eisa_add_iospace_m(device_t eisa, device_t dev, u_long iobase, u_long iosize,
587 int flags)
588 {
589 struct eisa_device *e_dev = device_get_ivars(dev);
590
591 return (eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
592 iosize, flags));
593 }
594
595 static device_method_t eisa_methods[] = {
596 /* Device interface */
597 DEVMETHOD(device_probe, eisa_probe),
598 DEVMETHOD(device_attach, bus_generic_attach),
599 DEVMETHOD(device_shutdown, bus_generic_shutdown),
600 DEVMETHOD(device_suspend, bus_generic_suspend),
601 DEVMETHOD(device_resume, bus_generic_resume),
602
603 /* Bus interface */
604 DEVMETHOD(bus_print_child, eisa_print_child),
605 DEVMETHOD(bus_probe_nomatch, eisa_probe_nomatch),
606 DEVMETHOD(bus_read_ivar, eisa_read_ivar),
607 DEVMETHOD(bus_write_ivar, eisa_write_ivar),
608 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
609 DEVMETHOD(bus_alloc_resource, eisa_alloc_resource),
610 DEVMETHOD(bus_release_resource, eisa_release_resource),
611 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
612 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
613 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
614 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
615
616 /* EISA interface */
617 DEVMETHOD(eisa_add_intr, eisa_add_intr_m),
618 DEVMETHOD(eisa_add_iospace, eisa_add_iospace_m),
619 DEVMETHOD(eisa_add_mspace, eisa_add_mspace_m),
620
621 { 0, 0 }
622 };
623
624 static driver_t eisa_driver = {
625 "eisa",
626 eisa_methods,
627 1, /* no softc */
628 };
629
630 DRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0);
631 DRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0);
Cache object: d6fab2a55f986ab330a3085fe7b57079
|