xref: /dragonfly/sys/kern/subr_bus.c (revision af79c6e5)
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.9 2003/11/18 05:10:31 dillon 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_set_devclass(device_t dev, const char *classname)
954 {
955     devclass_t dc;
956 
957     if (!classname) {
958 	if (dev->devclass)
959 	    devclass_delete_device(dev->devclass, dev);
960 	return 0;
961     }
962 
963     if (dev->devclass) {
964 	printf("device_set_devclass: device class already set\n");
965 	return EINVAL;
966     }
967 
968     dc = devclass_find_internal(classname, TRUE);
969     if (!dc)
970 	return ENOMEM;
971 
972     return devclass_add_device(dc, dev);
973 }
974 
975 int
976 device_set_driver(device_t dev, driver_t *driver)
977 {
978     if (dev->state >= DS_ATTACHED)
979 	return EBUSY;
980 
981     if (dev->driver == driver)
982 	return 0;
983 
984     if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) {
985 	free(dev->softc, M_BUS);
986 	dev->softc = NULL;
987     }
988     kobj_delete((kobj_t) dev, 0);
989     dev->driver = driver;
990     if (driver) {
991 	kobj_init((kobj_t) dev, (kobj_class_t) driver);
992 	if (!(dev->flags & DF_EXTERNALSOFTC)) {
993 	    dev->softc = malloc(driver->size, M_BUS, M_NOWAIT | M_ZERO);
994 	    if (!dev->softc) {
995 		kobj_delete((kobj_t)dev, 0);
996 		kobj_init((kobj_t) dev, &null_class);
997 		dev->driver = NULL;
998 		return ENOMEM;
999 	    }
1000 	}
1001     } else
1002 	kobj_init((kobj_t) dev, &null_class);
1003     return 0;
1004 }
1005 
1006 int
1007 device_probe_and_attach(device_t dev)
1008 {
1009     device_t bus = dev->parent;
1010     int error = 0;
1011     int hasclass = (dev->devclass != 0);
1012 
1013     if (dev->state >= DS_ALIVE)
1014 	return 0;
1015 
1016     if (dev->flags & DF_ENABLED) {
1017 	error = device_probe_child(bus, dev);
1018 	if (!error) {
1019 	    if (!device_is_quiet(dev))
1020 		device_print_child(bus, dev);
1021 	    error = DEVICE_ATTACH(dev);
1022 	    if (!error)
1023 		dev->state = DS_ATTACHED;
1024 	    else {
1025 		printf("device_probe_and_attach: %s%d attach returned %d\n",
1026 		       dev->driver->name, dev->unit, error);
1027 		/* Unset the class that was set in device_probe_child */
1028 		if (!hasclass)
1029 		    device_set_devclass(dev, 0);
1030 		device_set_driver(dev, NULL);
1031 		dev->state = DS_NOTPRESENT;
1032 	    }
1033 	} else {
1034 	    if (!(dev->flags & DF_DONENOMATCH)) {
1035 		BUS_PROBE_NOMATCH(bus, dev);
1036 		dev->flags |= DF_DONENOMATCH;
1037 	    }
1038 	}
1039     } else {
1040 	if (bootverbose) {
1041 	    device_print_prettyname(dev);
1042 	    printf("not probed (disabled)\n");
1043 	}
1044     }
1045 
1046     return error;
1047 }
1048 
1049 int
1050 device_detach(device_t dev)
1051 {
1052     int error;
1053 
1054     PDEBUG(("%s", DEVICENAME(dev)));
1055     if (dev->state == DS_BUSY)
1056 	return EBUSY;
1057     if (dev->state != DS_ATTACHED)
1058 	return 0;
1059 
1060     if ((error = DEVICE_DETACH(dev)) != 0)
1061 	return error;
1062     device_printf(dev, "detached\n");
1063     if (dev->parent)
1064 	BUS_CHILD_DETACHED(dev->parent, dev);
1065 
1066     if (!(dev->flags & DF_FIXEDCLASS))
1067 	devclass_delete_device(dev->devclass, dev);
1068 
1069     dev->state = DS_NOTPRESENT;
1070     device_set_driver(dev, NULL);
1071 
1072     return 0;
1073 }
1074 
1075 int
1076 device_shutdown(device_t dev)
1077 {
1078     if (dev->state < DS_ATTACHED)
1079 	return 0;
1080     return DEVICE_SHUTDOWN(dev);
1081 }
1082 
1083 int
1084 device_set_unit(device_t dev, int unit)
1085 {
1086     devclass_t dc;
1087     int err;
1088 
1089     dc = device_get_devclass(dev);
1090     if (unit < dc->maxunit && dc->devices[unit])
1091 	return EBUSY;
1092     err = devclass_delete_device(dc, dev);
1093     if (err)
1094 	return err;
1095     dev->unit = unit;
1096     err = devclass_add_device(dc, dev);
1097     if (err)
1098 	return err;
1099     return 0;
1100 }
1101 
1102 #ifdef DEVICE_SYSCTLS
1103 
1104 /*
1105  * Sysctl nodes for devices.
1106  */
1107 
1108 SYSCTL_NODE(_hw, OID_AUTO, devices, CTLFLAG_RW, 0, "A list of all devices");
1109 
1110 static int
1111 sysctl_handle_children(SYSCTL_HANDLER_ARGS)
1112 {
1113     device_t dev = arg1;
1114     device_t child;
1115     int first = 1, error = 0;
1116 
1117     TAILQ_FOREACH(child, &dev->children, link) {
1118 	if (child->nameunit) {
1119 	    if (!first) {
1120 		error = SYSCTL_OUT(req, ",", 1);
1121 		if (error) return error;
1122 	    } else {
1123 		first = 0;
1124 	    }
1125 	    error = SYSCTL_OUT(req, child->nameunit, strlen(child->nameunit));
1126 	    if (error) return error;
1127 	}
1128     }
1129 
1130     error = SYSCTL_OUT(req, "", 1);
1131 
1132     return error;
1133 }
1134 
1135 static int
1136 sysctl_handle_state(SYSCTL_HANDLER_ARGS)
1137 {
1138     device_t dev = arg1;
1139 
1140     switch (dev->state) {
1141     case DS_NOTPRESENT:
1142 	return SYSCTL_OUT(req, "notpresent", sizeof("notpresent"));
1143     case DS_ALIVE:
1144 	return SYSCTL_OUT(req, "alive", sizeof("alive"));
1145     case DS_ATTACHED:
1146 	return SYSCTL_OUT(req, "attached", sizeof("attached"));
1147     case DS_BUSY:
1148 	return SYSCTL_OUT(req, "busy", sizeof("busy"));
1149     }
1150 
1151     return 0;
1152 }
1153 
1154 static void
1155 device_register_oids(device_t dev)
1156 {
1157     struct sysctl_oid* oid;
1158 
1159     oid = &dev->oid[0];
1160     bzero(oid, sizeof(*oid));
1161     oid->oid_parent = &sysctl__hw_devices_children;
1162     oid->oid_number = OID_AUTO;
1163     oid->oid_kind = CTLTYPE_NODE | CTLFLAG_RW;
1164     oid->oid_arg1 = &dev->oidlist[0];
1165     oid->oid_arg2 = 0;
1166     oid->oid_name = dev->nameunit;
1167     oid->oid_handler = 0;
1168     oid->oid_fmt = "N";
1169     SLIST_INIT(&dev->oidlist[0]);
1170     sysctl_register_oid(oid);
1171 
1172     oid = &dev->oid[1];
1173     bzero(oid, sizeof(*oid));
1174     oid->oid_parent = &dev->oidlist[0];
1175     oid->oid_number = OID_AUTO;
1176     oid->oid_kind = CTLTYPE_STRING | CTLFLAG_RD;
1177     oid->oid_arg1 = dev->desc ? dev->desc : "";
1178     oid->oid_arg2 = dev->desc ? strlen(dev->desc) : 0;
1179     oid->oid_name = "desc";
1180     oid->oid_handler = sysctl_handle_string;
1181     oid->oid_fmt = "A";
1182     sysctl_register_oid(oid);
1183 
1184     oid = &dev->oid[2];
1185     bzero(oid, sizeof(*oid));
1186     oid->oid_parent = &dev->oidlist[0];
1187     oid->oid_number = OID_AUTO;
1188     oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD;
1189     oid->oid_arg1 = dev;
1190     oid->oid_arg2 = 0;
1191     oid->oid_name = "children";
1192     oid->oid_handler = sysctl_handle_children;
1193     oid->oid_fmt = "A";
1194     sysctl_register_oid(oid);
1195 
1196     oid = &dev->oid[3];
1197     bzero(oid, sizeof(*oid));
1198     oid->oid_parent = &dev->oidlist[0];
1199     oid->oid_number = OID_AUTO;
1200     oid->oid_kind = CTLTYPE_INT | CTLFLAG_RD;
1201     oid->oid_arg1 = dev;
1202     oid->oid_arg2 = 0;
1203     oid->oid_name = "state";
1204     oid->oid_handler = sysctl_handle_state;
1205     oid->oid_fmt = "A";
1206     sysctl_register_oid(oid);
1207 }
1208 
1209 static void
1210 device_unregister_oids(device_t dev)
1211 {
1212     sysctl_unregister_oid(&dev->oid[0]);
1213     sysctl_unregister_oid(&dev->oid[1]);
1214     sysctl_unregister_oid(&dev->oid[2]);
1215 }
1216 
1217 #endif
1218 
1219 /*======================================*/
1220 /*
1221  * Access functions for device resources.
1222  */
1223 
1224 /* Supplied by config(8) in ioconf.c */
1225 extern struct config_device config_devtab[];
1226 extern int devtab_count;
1227 
1228 /* Runtime version */
1229 struct config_device *devtab = config_devtab;
1230 
1231 static int
1232 resource_new_name(const char *name, int unit)
1233 {
1234 	struct config_device *new;
1235 
1236 	new = malloc((devtab_count + 1) * sizeof(*new), M_TEMP,
1237 		     M_NOWAIT | M_ZERO);
1238 	if (new == NULL)
1239 		return -1;
1240 	if (devtab && devtab_count > 0)
1241 		bcopy(devtab, new, devtab_count * sizeof(*new));
1242 	new[devtab_count].name = malloc(strlen(name) + 1, M_TEMP, M_NOWAIT);
1243 	if (new[devtab_count].name == NULL) {
1244 		free(new, M_TEMP);
1245 		return -1;
1246 	}
1247 	strcpy(new[devtab_count].name, name);
1248 	new[devtab_count].unit = unit;
1249 	new[devtab_count].resource_count = 0;
1250 	new[devtab_count].resources = NULL;
1251 	devtab = new;
1252 	return devtab_count++;
1253 }
1254 
1255 static int
1256 resource_new_resname(int j, const char *resname, resource_type type)
1257 {
1258 	struct config_resource *new;
1259 	int i;
1260 
1261 	i = devtab[j].resource_count;
1262 	new = malloc((i + 1) * sizeof(*new), M_TEMP, M_NOWAIT | M_ZERO);
1263 	if (new == NULL)
1264 		return -1;
1265 	if (devtab[j].resources && i > 0)
1266 		bcopy(devtab[j].resources, new, i * sizeof(*new));
1267 	new[i].name = malloc(strlen(resname) + 1, M_TEMP, M_NOWAIT);
1268 	if (new[i].name == NULL) {
1269 		free(new, M_TEMP);
1270 		return -1;
1271 	}
1272 	strcpy(new[i].name, resname);
1273 	new[i].type = type;
1274 	if (devtab[j].resources)
1275 		free(devtab[j].resources, M_TEMP);
1276 	devtab[j].resources = new;
1277 	devtab[j].resource_count = i + 1;
1278 	return i;
1279 }
1280 
1281 static int
1282 resource_match_string(int i, const char *resname, const char *value)
1283 {
1284 	int j;
1285 	struct config_resource *res;
1286 
1287 	for (j = 0, res = devtab[i].resources;
1288 	     j < devtab[i].resource_count; j++, res++)
1289 		if (!strcmp(res->name, resname)
1290 		    && res->type == RES_STRING
1291 		    && !strcmp(res->u.stringval, value))
1292 			return j;
1293 	return -1;
1294 }
1295 
1296 static int
1297 resource_find(const char *name, int unit, const char *resname,
1298 	      struct config_resource **result)
1299 {
1300 	int i, j;
1301 	struct config_resource *res;
1302 
1303 	/*
1304 	 * First check specific instances, then generic.
1305 	 */
1306 	for (i = 0; i < devtab_count; i++) {
1307 		if (devtab[i].unit < 0)
1308 			continue;
1309 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1310 			res = devtab[i].resources;
1311 			for (j = 0; j < devtab[i].resource_count; j++, res++)
1312 				if (!strcmp(res->name, resname)) {
1313 					*result = res;
1314 					return 0;
1315 				}
1316 		}
1317 	}
1318 	for (i = 0; i < devtab_count; i++) {
1319 		if (devtab[i].unit >= 0)
1320 			continue;
1321 		/* XXX should this `&& devtab[i].unit == unit' be here? */
1322 		/* XXX if so, then the generic match does nothing */
1323 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1324 			res = devtab[i].resources;
1325 			for (j = 0; j < devtab[i].resource_count; j++, res++)
1326 				if (!strcmp(res->name, resname)) {
1327 					*result = res;
1328 					return 0;
1329 				}
1330 		}
1331 	}
1332 	return ENOENT;
1333 }
1334 
1335 int
1336 resource_int_value(const char *name, int unit, const char *resname, int *result)
1337 {
1338 	int error;
1339 	struct config_resource *res;
1340 
1341 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1342 		return error;
1343 	if (res->type != RES_INT)
1344 		return EFTYPE;
1345 	*result = res->u.intval;
1346 	return 0;
1347 }
1348 
1349 int
1350 resource_long_value(const char *name, int unit, const char *resname,
1351 		    long *result)
1352 {
1353 	int error;
1354 	struct config_resource *res;
1355 
1356 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1357 		return error;
1358 	if (res->type != RES_LONG)
1359 		return EFTYPE;
1360 	*result = res->u.longval;
1361 	return 0;
1362 }
1363 
1364 int
1365 resource_string_value(const char *name, int unit, const char *resname,
1366 		      char **result)
1367 {
1368 	int error;
1369 	struct config_resource *res;
1370 
1371 	if ((error = resource_find(name, unit, resname, &res)) != 0)
1372 		return error;
1373 	if (res->type != RES_STRING)
1374 		return EFTYPE;
1375 	*result = res->u.stringval;
1376 	return 0;
1377 }
1378 
1379 int
1380 resource_query_string(int i, const char *resname, const char *value)
1381 {
1382 	if (i < 0)
1383 		i = 0;
1384 	else
1385 		i = i + 1;
1386 	for (; i < devtab_count; i++)
1387 		if (resource_match_string(i, resname, value) >= 0)
1388 			return i;
1389 	return -1;
1390 }
1391 
1392 int
1393 resource_locate(int i, const char *resname)
1394 {
1395 	if (i < 0)
1396 		i = 0;
1397 	else
1398 		i = i + 1;
1399 	for (; i < devtab_count; i++)
1400 		if (!strcmp(devtab[i].name, resname))
1401 			return i;
1402 	return -1;
1403 }
1404 
1405 int
1406 resource_count(void)
1407 {
1408 	return devtab_count;
1409 }
1410 
1411 char *
1412 resource_query_name(int i)
1413 {
1414 	return devtab[i].name;
1415 }
1416 
1417 int
1418 resource_query_unit(int i)
1419 {
1420 	return devtab[i].unit;
1421 }
1422 
1423 static int
1424 resource_create(const char *name, int unit, const char *resname,
1425 		resource_type type, struct config_resource **result)
1426 {
1427 	int i, j;
1428 	struct config_resource *res = NULL;
1429 
1430 	for (i = 0; i < devtab_count; i++) {
1431 		if (!strcmp(devtab[i].name, name) && devtab[i].unit == unit) {
1432 			res = devtab[i].resources;
1433 			break;
1434 		}
1435 	}
1436 	if (res == NULL) {
1437 		i = resource_new_name(name, unit);
1438 		if (i < 0)
1439 			return ENOMEM;
1440 		res = devtab[i].resources;
1441 	}
1442 	for (j = 0; j < devtab[i].resource_count; j++, res++) {
1443 		if (!strcmp(res->name, resname)) {
1444 			*result = res;
1445 			return 0;
1446 		}
1447 	}
1448 	j = resource_new_resname(i, resname, type);
1449 	if (j < 0)
1450 		return ENOMEM;
1451 	res = &devtab[i].resources[j];
1452 	*result = res;
1453 	return 0;
1454 }
1455 
1456 int
1457 resource_set_int(const char *name, int unit, const char *resname, int value)
1458 {
1459 	int error;
1460 	struct config_resource *res;
1461 
1462 	error = resource_create(name, unit, resname, RES_INT, &res);
1463 	if (error)
1464 		return error;
1465 	if (res->type != RES_INT)
1466 		return EFTYPE;
1467 	res->u.intval = value;
1468 	return 0;
1469 }
1470 
1471 int
1472 resource_set_long(const char *name, int unit, const char *resname, long value)
1473 {
1474 	int error;
1475 	struct config_resource *res;
1476 
1477 	error = resource_create(name, unit, resname, RES_LONG, &res);
1478 	if (error)
1479 		return error;
1480 	if (res->type != RES_LONG)
1481 		return EFTYPE;
1482 	res->u.longval = value;
1483 	return 0;
1484 }
1485 
1486 int
1487 resource_set_string(const char *name, int unit, const char *resname,
1488 		    const char *value)
1489 {
1490 	int error;
1491 	struct config_resource *res;
1492 
1493 	error = resource_create(name, unit, resname, RES_STRING, &res);
1494 	if (error)
1495 		return error;
1496 	if (res->type != RES_STRING)
1497 		return EFTYPE;
1498 	if (res->u.stringval)
1499 		free(res->u.stringval, M_TEMP);
1500 	res->u.stringval = malloc(strlen(value) + 1, M_TEMP, M_NOWAIT);
1501 	if (res->u.stringval == NULL)
1502 		return ENOMEM;
1503 	strcpy(res->u.stringval, value);
1504 	return 0;
1505 }
1506 
1507 
1508 static void
1509 resource_cfgload(void *dummy __unused)
1510 {
1511 	struct config_resource *res, *cfgres;
1512 	int i, j;
1513 	int error;
1514 	char *name, *resname;
1515 	int unit;
1516 	resource_type type;
1517 	char *stringval;
1518 	int config_devtab_count;
1519 
1520 	config_devtab_count = devtab_count;
1521 	devtab = NULL;
1522 	devtab_count = 0;
1523 
1524 	for (i = 0; i < config_devtab_count; i++) {
1525 		name = config_devtab[i].name;
1526 		unit = config_devtab[i].unit;
1527 
1528 		for (j = 0; j < config_devtab[i].resource_count; j++) {
1529 			cfgres = config_devtab[i].resources;
1530 			resname = cfgres[j].name;
1531 			type = cfgres[j].type;
1532 			error = resource_create(name, unit, resname, type,
1533 						&res);
1534 			if (error) {
1535 				printf("create resource %s%d: error %d\n",
1536 					name, unit, error);
1537 				continue;
1538 			}
1539 			if (res->type != type) {
1540 				printf("type mismatch %s%d: %d != %d\n",
1541 					name, unit, res->type, type);
1542 				continue;
1543 			}
1544 			switch (type) {
1545 			case RES_INT:
1546 				res->u.intval = cfgres[j].u.intval;
1547 				break;
1548 			case RES_LONG:
1549 				res->u.longval = cfgres[j].u.longval;
1550 				break;
1551 			case RES_STRING:
1552 				if (res->u.stringval)
1553 					free(res->u.stringval, M_TEMP);
1554 				stringval = cfgres[j].u.stringval;
1555 				res->u.stringval = malloc(strlen(stringval) + 1,
1556 							  M_TEMP, M_NOWAIT);
1557 				if (res->u.stringval == NULL)
1558 					break;
1559 				strcpy(res->u.stringval, stringval);
1560 				break;
1561 			default:
1562 				panic("unknown resource type %d\n", type);
1563 			}
1564 		}
1565 	}
1566 }
1567 SYSINIT(cfgload, SI_SUB_KMEM, SI_ORDER_ANY + 50, resource_cfgload, 0)
1568 
1569 
1570 /*======================================*/
1571 /*
1572  * Some useful method implementations to make life easier for bus drivers.
1573  */
1574 
1575 void
1576 resource_list_init(struct resource_list *rl)
1577 {
1578 	SLIST_INIT(rl);
1579 }
1580 
1581 void
1582 resource_list_free(struct resource_list *rl)
1583 {
1584     struct resource_list_entry *rle;
1585 
1586     while ((rle = SLIST_FIRST(rl)) != NULL) {
1587 	if (rle->res)
1588 	    panic("resource_list_free: resource entry is busy");
1589 	SLIST_REMOVE_HEAD(rl, link);
1590 	free(rle, M_BUS);
1591     }
1592 }
1593 
1594 void
1595 resource_list_add(struct resource_list *rl,
1596 		  int type, int rid,
1597 		  u_long start, u_long end, u_long count)
1598 {
1599     struct resource_list_entry *rle;
1600 
1601     rle = resource_list_find(rl, type, rid);
1602     if (!rle) {
1603 	rle = malloc(sizeof(struct resource_list_entry), M_BUS, M_NOWAIT);
1604 	if (!rle)
1605 	    panic("resource_list_add: can't record entry");
1606 	SLIST_INSERT_HEAD(rl, rle, link);
1607 	rle->type = type;
1608 	rle->rid = rid;
1609 	rle->res = NULL;
1610     }
1611 
1612     if (rle->res)
1613 	panic("resource_list_add: resource entry is busy");
1614 
1615     rle->start = start;
1616     rle->end = end;
1617     rle->count = count;
1618 }
1619 
1620 struct resource_list_entry*
1621 resource_list_find(struct resource_list *rl,
1622 		   int type, int rid)
1623 {
1624     struct resource_list_entry *rle;
1625 
1626     SLIST_FOREACH(rle, rl, link)
1627 	if (rle->type == type && rle->rid == rid)
1628 	    return rle;
1629     return NULL;
1630 }
1631 
1632 void
1633 resource_list_delete(struct resource_list *rl,
1634 		     int type, int rid)
1635 {
1636     struct resource_list_entry *rle = resource_list_find(rl, type, rid);
1637 
1638     if (rle) {
1639 	SLIST_REMOVE(rl, rle, resource_list_entry, link);
1640 	free(rle, M_BUS);
1641     }
1642 }
1643 
1644 struct resource *
1645 resource_list_alloc(struct resource_list *rl,
1646 		    device_t bus, device_t child,
1647 		    int type, int *rid,
1648 		    u_long start, u_long end,
1649 		    u_long count, u_int flags)
1650 {
1651     struct resource_list_entry *rle = 0;
1652     int passthrough = (device_get_parent(child) != bus);
1653     int isdefault = (start == 0UL && end == ~0UL);
1654 
1655     if (passthrough) {
1656 	return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
1657 				  type, rid,
1658 				  start, end, count, flags);
1659     }
1660 
1661     rle = resource_list_find(rl, type, *rid);
1662 
1663     if (!rle)
1664 	return 0;		/* no resource of that type/rid */
1665     if (rle->res)
1666 	panic("resource_list_alloc: resource entry is busy");
1667 
1668     if (isdefault) {
1669 	start = rle->start;
1670 	count = max(count, rle->count);
1671 	end = max(rle->end, start + count - 1);
1672     }
1673 
1674     rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
1675 				  type, rid, start, end, count, flags);
1676 
1677     /*
1678      * Record the new range.
1679      */
1680     if (rle->res) {
1681 	    rle->start = rman_get_start(rle->res);
1682 	    rle->end = rman_get_end(rle->res);
1683 	    rle->count = count;
1684     }
1685 
1686     return rle->res;
1687 }
1688 
1689 int
1690 resource_list_release(struct resource_list *rl,
1691 		      device_t bus, device_t child,
1692 		      int type, int rid, struct resource *res)
1693 {
1694     struct resource_list_entry *rle = 0;
1695     int passthrough = (device_get_parent(child) != bus);
1696     int error;
1697 
1698     if (passthrough) {
1699 	return BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
1700 				    type, rid, res);
1701     }
1702 
1703     rle = resource_list_find(rl, type, rid);
1704 
1705     if (!rle)
1706 	panic("resource_list_release: can't find resource");
1707     if (!rle->res)
1708 	panic("resource_list_release: resource entry is not busy");
1709 
1710     error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
1711 				 type, rid, res);
1712     if (error)
1713 	return error;
1714 
1715     rle->res = NULL;
1716     return 0;
1717 }
1718 
1719 int
1720 resource_list_print_type(struct resource_list *rl, const char *name, int type,
1721     const char *format)
1722 {
1723 	struct resource_list_entry *rle;
1724 	int printed, retval;
1725 
1726 	printed = 0;
1727 	retval = 0;
1728 	/* Yes, this is kinda cheating */
1729 	SLIST_FOREACH(rle, rl, link) {
1730 		if (rle->type == type) {
1731 			if (printed == 0)
1732 				retval += printf(" %s ", name);
1733 			else
1734 				retval += printf(",");
1735 			printed++;
1736 			retval += printf(format, rle->start);
1737 			if (rle->count > 1) {
1738 				retval += printf("-");
1739 				retval += printf(format, rle->start +
1740 						 rle->count - 1);
1741 			}
1742 		}
1743 	}
1744 	return (retval);
1745 }
1746 
1747 /*
1748  * Call DEVICE_IDENTIFY for each driver.
1749  */
1750 int
1751 bus_generic_probe(device_t dev)
1752 {
1753     devclass_t dc = dev->devclass;
1754     driverlink_t dl;
1755 
1756     TAILQ_FOREACH(dl, &dc->drivers, link) {
1757 	DEVICE_IDENTIFY(dl->driver, dev);
1758     }
1759 
1760     return 0;
1761 }
1762 
1763 int
1764 bus_generic_attach(device_t dev)
1765 {
1766     device_t child;
1767 
1768     TAILQ_FOREACH(child, &dev->children, link) {
1769 	device_probe_and_attach(child);
1770     }
1771 
1772     return 0;
1773 }
1774 
1775 int
1776 bus_generic_detach(device_t dev)
1777 {
1778     device_t child;
1779     int error;
1780 
1781     if (dev->state != DS_ATTACHED)
1782 	return EBUSY;
1783 
1784     TAILQ_FOREACH(child, &dev->children, link) {
1785 	if ((error = device_detach(child)) != 0)
1786 	    return error;
1787     }
1788 
1789     return 0;
1790 }
1791 
1792 int
1793 bus_generic_shutdown(device_t dev)
1794 {
1795     device_t child;
1796 
1797     TAILQ_FOREACH(child, &dev->children, link) {
1798 	device_shutdown(child);
1799     }
1800 
1801     return 0;
1802 }
1803 
1804 int
1805 bus_generic_suspend(device_t dev)
1806 {
1807 	int		error;
1808 	device_t	child, child2;
1809 
1810 	TAILQ_FOREACH(child, &dev->children, link) {
1811 		error = DEVICE_SUSPEND(child);
1812 		if (error) {
1813 			for (child2 = TAILQ_FIRST(&dev->children);
1814 			     child2 && child2 != child;
1815 			     child2 = TAILQ_NEXT(child2, link))
1816 				DEVICE_RESUME(child2);
1817 			return (error);
1818 		}
1819 	}
1820 	return 0;
1821 }
1822 
1823 int
1824 bus_generic_resume(device_t dev)
1825 {
1826 	device_t	child;
1827 
1828 	TAILQ_FOREACH(child, &dev->children, link) {
1829 		DEVICE_RESUME(child);
1830 		/* if resume fails, there's nothing we can usefully do... */
1831 	}
1832 	return 0;
1833 }
1834 
1835 int
1836 bus_print_child_header (device_t dev, device_t child)
1837 {
1838 	int	retval = 0;
1839 
1840 	if (device_get_desc(child)) {
1841 		retval += device_printf(child, "<%s>",
1842 				       device_get_desc(child));
1843 	} else {
1844 		retval += printf("%s", device_get_nameunit(child));
1845 	}
1846 
1847 	return (retval);
1848 }
1849 
1850 int
1851 bus_print_child_footer (device_t dev, device_t child)
1852 {
1853 	return(printf(" on %s\n", device_get_nameunit(dev)));
1854 }
1855 
1856 int
1857 bus_generic_print_child(device_t dev, device_t child)
1858 {
1859 	int	retval = 0;
1860 
1861 	retval += bus_print_child_header(dev, child);
1862 	retval += bus_print_child_footer(dev, child);
1863 
1864 	return (retval);
1865 }
1866 
1867 int
1868 bus_generic_read_ivar(device_t dev, device_t child, int index,
1869 		      uintptr_t * result)
1870 {
1871     return ENOENT;
1872 }
1873 
1874 int
1875 bus_generic_write_ivar(device_t dev, device_t child, int index,
1876 		       uintptr_t value)
1877 {
1878     return ENOENT;
1879 }
1880 
1881 void
1882 bus_generic_driver_added(device_t dev, driver_t *driver)
1883 {
1884     device_t child;
1885 
1886     DEVICE_IDENTIFY(driver, dev);
1887     TAILQ_FOREACH(child, &dev->children, link) {
1888 	if (child->state == DS_NOTPRESENT)
1889 	    device_probe_and_attach(child);
1890     }
1891 }
1892 
1893 int
1894 bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
1895 		       int flags, driver_intr_t *intr, void *arg,
1896 		       void **cookiep)
1897 {
1898 	/* Propagate up the bus hierarchy until someone handles it. */
1899 	if (dev->parent)
1900 		return (BUS_SETUP_INTR(dev->parent, child, irq, flags,
1901 				       intr, arg, cookiep));
1902 	else
1903 		return (EINVAL);
1904 }
1905 
1906 int
1907 bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq,
1908 			  void *cookie)
1909 {
1910 	/* Propagate up the bus hierarchy until someone handles it. */
1911 	if (dev->parent)
1912 		return (BUS_TEARDOWN_INTR(dev->parent, child, irq, cookie));
1913 	else
1914 		return (EINVAL);
1915 }
1916 
1917 struct resource *
1918 bus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid,
1919 			   u_long start, u_long end, u_long count, u_int flags)
1920 {
1921 	/* Propagate up the bus hierarchy until someone handles it. */
1922 	if (dev->parent)
1923 		return (BUS_ALLOC_RESOURCE(dev->parent, child, type, rid,
1924 					   start, end, count, flags));
1925 	else
1926 		return (NULL);
1927 }
1928 
1929 int
1930 bus_generic_release_resource(device_t dev, device_t child, int type, int rid,
1931 			     struct resource *r)
1932 {
1933 	/* Propagate up the bus hierarchy until someone handles it. */
1934 	if (dev->parent)
1935 		return (BUS_RELEASE_RESOURCE(dev->parent, child, type, rid,
1936 					     r));
1937 	else
1938 		return (EINVAL);
1939 }
1940 
1941 int
1942 bus_generic_activate_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_ACTIVATE_RESOURCE(dev->parent, child, type, rid,
1948 					      r));
1949 	else
1950 		return (EINVAL);
1951 }
1952 
1953 int
1954 bus_generic_deactivate_resource(device_t dev, device_t child, int type,
1955 				int rid, struct resource *r)
1956 {
1957 	/* Propagate up the bus hierarchy until someone handles it. */
1958 	if (dev->parent)
1959 		return (BUS_DEACTIVATE_RESOURCE(dev->parent, child, type, rid,
1960 						r));
1961 	else
1962 		return (EINVAL);
1963 }
1964 
1965 /*
1966  * Some convenience functions to make it easier for drivers to use the
1967  * resource-management functions.  All these really do is hide the
1968  * indirection through the parent's method table, making for slightly
1969  * less-wordy code.  In the future, it might make sense for this code
1970  * to maintain some sort of a list of resources allocated by each device.
1971  */
1972 struct resource *
1973 bus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end,
1974 		   u_long count, u_int flags)
1975 {
1976 	if (dev->parent == 0)
1977 		return (0);
1978 	return (BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end,
1979 				   count, flags));
1980 }
1981 
1982 int
1983 bus_activate_resource(device_t dev, int type, int rid, struct resource *r)
1984 {
1985 	if (dev->parent == 0)
1986 		return (EINVAL);
1987 	return (BUS_ACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
1988 }
1989 
1990 int
1991 bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r)
1992 {
1993 	if (dev->parent == 0)
1994 		return (EINVAL);
1995 	return (BUS_DEACTIVATE_RESOURCE(dev->parent, dev, type, rid, r));
1996 }
1997 
1998 int
1999 bus_release_resource(device_t dev, int type, int rid, struct resource *r)
2000 {
2001 	if (dev->parent == 0)
2002 		return (EINVAL);
2003 	return (BUS_RELEASE_RESOURCE(dev->parent, dev,
2004 				     type, rid, r));
2005 }
2006 
2007 int
2008 bus_setup_intr(device_t dev, struct resource *r, int flags,
2009 	       driver_intr_t handler, void *arg, void **cookiep)
2010 {
2011 	if (dev->parent == 0)
2012 		return (EINVAL);
2013 	return (BUS_SETUP_INTR(dev->parent, dev, r, flags,
2014 			       handler, arg, cookiep));
2015 }
2016 
2017 int
2018 bus_teardown_intr(device_t dev, struct resource *r, void *cookie)
2019 {
2020 	if (dev->parent == 0)
2021 		return (EINVAL);
2022 	return (BUS_TEARDOWN_INTR(dev->parent, dev, r, cookie));
2023 }
2024 
2025 int
2026 bus_set_resource(device_t dev, int type, int rid,
2027 		 u_long start, u_long count)
2028 {
2029 	return BUS_SET_RESOURCE(device_get_parent(dev), dev, type, rid,
2030 				start, count);
2031 }
2032 
2033 int
2034 bus_get_resource(device_t dev, int type, int rid,
2035 		 u_long *startp, u_long *countp)
2036 {
2037 	return BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2038 				startp, countp);
2039 }
2040 
2041 u_long
2042 bus_get_resource_start(device_t dev, int type, int rid)
2043 {
2044 	u_long start, count;
2045 	int error;
2046 
2047 	error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2048 				 &start, &count);
2049 	if (error)
2050 		return 0;
2051 	return start;
2052 }
2053 
2054 u_long
2055 bus_get_resource_count(device_t dev, int type, int rid)
2056 {
2057 	u_long start, count;
2058 	int error;
2059 
2060 	error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid,
2061 				 &start, &count);
2062 	if (error)
2063 		return 0;
2064 	return count;
2065 }
2066 
2067 void
2068 bus_delete_resource(device_t dev, int type, int rid)
2069 {
2070 	BUS_DELETE_RESOURCE(device_get_parent(dev), dev, type, rid);
2071 }
2072 
2073 static int
2074 root_print_child(device_t dev, device_t child)
2075 {
2076 	return (0);
2077 }
2078 
2079 static int
2080 root_setup_intr(device_t dev, device_t child, driver_intr_t *intr, void *arg,
2081 		void **cookiep)
2082 {
2083 	/*
2084 	 * If an interrupt mapping gets to here something bad has happened.
2085 	 */
2086 	panic("root_setup_intr");
2087 }
2088 
2089 static kobj_method_t root_methods[] = {
2090 	/* Device interface */
2091 	KOBJMETHOD(device_shutdown,	bus_generic_shutdown),
2092 	KOBJMETHOD(device_suspend,	bus_generic_suspend),
2093 	KOBJMETHOD(device_resume,	bus_generic_resume),
2094 
2095 	/* Bus interface */
2096 	KOBJMETHOD(bus_print_child,	root_print_child),
2097 	KOBJMETHOD(bus_read_ivar,	bus_generic_read_ivar),
2098 	KOBJMETHOD(bus_write_ivar,	bus_generic_write_ivar),
2099 	KOBJMETHOD(bus_setup_intr,	root_setup_intr),
2100 
2101 	{ 0, 0 }
2102 };
2103 
2104 static driver_t root_driver = {
2105 	"root",
2106 	root_methods,
2107 	1,			/* no softc */
2108 };
2109 
2110 device_t	root_bus;
2111 devclass_t	root_devclass;
2112 
2113 static int
2114 root_bus_module_handler(module_t mod, int what, void* arg)
2115 {
2116     switch (what) {
2117     case MOD_LOAD:
2118 	kobj_class_compile((kobj_class_t) &root_driver);
2119 	root_bus = make_device(NULL, "root", 0);
2120 	root_bus->desc = "System root bus";
2121 	kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver);
2122 	root_bus->driver = &root_driver;
2123 	root_bus->state = DS_ATTACHED;
2124 	root_devclass = devclass_find_internal("root", FALSE);
2125 	return 0;
2126 
2127     case MOD_SHUTDOWN:
2128 	device_shutdown(root_bus);
2129 	return 0;
2130     }
2131 
2132     return 0;
2133 }
2134 
2135 static moduledata_t root_bus_mod = {
2136 	"rootbus",
2137 	root_bus_module_handler,
2138 	0
2139 };
2140 DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
2141 
2142 void
2143 root_bus_configure(void)
2144 {
2145     device_t dev;
2146 
2147     PDEBUG(("."));
2148 
2149     TAILQ_FOREACH(dev, &root_bus->children, link) {
2150 	    device_probe_and_attach(dev);
2151     }
2152 }
2153 
2154 int
2155 driver_module_handler(module_t mod, int what, void *arg)
2156 {
2157 	int error, i;
2158 	struct driver_module_data *dmd;
2159 	devclass_t bus_devclass;
2160 
2161 	dmd = (struct driver_module_data *)arg;
2162 	bus_devclass = devclass_find_internal(dmd->dmd_busname, TRUE);
2163 	error = 0;
2164 
2165 	switch (what) {
2166 	case MOD_LOAD:
2167 		if (dmd->dmd_chainevh)
2168 			error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2169 
2170 		for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
2171 			PDEBUG(("Loading module: driver %s on bus %s",
2172 				DRIVERNAME(dmd->dmd_drivers[i]),
2173 				dmd->dmd_busname));
2174 			error = devclass_add_driver(bus_devclass,
2175 						    dmd->dmd_drivers[i]);
2176 		}
2177 		if (error)
2178 			break;
2179 
2180 		/*
2181 		 * The drivers loaded in this way are assumed to all
2182 		 * implement the same devclass.
2183 		 */
2184 		*dmd->dmd_devclass =
2185 			devclass_find_internal(dmd->dmd_drivers[0]->name,
2186 					       TRUE);
2187 		break;
2188 
2189 	case MOD_UNLOAD:
2190 		for (i = 0; !error && i < dmd->dmd_ndrivers; i++) {
2191 			PDEBUG(("Unloading module: driver %s from bus %s",
2192 				DRIVERNAME(dmd->dmd_drivers[i]),
2193 				dmd->dmd_busname));
2194 			error = devclass_delete_driver(bus_devclass,
2195 						       dmd->dmd_drivers[i]);
2196 		}
2197 
2198 		if (!error && dmd->dmd_chainevh)
2199 			error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2200 		break;
2201 	}
2202 
2203 	return (error);
2204 }
2205 
2206 #ifdef BUS_DEBUG
2207 
2208 /* the _short versions avoid iteration by not calling anything that prints
2209  * more than oneliners. I love oneliners.
2210  */
2211 
2212 static void
2213 print_device_short(device_t dev, int indent)
2214 {
2215 	if (!dev)
2216 		return;
2217 
2218 	indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%s,%sivars,%ssoftc,busy=%d\n",
2219 		dev->unit, dev->desc,
2220 		(dev->parent? "":"no "),
2221 		(TAILQ_EMPTY(&dev->children)? "no ":""),
2222 		(dev->flags&DF_ENABLED? "enabled,":"disabled,"),
2223 		(dev->flags&DF_FIXEDCLASS? "fixed,":""),
2224 		(dev->flags&DF_WILDCARD? "wildcard,":""),
2225 		(dev->flags&DF_DESCMALLOCED? "descmalloced,":""),
2226 		(dev->ivars? "":"no "),
2227 		(dev->softc? "":"no "),
2228 		dev->busy));
2229 }
2230 
2231 static void
2232 print_device(device_t dev, int indent)
2233 {
2234 	if (!dev)
2235 		return;
2236 
2237 	print_device_short(dev, indent);
2238 
2239 	indentprintf(("Parent:\n"));
2240 	print_device_short(dev->parent, indent+1);
2241 	indentprintf(("Driver:\n"));
2242 	print_driver_short(dev->driver, indent+1);
2243 	indentprintf(("Devclass:\n"));
2244 	print_devclass_short(dev->devclass, indent+1);
2245 }
2246 
2247 void
2248 print_device_tree_short(device_t dev, int indent)
2249 /* print the device and all its children (indented) */
2250 {
2251 	device_t child;
2252 
2253 	if (!dev)
2254 		return;
2255 
2256 	print_device_short(dev, indent);
2257 
2258 	TAILQ_FOREACH(child, &dev->children, link) {
2259 		print_device_tree_short(child, indent+1);
2260 	}
2261 }
2262 
2263 void
2264 print_device_tree(device_t dev, int indent)
2265 /* print the device and all its children (indented) */
2266 {
2267 	device_t child;
2268 
2269 	if (!dev)
2270 		return;
2271 
2272 	print_device(dev, indent);
2273 
2274 	TAILQ_FOREACH(child, &dev->children, link) {
2275 		print_device_tree(child, indent+1);
2276 	}
2277 }
2278 
2279 static void
2280 print_driver_short(driver_t *driver, int indent)
2281 {
2282 	if (!driver)
2283 		return;
2284 
2285 	indentprintf(("driver %s: softc size = %d\n",
2286 		driver->name, driver->size));
2287 }
2288 
2289 static void
2290 print_driver(driver_t *driver, int indent)
2291 {
2292 	if (!driver)
2293 		return;
2294 
2295 	print_driver_short(driver, indent);
2296 }
2297 
2298 
2299 static void
2300 print_driver_list(driver_list_t drivers, int indent)
2301 {
2302 	driverlink_t driver;
2303 
2304 	TAILQ_FOREACH(driver, &drivers, link) {
2305 		print_driver(driver->driver, indent);
2306 	}
2307 }
2308 
2309 static void
2310 print_devclass_short(devclass_t dc, int indent)
2311 {
2312 	if ( !dc )
2313 		return;
2314 
2315 	indentprintf(("devclass %s: max units = %d\n",
2316 		dc->name, dc->maxunit));
2317 }
2318 
2319 static void
2320 print_devclass(devclass_t dc, int indent)
2321 {
2322 	int i;
2323 
2324 	if ( !dc )
2325 		return;
2326 
2327 	print_devclass_short(dc, indent);
2328 	indentprintf(("Drivers:\n"));
2329 	print_driver_list(dc->drivers, indent+1);
2330 
2331 	indentprintf(("Devices:\n"));
2332 	for (i = 0; i < dc->maxunit; i++)
2333 		if (dc->devices[i])
2334 			print_device(dc->devices[i], indent+1);
2335 }
2336 
2337 void
2338 print_devclass_list_short(void)
2339 {
2340 	devclass_t dc;
2341 
2342 	printf("Short listing of devclasses, drivers & devices:\n");
2343 	TAILQ_FOREACH(dc, &devclasses, link) {
2344 		print_devclass_short(dc, 0);
2345 	}
2346 }
2347 
2348 void
2349 print_devclass_list(void)
2350 {
2351 	devclass_t dc;
2352 
2353 	printf("Full listing of devclasses, drivers & devices:\n");
2354 	TAILQ_FOREACH(dc, &devclasses, link) {
2355 		print_devclass(dc, 0);
2356 	}
2357 }
2358 
2359 #endif
2360