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 * $FreeBSD: releng/5.0/sys/dev/eisa/eisaconf.c 106229 2002-10-31 00:45:49Z peter $
32 */
33
34 #include "opt_eisa.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/queue.h>
39 #include <sys/malloc.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/bus.h>
43
44 #include <machine/limits.h>
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47 #include <sys/rman.h>
48
49 #include <dev/eisa/eisaconf.h>
50
51 typedef struct resvaddr {
52 u_long addr; /* start address */
53 u_long size; /* size of reserved area */
54 int flags;
55 struct resource *res; /* resource manager handle */
56 LIST_ENTRY(resvaddr) links; /* List links */
57 } resvaddr_t;
58
59 LIST_HEAD(resvlist, resvaddr);
60
61 struct irq_node {
62 int irq_no;
63 int irq_trigger;
64 void *idesc;
65 TAILQ_ENTRY(irq_node) links;
66 };
67
68 TAILQ_HEAD(irqlist, irq_node);
69
70 struct eisa_ioconf {
71 int slot;
72 struct resvlist ioaddrs; /* list of reserved I/O ranges */
73 struct resvlist maddrs; /* list of reserved memory ranges */
74 struct irqlist irqs; /* list of reserved irqs */
75 };
76
77 /* To be replaced by the "super device" generic device structure... */
78 struct eisa_device {
79 eisa_id_t id;
80 struct eisa_ioconf ioconf;
81 };
82
83
84 #define MAX_COL 79
85 #ifndef EISA_SLOTS
86 #define EISA_SLOTS 10 /* PCI clashes with higher ones.. fix later */
87 #endif
88 int num_eisa_slots = EISA_SLOTS;
89 TUNABLE_INT("hw.eisa_slots", &num_eisa_slots);
90
91 static devclass_t eisa_devclass;
92
93 static void eisa_reg_print (device_t, char *, char *, int *);
94 static struct irq_node * eisa_find_irq(struct eisa_device *e_dev, int rid);
95 static struct resvaddr * eisa_find_maddr(struct eisa_device *e_dev, int rid);
96 static struct resvaddr * eisa_find_ioaddr(struct eisa_device *e_dev, int rid);
97
98 static int
99 mainboard_probe(device_t dev)
100 {
101 char *idstring;
102 eisa_id_t id = eisa_get_id(dev);
103
104 if (eisa_get_slot(dev) != 0)
105 return (ENXIO);
106
107 idstring = (char *)malloc(8 + sizeof(" (System Board)") + 1,
108 M_DEVBUF, M_NOWAIT);
109 if (idstring == NULL) {
110 panic("Eisa probe unable to malloc");
111 }
112 sprintf(idstring, "%c%c%c%03x%01x (System Board)",
113 EISA_MFCTR_CHAR0(id),
114 EISA_MFCTR_CHAR1(id),
115 EISA_MFCTR_CHAR2(id),
116 EISA_PRODUCT_ID(id),
117 EISA_REVISION_ID(id));
118 device_set_desc(dev, idstring);
119
120 return (0);
121 }
122
123 static int
124 mainboard_attach(device_t dev)
125 {
126 return (0);
127 }
128
129 static device_method_t mainboard_methods[] = {
130 /* Device interface */
131 DEVMETHOD(device_probe, mainboard_probe),
132 DEVMETHOD(device_attach, mainboard_attach),
133
134 { 0, 0 }
135 };
136
137 static driver_t mainboard_driver = {
138 "mainboard",
139 mainboard_methods,
140 1,
141 };
142
143 static devclass_t mainboard_devclass;
144
145 DRIVER_MODULE(mainboard, eisa, mainboard_driver, mainboard_devclass, 0, 0);
146
147 /*
148 ** probe for EISA devices
149 */
150 static int
151 eisa_probe(device_t dev)
152 {
153 int i,slot;
154 struct eisa_device *e_dev;
155 device_t child;
156 int eisaBase = 0xc80;
157 eisa_id_t eisa_id;
158 int devices_found = 0;
159
160 device_set_desc(dev, "EISA bus");
161
162 for (slot = 0; slot < num_eisa_slots; eisaBase+=0x1000, slot++) {
163 int id_size = sizeof(eisa_id);
164 eisa_id = 0;
165 for( i = 0; i < id_size; i++ ) {
166 outb(eisaBase,0x80 + i); /*Some cards require priming*/
167 eisa_id |= inb(eisaBase+i) << ((id_size-i-1)*CHAR_BIT);
168 }
169 if (eisa_id & 0x80000000)
170 continue; /* no EISA card in slot */
171
172 devices_found++;
173
174 /* Prepare an eisa_device_node for this slot */
175 e_dev = (struct eisa_device *)malloc(sizeof(*e_dev),
176 M_DEVBUF, M_NOWAIT|M_ZERO);
177 if (!e_dev) {
178 device_printf(dev, "cannot malloc eisa_device");
179 break; /* Try to attach what we have already */
180 }
181
182 e_dev->id = eisa_id;
183
184 e_dev->ioconf.slot = slot;
185
186 /* Initialize our lists of reserved addresses */
187 LIST_INIT(&(e_dev->ioconf.ioaddrs));
188 LIST_INIT(&(e_dev->ioconf.maddrs));
189 TAILQ_INIT(&(e_dev->ioconf.irqs));
190
191 child = device_add_child(dev, NULL, -1);
192 device_set_ivars(child, e_dev);
193 }
194
195 /*
196 * EISA busses themselves are not easily detectable, the easiest way
197 * to tell if there is an eisa bus is if we found something - there
198 * should be a motherboard "card" there somewhere.
199 */
200 return devices_found ? 0 : ENXIO;
201 }
202
203 static void
204 eisa_probe_nomatch(device_t dev, device_t child)
205 {
206 u_int32_t eisa_id = eisa_get_id(child);
207 u_int8_t slot = eisa_get_slot(child);
208
209 device_printf(dev, "unknown card %c%c%c%03x%01x (0x%08x) at slot %d\n",
210 EISA_MFCTR_CHAR0(eisa_id),
211 EISA_MFCTR_CHAR1(eisa_id),
212 EISA_MFCTR_CHAR2(eisa_id),
213 EISA_PRODUCT_ID(eisa_id),
214 EISA_REVISION_ID(eisa_id),
215 eisa_id,
216 slot);
217
218 return;
219 }
220
221 static void
222 eisa_reg_print (dev, string, separator, column)
223 device_t dev;
224 char * string;
225 char * separator;
226 int * column;
227 {
228 int length = strlen(string);
229
230 length += (separator ? 2 : 1);
231
232 if (((*column) + length) >= MAX_COL) {
233 printf("\n");
234 (*column) = 0;
235 } else if ((*column) != 0) {
236 if (separator) {
237 printf("%c", *separator);
238 (*column)++;
239 }
240 printf(" ");
241 (*column)++;
242 }
243
244 if ((*column) == 0) {
245 (*column) += device_printf(dev, "%s", string);
246 } else {
247 (*column) += printf("%s", string);
248 }
249
250 return;
251 }
252
253 static int
254 eisa_print_child(device_t dev, device_t child)
255 {
256 char buf[81];
257 struct eisa_device * e_dev = device_get_ivars(child);
258 int rid;
259 struct irq_node * irq;
260 struct resvaddr * resv;
261 char separator = ',';
262 int column = 0;
263 int retval = 0;
264
265 if (device_get_desc(child)) {
266 snprintf(buf, sizeof(buf), "<%s>", device_get_desc(child));
267 eisa_reg_print(child, buf, NULL, &column);
268 }
269
270 rid = 0;
271 while ((resv = eisa_find_ioaddr(e_dev, rid++))) {
272 if ((resv->size == 1) ||
273 (resv->flags & RESVADDR_BITMASK)) {
274 snprintf(buf, sizeof(buf), "%s%lx",
275 ((rid == 1) ? "at 0x" : "0x"),
276 resv->addr);
277 } else {
278 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
279 ((rid == 1) ? "at 0x" : "0x"),
280 resv->addr,
281 (resv->addr + (resv->size - 1)));
282 }
283 eisa_reg_print(child, buf,
284 ((rid == 2) ? &separator : NULL), &column);
285 }
286
287 rid = 0;
288 while ((resv = eisa_find_maddr(e_dev, rid++))) {
289 if ((resv->size == 1) ||
290 (resv->flags & RESVADDR_BITMASK)) {
291 snprintf(buf, sizeof(buf), "%s%lx",
292 ((rid == 1) ? "at 0x" : "0x"),
293 resv->addr);
294 } else {
295 snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
296 ((rid == 1) ? "at 0x" : "0x"),
297 resv->addr,
298 (resv->addr + (resv->size - 1)));
299 }
300 eisa_reg_print(child, buf,
301 ((rid == 2) ? &separator : NULL), &column);
302 }
303
304 rid = 0;
305 while ((irq = eisa_find_irq(e_dev, rid++)) != NULL) {
306 snprintf(buf, sizeof(buf), "irq %d (%s)", irq->irq_no,
307 (irq->irq_trigger ? "level" : "edge"));
308 eisa_reg_print(child, buf,
309 ((rid == 1) ? &separator : NULL), &column);
310 }
311
312 snprintf(buf, sizeof(buf), "on %s slot %d\n",
313 device_get_nameunit(dev), eisa_get_slot(child));
314 eisa_reg_print(child, buf, NULL, &column);
315
316 return (retval);
317 }
318
319 static struct irq_node *
320 eisa_find_irq(struct eisa_device *e_dev, int rid)
321 {
322 int i;
323 struct irq_node *irq;
324
325 for (i = 0, irq = TAILQ_FIRST(&e_dev->ioconf.irqs);
326 i < rid && irq;
327 i++, irq = TAILQ_NEXT(irq, links))
328 ;
329
330 if (irq)
331 return (irq);
332 else
333 return (NULL);
334 }
335
336 static struct resvaddr *
337 eisa_find_maddr(struct eisa_device *e_dev, int rid)
338 {
339 int i;
340 struct resvaddr *resv;
341
342 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.maddrs);
343 i < rid && resv;
344 i++, resv = LIST_NEXT(resv, links))
345 ;
346
347 return resv;
348 }
349
350 static struct resvaddr *
351 eisa_find_ioaddr(struct eisa_device *e_dev, int rid)
352 {
353 int i;
354 struct resvaddr *resv;
355
356 for (i = 0, resv = LIST_FIRST(&e_dev->ioconf.ioaddrs);
357 i < rid && resv;
358 i++, resv = LIST_NEXT(resv, links))
359 ;
360
361 return resv;
362 }
363
364 static int
365 eisa_read_ivar(device_t dev, device_t child, int which, u_long *result)
366 {
367 struct eisa_device *e_dev = device_get_ivars(child);
368 struct irq_node *irq;
369
370 switch (which) {
371 case EISA_IVAR_SLOT:
372 *result = e_dev->ioconf.slot;
373 break;
374
375 case EISA_IVAR_ID:
376 *result = e_dev->id;
377 break;
378
379 case EISA_IVAR_IRQ:
380 /* XXX only first irq */
381 if ((irq = eisa_find_irq(e_dev, 0)) != NULL) {
382 *result = irq->irq_no;
383 } else {
384 *result = -1;
385 }
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 0;
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 }
426 break;
427
428 case SYS_RES_MEMORY:
429 if (isdefault) {
430 struct resvaddr *resv;
431
432 resv = eisa_find_maddr(e_dev, *rid);
433 if (!resv)
434 return 0;
435
436 start = resv->addr;
437 end = resv->addr + (resv->size - 1);
438 count = resv->size;
439 rvp = &resv->res;
440 }
441 break;
442
443 case SYS_RES_IOPORT:
444 if (isdefault) {
445 struct resvaddr *resv;
446
447 resv = eisa_find_ioaddr(e_dev, *rid);
448 if (!resv)
449 return 0;
450
451 start = resv->addr;
452 end = resv->addr + (resv->size - 1);
453 count = resv->size;
454 rvp = &resv->res;
455 }
456 break;
457
458 default:
459 return 0;
460 }
461
462 rv = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
463 type, rid, start, end, count, flags);
464 if (rvp)
465 *rvp = rv;
466
467 return rv;
468 }
469
470 static int
471 eisa_release_resource(device_t dev, device_t child, int type, int rid,
472 struct resource *r)
473 {
474 int rv;
475 struct eisa_device *e_dev = device_get_ivars(child);
476 struct resvaddr *resv = 0;
477
478 switch (type) {
479 case SYS_RES_IRQ:
480 if (eisa_find_irq(e_dev, rid) == NULL)
481 return EINVAL;
482 break;
483
484 case SYS_RES_MEMORY:
485 if (device_get_parent(child) == dev)
486 resv = eisa_find_maddr(e_dev, rid);
487 break;
488
489
490 case SYS_RES_IOPORT:
491 if (device_get_parent(child) == dev)
492 resv = eisa_find_ioaddr(e_dev, rid);
493 break;
494
495 default:
496 return (ENOENT);
497 }
498
499 rv = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, type, rid, r);
500
501 if (rv == 0) {
502 if (resv)
503 resv->res = 0;
504 }
505
506 return rv;
507 }
508
509 int
510 eisa_add_intr(device_t dev, int irq, int trigger)
511 {
512 struct eisa_device *e_dev = device_get_ivars(dev);
513 struct irq_node *irq_info;
514
515 irq_info = (struct irq_node *)malloc(sizeof(*irq_info), M_DEVBUF,
516 M_NOWAIT);
517 if (irq_info == NULL)
518 return (1);
519
520 irq_info->irq_no = irq;
521 irq_info->irq_trigger = trigger;
522 irq_info->idesc = NULL;
523 TAILQ_INSERT_TAIL(&e_dev->ioconf.irqs, irq_info, links);
524 return 0;
525 }
526
527 static int
528 eisa_add_resvaddr(struct eisa_device *e_dev, struct resvlist *head, u_long base,
529 u_long size, int flags)
530 {
531 resvaddr_t *reservation;
532
533 reservation = (resvaddr_t *)malloc(sizeof(resvaddr_t),
534 M_DEVBUF, M_NOWAIT);
535 if(!reservation)
536 return (ENOMEM);
537
538 reservation->addr = base;
539 reservation->size = size;
540 reservation->flags = flags;
541
542 if (!LIST_FIRST(head)) {
543 LIST_INSERT_HEAD(head, reservation, links);
544 }
545 else {
546 resvaddr_t *node;
547 LIST_FOREACH(node, head, links) {
548 if (node->addr > reservation->addr) {
549 /*
550 * List is sorted in increasing
551 * address order.
552 */
553 LIST_INSERT_BEFORE(node, reservation, links);
554 break;
555 }
556
557 if (node->addr == reservation->addr) {
558 /*
559 * If the entry we want to add
560 * matches any already in here,
561 * fail.
562 */
563 free(reservation, M_DEVBUF);
564 return (EEXIST);
565 }
566
567 if (!LIST_NEXT(node, links)) {
568 LIST_INSERT_AFTER(node, reservation, links);
569 break;
570 }
571 }
572 }
573 return (0);
574 }
575
576 int
577 eisa_add_mspace(device_t dev, u_long mbase, u_long msize, 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 int
586 eisa_add_iospace(device_t dev, u_long iobase, u_long iosize, int flags)
587 {
588 struct eisa_device *e_dev = device_get_ivars(dev);
589
590 return eisa_add_resvaddr(e_dev, &(e_dev->ioconf.ioaddrs), iobase,
591 iosize, flags);
592 }
593
594 static device_method_t eisa_methods[] = {
595 /* Device interface */
596 DEVMETHOD(device_probe, eisa_probe),
597 DEVMETHOD(device_attach, bus_generic_attach),
598 DEVMETHOD(device_shutdown, bus_generic_shutdown),
599 DEVMETHOD(device_suspend, bus_generic_suspend),
600 DEVMETHOD(device_resume, bus_generic_resume),
601
602 /* Bus interface */
603 DEVMETHOD(bus_print_child, eisa_print_child),
604 DEVMETHOD(bus_probe_nomatch, eisa_probe_nomatch),
605 DEVMETHOD(bus_read_ivar, eisa_read_ivar),
606 DEVMETHOD(bus_write_ivar, eisa_write_ivar),
607 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
608 DEVMETHOD(bus_alloc_resource, eisa_alloc_resource),
609 DEVMETHOD(bus_release_resource, eisa_release_resource),
610 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
611 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
612 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
613 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
614
615 { 0, 0 }
616 };
617
618 static driver_t eisa_driver = {
619 "eisa",
620 eisa_methods,
621 1, /* no softc */
622 };
623
624 DRIVER_MODULE(eisa, eisab, eisa_driver, eisa_devclass, 0, 0);
625 DRIVER_MODULE(eisa, legacy, eisa_driver, eisa_devclass, 0, 0);
Cache object: 1b531a952aa62a0ea4b129f1612b52ba
|