xref: /dflybsd-src/sys/kern/subr_bus.c (revision ece77bbaa23bf75f3b7bb9d110e2a795e3112878)
1 /*
2  * Copyright (c) 1997,1998 Doug Rabson
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/kern/subr_bus.c,v 1.54.2.9 2002/10/10 15:13:32 jhb Exp $
27  * $DragonFly: src/sys/kern/subr_bus.c,v 1.11 2004/02/16 18:48:03 joerg Exp $
28  */
29 
30 #include "opt_bus.h"
31 
32 #include <sys/param.h>
33 #include <sys/queue.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #ifdef DEVICE_SYSCTLS
38 #include <sys/sysctl.h>
39 #endif
40 #include <sys/kobj.h>
41 #include <sys/bus_private.h>
42 #include <sys/systm.h>
43 #include <machine/bus.h>
44 #include <sys/rman.h>
45 #include <machine/stdarg.h>	/* for device_printf() */
46 
47 MALLOC_DEFINE(M_BUS, "bus", "Bus data structures");
48 
49 #ifdef BUS_DEBUG
50 #define PDEBUG(a)	(printf(__FUNCTION__ ":%d: ", __LINE__), printf a, printf("\n"))
51 #define DEVICENAME(d)	((d)? device_get_name(d): "no device")
52 #define DRIVERNAME(d)	((d)? d->name : "no driver")
53 #define DEVCLANAME(d)	((d)? d->name : "no devclass")
54 
55 /* Produce the indenting, indent*2 spaces plus a '.' ahead of that to
56  * prevent syslog from deleting initial spaces
57  */
58 #define indentprintf(p)	do { int iJ; printf("."); for (iJ=0; iJ<indent; iJ++) printf("  "); printf p ; } while(0)
59 
60 static void print_device_short(device_t dev, int indent);
61 static void print_device(device_t dev, int indent);
62 void print_device_tree_short(device_t dev, int indent);
63 void print_device_tree(device_t dev, int indent);
64 static void print_driver_short(driver_t *driver, int indent);
65 static void print_driver(driver_t *driver, int indent);
66 static void print_driver_list(driver_list_t drivers, int indent);
67 static void print_devclass_short(devclass_t dc, int indent);
68 static void print_devclass(devclass_t dc, int indent);
69 void print_devclass_list_short(void);
70 void print_devclass_list(void);
71 
72 #else
73 /* Make the compiler ignore the function calls */
74 #define PDEBUG(a)			/* nop */
75 #define DEVICENAME(d)			/* nop */
76 #define DRIVERNAME(d)			/* nop */
77 #define DEVCLANAME(d)			/* nop */
78 
79 #define print_device_short(d,i)		/* nop */
80 #define print_device(d,i)		/* nop */
81 #define print_device_tree_short(d,i)	/* nop */
82 #define print_device_tree(d,i)		/* nop */
83 #define print_driver_short(d,i)		/* nop */
84 #define print_driver(d,i)		/* nop */
85 #define print_driver_list(d,i)		/* nop */
86 #define print_devclass_short(d,i)	/* nop */
87 #define print_devclass(d,i)		/* nop */
88 #define print_devclass_list_short()	/* nop */
89 #define print_devclass_list()		/* nop */
90 #endif
91 
92 #ifdef DEVICE_SYSCTLS
93 static void device_register_oids(device_t dev);
94 static void device_unregister_oids(device_t dev);
95 #endif
96 
97 kobj_method_t null_methods[] = {
98     { 0, 0 }
99 };
100 
101 DEFINE_CLASS(null, null_methods, 0);
102 
103 /*
104  * Devclass implementation
105  */
106 
107 static devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses);
108 
109 static devclass_t
110 devclass_find_internal(const char *classname, int create)
111 {
112     devclass_t dc;
113 
114     PDEBUG(("looking for %s", classname));
115     if (!classname)
116 	return NULL;
117 
118     TAILQ_FOREACH(dc, &devclasses, link) {
119 	if (!strcmp(dc->name, classname))
120 	    return dc;
121     }
122 
123     PDEBUG(("%s not found%s", classname, (create? ", creating": "")));
124     if (create) {
125 	dc = malloc(sizeof(struct devclass) + strlen(classname) + 1,
126 		    M_BUS, M_NOWAIT | M_ZERO);
127 	if (!dc)
128 	    return NULL;
129 	dc->name = (char*) (dc + 1);
130 	strcpy(dc->name, classname);
131 	dc->devices = NULL;
132 	dc->maxunit = 0;
133 	TAILQ_INIT(&dc->drivers);
134 	TAILQ_INSERT_TAIL(&devclasses, dc, link);
135     }
136 
137     return dc;
138 }
139 
140 devclass_t
141 devclass_create(const char *classname)
142 {
143     return devclass_find_internal(classname, TRUE);
144 }
145 
146 devclass_t
147 devclass_find(const char *classname)
148 {
149     return devclass_find_internal(classname, FALSE);
150 }
151 
152 int
153 devclass_add_driver(devclass_t dc, driver_t *driver)
154 {
155     driverlink_t dl;
156     int i;
157 
158     PDEBUG(("%s", DRIVERNAME(driver)));
159 
160     dl = malloc(sizeof *dl, M_BUS, M_NOWAIT | M_ZERO);
161     if (!dl)
162 	return ENOMEM;
163 
164     /*
165      * Compile the driver's methods. Also increase the reference count
166      * so that the class doesn't get freed when the last instance
167      * goes. This means we can safely use static methods and avoids a
168      * double-free in devclass_delete_driver.
169      */
170     kobj_class_compile((kobj_class_t) driver);
171 
172     /*
173      * Make sure the devclass which the driver is implementing exists.
174      */
175     devclass_find_internal(driver->name, TRUE);
176 
177     dl->driver = driver;
178     TAILQ_INSERT_TAIL(&dc->drivers, dl, link);
179     driver->refs++;
180 
181     /*
182      * Call BUS_DRIVER_ADDED for any existing busses in this class.
183      */
184     for (i = 0; i < dc->maxunit; i++)
185 	if (dc->devices[i])
186 	    BUS_DRIVER_ADDED(dc->devices[i], driver);
187 
188     return 0;
189 }
190 
191 int
192 devclass_delete_driver(devclass_t busclass, driver_t *driver)
193 {
194     devclass_t dc = devclass_find(driver->name);
195     driverlink_t dl;
196     device_t dev;
197     int i;
198     int error;
199 
200     PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
201 
202     if (!dc)
203 	return 0;
204 
205     /*
206      * Find the link structure in the bus' list of drivers.
207      */
208     TAILQ_FOREACH(dl, &busclass->drivers, link) {
209 	if (dl->driver == driver)
210 	    break;
211     }
212 
213     if (!dl) {
214 	PDEBUG(("%s not found in %s list", driver->name, busclass->name));
215 	return ENOENT;
216     }
217 
218     /*
219      * Disassociate from any devices.  We iterate through all the
220      * devices in the devclass of the driver and detach any which are
221      * using the driver and which have a parent in the devclass which
222      * we are deleting from.
223      *
224      * Note that since a driver can be in multiple devclasses, we
225      * should not detach devices which are not children of devices in
226      * the affected devclass.
227      */
228     for (i = 0; i < dc->maxunit; i++) {
229 	if (dc->devices[i]) {
230 	    dev = dc->devices[i];
231 	    if (dev->driver == driver
232 		&& dev->parent && dev->parent->devclass == busclass) {
233 		if ((error = device_detach(dev)) != 0)
234 		    return error;
235 		device_set_driver(dev, NULL);
236 	    }
237 	}
238     }
239 
240     TAILQ_REMOVE(&busclass->drivers, dl, link);
241     free(dl, M_BUS);
242 
243     driver->refs--;
244     if (driver->refs == 0)
245 	kobj_class_free((kobj_class_t) driver);
246 
247     return 0;
248 }
249 
250 static driverlink_t
251 devclass_find_driver_internal(devclass_t dc, const char *classname)
252 {
253     driverlink_t dl;
254 
255     PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc)));
256 
257     TAILQ_FOREACH(dl, &dc->drivers, link) {
258 	if (!strcmp(dl->driver->name, classname))
259 	    return dl;
260     }
261 
262     PDEBUG(("not found"));
263     return NULL;
264 }
265 
266 driver_t *
267 devclass_find_driver(devclass_t dc, const char *classname)
268 {
269     driverlink_t dl;
270 
271     dl = devclass_find_driver_internal(dc, classname);
272     if (dl)
273 	return dl->driver;
274     else
275 	return NULL;
276 }
277 
278 const char *
279 devclass_get_name(devclass_t dc)
280 {
281     return dc->name;
282 }
283 
284 device_t
285 devclass_get_device(devclass_t dc, int unit)
286 {
287     if (dc == NULL || unit < 0 || unit >= dc->maxunit)
288 	return NULL;
289     return dc->devices[unit];
290 }
291 
292 void *
293 devclass_get_softc(devclass_t dc, int unit)
294 {
295     device_t dev;
296 
297     dev = devclass_get_device(dc, unit);
298     if (!dev)
299 	return (NULL);
300 
301     return (device_get_softc(dev));
302 }
303 
304 int
305 devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp)
306 {
307     int i;
308     int count;
309     device_t *list;
310 
311     count = 0;
312     for (i = 0; i < dc->maxunit; i++)
313 	if (dc->devices[i])
314 	    count++;
315 
316     list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT | M_ZERO);
317     if (!list)
318 	return ENOMEM;
319 
320     count = 0;
321     for (i = 0; i < dc->maxunit; i++)
322 	if (dc->devices[i]) {
323 	    list[count] = dc->devices[i];
324 	    count++;
325 	}
326 
327     *devlistp = list;
328     *devcountp = count;
329 
330     return 0;
331 }
332 
333 int
334 devclass_get_maxunit(devclass_t dc)
335 {
336     return dc->maxunit;
337 }
338 
339 static int
340 devclass_alloc_unit(devclass_t dc, int *unitp)
341 {
342     int unit = *unitp;
343 
344     PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc)));
345 
346     /* If we have been given a wired unit number, check for existing device */
347     if (unit != -1) {
348 	if (unit >= 0 && unit < dc->maxunit && dc->devices[unit] != NULL) {
349 	    if (bootverbose)
350 		printf("%s-: %s%d exists, using next available unit number\n",
351 		       dc->name, dc->name, unit);
352 	    /* find the next available slot */
353 	    while (++unit < dc->maxunit && dc->devices[unit] != NULL)
354 		;
355 	}
356     }
357     else {
358 	/* Unwired device, find the next available slot for it */
359     	unit = 0;
360 	while (unit < dc->maxunit && dc->devices[unit] != NULL)
361 	    unit++;
362     }
363 
364     /*
365      * We've selected a unit beyond the length of the table, so let's extend
366      * the table to make room for all units up to and including this one.
367      */
368     if (unit >= dc->maxunit) {
369 	device_t *newlist;
370 	int newsize;
371 
372 	newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t));
373 	newlist = malloc(sizeof(device_t) * newsize, M_BUS, M_NOWAIT | M_ZERO);
374 	if (!newlist)
375 	    return ENOMEM;
376 	bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit);
377 	if (dc->devices)
378 	    free(dc->devices, M_BUS);
379 	dc->devices = newlist;
380 	dc->maxunit = newsize;
381     }
382     PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc)));
383 
384     *unitp = unit;
385     return 0;
386 }
387 
388 static int
389 devclass_add_device(devclass_t dc, device_t dev)
390 {
391     int buflen, error;
392 
393     PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
394 
395     buflen = strlen(dc->name) + 5;
396     dev->nameunit = malloc(buflen, M_BUS, M_NOWAIT | M_ZERO);
397     if (!dev->nameunit)
398 	return ENOMEM;
399 
400     if ((error = devclass_alloc_unit(dc, &dev->unit)) != 0) {
401 	free(dev->nameunit, M_BUS);
402 	dev->nameunit = NULL;
403 	return error;
404     }
405     dc->devices[dev->unit] = dev;
406     dev->devclass = dc;
407     snprintf(dev->nameunit, buflen, "%s%d", dc->name, dev->unit);
408 
409 #ifdef DEVICE_SYSCTLS
410     device_register_oids(dev);
411 #endif
412 
413     return 0;
414 }
415 
416 static int
417 devclass_delete_device(devclass_t dc, device_t dev)
418 {
419     if (!dc || !dev)
420 	return 0;
421 
422     PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
423 
424     if (dev->devclass != dc
425 	|| dc->devices[dev->unit] != dev)
426 	panic("devclass_delete_device: inconsistent device class");
427     dc->devices[dev->unit] = NULL;
428     if (dev->flags & DF_WILDCARD)
429 	dev->unit = -1;
430     dev->devclass = NULL;
431     free(dev->nameunit, M_BUS);
432     dev->nameunit = NULL;
433 
434 #ifdef DEVICE_SYSCTLS
435     device_unregister_oids(dev);
436 #endif
437 
438     return 0;
439 }
440 
441 static device_t
442 make_device(device_t parent, const char *name, int unit)
443 {
444     device_t dev;
445     devclass_t dc;
446 
447     PDEBUG(("%s at %s as unit %d", name, DEVICENAME(parent), unit));
448 
449     if (name) {
450 	dc = devclass_find_internal(name, TRUE);
451 	if (!dc) {
452 	    printf("make_device: can't find device class %s\n", name);
453 	    return NULL;
454 	}
455     } else
456 	dc = NULL;
457 
458     dev = malloc(sizeof(struct device), M_BUS, M_NOWAIT | M_ZERO);
459     if (!dev)
460 	return 0;
461 
462     dev->parent = parent;
463     TAILQ_INIT(&dev->children);
464     kobj_init((kobj_t) dev, &null_class);
465     dev->driver = NULL;
466     dev->devclass = NULL;
467     dev->unit = unit;
468     dev->nameunit = NULL;
469     dev->desc = NULL;
470     dev->busy = 0;
471     dev->devflags = 0;
472     dev->flags = DF_ENABLED;
473     dev->order = 0;
474     if (unit == -1)
475 	dev->flags |= DF_WILDCARD;
476     if (name) {
477 	dev->flags |= DF_FIXEDCLASS;
478 	if (devclass_add_device(dc, dev) != 0) {
479 	    kobj_delete((kobj_t)dev, M_BUS);
480 	    return(NULL);
481 	}
482     }
483     dev->ivars = NULL;
484     dev->softc = NULL;
485 
486     dev->state = DS_NOTPRESENT;
487 
488     return dev;
489 }
490 
491 static int
492 device_print_child(device_t dev, device_t child)
493 {
494     int retval = 0;
495 
496     if (device_is_alive(child)) {
497 	retval += BUS_PRINT_CHILD(dev, child);
498     } else
499 	retval += device_printf(child, " not found\n");
500 
501     return (retval);
502 }
503 
504 device_t
505 device_add_child(device_t dev, const char *name, int unit)
506 {
507     return device_add_child_ordered(dev, 0, name, unit);
508 }
509 
510 device_t
511 device_add_child_ordered(device_t dev, int order, const char *name, int unit)
512 {
513     device_t child;
514     device_t place;
515 
516     PDEBUG(("%s at %s with order %d as unit %d",
517 	    name, DEVICENAME(dev), order, unit));
518 
519     child = make_device(dev, name, unit);
520     if (child == NULL)
521 	return child;
522     child->order = order;
523 
524     TAILQ_FOREACH(place, &dev->children, link) {
525 	if (place->order > order)
526 	    break;
527     }
528 
529     if (place) {
530 	/*
531 	 * The device 'place' is the first device whose order is
532 	 * greater than the new child.
533 	 */
534 	TAILQ_INSERT_BEFORE(place, child, link);
535     } else {
536 	/*
537 	 * The new child's order is greater or equal to the order of
538 	 * any existing device. Add the child to the tail of the list.
539 	 */
540 	TAILQ_INSERT_TAIL(&dev->children, child, link);
541     }
542 
543     return child;
544 }
545 
546 int
547 device_delete_child(device_t dev, device_t child)
548 {
549     int error;
550     device_t grandchild;
551 
552     PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev)));
553 
554     /* remove children first */
555     while ( (grandchild = TAILQ_FIRST(&child->children)) ) {
556         error = device_delete_child(child, grandchild);
557 	if (error)
558 	    return error;
559     }
560 
561     if ((error = device_detach(child)) != 0)
562 	return error;
563     if (child->devclass)
564 	devclass_delete_device(child->devclass, child);
565     TAILQ_REMOVE(&dev->children, child, link);
566     device_set_desc(child, NULL);
567     kobj_delete((kobj_t)child, M_BUS);
568 
569     return 0;
570 }
571 
572 /*
573  * Find only devices attached to this bus.
574  */
575 device_t
576 device_find_child(device_t dev, const char *classname, int unit)
577 {
578     devclass_t dc;
579     device_t child;
580 
581     dc = devclass_find(classname);
582     if (!dc)
583 	return NULL;
584 
585     child = devclass_get_device(dc, unit);
586     if (child && child->parent == dev)
587 	return child;
588     return NULL;
589 }
590 
591 static driverlink_t
592 first_matching_driver(devclass_t dc, device_t dev)
593 {
594     if (dev->devclass)
595 	return devclass_find_driver_internal(dc, dev->devclass->name);
596     else
597 	return TAILQ_FIRST(&dc->drivers);
598 }
599 
600 static driverlink_t
601 next_matching_driver(devclass_t dc, device_t dev, driverlink_t last)
602 {
603     if (dev->devclass) {
604 	driverlink_t dl;
605 	for (dl = TAILQ_NEXT(last, link); dl; dl = TAILQ_NEXT(dl, link)) {
606 	    if (!strcmp(dev->devclass->name, dl->driver->name))
607 		return dl;
608 	}
609 	return NULL;
610     } else
611 	return TAILQ_NEXT(last, link);
612 }
613 
614 static int
615 device_probe_child(device_t dev, device_t child)
616 {
617     devclass_t dc;
618     driverlink_t best = 0;
619     driverlink_t dl;
620     int result, pri = 0;
621     int hasclass = (child->devclass != 0);
622 
623     dc = dev->devclass;
624     if (!dc)
625 	panic("device_probe_child: parent device has no devclass");
626 
627     if (child->state == DS_ALIVE)
628 	return 0;
629 
630     for (dl = first_matching_driver(dc, child);
631 	 dl;
632 	 dl = next_matching_driver(dc, child, dl)) {
633 	PDEBUG(("Trying %s", DRIVERNAME(dl->driver)));
634 	device_set_driver(child, dl->driver);
635 	if (!hasclass)
636 	    device_set_devclass(child, dl->driver->name);
637 	result = DEVICE_PROBE(child);
638 	if (!hasclass)
639 	    device_set_devclass(child, 0);
640 
641 	/*
642 	 * If the driver returns SUCCESS, there can be no higher match
643 	 * for this device.
644 	 */
645 	if (result == 0) {
646 	    best = dl;
647 	    pri = 0;
648 	    break;
649 	}
650 
651 	/*
652 	 * The driver returned an error so it certainly doesn't match.
653 	 */
654 	if (result > 0) {
655 	    device_set_driver(child, 0);
656 	    continue;
657 	}
658 
659 	/*
660 	 * A priority lower than SUCCESS, remember the best matching
661 	 * driver. Initialise the value of pri for the first match.
662 	 */
663 	if (best == 0 || result > pri) {
664 	    best = dl;
665 	    pri = result;
666 	    continue;
667 	}
668     }
669 
670     /*
671      * If we found a driver, change state and initialise the devclass.
672      */
673     if (best) {
674 	if (!child->devclass)
675 	    device_set_devclass(child, best->driver->name);
676 	device_set_driver(child, best->driver);
677 	if (pri < 0) {
678 	    /*
679 	     * A bit bogus. Call the probe method again to make sure
680 	     * that we have the right description.
681 	     */
682 	    DEVICE_PROBE(child);
683 	}
684 	child->state = DS_ALIVE;
685 	return 0;
686     }
687 
688     return ENXIO;
689 }
690 
691 device_t
692 device_get_parent(device_t dev)
693 {
694     return dev->parent;
695 }
696 
697 int
698 device_get_children(device_t dev, device_t **devlistp, int *devcountp)
699 {
700     int count;
701     device_t child;
702     device_t *list;
703 
704     count = 0;
705     TAILQ_FOREACH(child, &dev->children, link) {
706 	count++;
707     }
708 
709     list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT | M_ZERO);
710     if (!list)
711 	return ENOMEM;
712 
713     count = 0;
714     TAILQ_FOREACH(child, &dev->children, link) {
715 	list[count] = child;
716 	count++;
717     }
718 
719     *devlistp = list;
720     *devcountp = count;
721 
722     return 0;
723 }
724 
725 driver_t *
726 device_get_driver(device_t dev)
727 {
728     return dev->driver;
729 }
730 
731 devclass_t
732 device_get_devclass(device_t dev)
733 {
734     return dev->devclass;
735 }
736 
737 const char *
738 device_get_name(device_t dev)
739 {
740     if (dev->devclass)
741 	return devclass_get_name(dev->devclass);
742     return NULL;
743 }
744 
745 const char *
746 device_get_nameunit(device_t dev)
747 {
748     return dev->nameunit;
749 }
750 
751 int
752 device_get_unit(device_t dev)
753 {
754     return dev->unit;
755 }
756 
757 const char *
758 device_get_desc(device_t dev)
759 {
760     return dev->desc;
761 }
762 
763 u_int32_t
764 device_get_flags(device_t dev)
765 {
766     return dev->devflags;
767 }
768 
769 int
770 device_print_prettyname(device_t dev)
771 {
772     const char *name = device_get_name(dev);
773 
774     if (name == 0)
775 	return printf("unknown: ");
776     else
777 	return printf("%s%d: ", name, device_get_unit(dev));
778 }
779 
780 int
781 device_printf(device_t dev, const char * fmt, ...)
782 {
783     __va_list ap;
784     int retval;
785 
786     retval = device_print_prettyname(dev);
787     __va_start(ap, fmt);
788     retval += vprintf(fmt, ap);
789     __va_end(ap);
790     return retval;
791 }
792 
793 static void
794 device_set_desc_internal(device_t dev, const char* desc, int copy)
795 {
796     if (dev->desc && (dev->flags & DF_DESCMALLOCED)) {
797 	free(dev->desc, M_BUS);
798 	dev->flags &= ~DF_DESCMALLOCED;
799 	dev->desc = NULL;
800     }
801 
802     if (copy && desc) {
803 	dev->desc = malloc(strlen(desc) + 1, M_BUS, M_NOWAIT);
804 	if (dev->desc) {
805 	    strcpy(dev->desc, desc);
806 	    dev->flags |= DF_DESCMALLOCED;
807 	}
808     } else
809 	/* Avoid a -Wcast-qual warning */
810 	dev->desc = (char *)(uintptr_t) desc;
811 
812 #ifdef DEVICE_SYSCTLS
813     {
814 	struct sysctl_oid *oid = &dev->oid[1];
815 	oid->oid_arg1 = dev->desc ? dev->desc : "";
816 	oid->oid_arg2 = dev->desc ? strlen(dev->desc) : 0;
817     }
818 #endif
819 }
820 
821 void
822 device_set_desc(device_t dev, const char* desc)
823 {
824     device_set_desc_internal(dev, desc, FALSE);
825 }
826 
827 void
828 device_set_desc_copy(device_t dev, const char* desc)
829 {
830     device_set_desc_internal(dev, desc, TRUE);
831 }
832 
833 void
834 device_set_flags(device_t dev, u_int32_t flags)
835 {
836     dev->devflags = flags;
837 }
838 
839 void *
840 device_get_softc(device_t dev)
841 {
842     return dev->softc;
843 }
844 
845 void
846 device_set_softc(device_t dev, void *softc)
847 {
848     if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC))
849 	free(dev->softc, M_BUS);
850     dev->softc = softc;
851     if (dev->softc)
852         dev->flags |= DF_EXTERNALSOFTC;
853     else
854         dev->flags &= ~DF_EXTERNALSOFTC;
855 }
856 
857 void *
858 device_get_ivars(device_t dev)
859 {
860     return dev->ivars;
861 }
862 
863 void
864 device_set_ivars(device_t dev, void * ivars)
865 {
866     if (!dev)
867 	return;
868 
869     dev->ivars = ivars;
870 
871     return;
872 }
873 
874 device_state_t
875 device_get_state(device_t dev)
876 {
877     return dev->state;
878 }
879 
880 void
881 device_enable(device_t dev)
882 {
883     dev->flags |= DF_ENABLED;
884 }
885 
886 void
887 device_disable(device_t dev)
888 {
889     dev->flags &= ~DF_ENABLED;
890 }
891 
892 /*
893  * YYY cannot block
894  */
895 void
896 device_busy(device_t dev)
897 {
898     if (dev->state < DS_ATTACHED)
899 	panic("device_busy: called for unattached device");
900     if (dev->busy == 0 && dev->parent)
901 	device_busy(dev->parent);
902     dev->busy++;
903     dev->state = DS_BUSY;
904 }
905 
906 /*
907  * YYY cannot block
908  */
909 void
910 device_unbusy(device_t dev)
911 {
912     if (dev->state != DS_BUSY)
913 	panic("device_unbusy: called for non-busy device");
914     dev->busy--;
915     if (dev->busy == 0) {
916 	if (dev->parent)
917 	    device_unbusy(dev->parent);
918 	dev->state = DS_ATTACHED;
919     }
920 }
921 
922 void
923 device_quiet(device_t dev)
924 {
925     dev->flags |= DF_QUIET;
926 }
927 
928 void
929 device_verbose(device_t dev)
930 {
931     dev->flags &= ~DF_QUIET;
932 }
933 
934 int
935 device_is_quiet(device_t dev)
936 {
937     return (dev->flags & DF_QUIET) != 0;
938 }
939 
940 int
941 device_is_enabled(device_t dev)
942 {
943     return (dev->flags & DF_ENABLED) != 0;
944 }
945 
946 int
947 device_is_alive(device_t dev)
948 {
949     return dev->state >= DS_ALIVE;
950 }
951 
952 int
953 device_is_attached(device_t dev)
954 {
955 	return (dev->state >= DS_ATTACHED);
956 }
957 
958 int
959 device_set_devclass(device_t dev, const char *classname)
960 {
961     devclass_t dc;
962 
963     if (!classname) {
964 	if (dev->devclass)
965 	    devclass_delete_device(dev->devclass, dev);
966 	return 0;
967     }
968 
969     if (dev->devclass) {
970 	printf("device_set_devclass: device class already set\n");
971 	return EINVAL;
972     }
973 
974     dc = devclass_find_internal(classname, TRUE);
975     if (!dc)
976 	return ENOMEM;
977 
978     return devclass_add_device(dc, dev);
979 }
980 
981 int
982 device_set_driver(device_t dev, driver_t *driver)
983 {
984     if (dev->state >= DS_ATTACHED)
985 	return EBUSY;
986 
987     if (dev->driver == driver)
988 	return 0;
989 
990     if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) {
991 	free(dev->softc, M_BUS);
992 	dev->softc = NULL;
993     }
994     kobj_delete((kobj_t) dev, 0);
995     dev->driver = driver;
996     if (driver) {
997 	kobj_init((kobj_t) dev, (kobj_class_t) driver);
998 	if (!(dev->flags & DF_EXTERNALSOFTC)) {
999 	    dev->softc = malloc(driver->size, M_BUS, M_NOWAIT | M_ZERO);
1000 	    if (!dev->softc) {
1001 		kobj_delete((kobj_t)dev, 0);
1002 		kobj_init((kobj_t) dev, &null_class);
1003 		dev->driver = NULL;
1004 		return ENOMEM;
1005 	    }
1006 	}
1007     } else
1008 	kobj_init((kobj_t) dev, &null_class);
1009     return 0;
1010 }
1011 
1012 int
1013 device_probe_and_attach(device_t dev)
1014 {
1015     device_t bus = dev->parent;
1016     int error = 0;
1017     int hasclass = (dev->devclass != 0);
1018 
1019     if (dev->state >= DS_ALIVE)
1020 	return 0;
1021 
1022     if (dev->flags & DF_ENABLED) {
1023 	error = device_probe_child(bus, dev);
1024 	if (!error) {
1025 	    if (!device_is_quiet(dev))
1026 		device_print_child(bus, dev);
1027 	    error = DEVICE_ATTACH(dev);
1028 	    if (!error)
1029 		dev->state = DS_ATTACHED;
1030 	    else {
1031 		printf("device_probe_and_attach: %s%d attach returned %d\n",
1032 		       dev->driver->name, dev->unit, error);
1033 		/* Unset the class that was set in device_probe_child */
1034 		if (!hasclass)
1035 		    device_set_devclass(dev, 0);
1036 		device_set_driver(dev, NULL);
1037 		dev->state = DS_NOTPRESENT;
1038 	    }
1039 	} else {
1040 	    if (!(dev->flags & DF_DONENOMATCH)) {
1041 		BUS_PROBE_NOMATCH(bus, dev);
1042 		dev->flags |= DF_DONENOMATCH;
1043 	    }
1044 	}
1045     } else {
1046 	if (bootverbose) {
1047 	    device_print_prettyname(dev);
1048 	    printf("not probed (disabled)\n");
1049 	}
1050     }
1051 
1052     return error;
1053 }
1054 
1055 int
1056 device_detach(device_t dev)
1057 {
1058     int error;
1059 
1060     PDEBUG(("%s", DEVICENAME(dev)));
1061     if (dev->state == DS_BUSY)
1062 	return EBUSY;
1063     if (dev->state != DS_ATTACHED)
1064 	return 0;
1065 
1066     if ((error = DEVICE_DETACH(dev)) != 0)
1067 	return error;
1068     device_printf(dev, "detached\n");
1069     if (dev->parent)
1070 	BUS_CHILD_DETACHED(dev->parent, dev);
1071 
1072     if (!(dev->flags & DF_FIXEDCLASS))
1073 	devclass_delete_device(dev->devclass, dev);
1074 
1075     dev->state = DS_NOTPRESENT;
1076     device_set_driver(dev, NULL);
1077 
1078     return 0;
1079 }
1080 
1081 int
1082 device_shutdown(device_t dev)
1083 {
1084     if (dev->state < DS_ATTACHED)
1085 	return 0;
1086     return DEVICE_SHUTDOWN(dev);
1087 }
1088 
1089 int
1090 device_set_unit(device_t dev, int unit)
1091 {
1092     devclass_t dc;
1093     int err;
1094 
1095     dc = device_get_devclass(dev);
1096     if (unit < dc->maxunit && dc->devices[unit])
1097 	return EBUSY;
1098     err = devclass_delete_device(dc, dev);
1099     if (err)
1100 	return err;
1101     dev->unit = unit;
1102     err = devclass_add_device(dc, dev);
1103     if (err)
1104 	return err;
1105     return 0;
1106 }
1107 
1108 #ifdef DEVICE_SYSCTLS
1109 
1110 /*
1111  * Sysctl nodes for devices.
1112  */
1113 
1114 SYSCTL_NODE(_hw, OID_AUTO, devices, CTLFLAG_RW, 0, "A list of all devices");
1115 
1116 static int
1117 sysctl_handle_children(SYSCTL_HANDLER_ARGS)
1118 {
1119     device_t dev = arg1;
1120     device_t child;
1121     int first = 1, error = 0;
1122 
1123     TAILQ_FOREACH(child, &dev->children, link) {
1124 	if (child->nameunit) {
1125 	    if (!first) {
1126 		error = SYSCTL_OUT(req, ",", 1);
1127 		if (error) return error;
1128 	    } else {
1129 		first = 0;
1130 	    }
1131 	    error = SYSCTL_OUT(req, child->nameunit, strlen(child->nameunit));
1132 	    if (error) return error;
1133 	}
1134     }
1135 
1136     error = SYSCTL_OUT(req, "", 1);
1137 
1138     return error;
1139 }
1140 
1141 static int
1142 sysctl_handle_state(SYSCTL_HANDLER_ARGS)
1143 {
1144     device_t dev = arg1;
1145 
1146     switch (dev->state) {
1147     case DS_NOTPRESENT:
1148 	return SYSCTL_OUT(req, "notpresent", sizeof("notpresent"));
1149     case DS_ALIVE:
1150 	return SYSCTL_OUT(req, "alive", sizeof("alive"));
1151     case DS_ATTACHED:
1152 	return SYSCTL_OUT(req, "attached", sizeof("attached"));
1153     case DS_BUSY:
1154 	return SYSCTL_OUT(req, "busy", sizeof("busy"));
1155     }
1156 
1157     return 0;
1158 }
1159 
1160 static void
1161 device_register_oids(device_t dev)
1162 {
1163     struct sysctl_oid* oid;
1164 
1165     oid = &dev->oid[0];
1166     bzero(oid, sizeof(*oid));
1167     oid->oid_parent = &sysctl__hw_devices_children;
1168     oid->oid_number = OID_AUTO;
1169     oid->oid_kind = CTLTYPE_NODE | CTLFLAG_RW;
1170     oid->oid_arg1 = &dev->oidlist[0];
1171     oid->oid_arg2 = 0;
1172     oid->oid_name = dev->nameunit;
1173     oid->oid_handler = 0;
1174     oid->oid_fmt = "N";
1175     SLIST_INIT(&dev->oidlist[0]);
1176     sysctl_register_oid(oid);
1177 
1178     oid = &dev->oid[1];
1179     bzero(oid, sizeof(*oid));
1180     oid->oid_parent = &dev->oidlist[0];
1181     oid->oid_number = OID_AUTO;
1182     oid->oid_kind = CTLTYPE_STRING | CTLFLAG_RD;
1183     oid->oid_arg1 = dev->desc ? dev->desc : "";
1184     oid->oid_arg2 = dev->desc ? strlen(dev->desc) : 0;
1185     oid->oid_name = "desc";
1186     oid->oid_handler = sysctl_handle_string;
1187     oid->oid_fmt = "A";
1188     sysctl_register_oid(oid);
1189 
1190     oid = &dev->oid[2];
1191     bzero(oid, sizeof(*oid));
1192     oid->oid_parent = &dev->oidlist[0];
1193     oid->oid_number = OID_AUTO;
1194     oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD;
1195     oid->oid_arg1 = dev;
1196     oid->oid_arg2 = 0;
1197     oid->oid_name = "children";
1198     oid->oid_handler = sysctl_handle_children;
1199     oid->oid_fmt = "A";
1200     sysctl_register_oid(oid);
1201 
1202     oid = &dev->oid[3];
1203     bzero(oid, sizeof(*oid));
1204     oid->oid_parent = &dev->oidlist[0];
1205     oid->oid_number = OID_AUTO;
1206     oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD;
1207     oid->oid_arg1 = dev;
1208     oid->oid_arg2 = 0;
1209     oid->oid_name = "state";
1210     oid->oid_handler = sysctl_handle_state;
1211     oid->oid_fmt = "A";
1212     sysctl_register_oid(oid);
1213 }
1214 
1215 static void
1216 device_unregister_oids(device_t dev)
1217 {
1218     sysctl_unregister_oid(&dev->oid[0]);
1219     sysctl_unregister_oid(&dev->oid[1]);
1220     sysctl_unregister_oid(&dev->oid[2]);
1221 }
1222 
1223 #endif
1224 
1225 /*======================================*/
1226 /*
1227  * Access functions for device resources.
1228  */
1229 
1230 /* Supplied by config(8) in ioconf.c */
1231 extern struct config_device config_devtab[];
1232 extern int devtab_count;
1233 
1234 /* Runtime version */
1235 struct config_device *devtab = config_devtab;
1236 
1237 static int
1238 resource_new_name(const char *name, int unit)
1239 {
1240 	struct config_device *new;
1241 
1242 	new = malloc((devtab_count + 1) * sizeof(*new), M_TEMP,
1243 		     M_NOWAIT | M_ZERO);
1244 	if (new == NULL)
1245 		return -1;
1246 	if (devtab && devtab_count > 0)
1247 		bcopy(devtab, new, devtab_count * sizeof(*new));
1248 	new[devtab_count].name = malloc(strlen(name) + 1, M_TEMP, M_NOWAIT);
1249 	if (new[devtab_count].name == NULL) {
1250 		free(new, M_TEMP);
1251 		return -1;
1252 	}
1253 	strcpy(new[devtab_count].name, name);
1254 	new[devtab_count].unit = unit;
1255 	new[devtab_count].resource_count = 0;
1256 	new[devtab_count].resources = NULL;
1257 	devtab = new;
1258 	return devtab_count++;
1259 }
1260 
1261 static int
1262 resource_new_resname(int j, const char *resname, resource_type type)
1263 {
1264 	struct config_resource *new;
1265 	int i;
1266 
1267 	i = devtab[j].resource_count;
1268 	new = malloc((i + 1) * sizeof(*new), M_TEMP, M_NOWAIT | M_ZERO);
1269 	if (new == NULL)
1270 		return -1;
1271 	if (devtab[j].resources && i > 0)
1272 		bcopy(devtab[j].resources, new, i * sizeof(*new));
1273 	new[i].name = malloc(strlen(resname) + 1, M_TEMP, M_NOWAIT);
1274 	if (new[i].name == NULL) {
1275 		free(new, M_TEMP);
1276 		return -1;
1277 	}
1278 	strcpy(new[i].name, resname);
1279 	new[i].type = type;
1280 	if (devtab[j].resources)
1281 		free(devtab[j].resources, M_TEMP);
1282 	devtab[j].resources = new;
1283 	devtab[j].resource_count = i + 1;
1284 	return i;
1285 }
1286 
1287 static int
1288 resource_match_string(int i, const char *resname, const char *value)
1289 {
1290 	int j;
1291 	struct config_resource *res;
1292 
1293 	for (j = 0, res = devtab[i].resources;
1294 	     j < devtab[i].resource_count; j++, res++)
1295 		if (!strcmp(res->name, resname)
1296 		    && res->type == RES_STRING
1297 		    && !strcmp(res->u.stringval, value))
1298 			return j;
1299 	return -1;
1300 }
1301 
1302 static int
1303 resource_find(const char *name, int unit, const char *resname,
1304 	      struct config_resource **result)
1305 {
1306 	int i, j;
1307 	struct config_resource *res;
1308 
1309 	/*
1310 	 * First check specific instances, then generic.
1311 	 */
1312 	for (i = 0; i < devtab_count; i++) {
1313 		if (devtab[i].unit < 0)
1314 			continue;
1315 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1316 			res = devtab[i].resources;
1317 			for (j = 0; j < devtab[i].resource_count; j++, res++)
1318 				if (!strcmp(res->name, resname)) {
1319 					*result = res;
1320 					return 0;
1321 				}
1322 		}
1323 	}
1324 	for (i = 0; i < devtab_count; i++) {
1325 		if (devtab[i].unit >= 0)
1326 			continue;
1327 		/* XXX should this `&& devtab[i].unit == unit' be here? */
1328 		/* XXX if so, then the generic match does nothing */
1329 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1330 			res = devtab[i].resources;
1331 			for (j = 0; j < devtab[i].resource_count; j++, res++)
1332 				if (!strcmp(res->name, resname)) {
1333 					*result = res;
1334 					return 0;
1335 				}
1336 		}
1337 	}
1338 	return ENOENT;
1339 }
1340 
1341 int
1342 resource_int_value(const char *name, int unit, const char *resname, int *result)
1343 {
1344 	int error;
1345 	struct config_resource *res;
1346 
1347 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1348 		return error;
1349 	if (res->type != RES_INT)
1350 		return EFTYPE;
1351 	*result = res->u.intval;
1352 	return 0;
1353 }
1354 
1355 int
1356 resource_long_value(const char *name, int unit, const char *resname,
1357 		    long *result)
1358 {
1359 	int error;
1360 	struct config_resource *res;
1361 
1362 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1363 		return error;
1364 	if (res->type != RES_LONG)
1365 		return EFTYPE;
1366 	*result = res->u.longval;
1367 	return 0;
1368 }
1369 
1370 int
1371 resource_string_value(const char *name, int unit, const char *resname,
1372 		      char **result)
1373 {
1374 	int error;
1375 	struct config_resource *res;
1376 
1377 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1378 		return error;
1379 	if (res->type != RES_STRING)
1380 		return EFTYPE;
1381 	*result = res->u.stringval;
1382 	return 0;
1383 }
1384 
1385 int
1386 resource_query_string(int i, const char *resname, const char *value)
1387 {
1388 	if (i < 0)
1389 		i = 0;
1390 	else
1391 		i = i + 1;
1392 	for (; i < devtab_count; i++)
1393 		if (resource_match_string(i, resname, value) >= 0)
1394 			return i;
1395 	return -1;
1396 }
1397 
1398 int
1399 resource_locate(int i, const char *resname)
1400 {
1401 	if (i < 0)
1402 		i = 0;
1403 	else
1404 		i = i + 1;
1405 	for (; i < devtab_count; i++)
1406 		if (!strcmp(devtab[i].name, resname))
1407 			return i;
1408 	return -1;
1409 }
1410 
1411 int
1412 resource_count(void)
1413 {
1414 	return devtab_count;
1415 }
1416 
1417 char *
1418 resource_query_name(int i)
1419 {
1420 	return devtab[i].name;
1421 }
1422 
1423 int
1424 resource_query_unit(int i)
1425 {
1426 	return devtab[i].unit;
1427 }
1428 
1429 static int
1430 resource_create(const char *name, int unit, const char *resname,
1431 		resource_type type, struct config_resource **result)
1432 {
1433 	int i, j;
1434 	struct config_resource *res = NULL;
1435 
1436 	for (i = 0; i < devtab_count; i++) {
1437 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1438 			res = devtab[i].resources;
1439 			break;
1440 		}
1441 	}
1442 	if (res == NULL) {
1443 		i = resource_new_name(name, unit);
1444 		if (i < 0)
1445 			return ENOMEM;
1446 		res = devtab[i].resources;
1447 	}
1448 	for (j = 0; j < devtab[i].resource_count; j++, res++) {
1449 		if (!strcmp(res->name, resname)) {
1450 			*result = res;
1451 			return 0;
1452 		}
1453 	}
1454 	j = resource_new_resname(i, resname, type);
1455 	if (j < 0)
1456 		return ENOMEM;
1457 	res = &devtab[i].resources[j];
1458 	*result = res;
1459 	return 0;
1460 }
1461 
1462 int
1463 resource_set_int(const char *name, int unit, const char *resname, int value)
1464 {
1465 	int error;
1466 	struct config_resource *res;
1467 
1468 	error = resource_create(name, unit, resname, RES_INT, &res);
1469 	if (error)
1470 		return error;
1471 	if (res->type != RES_INT)
1472 		return EFTYPE;
1473 	res->u.intval = value;
1474 	return 0;
1475 }
1476 
1477 int
1478 resource_set_long(const char *name, int unit, const char *resname, long value)
1479 {
1480 	int error;
1481 	struct config_resource *res;
1482 
1483 	error = resource_create(name, unit, resname, RES_LONG, &res);
1484 	if (error)
1485 		return error;
1486 	if (res->type != RES_LONG)
1487 		return EFTYPE;
1488 	res->u.longval = value;
1489 	return 0;
1490 }
1491 
1492 int
1493 resource_set_string(const char *name, int unit, const char *resname,
1494 		    const char *value)
1495 {
1496 	int error;
1497 	struct config_resource *res;
1498 
1499 	error = resource_create(name, unit, resname, RES_STRING, &res);
1500 	if (error)
1501 		return error;
1502 	if (res->type != RES_STRING)
1503 		return EFTYPE;
1504 	if (res->u.stringval)
1505 		free(res->u.stringval, M_TEMP);
1506 	res->u.stringval = malloc(strlen(value) + 1, M_TEMP, M_NOWAIT);
1507 	if (res->u.stringval == NULL)
1508 		return ENOMEM;
1509 	strcpy(res->u.stringval, value);
1510 	return 0;
1511 }
1512 
1513 
1514 static void
1515 resource_cfgload(void *dummy __unused)
1516 {
1517 	struct config_resource *res, *cfgres;
1518 	int i, j;
1519 	int error;
1520 	char *name, *resname;
1521 	int unit;
1522 	resource_type type;
1523 	char *stringval;
1524 	int config_devtab_count;
1525 
1526 	config_devtab_count = devtab_count;
1527 	devtab = NULL;
1528 	devtab_count = 0;
1529 
1530 	for (i = 0; i < config_devtab_count; i++) {
1531 		name = config_devtab[i].name;
1532 		unit = config_devtab[i].unit;
1533 
1534 		for (j = 0; j < config_devtab[i].resource_count; j++) {
1535 			cfgres = config_devtab[i].resources;
1536 			resname = cfgres[j].name;
1537 			type = cfgres[j].type;
1538 			error = resource_create(name, unit, resname, type,
1539 						&res);
1540 			if (error) {
1541 				printf("create resource %s%d: error %d\n",
1542 					name, unit, error);
1543 				continue;
1544 			}
1545 			if (res->type != type) {
1546 				printf("type mismatch %s%d: %d != %d\n",
1547 					name, unit, res->type, type);
1548 				continue;
1549 			}
1550 			switch (type) {
1551 			case RES_INT:
1552 				res->u.intval = cfgres[j].u.intval;
1553 				break;
1554 			case RES_LONG:
1555 				res->u.longval = cfgres[j].u.longval;
1556 				break;
1557 			case RES_STRING:
1558 				if (res->u.stringval)
1559 					free(res->u.stringval, M_TEMP);
1560 				stringval = cfgres[j].u.stringval;
1561 				res->u.stringval = malloc(strlen(stringval) + 1,
1562 							  M_TEMP, M_NOWAIT);
1563 				if (res->u.stringval == NULL)
1564 					break;
1565 				strcpy(res->u.stringval, stringval);
1566 				break;
1567 			default:
1568 				panic("unknown resource type %d\n", type);
1569 			}
1570 		}
1571 	}
1572 }
1573 SYSINIT(cfgload, SI_SUB_KMEM, SI_ORDER_ANY + 50, resource_cfgload, 0)
1574 
1575 
1576 /*======================================*/
1577 /*
1578  * Some useful method implementations to make life easier for bus drivers.
1579  */
1580 
1581 void
1582 resource_list_init(struct resource_list *rl)
1583 {
1584 	SLIST_INIT(rl);
1585 }
1586 
1587 void
1588 resource_list_free(struct resource_list *rl)
1589 {
1590     struct resource_list_entry *rle;
1591 
1592     while ((rle = SLIST_FIRST(rl)) != NULL) {
1593 	if (rle->res)
1594 	    panic("resource_list_free: resource entry is busy");
1595 	SLIST_REMOVE_HEAD(rl, link);
1596 	free(rle, M_BUS);
1597     }
1598 }
1599 
1600 void
1601 resource_list_add(struct resource_list *rl,
1602 		  int type, int rid,
1603 		  u_long start, u_long end, u_long count)
1604 {
1605     struct resource_list_entry *rle;
1606 
1607     rle = resource_list_find(rl, type, rid);
1608     if (!rle) {
1609 	rle = malloc(sizeof(struct resource_list_entry), M_BUS, M_NOWAIT);
1610 	if (!rle)
1611 	    panic("resource_list_add: can't record entry");
1612 	SLIST_INSERT_HEAD(rl, rle, link);
1613 	rle->type = type;
1614 	rle->rid = rid;
1615 	rle->res = NULL;
1616     }
1617 
1618     if (rle->res)
1619 	panic("resource_list_add: resource entry is busy");
1620 
1621     rle->start = start;
1622     rle->end = end;
1623     rle->count = count;
1624 }
1625 
1626 struct resource_list_entry*
1627 resource_list_find(struct resource_list *rl,
1628 		   int type, int rid)
1629 {
1630     struct resource_list_entry *rle;
1631 
1632     SLIST_FOREACH(rle, rl, link)
1633 	if (rle->type == type && rle->rid == rid)
1634 	    return rle;
1635     return NULL;
1636 }
1637 
1638 void
1639 resource_list_delete(struct resource_list *rl,
1640 		     int type, int rid)
1641 {
1642     struct resource_list_entry *rle = resource_list_find(rl, type, rid);
1643 
1644     if (rle) {
1645 	SLIST_REMOVE(rl, rle, resource_list_entry, link);
1646 	free(rle, M_BUS);
1647     }
1648 }
1649 
1650 struct resource *
1651 resource_list_alloc(struct resource_list *rl,
1652 		    device_t bus, device_t child,
1653 		    int type, int *rid,
1654 		    u_long start, u_long end,
1655 		    u_long count, u_int flags)
1656 {
1657     struct resource_list_entry *rle = 0;
1658     int passthrough = (device_get_parent(child) != bus);
1659     int isdefault = (start == 0UL && end == ~0UL);
1660 
1661     if (passthrough) {
1662 	return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
1663 				  type, rid,
1664 				  start, end, count, flags);
1665     }
1666 
1667     rle = resource_list_find(rl, type, *rid);
1668 
1669     if (!rle)
1670 	return 0;		/* no resource of that type/rid */
1671     if (rle->res)
1672 	panic("resource_list_alloc: resource entry is busy");
1673 
1674     if (isdefault) {
1675 	start = rle->start;
1676 	count = max(count, rle->count);
1677 	end = max(rle->end, start + count - 1);
1678     }
1679 
1680     rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
1681 				  type, rid, start, end, count, flags);
1682 
1683     /*
1684      * Record the new range.
1685      */
1686     if (rle->res) {
1687 	    rle->start = rman_get_start(rle->res);
1688 	    rle->end = rman_get_end(rle->res);
1689 	    rle->count = count;
1690     }
1691 
1692     return rle->res;
1693 }
1694 
1695 int
1696 resource_list_release(struct resource_list *rl,
1697 		      device_t bus, device_t child,
1698 		      int type, int rid, struct resource *res)
1699 {
1700     struct resource_list_entry *rle = 0;
1701     int passthrough = (device_get_parent(child) != bus);
1702     int error;
1703 
1704     if (passthrough) {
1705 	return BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
1706 				    type, rid, res);
1707     }
1708 
1709     rle = resource_list_find(rl, type, rid);
1710 
1711     if (!rle)
1712 	panic("resource_list_release: can't find resource");
1713     if (!rle->res)
1714 	panic("resource_list_release: resource entry is not busy");
1715 
1716     error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
1717 				 type, rid, res);
1718     if (error)
1719 	return error;
1720 
1721     rle->res = NULL;
1722     return 0;
1723 }
1724 
1725 int
1726 resource_list_print_type(struct resource_list *rl, const char *name, int type,
1727     const char *format)
1728 {
1729 	struct resource_list_entry *rle;
1730 	int printed, retval;
1731 
1732 	printed = 0;
1733 	retval = 0;
1734 	/* Yes, this is kinda cheating */
1735 	SLIST_FOREACH(rle, rl, link) {
1736 		if (rle->type == type) {
1737 			if (printed == 0)
1738 				retval += printf(" %s ", name);
1739 			else
1740 				retval += printf(",");
1741 			printed++;
1742 			retval += printf(format, rle->start);
1743 			if (rle->count > 1) {
1744 				retval += printf("-");
1745 				retval += printf(format, rle->start +
1746 						 rle->count - 1);
1747 			}
1748 		}
1749 	}
1750 	return (retval);
1751 }
1752 
1753 /*
1754  * Call DEVICE_IDENTIFY for each driver.
1755  */
1756 int
1757 bus_generic_probe(device_t dev)
1758 {
1759     devclass_t dc = dev->devclass;
1760     driverlink_t dl;
1761 
1762     TAILQ_FOREACH(dl, &dc->drivers, link) {
1763 	DEVICE_IDENTIFY(dl->driver, dev);
1764     }
1765 
1766     return 0;
1767 }
1768 
1769 int
1770 bus_generic_attach(device_t dev)
1771 {
1772     device_t child;
1773 
1774     TAILQ_FOREACH(child, &dev->children, link) {
1775 	device_probe_and_attach(child);
1776     }
1777 
1778     return 0;
1779 }
1780 
1781 int
1782 bus_generic_detach(device_t dev)
1783 {
1784     device_t child;
1785     int error;
1786 
1787     if (dev->state != DS_ATTACHED)
1788 	return EBUSY;
1789 
1790     TAILQ_FOREACH(child, &dev->children, link) {
1791 	if ((error = device_detach(child)) != 0)
1792 	    return error;
1793     }
1794 
1795     return 0;
1796 }
1797 
1798 int
1799 bus_generic_shutdown(device_t dev)
1800 {
1801     device_t child;
1802 
1803     TAILQ_FOREACH(child, &dev->children, link) {
1804 	device_shutdown(child);
1805     }
1806 
1807     return 0;
1808 }
1809 
1810 int
1811 bus_generic_suspend(device_t dev)
1812 {
1813 	int		error;
1814 	device_t	child, child2;
1815 
1816 	TAILQ_FOREACH(child, &dev->children, link) {
1817 		error = DEVICE_SUSPEND(child);
1818 		if (error) {
1819 			for (child2 = TAILQ_FIRST(&dev->children);
1820 			     child2 && child2 != child;
1821 			     child2 = TAILQ_NEXT(child2, link))
1822 				DEVICE_RESUME(child2);
1823 			return (error);
1824 		}
1825 	}
1826 	return 0;
1827 }
1828 
1829 int
1830 bus_generic_resume(device_t dev)
1831 {
1832 	device_t	child;
1833 
1834 	TAILQ_FOREACH(child, &dev->children, link) {
1835 		DEVICE_RESUME(child);
1836 		/* if resume fails, there's nothing we can usefully do... */
1837 	}
1838 	return 0;
1839 }
1840 
1841 int
1842 bus_print_child_header (device_t dev, device_t child)
1843 {
1844 	int	retval = 0;
1845 
1846 	if (device_get_desc(child)) {
1847 		retval += device_printf(child, "<%s>",
1848 				       device_get_desc(child));
1849 	} else {
1850 		retval += printf("%s", device_get_nameunit(child));
1851 	}
1852 
1853 	return (retval);
1854 }
1855 
1856 int
1857 bus_print_child_footer (device_t dev, device_t child)
1858 {
1859 	return(printf(" on %s\n", device_get_nameunit(dev)));
1860 }
1861 
1862 int
1863 bus_generic_print_child(device_t dev, device_t child)
1864 {
1865 	int	retval = 0;
1866 
1867 	retval += bus_print_child_header(dev, child);
1868 	retval += bus_print_child_footer(dev, child);
1869 
1870 	return (retval);
1871 }
1872 
1873 int
1874 bus_generic_read_ivar(device_t dev, device_t child, int index,
1875 		      uintptr_t * result)
1876 {
1877     return ENOENT;
1878 }
1879 
1880 int
1881 bus_generic_write_ivar(device_t dev, device_t child, int index,
1882 		       uintptr_t value)
1883 {
1884     return ENOENT;
1885 }
1886 
1887 void
1888 bus_generic_driver_added(device_t dev, driver_t *driver)
1889 {
1890     device_t child;
1891 
1892     DEVICE_IDENTIFY(driver, dev);
1893     TAILQ_FOREACH(child, &dev->children, link) {
1894 	if (child->state == DS_NOTPRESENT)
1895 	    device_probe_and_attach(child);
1896     }
1897 }
1898 
1899 int
1900 bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
1901 		       int flags, driver_intr_t *intr, void *arg,
1902 		       void **cookiep)
1903 {
1904 	/* Propagate up the bus hierarchy until someone handles it. */
1905 	if (dev->parent)
1906 		return (BUS_SETUP_INTR(dev->parent, child, irq, flags,
1907 				       intr, arg, cookiep));
1908 	else
1909 		return (EINVAL);
1910 }
1911 
1912 int
1913 bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq,
1914 			  void *cookie)
1915 {
1916 	/* Propagate up the bus hierarchy until someone handles it. */
1917 	if (dev->parent)
1918 		return (BUS_TEARDOWN_INTR(dev->parent, child, irq, cookie));
1919 	else
1920 		return (EINVAL);
1921 }
1922 
1923 int
1924 bus_generic_child_present(device_t bus, device_t child)
1925 {
1926 	return (BUS_CHILD_PRESENT(device_get_parent(bus), bus));
1927 }
1928 
1929 struct resource *
1930 bus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid,
1931 			   u_long start, u_long end, u_long count, u_int flags)
1932 {
1933 	/* Propagate up the bus hierarchy until someone handles it. */
1934 	if (dev->parent)
1935 		return (BUS_ALLOC_RESOURCE(dev->parent, child, type, rid,
1936 					   start, end, count, flags));
1937 	else
1938 		return (NULL);
1939 }
1940 
1941 int
1942 bus_generic_release_resource(device_t dev, device_t child, int type, int rid,
1943 			     struct resource *r)
1944 {
1945 	/* Propagate up the bus hierarchy until someone handles it. */
1946 	if (dev->parent)
1947 		return (BUS_RELEASE_RESOURCE(dev->parent, child, type, rid,
1948 					     r));
1949 	else
1950 		return (EINVAL);
1951 }
1952 
1953 int
1954 bus_generic_activate_resource(device_t dev, device_t child, int type, int rid,
1955 			      struct resource *r)
1956 {
1957 	/* Propagate up the bus hierarchy until someone handles it. */
1958 	if (dev->parent)
1959 		return (BUS_ACTIVATE_RESOURCE(dev->parent, child, type, rid,
1960 					      r));
1961 	else
1962 		return (EINVAL);
1963 }
1964 
1965 int
1966 bus_generic_deactivate_resource(device_t dev, device_t child, int type,
1967 				int rid, struct resource *r)
1968 {
1969 	/* Propagate up the bus hierarchy until someone handles it. */
1970 	if (dev->parent)
1971 		return (BUS_DEACTIVATE_RESOURCE(dev->parent, child, type, rid,
1972 						r));
1973 	else
1974 		return (EINVAL);
1975 }
1976 
1977 /*
1978  * Some convenience functions to make it easier for drivers to use the
1979  * resource-management functions.  All these really do is hide the
1980  * indirection through the parent's method table, making for slightly
1981  * less-wordy code.  In the future, it might make sense for this code
1982  * to maintain some sort of a list of resources allocated by each device.
1983  */
1984 struct resource *
1985 bus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end,
1986 		   u_long count, u_int flags)
1987 {
1988 	if (dev->parent == 0)
1989 		return (0);
1990 	return (BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end,
1991 				   count, flags));
1992 }
1993 
1994 int
1995 bus_activate_resource(device_t dev, int type, int rid, struct resource *r)
1996 {
1997 	if (dev->parent == 0)
1998 		return (EINVAL);
1999 	return (BUS_ACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
2000 }
2001 
2002 int
2003 bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r)
2004 {
2005 	if (dev->parent == 0)
2006 		return (EINVAL);
2007 	return (BUS_DEACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
2008 }
2009 
2010 int
2011 bus_release_resource(device_t dev, int type, int rid, struct resource *r)
2012 {
2013 	if (dev->parent == 0)
2014 		return (EINVAL);
2015 	return (BUS_RELEASE_RESOURCE(dev->parent, dev,
2016 				     type, rid, r));
2017 }
2018 
2019 int
2020 bus_setup_intr(device_t dev, struct resource *r, int flags,
2021 	       driver_intr_t handler, void *arg, void **cookiep)
2022 {
2023 	if (dev->parent == 0)
2024 		return (EINVAL);
2025 	return (BUS_SETUP_INTR(dev->parent, dev, r, flags,
2026 			       handler, arg, cookiep));
2027 }
2028 
2029 int
2030 bus_teardown_intr(device_t dev, struct resource *r, void *cookie)
2031 {
2032 	if (dev->parent == 0)
2033 		return (EINVAL);
2034 	return (BUS_TEARDOWN_INTR(dev->parent, dev, r, cookie));
2035 }
2036 
2037 int
2038 bus_set_resource(device_t dev, int type, int rid,
2039 		 u_long start, u_long count)
2040 {
2041 	return BUS_SET_RESOURCE(device_get_parent(dev), dev, type, rid,
2042 				start, count);
2043 }
2044 
2045 int
2046 bus_get_resource(device_t dev, int type, int rid,
2047 		 u_long *startp, u_long *countp)
2048 {
2049 	return BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2050 				startp, countp);
2051 }
2052 
2053 u_long
2054 bus_get_resource_start(device_t dev, int type, int rid)
2055 {
2056 	u_long start, count;
2057 	int error;
2058 
2059 	error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2060 				 &start, &count);
2061 	if (error)
2062 		return 0;
2063 	return start;
2064 }
2065 
2066 u_long
2067 bus_get_resource_count(device_t dev, int type, int rid)
2068 {
2069 	u_long start, count;
2070 	int error;
2071 
2072 	error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2073 				 &start, &count);
2074 	if (error)
2075 		return 0;
2076 	return count;
2077 }
2078 
2079 void
2080 bus_delete_resource(device_t dev, int type, int rid)
2081 {
2082 	BUS_DELETE_RESOURCE(device_get_parent(dev), dev, type, rid);
2083 }
2084 
2085 static int
2086 root_print_child(device_t dev, device_t child)
2087 {
2088 	return (0);
2089 }
2090 
2091 static int
2092 root_setup_intr(device_t dev, device_t child, driver_intr_t *intr, void *arg,
2093 		void **cookiep)
2094 {
2095 	/*
2096 	 * If an interrupt mapping gets to here something bad has happened.
2097 	 */
2098 	panic("root_setup_intr");
2099 }
2100 
2101 static kobj_method_t root_methods[] = {
2102 	/* Device interface */
2103 	KOBJMETHOD(device_shutdown,	bus_generic_shutdown),
2104 	KOBJMETHOD(device_suspend,	bus_generic_suspend),
2105 	KOBJMETHOD(device_resume,	bus_generic_resume),
2106 
2107 	/* Bus interface */
2108 	KOBJMETHOD(bus_print_child,	root_print_child),
2109 	KOBJMETHOD(bus_read_ivar,	bus_generic_read_ivar),
2110 	KOBJMETHOD(bus_write_ivar,	bus_generic_write_ivar),
2111 	KOBJMETHOD(bus_setup_intr,	root_setup_intr),
2112 
2113 	{ 0, 0 }
2114 };
2115 
2116 static driver_t root_driver = {
2117 	"root",
2118 	root_methods,
2119 	1,			/* no softc */
2120 };
2121 
2122 device_t	root_bus;
2123 devclass_t	root_devclass;
2124 
2125 static int
2126 root_bus_module_handler(module_t mod, int what, void* arg)
2127 {
2128     switch (what) {
2129     case MOD_LOAD:
2130 	kobj_class_compile((kobj_class_t) &root_driver);
2131 	root_bus = make_device(NULL, "root", 0);
2132 	root_bus->desc = "System root bus";
2133 	kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver);
2134 	root_bus->driver = &root_driver;
2135 	root_bus->state = DS_ATTACHED;
2136 	root_devclass = devclass_find_internal("root", FALSE);
2137 	return 0;
2138 
2139     case MOD_SHUTDOWN:
2140 	device_shutdown(root_bus);
2141 	return 0;
2142     }
2143 
2144     return 0;
2145 }
2146 
2147 static moduledata_t root_bus_mod = {
2148 	"rootbus",
2149 	root_bus_module_handler,
2150 	0
2151 };
2152 DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
2153 
2154 void
2155 root_bus_configure(void)
2156 {
2157     device_t dev;
2158 
2159     PDEBUG(("."));
2160 
2161     TAILQ_FOREACH(dev, &root_bus->children, link) {
2162 	    device_probe_and_attach(dev);
2163     }
2164 }
2165 
2166 int
2167 driver_module_handler(module_t mod, int what, void *arg)
2168 {
2169 	int error, i;
2170 	struct driver_module_data *dmd;
2171 	devclass_t bus_devclass;
2172 
2173 	dmd = (struct driver_module_data *)arg;
2174 	bus_devclass = devclass_find_internal(dmd->dmd_busname, TRUE);
2175 	error = 0;
2176 
2177 	switch (what) {
2178 	case MOD_LOAD:
2179 		if (dmd->dmd_chainevh)
2180 			error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2181 
2182 		for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
2183 			PDEBUG(("Loading module: driver %s on bus %s",
2184 				DRIVERNAME(dmd->dmd_drivers[i]),
2185 				dmd->dmd_busname));
2186 			error = devclass_add_driver(bus_devclass,
2187 						    dmd->dmd_drivers[i]);
2188 		}
2189 		if (error)
2190 			break;
2191 
2192 		/*
2193 		 * The drivers loaded in this way are assumed to all
2194 		 * implement the same devclass.
2195 		 */
2196 		*dmd->dmd_devclass =
2197 			devclass_find_internal(dmd->dmd_drivers[0]->name,
2198 					       TRUE);
2199 		break;
2200 
2201 	case MOD_UNLOAD:
2202 		for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
2203 			PDEBUG(("Unloading module: driver %s from bus %s",
2204 				DRIVERNAME(dmd->dmd_drivers[i]),
2205 				dmd->dmd_busname));
2206 			error = devclass_delete_driver(bus_devclass,
2207 						       dmd->dmd_drivers[i]);
2208 		}
2209 
2210 		if (!error && dmd->dmd_chainevh)
2211 			error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2212 		break;
2213 	}
2214 
2215 	return (error);
2216 }
2217 
2218 #ifdef BUS_DEBUG
2219 
2220 /* the _short versions avoid iteration by not calling anything that prints
2221  * more than oneliners. I love oneliners.
2222  */
2223 
2224 static void
2225 print_device_short(device_t dev, int indent)
2226 {
2227 	if (!dev)
2228 		return;
2229 
2230 	indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%s,%sivars,%ssoftc,busy=%d\n",
2231 		dev->unit, dev->desc,
2232 		(dev->parent? "":"no "),
2233 		(TAILQ_EMPTY(&dev->children)? "no ":""),
2234 		(dev->flags&DF_ENABLED? "enabled,":"disabled,"),
2235 		(dev->flags&DF_FIXEDCLASS? "fixed,":""),
2236 		(dev->flags&DF_WILDCARD? "wildcard,":""),
2237 		(dev->flags&DF_DESCMALLOCED? "descmalloced,":""),
2238 		(dev->ivars? "":"no "),
2239 		(dev->softc? "":"no "),
2240 		dev->busy));
2241 }
2242 
2243 static void
2244 print_device(device_t dev, int indent)
2245 {
2246 	if (!dev)
2247 		return;
2248 
2249 	print_device_short(dev, indent);
2250 
2251 	indentprintf(("Parent:\n"));
2252 	print_device_short(dev->parent, indent+1);
2253 	indentprintf(("Driver:\n"));
2254 	print_driver_short(dev->driver, indent+1);
2255 	indentprintf(("Devclass:\n"));
2256 	print_devclass_short(dev->devclass, indent+1);
2257 }
2258 
2259 void
2260 print_device_tree_short(device_t dev, int indent)
2261 /* print the device and all its children (indented) */
2262 {
2263 	device_t child;
2264 
2265 	if (!dev)
2266 		return;
2267 
2268 	print_device_short(dev, indent);
2269 
2270 	TAILQ_FOREACH(child, &dev->children, link) {
2271 		print_device_tree_short(child, indent+1);
2272 	}
2273 }
2274 
2275 void
2276 print_device_tree(device_t dev, int indent)
2277 /* print the device and all its children (indented) */
2278 {
2279 	device_t child;
2280 
2281 	if (!dev)
2282 		return;
2283 
2284 	print_device(dev, indent);
2285 
2286 	TAILQ_FOREACH(child, &dev->children, link) {
2287 		print_device_tree(child, indent+1);
2288 	}
2289 }
2290 
2291 static void
2292 print_driver_short(driver_t *driver, int indent)
2293 {
2294 	if (!driver)
2295 		return;
2296 
2297 	indentprintf(("driver %s: softc size = %d\n",
2298 		driver->name, driver->size));
2299 }
2300 
2301 static void
2302 print_driver(driver_t *driver, int indent)
2303 {
2304 	if (!driver)
2305 		return;
2306 
2307 	print_driver_short(driver, indent);
2308 }
2309 
2310 
2311 static void
2312 print_driver_list(driver_list_t drivers, int indent)
2313 {
2314 	driverlink_t driver;
2315 
2316 	TAILQ_FOREACH(driver, &drivers, link) {
2317 		print_driver(driver->driver, indent);
2318 	}
2319 }
2320 
2321 static void
2322 print_devclass_short(devclass_t dc, int indent)
2323 {
2324 	if ( !dc )
2325 		return;
2326 
2327 	indentprintf(("devclass %s: max units = %d\n",
2328 		dc->name, dc->maxunit));
2329 }
2330 
2331 static void
2332 print_devclass(devclass_t dc, int indent)
2333 {
2334 	int i;
2335 
2336 	if ( !dc )
2337 		return;
2338 
2339 	print_devclass_short(dc, indent);
2340 	indentprintf(("Drivers:\n"));
2341 	print_driver_list(dc->drivers, indent+1);
2342 
2343 	indentprintf(("Devices:\n"));
2344 	for (i = 0; i < dc->maxunit; i++)
2345 		if (dc->devices[i])
2346 			print_device(dc->devices[i], indent+1);
2347 }
2348 
2349 void
2350 print_devclass_list_short(void)
2351 {
2352 	devclass_t dc;
2353 
2354 	printf("Short listing of devclasses, drivers & devices:\n");
2355 	TAILQ_FOREACH(dc, &devclasses, link) {
2356 		print_devclass_short(dc, 0);
2357 	}
2358 }
2359 
2360 void
2361 print_devclass_list(void)
2362 {
2363 	devclass_t dc;
2364 
2365 	printf("Full listing of devclasses, drivers & devices:\n");
2366 	TAILQ_FOREACH(dc, &devclasses, link) {
2367 		print_devclass(dc, 0);
2368 	}
2369 }
2370 
2371 #endif
2372