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