1 /* $OpenBSD: subr_autoconf.c,v 1.55 2007/11/23 18:21:43 kettenis 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 root should ever be 281 * searched (and it must be done first). 282 */ 283 for (p = cfroots; *p >= 0; p++) { 284 cf = &cfdata[*p]; 285 if (strcmp(cf->cf_driver->cd_name, rootname) == 0) 286 mapply(&m, cf); 287 } 288 return (m.match); 289 } 290 291 char *msgs[3] = { "", " not configured\n", " unsupported\n" }; 292 293 /* 294 * The given `aux' argument describes a device that has been found 295 * on the given parent, but not necessarily configured. Locate the 296 * configuration data for that device (using the submatch function 297 * provided, or using candidates' cd_match configuration driver 298 * functions) and attach it, and return true. If the device was 299 * not configured, call the given `print' function and return 0. 300 */ 301 struct device * 302 config_found_sm(struct device *parent, void *aux, cfprint_t print, 303 cfmatch_t submatch) 304 { 305 void *match; 306 307 if ((match = config_search(submatch, parent, aux)) != NULL) 308 return (config_attach(parent, match, aux, print)); 309 if (print) 310 printf(msgs[(*print)(aux, parent->dv_xname)]); 311 return (NULL); 312 } 313 314 /* 315 * As above, but for root devices. 316 */ 317 struct device * 318 config_rootfound(char *rootname, void *aux) 319 { 320 void *match; 321 322 if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) 323 return (config_attach(ROOT, match, aux, (cfprint_t)NULL)); 324 printf("root device %s not configured\n", rootname); 325 return (NULL); 326 } 327 328 /* 329 * Attach a found device. Allocates memory for device variables. 330 */ 331 struct device * 332 config_attach(struct device *parent, void *match, void *aux, cfprint_t print) 333 { 334 struct cfdata *cf; 335 struct device *dev; 336 struct cfdriver *cd; 337 struct cfattach *ca; 338 struct cftable *t; 339 340 if (parent && parent->dv_cfdata->cf_driver->cd_indirect) { 341 dev = match; 342 cf = dev->dv_cfdata; 343 } else { 344 cf = match; 345 dev = config_make_softc(parent, cf); 346 } 347 348 cd = cf->cf_driver; 349 ca = cf->cf_attach; 350 351 cd->cd_devs[dev->dv_unit] = dev; 352 353 /* 354 * If this is a "STAR" device and we used the last unit, prepare for 355 * another one. 356 */ 357 if (cf->cf_fstate == FSTATE_STAR) { 358 if (dev->dv_unit == cf->cf_unit) 359 cf->cf_unit++; 360 } else 361 cf->cf_fstate = FSTATE_FOUND; 362 363 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); 364 device_ref(dev); 365 366 if (parent == ROOT) 367 printf("%s at root", dev->dv_xname); 368 else { 369 printf("%s at %s", dev->dv_xname, parent->dv_xname); 370 if (print) 371 (void) (*print)(aux, (char *)0); 372 } 373 374 /* 375 * Before attaching, clobber any unfound devices that are 376 * otherwise identical, or bump the unit number on all starred 377 * cfdata for this device. 378 */ 379 TAILQ_FOREACH(t, &allcftables, list) { 380 for (cf = t->tab; cf->cf_driver; cf++) 381 if (cf->cf_driver == cd && 382 cf->cf_unit == dev->dv_unit) { 383 if (cf->cf_fstate == FSTATE_NOTFOUND) 384 cf->cf_fstate = FSTATE_FOUND; 385 if (cf->cf_fstate == FSTATE_STAR) 386 cf->cf_unit++; 387 } 388 } 389 device_register(dev, aux); 390 (*ca->ca_attach)(parent, dev, aux); 391 config_process_deferred_children(dev); 392 #if NHOTPLUG > 0 393 if (!cold) 394 hotplug_device_attach(cd->cd_class, dev->dv_xname); 395 #endif 396 return (dev); 397 } 398 399 struct device * 400 config_make_softc(struct device *parent, struct cfdata *cf) 401 { 402 struct device *dev; 403 struct cfdriver *cd; 404 struct cfattach *ca; 405 406 cd = cf->cf_driver; 407 ca = cf->cf_attach; 408 if (ca->ca_devsize < sizeof(struct device)) 409 panic("config_make_softc"); 410 411 /* get memory for all device vars */ 412 dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO); 413 if (!dev) 414 panic("config_make_softc: allocation for device softc failed"); 415 416 dev->dv_class = cd->cd_class; 417 dev->dv_cfdata = cf; 418 dev->dv_flags = DVF_ACTIVE; /* always initially active */ 419 420 /* If this is a STAR device, search for a free unit number */ 421 if (cf->cf_fstate == FSTATE_STAR) { 422 for (dev->dv_unit = cf->cf_starunit1; 423 dev->dv_unit < cf->cf_unit; dev->dv_unit++) 424 if (cd->cd_ndevs == 0 || 425 dev->dv_unit >= cd->cd_ndevs || 426 cd->cd_devs[dev->dv_unit] == NULL) 427 break; 428 } else 429 dev->dv_unit = cf->cf_unit; 430 431 /* Build the device name into dv_xname. */ 432 if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", 433 cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname)) 434 panic("config_make_softc: device name too long"); 435 dev->dv_parent = parent; 436 437 /* put this device in the devices array */ 438 if (dev->dv_unit >= cd->cd_ndevs) { 439 /* 440 * Need to expand the array. 441 */ 442 int old = cd->cd_ndevs, new; 443 void **nsp; 444 445 if (old == 0) 446 new = MINALLOCSIZE / sizeof(void *); 447 else 448 new = old * 2; 449 while (new <= dev->dv_unit) 450 new *= 2; 451 cd->cd_ndevs = new; 452 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO); 453 if (nsp == 0) 454 panic("config_make_softc: %sing dev array", 455 old != 0 ? "expand" : "creat"); 456 if (old != 0) { 457 bcopy(cd->cd_devs, nsp, old * sizeof(void *)); 458 free(cd->cd_devs, M_DEVBUF); 459 } 460 cd->cd_devs = nsp; 461 } 462 if (cd->cd_devs[dev->dv_unit]) 463 panic("config_make_softc: duplicate %s", dev->dv_xname); 464 465 dev->dv_ref = 1; 466 467 return (dev); 468 } 469 470 /* 471 * Detach a device. Optionally forced (e.g. because of hardware 472 * removal) and quiet. Returns zero if successful, non-zero 473 * (an error code) otherwise. 474 * 475 * Note that this code wants to be run from a process context, so 476 * that the detach can sleep to allow processes which have a device 477 * open to run and unwind their stacks. 478 */ 479 int 480 config_detach(struct device *dev, int flags) 481 { 482 struct cfdata *cf; 483 struct cfattach *ca; 484 struct cfdriver *cd; 485 int rv = 0, i; 486 #ifdef DIAGNOSTIC 487 struct device *d; 488 #endif 489 #if NHOTPLUG > 0 490 char devname[16]; 491 #endif 492 493 #if NHOTPLUG > 0 494 strlcpy(devname, dev->dv_xname, sizeof(devname)); 495 #endif 496 497 cf = dev->dv_cfdata; 498 #ifdef DIAGNOSTIC 499 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR) 500 panic("config_detach: bad device fstate"); 501 #endif 502 ca = cf->cf_attach; 503 cd = cf->cf_driver; 504 505 /* 506 * Ensure the device is deactivated. If the device doesn't 507 * have an activation entry point, we allow DVF_ACTIVE to 508 * remain set. Otherwise, if DVF_ACTIVE is still set, the 509 * device is busy, and the detach fails. 510 */ 511 if (ca->ca_activate != NULL) 512 rv = config_deactivate(dev); 513 514 /* 515 * Try to detach the device. If that's not possible, then 516 * we either panic() (for the forced but failed case), or 517 * return an error. 518 */ 519 if (rv == 0) { 520 if (ca->ca_detach != NULL) 521 rv = (*ca->ca_detach)(dev, flags); 522 else 523 rv = EOPNOTSUPP; 524 } 525 if (rv != 0) { 526 if ((flags & DETACH_FORCE) == 0) 527 return (rv); 528 else 529 panic("config_detach: forced detach of %s failed (%d)", 530 dev->dv_xname, rv); 531 } 532 533 /* 534 * The device has now been successfully detached. 535 */ 536 537 #ifdef DIAGNOSTIC 538 /* 539 * Sanity: If you're successfully detached, you should have no 540 * children. (Note that because children must be attached 541 * after parents, we only need to search the latter part of 542 * the list.) 543 */ 544 for (d = TAILQ_NEXT(dev, dv_list); d != NULL; 545 d = TAILQ_NEXT(d, dv_list)) { 546 if (d->dv_parent == dev) 547 panic("config_detach: detached device has children"); 548 } 549 #endif 550 551 /* 552 * Mark cfdata to show that the unit can be reused, if possible. 553 * Note that we can only re-use a starred unit number if the unit 554 * being detached had the last assigned unit number. 555 */ 556 for (cf = cfdata; cf->cf_driver; cf++) { 557 if (cf->cf_driver == cd) { 558 if (cf->cf_fstate == FSTATE_FOUND && 559 cf->cf_unit == dev->dv_unit) 560 cf->cf_fstate = FSTATE_NOTFOUND; 561 if (cf->cf_fstate == FSTATE_STAR && 562 cf->cf_unit == dev->dv_unit + 1) 563 cf->cf_unit--; 564 } 565 } 566 567 /* 568 * Unlink from device list. 569 */ 570 TAILQ_REMOVE(&alldevs, dev, dv_list); 571 device_unref(dev); 572 573 /* 574 * Remove from cfdriver's array, tell the world, and free softc. 575 */ 576 cd->cd_devs[dev->dv_unit] = NULL; 577 if ((flags & DETACH_QUIET) == 0) 578 printf("%s detached\n", dev->dv_xname); 579 580 device_unref(dev); 581 /* 582 * If the device now has no units in use, deallocate its softc array. 583 */ 584 for (i = 0; i < cd->cd_ndevs; i++) 585 if (cd->cd_devs[i] != NULL) 586 break; 587 if (i == cd->cd_ndevs) { /* nothing found; deallocate */ 588 free(cd->cd_devs, M_DEVBUF); 589 cd->cd_devs = NULL; 590 cd->cd_ndevs = 0; 591 cf->cf_unit = 0; 592 } 593 594 #if NHOTPLUG > 0 595 if (!cold) 596 hotplug_device_detach(cd->cd_class, devname); 597 #endif 598 599 /* 600 * Return success. 601 */ 602 return (0); 603 } 604 605 int 606 config_activate(struct device *dev) 607 { 608 struct cfattach *ca = dev->dv_cfdata->cf_attach; 609 int rv = 0, oflags = dev->dv_flags; 610 611 if (ca->ca_activate == NULL) 612 return (EOPNOTSUPP); 613 614 if ((dev->dv_flags & DVF_ACTIVE) == 0) { 615 dev->dv_flags |= DVF_ACTIVE; 616 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE); 617 if (rv) 618 dev->dv_flags = oflags; 619 } 620 return (rv); 621 } 622 623 int 624 config_deactivate(struct device *dev) 625 { 626 struct cfattach *ca = dev->dv_cfdata->cf_attach; 627 int rv = 0, oflags = dev->dv_flags; 628 629 if (ca->ca_activate == NULL) 630 return (EOPNOTSUPP); 631 632 if (dev->dv_flags & DVF_ACTIVE) { 633 dev->dv_flags &= ~DVF_ACTIVE; 634 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE); 635 if (rv) 636 dev->dv_flags = oflags; 637 } 638 return (rv); 639 } 640 641 /* 642 * Defer the configuration of the specified device until all 643 * of its parent's devices have been attached. 644 */ 645 void 646 config_defer(struct device *dev, void (*func)(struct device *)) 647 { 648 struct deferred_config *dc; 649 650 if (dev->dv_parent == NULL) 651 panic("config_defer: can't defer config of a root device"); 652 653 #ifdef DIAGNOSTIC 654 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL; 655 dc = TAILQ_NEXT(dc, dc_queue)) { 656 if (dc->dc_dev == dev) 657 panic("config_defer: deferred twice"); 658 } 659 #endif 660 661 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL) 662 panic("config_defer: can't allocate defer structure"); 663 664 dc->dc_dev = dev; 665 dc->dc_func = func; 666 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue); 667 config_pending_incr(); 668 } 669 670 /* 671 * Process the deferred configuration queue for a device. 672 */ 673 void 674 config_process_deferred_children(struct device *parent) 675 { 676 struct deferred_config *dc, *ndc; 677 678 for (dc = TAILQ_FIRST(&deferred_config_queue); 679 dc != NULL; dc = ndc) { 680 ndc = TAILQ_NEXT(dc, dc_queue); 681 if (dc->dc_dev->dv_parent == parent) { 682 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue); 683 (*dc->dc_func)(dc->dc_dev); 684 free(dc, M_DEVBUF); 685 config_pending_decr(); 686 } 687 } 688 } 689 690 /* 691 * Manipulate the config_pending semaphore. 692 */ 693 void 694 config_pending_incr(void) 695 { 696 697 config_pending++; 698 } 699 700 void 701 config_pending_decr(void) 702 { 703 704 #ifdef DIAGNOSTIC 705 if (config_pending == 0) 706 panic("config_pending_decr: config_pending == 0"); 707 #endif 708 config_pending--; 709 if (config_pending == 0) 710 wakeup((void *)&config_pending); 711 } 712 713 int 714 config_detach_children(struct device *parent, int flags) 715 { 716 struct device *dev, *next_dev; 717 int rv = 0; 718 719 /* 720 * The config_detach routine may sleep, meaning devices 721 * may be added to the queue. However, all devices will 722 * be added to the tail of the queue, the queue won't 723 * be re-organized, and the subtree of parent here should be locked 724 * for purposes of adding/removing children. 725 * 726 * Note that we can not afford trying to walk the device list 727 * once - our ``next'' device might be a child of the device 728 * we are about to detach, so it would disappear. 729 * Just play it safe and restart from the parent. 730 */ 731 for (dev = TAILQ_LAST(&alldevs, devicelist); 732 dev != NULL; dev = next_dev) { 733 if (dev->dv_parent == parent) { 734 if ((rv = config_detach(dev, flags)) != 0) 735 return (rv); 736 next_dev = TAILQ_LAST(&alldevs, devicelist); 737 } else { 738 next_dev = TAILQ_PREV(dev, devicelist, dv_list); 739 } 740 } 741 742 return (0); 743 } 744 745 int 746 config_activate_children(struct device *parent, enum devact act) 747 { 748 struct device *dev, *next_dev; 749 int rv = 0; 750 751 /* The config_deactivate routine may sleep, meaning devices 752 may be added to the queue. However, all devices will 753 be added to the tail of the queue, the queue won't 754 be re-organized, and the subtree of parent here should be locked 755 for purposes of adding/removing children. 756 */ 757 for (dev = TAILQ_FIRST(&alldevs); 758 dev != NULL; dev = next_dev) { 759 next_dev = TAILQ_NEXT(dev, dv_list); 760 if (dev->dv_parent == parent) { 761 switch (act) { 762 case DVACT_ACTIVATE: 763 rv = config_activate(dev); 764 break; 765 case DVACT_DEACTIVATE: 766 rv = config_deactivate(dev); 767 break; 768 default: 769 #ifdef DIAGNOSTIC 770 printf ("config_activate_children: shouldn't get here"); 771 #endif 772 rv = EOPNOTSUPP; 773 break; 774 775 } 776 777 if (rv) 778 break; 779 } 780 } 781 782 return (rv); 783 } 784 785 /* 786 * Lookup a device in the cfdriver device array. Does not return a 787 * device if it is not active. 788 * 789 * Increments ref count on the device by one, reflecting the 790 * new reference created on the stack. 791 * 792 * Context: process only 793 */ 794 struct device * 795 device_lookup(struct cfdriver *cd, int unit) 796 { 797 struct device *dv = NULL; 798 799 if (unit >= 0 && unit < cd->cd_ndevs) 800 dv = (struct device *)(cd->cd_devs[unit]); 801 802 if (!dv) 803 return (NULL); 804 805 if (!(dv->dv_flags & DVF_ACTIVE)) 806 dv = NULL; 807 808 if (dv != NULL) 809 device_ref(dv); 810 811 return (dv); 812 } 813 814 815 /* 816 * Increments the ref count on the device structure. The device 817 * structure is freed when the ref count hits 0. 818 * 819 * Context: process or interrupt 820 */ 821 void 822 device_ref(struct device *dv) 823 { 824 dv->dv_ref++; 825 } 826 827 /* 828 * Decrement the ref count on the device structure. 829 * 830 * free's the structure when the ref count hits zero. 831 * 832 * Context: process or interrupt 833 */ 834 void 835 device_unref(struct device *dv) 836 { 837 dv->dv_ref--; 838 if (dv->dv_ref == 0) { 839 free(dv, M_DEVBUF); 840 } 841 } 842