1 /* $OpenBSD: subr_autoconf.c,v 1.56 2008/08/20 04:37:15 miod Exp $ */ 2 /* $NetBSD: subr_autoconf.c,v 1.21 1996/04/04 06:06:18 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by the University of 15 * California, Lawrence Berkeley Laboratories. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) 42 * 43 * @(#)subr_autoconf.c 8.1 (Berkeley) 6/10/93 44 */ 45 46 #include <sys/param.h> 47 #include <sys/device.h> 48 #include <sys/hotplug.h> 49 #include <sys/limits.h> 50 #include <sys/malloc.h> 51 #include <sys/systm.h> 52 /* Extra stuff from Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de> */ 53 #include <sys/queue.h> 54 #include <sys/proc.h> 55 56 #include "hotplug.h" 57 58 /* 59 * Autoconfiguration subroutines. 60 */ 61 62 /* 63 * ioconf.c exports exactly two names: cfdata and cfroots. All system 64 * devices and drivers are found via these tables. 65 */ 66 extern short cfroots[]; 67 68 #define ROOT ((struct device *)NULL) 69 70 struct matchinfo { 71 cfmatch_t fn; 72 struct device *parent; 73 void *match, *aux; 74 int indirect, pri; 75 }; 76 77 struct cftable_head allcftables; 78 79 static struct cftable staticcftable = { 80 cfdata 81 }; 82 83 #ifndef AUTOCONF_VERBOSE 84 #define AUTOCONF_VERBOSE 0 85 #endif /* AUTOCONF_VERBOSE */ 86 int autoconf_verbose = AUTOCONF_VERBOSE; /* trace probe calls */ 87 88 static void mapply(struct matchinfo *, struct cfdata *); 89 90 struct deferred_config { 91 TAILQ_ENTRY(deferred_config) dc_queue; 92 struct device *dc_dev; 93 void (*dc_func)(struct device *); 94 }; 95 96 TAILQ_HEAD(, deferred_config) deferred_config_queue; 97 98 void config_process_deferred_children(struct device *); 99 100 struct devicelist alldevs; /* list of all devices */ 101 102 __volatile int config_pending; /* semaphore for mountroot */ 103 104 /* 105 * Initialize autoconfiguration data structures. This occurs before console 106 * initialization as that might require use of this subsystem. Furthermore 107 * this means that malloc et al. isn't yet available. 108 */ 109 void 110 config_init(void) 111 { 112 TAILQ_INIT(&deferred_config_queue); 113 TAILQ_INIT(&alldevs); 114 TAILQ_INIT(&allcftables); 115 TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list); 116 } 117 118 /* 119 * Apply the matching function and choose the best. This is used 120 * a few times and we want to keep the code small. 121 */ 122 void 123 mapply(struct matchinfo *m, struct cfdata *cf) 124 { 125 int pri; 126 void *match; 127 128 if (m->indirect) 129 match = config_make_softc(m->parent, cf); 130 else 131 match = cf; 132 133 if (autoconf_verbose) { 134 printf(">>> probing for %s", cf->cf_driver->cd_name); 135 if (cf->cf_fstate == FSTATE_STAR) 136 printf("*\n"); 137 else 138 printf("%d\n", cf->cf_unit); 139 } 140 if (m->fn != NULL) 141 pri = (*m->fn)(m->parent, match, m->aux); 142 else { 143 if (cf->cf_attach->ca_match == NULL) { 144 panic("mapply: no match function for '%s' device", 145 cf->cf_driver->cd_name); 146 } 147 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux); 148 } 149 if (autoconf_verbose) 150 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name, 151 pri); 152 153 if (pri > m->pri) { 154 if (m->indirect && m->match) 155 free(m->match, M_DEVBUF); 156 m->match = match; 157 m->pri = pri; 158 } else { 159 if (m->indirect) 160 free(match, M_DEVBUF); 161 } 162 } 163 164 /* 165 * Iterate over all potential children of some device, calling the given 166 * function (default being the child's match function) for each one. 167 * Nonzero returns are matches; the highest value returned is considered 168 * the best match. Return the `found child' if we got a match, or NULL 169 * otherwise. The `aux' pointer is simply passed on through. 170 * 171 * Note that this function is designed so that it can be used to apply 172 * an arbitrary function to all potential children (its return value 173 * can be ignored). 174 */ 175 void * 176 config_search(cfmatch_t fn, struct device *parent, void *aux) 177 { 178 struct cfdata *cf; 179 short *p; 180 struct matchinfo m; 181 struct cftable *t; 182 183 m.fn = fn; 184 m.parent = parent; 185 m.match = NULL; 186 m.aux = aux; 187 m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect; 188 m.pri = 0; 189 TAILQ_FOREACH(t, &allcftables, list) { 190 for (cf = t->tab; cf->cf_driver; cf++) { 191 /* 192 * Skip cf if no longer eligible, otherwise scan 193 * through parents for one matching `parent', 194 * and try match function. 195 */ 196 if (cf->cf_fstate == FSTATE_FOUND) 197 continue; 198 if (cf->cf_fstate == FSTATE_DNOTFOUND || 199 cf->cf_fstate == FSTATE_DSTAR) 200 continue; 201 for (p = cf->cf_parents; *p >= 0; p++) 202 if (parent->dv_cfdata == &(t->tab)[*p]) 203 mapply(&m, cf); 204 } 205 } 206 if (autoconf_verbose) { 207 if (m.match) { 208 if (m.indirect) 209 cf = ((struct device *)m.match)->dv_cfdata; 210 else 211 cf = (struct cfdata *)m.match; 212 printf(">>> %s probe won\n", 213 cf->cf_driver->cd_name); 214 } else 215 printf(">>> no winning probe\n"); 216 } 217 return (m.match); 218 } 219 220 /* 221 * Iterate over all potential children of some device, calling the given 222 * function for each one. 223 * 224 * Note that this function is designed so that it can be used to apply 225 * an arbitrary function to all potential children (its return value 226 * can be ignored). 227 */ 228 void 229 config_scan(cfscan_t fn, struct device *parent) 230 { 231 struct cfdata *cf; 232 short *p; 233 void *match; 234 int indirect; 235 struct cftable *t; 236 237 indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect; 238 TAILQ_FOREACH(t, &allcftables, list) { 239 for (cf = t->tab; cf->cf_driver; cf++) { 240 /* 241 * Skip cf if no longer eligible, otherwise scan 242 * through parents for one matching `parent', 243 * and try match function. 244 */ 245 if (cf->cf_fstate == FSTATE_FOUND) 246 continue; 247 if (cf->cf_fstate == FSTATE_DNOTFOUND || 248 cf->cf_fstate == FSTATE_DSTAR) 249 continue; 250 for (p = cf->cf_parents; *p >= 0; p++) 251 if (parent->dv_cfdata == &(t->tab)[*p]) { 252 match = indirect? 253 config_make_softc(parent, cf) : 254 (void *)cf; 255 (*fn)(parent, match); 256 } 257 } 258 } 259 } 260 261 /* 262 * Find the given root device. 263 * This is much like config_search, but there is no parent. 264 */ 265 void * 266 config_rootsearch(cfmatch_t fn, char *rootname, void *aux) 267 { 268 struct cfdata *cf; 269 short *p; 270 struct matchinfo m; 271 272 m.fn = fn; 273 m.parent = ROOT; 274 m.match = NULL; 275 m.aux = aux; 276 m.indirect = 0; 277 m.pri = 0; 278 /* 279 * Look at root entries for matching name. We do not bother 280 * with found-state here since only one instance of each possible 281 * root child should ever be searched. 282 */ 283 for (p = cfroots; *p >= 0; p++) { 284 cf = &cfdata[*p]; 285 if (cf->cf_fstate == FSTATE_DNOTFOUND || 286 cf->cf_fstate == FSTATE_DSTAR) 287 continue; 288 if (strcmp(cf->cf_driver->cd_name, rootname) == 0) 289 mapply(&m, cf); 290 } 291 return (m.match); 292 } 293 294 char *msgs[3] = { "", " not configured\n", " unsupported\n" }; 295 296 /* 297 * The given `aux' argument describes a device that has been found 298 * on the given parent, but not necessarily configured. Locate the 299 * configuration data for that device (using the submatch function 300 * provided, or using candidates' cd_match configuration driver 301 * functions) and attach it, and return true. If the device was 302 * not configured, call the given `print' function and return 0. 303 */ 304 struct device * 305 config_found_sm(struct device *parent, void *aux, cfprint_t print, 306 cfmatch_t submatch) 307 { 308 void *match; 309 310 if ((match = config_search(submatch, parent, aux)) != NULL) 311 return (config_attach(parent, match, aux, print)); 312 if (print) 313 printf(msgs[(*print)(aux, parent->dv_xname)]); 314 return (NULL); 315 } 316 317 /* 318 * As above, but for root devices. 319 */ 320 struct device * 321 config_rootfound(char *rootname, void *aux) 322 { 323 void *match; 324 325 if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) 326 return (config_attach(ROOT, match, aux, (cfprint_t)NULL)); 327 printf("root device %s not configured\n", rootname); 328 return (NULL); 329 } 330 331 /* 332 * Attach a found device. Allocates memory for device variables. 333 */ 334 struct device * 335 config_attach(struct device *parent, void *match, void *aux, cfprint_t print) 336 { 337 struct cfdata *cf; 338 struct device *dev; 339 struct cfdriver *cd; 340 struct cfattach *ca; 341 struct cftable *t; 342 343 if (parent && parent->dv_cfdata->cf_driver->cd_indirect) { 344 dev = match; 345 cf = dev->dv_cfdata; 346 } else { 347 cf = match; 348 dev = config_make_softc(parent, cf); 349 } 350 351 cd = cf->cf_driver; 352 ca = cf->cf_attach; 353 354 cd->cd_devs[dev->dv_unit] = dev; 355 356 /* 357 * If this is a "STAR" device and we used the last unit, prepare for 358 * another one. 359 */ 360 if (cf->cf_fstate == FSTATE_STAR) { 361 if (dev->dv_unit == cf->cf_unit) 362 cf->cf_unit++; 363 } else 364 cf->cf_fstate = FSTATE_FOUND; 365 366 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); 367 device_ref(dev); 368 369 if (parent == ROOT) 370 printf("%s at root", dev->dv_xname); 371 else { 372 printf("%s at %s", dev->dv_xname, parent->dv_xname); 373 if (print) 374 (void) (*print)(aux, (char *)0); 375 } 376 377 /* 378 * Before attaching, clobber any unfound devices that are 379 * otherwise identical, or bump the unit number on all starred 380 * cfdata for this device. 381 */ 382 TAILQ_FOREACH(t, &allcftables, list) { 383 for (cf = t->tab; cf->cf_driver; cf++) 384 if (cf->cf_driver == cd && 385 cf->cf_unit == dev->dv_unit) { 386 if (cf->cf_fstate == FSTATE_NOTFOUND) 387 cf->cf_fstate = FSTATE_FOUND; 388 if (cf->cf_fstate == FSTATE_STAR) 389 cf->cf_unit++; 390 } 391 } 392 device_register(dev, aux); 393 (*ca->ca_attach)(parent, dev, aux); 394 config_process_deferred_children(dev); 395 #if NHOTPLUG > 0 396 if (!cold) 397 hotplug_device_attach(cd->cd_class, dev->dv_xname); 398 #endif 399 return (dev); 400 } 401 402 struct device * 403 config_make_softc(struct device *parent, struct cfdata *cf) 404 { 405 struct device *dev; 406 struct cfdriver *cd; 407 struct cfattach *ca; 408 409 cd = cf->cf_driver; 410 ca = cf->cf_attach; 411 if (ca->ca_devsize < sizeof(struct device)) 412 panic("config_make_softc"); 413 414 /* get memory for all device vars */ 415 dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO); 416 if (!dev) 417 panic("config_make_softc: allocation for device softc failed"); 418 419 dev->dv_class = cd->cd_class; 420 dev->dv_cfdata = cf; 421 dev->dv_flags = DVF_ACTIVE; /* always initially active */ 422 423 /* If this is a STAR device, search for a free unit number */ 424 if (cf->cf_fstate == FSTATE_STAR) { 425 for (dev->dv_unit = cf->cf_starunit1; 426 dev->dv_unit < cf->cf_unit; dev->dv_unit++) 427 if (cd->cd_ndevs == 0 || 428 dev->dv_unit >= cd->cd_ndevs || 429 cd->cd_devs[dev->dv_unit] == NULL) 430 break; 431 } else 432 dev->dv_unit = cf->cf_unit; 433 434 /* Build the device name into dv_xname. */ 435 if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", 436 cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname)) 437 panic("config_make_softc: device name too long"); 438 dev->dv_parent = parent; 439 440 /* put this device in the devices array */ 441 if (dev->dv_unit >= cd->cd_ndevs) { 442 /* 443 * Need to expand the array. 444 */ 445 int old = cd->cd_ndevs, new; 446 void **nsp; 447 448 if (old == 0) 449 new = MINALLOCSIZE / sizeof(void *); 450 else 451 new = old * 2; 452 while (new <= dev->dv_unit) 453 new *= 2; 454 cd->cd_ndevs = new; 455 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO); 456 if (nsp == 0) 457 panic("config_make_softc: %sing dev array", 458 old != 0 ? "expand" : "creat"); 459 if (old != 0) { 460 bcopy(cd->cd_devs, nsp, old * sizeof(void *)); 461 free(cd->cd_devs, M_DEVBUF); 462 } 463 cd->cd_devs = nsp; 464 } 465 if (cd->cd_devs[dev->dv_unit]) 466 panic("config_make_softc: duplicate %s", dev->dv_xname); 467 468 dev->dv_ref = 1; 469 470 return (dev); 471 } 472 473 /* 474 * Detach a device. Optionally forced (e.g. because of hardware 475 * removal) and quiet. Returns zero if successful, non-zero 476 * (an error code) otherwise. 477 * 478 * Note that this code wants to be run from a process context, so 479 * that the detach can sleep to allow processes which have a device 480 * open to run and unwind their stacks. 481 */ 482 int 483 config_detach(struct device *dev, int flags) 484 { 485 struct cfdata *cf; 486 struct cfattach *ca; 487 struct cfdriver *cd; 488 int rv = 0, i; 489 #ifdef DIAGNOSTIC 490 struct device *d; 491 #endif 492 #if NHOTPLUG > 0 493 char devname[16]; 494 #endif 495 496 #if NHOTPLUG > 0 497 strlcpy(devname, dev->dv_xname, sizeof(devname)); 498 #endif 499 500 cf = dev->dv_cfdata; 501 #ifdef DIAGNOSTIC 502 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR) 503 panic("config_detach: bad device fstate"); 504 #endif 505 ca = cf->cf_attach; 506 cd = cf->cf_driver; 507 508 /* 509 * Ensure the device is deactivated. If the device doesn't 510 * have an activation entry point, we allow DVF_ACTIVE to 511 * remain set. Otherwise, if DVF_ACTIVE is still set, the 512 * device is busy, and the detach fails. 513 */ 514 if (ca->ca_activate != NULL) 515 rv = config_deactivate(dev); 516 517 /* 518 * Try to detach the device. If that's not possible, then 519 * we either panic() (for the forced but failed case), or 520 * return an error. 521 */ 522 if (rv == 0) { 523 if (ca->ca_detach != NULL) 524 rv = (*ca->ca_detach)(dev, flags); 525 else 526 rv = EOPNOTSUPP; 527 } 528 if (rv != 0) { 529 if ((flags & DETACH_FORCE) == 0) 530 return (rv); 531 else 532 panic("config_detach: forced detach of %s failed (%d)", 533 dev->dv_xname, rv); 534 } 535 536 /* 537 * The device has now been successfully detached. 538 */ 539 540 #ifdef DIAGNOSTIC 541 /* 542 * Sanity: If you're successfully detached, you should have no 543 * children. (Note that because children must be attached 544 * after parents, we only need to search the latter part of 545 * the list.) 546 */ 547 for (d = TAILQ_NEXT(dev, dv_list); d != NULL; 548 d = TAILQ_NEXT(d, dv_list)) { 549 if (d->dv_parent == dev) 550 panic("config_detach: detached device has children"); 551 } 552 #endif 553 554 /* 555 * Mark cfdata to show that the unit can be reused, if possible. 556 * Note that we can only re-use a starred unit number if the unit 557 * being detached had the last assigned unit number. 558 */ 559 for (cf = cfdata; cf->cf_driver; cf++) { 560 if (cf->cf_driver == cd) { 561 if (cf->cf_fstate == FSTATE_FOUND && 562 cf->cf_unit == dev->dv_unit) 563 cf->cf_fstate = FSTATE_NOTFOUND; 564 if (cf->cf_fstate == FSTATE_STAR && 565 cf->cf_unit == dev->dv_unit + 1) 566 cf->cf_unit--; 567 } 568 } 569 570 /* 571 * Unlink from device list. 572 */ 573 TAILQ_REMOVE(&alldevs, dev, dv_list); 574 device_unref(dev); 575 576 /* 577 * Remove from cfdriver's array, tell the world, and free softc. 578 */ 579 cd->cd_devs[dev->dv_unit] = NULL; 580 if ((flags & DETACH_QUIET) == 0) 581 printf("%s detached\n", dev->dv_xname); 582 583 device_unref(dev); 584 /* 585 * If the device now has no units in use, deallocate its softc array. 586 */ 587 for (i = 0; i < cd->cd_ndevs; i++) 588 if (cd->cd_devs[i] != NULL) 589 break; 590 if (i == cd->cd_ndevs) { /* nothing found; deallocate */ 591 free(cd->cd_devs, M_DEVBUF); 592 cd->cd_devs = NULL; 593 cd->cd_ndevs = 0; 594 cf->cf_unit = 0; 595 } 596 597 #if NHOTPLUG > 0 598 if (!cold) 599 hotplug_device_detach(cd->cd_class, devname); 600 #endif 601 602 /* 603 * Return success. 604 */ 605 return (0); 606 } 607 608 int 609 config_activate(struct device *dev) 610 { 611 struct cfattach *ca = dev->dv_cfdata->cf_attach; 612 int rv = 0, oflags = dev->dv_flags; 613 614 if (ca->ca_activate == NULL) 615 return (EOPNOTSUPP); 616 617 if ((dev->dv_flags & DVF_ACTIVE) == 0) { 618 dev->dv_flags |= DVF_ACTIVE; 619 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE); 620 if (rv) 621 dev->dv_flags = oflags; 622 } 623 return (rv); 624 } 625 626 int 627 config_deactivate(struct device *dev) 628 { 629 struct cfattach *ca = dev->dv_cfdata->cf_attach; 630 int rv = 0, oflags = dev->dv_flags; 631 632 if (ca->ca_activate == NULL) 633 return (EOPNOTSUPP); 634 635 if (dev->dv_flags & DVF_ACTIVE) { 636 dev->dv_flags &= ~DVF_ACTIVE; 637 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE); 638 if (rv) 639 dev->dv_flags = oflags; 640 } 641 return (rv); 642 } 643 644 /* 645 * Defer the configuration of the specified device until all 646 * of its parent's devices have been attached. 647 */ 648 void 649 config_defer(struct device *dev, void (*func)(struct device *)) 650 { 651 struct deferred_config *dc; 652 653 if (dev->dv_parent == NULL) 654 panic("config_defer: can't defer config of a root device"); 655 656 #ifdef DIAGNOSTIC 657 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL; 658 dc = TAILQ_NEXT(dc, dc_queue)) { 659 if (dc->dc_dev == dev) 660 panic("config_defer: deferred twice"); 661 } 662 #endif 663 664 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL) 665 panic("config_defer: can't allocate defer structure"); 666 667 dc->dc_dev = dev; 668 dc->dc_func = func; 669 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue); 670 config_pending_incr(); 671 } 672 673 /* 674 * Process the deferred configuration queue for a device. 675 */ 676 void 677 config_process_deferred_children(struct device *parent) 678 { 679 struct deferred_config *dc, *ndc; 680 681 for (dc = TAILQ_FIRST(&deferred_config_queue); 682 dc != NULL; dc = ndc) { 683 ndc = TAILQ_NEXT(dc, dc_queue); 684 if (dc->dc_dev->dv_parent == parent) { 685 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue); 686 (*dc->dc_func)(dc->dc_dev); 687 free(dc, M_DEVBUF); 688 config_pending_decr(); 689 } 690 } 691 } 692 693 /* 694 * Manipulate the config_pending semaphore. 695 */ 696 void 697 config_pending_incr(void) 698 { 699 700 config_pending++; 701 } 702 703 void 704 config_pending_decr(void) 705 { 706 707 #ifdef DIAGNOSTIC 708 if (config_pending == 0) 709 panic("config_pending_decr: config_pending == 0"); 710 #endif 711 config_pending--; 712 if (config_pending == 0) 713 wakeup((void *)&config_pending); 714 } 715 716 int 717 config_detach_children(struct device *parent, int flags) 718 { 719 struct device *dev, *next_dev; 720 int rv = 0; 721 722 /* 723 * The config_detach routine may sleep, meaning devices 724 * may be added to the queue. However, all devices will 725 * be added to the tail of the queue, the queue won't 726 * be re-organized, and the subtree of parent here should be locked 727 * for purposes of adding/removing children. 728 * 729 * Note that we can not afford trying to walk the device list 730 * once - our ``next'' device might be a child of the device 731 * we are about to detach, so it would disappear. 732 * Just play it safe and restart from the parent. 733 */ 734 for (dev = TAILQ_LAST(&alldevs, devicelist); 735 dev != NULL; dev = next_dev) { 736 if (dev->dv_parent == parent) { 737 if ((rv = config_detach(dev, flags)) != 0) 738 return (rv); 739 next_dev = TAILQ_LAST(&alldevs, devicelist); 740 } else { 741 next_dev = TAILQ_PREV(dev, devicelist, dv_list); 742 } 743 } 744 745 return (0); 746 } 747 748 int 749 config_activate_children(struct device *parent, enum devact act) 750 { 751 struct device *dev, *next_dev; 752 int rv = 0; 753 754 /* The config_deactivate routine may sleep, meaning devices 755 may be added to the queue. However, all devices will 756 be added to the tail of the queue, the queue won't 757 be re-organized, and the subtree of parent here should be locked 758 for purposes of adding/removing children. 759 */ 760 for (dev = TAILQ_FIRST(&alldevs); 761 dev != NULL; dev = next_dev) { 762 next_dev = TAILQ_NEXT(dev, dv_list); 763 if (dev->dv_parent == parent) { 764 switch (act) { 765 case DVACT_ACTIVATE: 766 rv = config_activate(dev); 767 break; 768 case DVACT_DEACTIVATE: 769 rv = config_deactivate(dev); 770 break; 771 default: 772 #ifdef DIAGNOSTIC 773 printf ("config_activate_children: shouldn't get here"); 774 #endif 775 rv = EOPNOTSUPP; 776 break; 777 778 } 779 780 if (rv) 781 break; 782 } 783 } 784 785 return (rv); 786 } 787 788 /* 789 * Lookup a device in the cfdriver device array. Does not return a 790 * device if it is not active. 791 * 792 * Increments ref count on the device by one, reflecting the 793 * new reference created on the stack. 794 * 795 * Context: process only 796 */ 797 struct device * 798 device_lookup(struct cfdriver *cd, int unit) 799 { 800 struct device *dv = NULL; 801 802 if (unit >= 0 && unit < cd->cd_ndevs) 803 dv = (struct device *)(cd->cd_devs[unit]); 804 805 if (!dv) 806 return (NULL); 807 808 if (!(dv->dv_flags & DVF_ACTIVE)) 809 dv = NULL; 810 811 if (dv != NULL) 812 device_ref(dv); 813 814 return (dv); 815 } 816 817 818 /* 819 * Increments the ref count on the device structure. The device 820 * structure is freed when the ref count hits 0. 821 * 822 * Context: process or interrupt 823 */ 824 void 825 device_ref(struct device *dv) 826 { 827 dv->dv_ref++; 828 } 829 830 /* 831 * Decrement the ref count on the device structure. 832 * 833 * free's the structure when the ref count hits zero. 834 * 835 * Context: process or interrupt 836 */ 837 void 838 device_unref(struct device *dv) 839 { 840 dv->dv_ref--; 841 if (dv->dv_ref == 0) { 842 free(dv, M_DEVBUF); 843 } 844 } 845