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