1 /* $OpenBSD: subr_autoconf.c,v 1.66 2011/07/03 15:47:16 matthew 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 #include <sys/queue.h> 53 #include <sys/proc.h> 54 #include <sys/mutex.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 struct mutex autoconf_attdet_mtx = MUTEX_INITIALIZER(IPL_HIGH); 105 /* 106 * If > 0, devices are being attached and any thread which tries to 107 * detach will sleep; if < 0 devices are being detached and any 108 * thread which tries to attach will sleep. 109 */ 110 int autoconf_attdet; 111 112 /* 113 * Initialize autoconfiguration data structures. This occurs before console 114 * initialization as that might require use of this subsystem. Furthermore 115 * this means that malloc et al. isn't yet available. 116 */ 117 void 118 config_init(void) 119 { 120 TAILQ_INIT(&deferred_config_queue); 121 TAILQ_INIT(&alldevs); 122 TAILQ_INIT(&allcftables); 123 TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list); 124 } 125 126 /* 127 * Apply the matching function and choose the best. This is used 128 * a few times and we want to keep the code small. 129 */ 130 void 131 mapply(struct matchinfo *m, struct cfdata *cf) 132 { 133 int pri; 134 void *match; 135 136 if (m->indirect) 137 match = config_make_softc(m->parent, cf); 138 else 139 match = cf; 140 141 if (autoconf_verbose) { 142 printf(">>> probing for %s", cf->cf_driver->cd_name); 143 if (cf->cf_fstate == FSTATE_STAR) 144 printf("*\n"); 145 else 146 printf("%d\n", cf->cf_unit); 147 } 148 if (m->fn != NULL) 149 pri = (*m->fn)(m->parent, match, m->aux); 150 else { 151 if (cf->cf_attach->ca_match == NULL) { 152 panic("mapply: no match function for '%s' device", 153 cf->cf_driver->cd_name); 154 } 155 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux); 156 } 157 if (autoconf_verbose) 158 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name, 159 pri); 160 161 if (pri > m->pri) { 162 if (m->indirect && m->match) 163 free(m->match, M_DEVBUF); 164 m->match = match; 165 m->pri = pri; 166 } else { 167 if (m->indirect) 168 free(match, M_DEVBUF); 169 } 170 } 171 172 /* 173 * Iterate over all potential children of some device, calling the given 174 * function (default being the child's match function) for each one. 175 * Nonzero returns are matches; the highest value returned is considered 176 * the best match. Return the `found child' if we got a match, or NULL 177 * otherwise. The `aux' pointer is simply passed on through. 178 * 179 * Note that this function is designed so that it can be used to apply 180 * an arbitrary function to all potential children (its return value 181 * can be ignored). 182 */ 183 void * 184 config_search(cfmatch_t fn, struct device *parent, void *aux) 185 { 186 struct cfdata *cf; 187 short *p; 188 struct matchinfo m; 189 struct cftable *t; 190 191 m.fn = fn; 192 m.parent = parent; 193 m.match = NULL; 194 m.aux = aux; 195 m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect; 196 m.pri = 0; 197 TAILQ_FOREACH(t, &allcftables, list) { 198 for (cf = t->tab; cf->cf_driver; cf++) { 199 /* 200 * Skip cf if no longer eligible, otherwise scan 201 * through parents for one matching `parent', 202 * and try match function. 203 */ 204 if (cf->cf_fstate == FSTATE_FOUND) 205 continue; 206 if (cf->cf_fstate == FSTATE_DNOTFOUND || 207 cf->cf_fstate == FSTATE_DSTAR) 208 continue; 209 for (p = cf->cf_parents; *p >= 0; p++) 210 if (parent->dv_cfdata == &(t->tab)[*p]) 211 mapply(&m, cf); 212 } 213 } 214 if (autoconf_verbose) { 215 if (m.match) { 216 if (m.indirect) 217 cf = ((struct device *)m.match)->dv_cfdata; 218 else 219 cf = (struct cfdata *)m.match; 220 printf(">>> %s probe won\n", 221 cf->cf_driver->cd_name); 222 } else 223 printf(">>> no winning probe\n"); 224 } 225 return (m.match); 226 } 227 228 /* 229 * Iterate over all potential children of some device, calling the given 230 * function for each one. 231 * 232 * Note that this function is designed so that it can be used to apply 233 * an arbitrary function to all potential children (its return value 234 * can be ignored). 235 */ 236 void 237 config_scan(cfscan_t fn, struct device *parent) 238 { 239 struct cfdata *cf; 240 short *p; 241 void *match; 242 int indirect; 243 struct cftable *t; 244 245 indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect; 246 TAILQ_FOREACH(t, &allcftables, list) { 247 for (cf = t->tab; cf->cf_driver; cf++) { 248 /* 249 * Skip cf if no longer eligible, otherwise scan 250 * through parents for one matching `parent', 251 * and try match function. 252 */ 253 if (cf->cf_fstate == FSTATE_FOUND) 254 continue; 255 if (cf->cf_fstate == FSTATE_DNOTFOUND || 256 cf->cf_fstate == FSTATE_DSTAR) 257 continue; 258 for (p = cf->cf_parents; *p >= 0; p++) 259 if (parent->dv_cfdata == &(t->tab)[*p]) { 260 match = indirect? 261 config_make_softc(parent, cf) : 262 (void *)cf; 263 (*fn)(parent, match); 264 } 265 } 266 } 267 } 268 269 /* 270 * Find the given root device. 271 * This is much like config_search, but there is no parent. 272 */ 273 void * 274 config_rootsearch(cfmatch_t fn, char *rootname, void *aux) 275 { 276 struct cfdata *cf; 277 short *p; 278 struct matchinfo m; 279 280 m.fn = fn; 281 m.parent = ROOT; 282 m.match = NULL; 283 m.aux = aux; 284 m.indirect = 0; 285 m.pri = 0; 286 /* 287 * Look at root entries for matching name. We do not bother 288 * with found-state here since only one instance of each possible 289 * root child should ever be searched. 290 */ 291 for (p = cfroots; *p >= 0; p++) { 292 cf = &cfdata[*p]; 293 if (cf->cf_fstate == FSTATE_DNOTFOUND || 294 cf->cf_fstate == FSTATE_DSTAR) 295 continue; 296 if (strcmp(cf->cf_driver->cd_name, rootname) == 0) 297 mapply(&m, cf); 298 } 299 return (m.match); 300 } 301 302 char *msgs[3] = { "", " not configured\n", " unsupported\n" }; 303 304 /* 305 * The given `aux' argument describes a device that has been found 306 * on the given parent, but not necessarily configured. Locate the 307 * configuration data for that device (using the submatch function 308 * provided, or using candidates' cd_match configuration driver 309 * functions) and attach it, and return true. If the device was 310 * not configured, call the given `print' function and return 0. 311 */ 312 struct device * 313 config_found_sm(struct device *parent, void *aux, cfprint_t print, 314 cfmatch_t submatch) 315 { 316 void *match; 317 318 if ((match = config_search(submatch, parent, aux)) != NULL) 319 return (config_attach(parent, match, aux, print)); 320 if (print) 321 printf(msgs[(*print)(aux, parent->dv_xname)]); 322 return (NULL); 323 } 324 325 /* 326 * As above, but for root devices. 327 */ 328 struct device * 329 config_rootfound(char *rootname, void *aux) 330 { 331 void *match; 332 333 if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) 334 return (config_attach(ROOT, match, aux, (cfprint_t)NULL)); 335 printf("root device %s not configured\n", rootname); 336 return (NULL); 337 } 338 339 /* 340 * Attach a found device. Allocates memory for device variables. 341 */ 342 struct device * 343 config_attach(struct device *parent, void *match, void *aux, cfprint_t print) 344 { 345 struct cfdata *cf; 346 struct device *dev; 347 struct cfdriver *cd; 348 struct cfattach *ca; 349 struct cftable *t; 350 351 mtx_enter(&autoconf_attdet_mtx); 352 while (autoconf_attdet < 0) 353 msleep(&autoconf_attdet, &autoconf_attdet_mtx, 354 PWAIT, "autoconf", 0); 355 autoconf_attdet++; 356 mtx_leave(&autoconf_attdet_mtx); 357 358 if (parent && parent->dv_cfdata->cf_driver->cd_indirect) { 359 dev = match; 360 cf = dev->dv_cfdata; 361 } else { 362 cf = match; 363 dev = config_make_softc(parent, cf); 364 } 365 366 cd = cf->cf_driver; 367 ca = cf->cf_attach; 368 369 KASSERT(cd->cd_devs != NULL); 370 KASSERT(dev->dv_unit < cd->cd_ndevs); 371 KASSERT(cd->cd_devs[dev->dv_unit] == NULL); 372 cd->cd_devs[dev->dv_unit] = dev; 373 374 /* 375 * If this is a "STAR" device and we used the last unit, prepare for 376 * another one. 377 */ 378 if (cf->cf_fstate == FSTATE_STAR) { 379 if (dev->dv_unit == cf->cf_unit) 380 cf->cf_unit++; 381 } else 382 cf->cf_fstate = FSTATE_FOUND; 383 384 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); 385 device_ref(dev); 386 387 if (parent == ROOT) 388 printf("%s at root", dev->dv_xname); 389 else { 390 printf("%s at %s", dev->dv_xname, parent->dv_xname); 391 if (print) 392 (void) (*print)(aux, (char *)0); 393 } 394 395 /* 396 * Before attaching, clobber any unfound devices that are 397 * otherwise identical, or bump the unit number on all starred 398 * cfdata for this device. 399 */ 400 TAILQ_FOREACH(t, &allcftables, list) { 401 for (cf = t->tab; cf->cf_driver; cf++) 402 if (cf->cf_driver == cd && 403 cf->cf_unit == dev->dv_unit) { 404 if (cf->cf_fstate == FSTATE_NOTFOUND) 405 cf->cf_fstate = FSTATE_FOUND; 406 if (cf->cf_fstate == FSTATE_STAR) 407 cf->cf_unit++; 408 } 409 } 410 device_register(dev, aux); 411 (*ca->ca_attach)(parent, dev, aux); 412 config_process_deferred_children(dev); 413 #if NHOTPLUG > 0 414 if (!cold) 415 hotplug_device_attach(cd->cd_class, dev->dv_xname); 416 #endif 417 418 mtx_enter(&autoconf_attdet_mtx); 419 if (--autoconf_attdet == 0) 420 wakeup(&autoconf_attdet); 421 mtx_leave(&autoconf_attdet_mtx); 422 return (dev); 423 } 424 425 struct device * 426 config_make_softc(struct device *parent, struct cfdata *cf) 427 { 428 struct device *dev; 429 struct cfdriver *cd; 430 struct cfattach *ca; 431 432 cd = cf->cf_driver; 433 ca = cf->cf_attach; 434 if (ca->ca_devsize < sizeof(struct device)) 435 panic("config_make_softc"); 436 437 /* get memory for all device vars */ 438 dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO); 439 if (!dev) 440 panic("config_make_softc: allocation for device softc failed"); 441 442 dev->dv_class = cd->cd_class; 443 dev->dv_cfdata = cf; 444 dev->dv_flags = DVF_ACTIVE; /* always initially active */ 445 446 /* If this is a STAR device, search for a free unit number */ 447 if (cf->cf_fstate == FSTATE_STAR) { 448 for (dev->dv_unit = cf->cf_starunit1; 449 dev->dv_unit < cf->cf_unit; dev->dv_unit++) 450 if (cd->cd_ndevs == 0 || 451 dev->dv_unit >= cd->cd_ndevs || 452 cd->cd_devs[dev->dv_unit] == NULL) 453 break; 454 } else 455 dev->dv_unit = cf->cf_unit; 456 457 /* Build the device name into dv_xname. */ 458 if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", 459 cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname)) 460 panic("config_make_softc: device name too long"); 461 dev->dv_parent = parent; 462 463 /* put this device in the devices array */ 464 if (dev->dv_unit >= cd->cd_ndevs) { 465 /* 466 * Need to expand the array. 467 */ 468 int old = cd->cd_ndevs, new; 469 void **nsp; 470 471 if (old == 0) 472 new = MINALLOCSIZE / sizeof(void *); 473 else 474 new = old * 2; 475 while (new <= dev->dv_unit) 476 new *= 2; 477 cd->cd_ndevs = new; 478 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO); 479 if (nsp == 0) 480 panic("config_make_softc: %sing dev array", 481 old != 0 ? "expand" : "creat"); 482 if (old != 0) { 483 bcopy(cd->cd_devs, nsp, old * sizeof(void *)); 484 free(cd->cd_devs, M_DEVBUF); 485 } 486 cd->cd_devs = nsp; 487 } 488 if (cd->cd_devs[dev->dv_unit]) 489 panic("config_make_softc: duplicate %s", dev->dv_xname); 490 491 dev->dv_ref = 1; 492 493 return (dev); 494 } 495 496 /* 497 * Detach a device. Optionally forced (e.g. because of hardware 498 * removal) and quiet. Returns zero if successful, non-zero 499 * (an error code) otherwise. 500 * 501 * Note that this code wants to be run from a process context, so 502 * that the detach can sleep to allow processes which have a device 503 * open to run and unwind their stacks. 504 */ 505 int 506 config_detach(struct device *dev, int flags) 507 { 508 struct cfdata *cf; 509 struct cfattach *ca; 510 struct cfdriver *cd; 511 int rv = 0, i; 512 #ifdef DIAGNOSTIC 513 struct device *d; 514 #endif 515 #if NHOTPLUG > 0 516 char devname[16]; 517 #endif 518 519 mtx_enter(&autoconf_attdet_mtx); 520 while (autoconf_attdet > 0) 521 msleep(&autoconf_attdet, &autoconf_attdet_mtx, 522 PWAIT, "autoconf", 0); 523 autoconf_attdet--; 524 mtx_leave(&autoconf_attdet_mtx); 525 526 #if NHOTPLUG > 0 527 strlcpy(devname, dev->dv_xname, sizeof(devname)); 528 #endif 529 530 cf = dev->dv_cfdata; 531 #ifdef DIAGNOSTIC 532 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR) 533 panic("config_detach: bad device fstate"); 534 #endif 535 ca = cf->cf_attach; 536 cd = cf->cf_driver; 537 538 /* 539 * Ensure the device is deactivated. If the device doesn't 540 * have an activation entry point, we allow DVF_ACTIVE to 541 * remain set. Otherwise, if DVF_ACTIVE is still set, the 542 * device is busy, and the detach fails. 543 */ 544 if (ca->ca_activate != NULL) 545 rv = config_deactivate(dev); 546 547 /* 548 * Try to detach the device. If that's not possible, then 549 * we either panic() (for the forced but failed case), or 550 * return an error. 551 */ 552 if (rv == 0) { 553 if (ca->ca_detach != NULL) 554 rv = (*ca->ca_detach)(dev, flags); 555 else 556 rv = EOPNOTSUPP; 557 } 558 if (rv != 0) { 559 if ((flags & DETACH_FORCE) == 0) 560 goto done; 561 else 562 panic("config_detach: forced detach of %s failed (%d)", 563 dev->dv_xname, rv); 564 } 565 566 /* 567 * The device has now been successfully detached. 568 */ 569 570 #ifdef DIAGNOSTIC 571 /* 572 * Sanity: If you're successfully detached, you should have no 573 * children. (Note that because children must be attached 574 * after parents, we only need to search the latter part of 575 * the list.) 576 */ 577 i = 0; 578 for (d = TAILQ_NEXT(dev, dv_list); d != NULL; 579 d = TAILQ_NEXT(d, dv_list)) { 580 if (d->dv_parent == dev) { 581 printf("config_detach: %s attached at %s\n", 582 d->dv_xname, dev->dv_xname); 583 i = 1; 584 } 585 } 586 if (i != 0) 587 panic("config_detach: detached device (%s) has children", 588 dev->dv_xname); 589 #endif 590 591 /* 592 * Mark cfdata to show that the unit can be reused, if possible. 593 * Note that we can only re-use a starred unit number if the unit 594 * being detached had the last assigned unit number. 595 */ 596 for (cf = cfdata; cf->cf_driver; cf++) { 597 if (cf->cf_driver == cd) { 598 if (cf->cf_fstate == FSTATE_FOUND && 599 cf->cf_unit == dev->dv_unit) 600 cf->cf_fstate = FSTATE_NOTFOUND; 601 if (cf->cf_fstate == FSTATE_STAR && 602 cf->cf_unit == dev->dv_unit + 1) 603 cf->cf_unit--; 604 } 605 } 606 607 /* 608 * Unlink from device list. 609 */ 610 TAILQ_REMOVE(&alldevs, dev, dv_list); 611 device_unref(dev); 612 613 /* 614 * Remove from cfdriver's array, tell the world, and free softc. 615 */ 616 cd->cd_devs[dev->dv_unit] = NULL; 617 if ((flags & DETACH_QUIET) == 0) 618 printf("%s detached\n", dev->dv_xname); 619 620 device_unref(dev); 621 /* 622 * If the device now has no units in use, deallocate its softc array. 623 */ 624 for (i = 0; i < cd->cd_ndevs; i++) 625 if (cd->cd_devs[i] != NULL) 626 break; 627 if (i == cd->cd_ndevs) { /* nothing found; deallocate */ 628 free(cd->cd_devs, M_DEVBUF); 629 cd->cd_devs = NULL; 630 cd->cd_ndevs = 0; 631 cf->cf_unit = 0; 632 } 633 634 #if NHOTPLUG > 0 635 if (!cold) 636 hotplug_device_detach(cd->cd_class, devname); 637 #endif 638 639 /* 640 * Return success. 641 */ 642 done: 643 mtx_enter(&autoconf_attdet_mtx); 644 if (++autoconf_attdet == 0) 645 wakeup(&autoconf_attdet); 646 mtx_leave(&autoconf_attdet_mtx); 647 return (rv); 648 } 649 650 int 651 config_deactivate(struct device *dev) 652 { 653 struct cfattach *ca = dev->dv_cfdata->cf_attach; 654 int rv = 0, oflags = dev->dv_flags; 655 656 if (ca->ca_activate == NULL) 657 return (EOPNOTSUPP); 658 659 if (dev->dv_flags & DVF_ACTIVE) { 660 dev->dv_flags &= ~DVF_ACTIVE; 661 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE); 662 if (rv) 663 dev->dv_flags = oflags; 664 } 665 return (rv); 666 } 667 668 /* 669 * Defer the configuration of the specified device until all 670 * of its parent's devices have been attached. 671 */ 672 void 673 config_defer(struct device *dev, void (*func)(struct device *)) 674 { 675 struct deferred_config *dc; 676 677 if (dev->dv_parent == NULL) 678 panic("config_defer: can't defer config of a root device"); 679 680 #ifdef DIAGNOSTIC 681 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL; 682 dc = TAILQ_NEXT(dc, dc_queue)) { 683 if (dc->dc_dev == dev) 684 panic("config_defer: deferred twice"); 685 } 686 #endif 687 688 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL) 689 panic("config_defer: can't allocate defer structure"); 690 691 dc->dc_dev = dev; 692 dc->dc_func = func; 693 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue); 694 config_pending_incr(); 695 } 696 697 /* 698 * Process the deferred configuration queue for a device. 699 */ 700 void 701 config_process_deferred_children(struct device *parent) 702 { 703 struct deferred_config *dc, *ndc; 704 705 for (dc = TAILQ_FIRST(&deferred_config_queue); 706 dc != NULL; dc = ndc) { 707 ndc = TAILQ_NEXT(dc, dc_queue); 708 if (dc->dc_dev->dv_parent == parent) { 709 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue); 710 (*dc->dc_func)(dc->dc_dev); 711 free(dc, M_DEVBUF); 712 config_pending_decr(); 713 } 714 } 715 } 716 717 /* 718 * Manipulate the config_pending semaphore. 719 */ 720 void 721 config_pending_incr(void) 722 { 723 724 config_pending++; 725 } 726 727 void 728 config_pending_decr(void) 729 { 730 731 #ifdef DIAGNOSTIC 732 if (config_pending == 0) 733 panic("config_pending_decr: config_pending == 0"); 734 #endif 735 config_pending--; 736 if (config_pending == 0) 737 wakeup((void *)&config_pending); 738 } 739 740 int 741 config_detach_children(struct device *parent, int flags) 742 { 743 struct device *dev, *next_dev; 744 int rv = 0; 745 746 /* 747 * The config_detach routine may sleep, meaning devices 748 * may be added to the queue. However, all devices will 749 * be added to the tail of the queue, the queue won't 750 * be re-organized, and the subtree of parent here should be locked 751 * for purposes of adding/removing children. 752 * 753 * Note that we can not afford trying to walk the device list 754 * once - our ``next'' device might be a child of the device 755 * we are about to detach, so it would disappear. 756 * Just play it safe and restart from the parent. 757 */ 758 for (dev = TAILQ_LAST(&alldevs, devicelist); 759 dev != NULL; dev = next_dev) { 760 if (dev->dv_parent == parent) { 761 if ((rv = config_detach(dev, flags)) != 0) 762 return (rv); 763 next_dev = TAILQ_LAST(&alldevs, devicelist); 764 } else { 765 next_dev = TAILQ_PREV(dev, devicelist, dv_list); 766 } 767 } 768 769 return (0); 770 } 771 772 int 773 config_suspend(struct device *dev, int act) 774 { 775 struct cfattach *ca = dev->dv_cfdata->cf_attach; 776 777 if (ca->ca_activate) { 778 #if 0 779 printf("activate: %s %d\n", dev->dv_xname, act); 780 #endif 781 return (*ca->ca_activate)(dev, act); 782 } 783 return (0); 784 } 785 786 /* 787 * Call the ca_activate for each of our children, letting each 788 * decide whether they wish to do the same for their children 789 * and more. 790 */ 791 int 792 config_activate_children(struct device *parent, int act) 793 { 794 struct device *d; 795 int rv = 0; 796 797 for (d = TAILQ_NEXT(parent, dv_list); d != NULL; 798 d = TAILQ_NEXT(d, dv_list)) { 799 if (d->dv_parent != parent) 800 continue; 801 switch (act) { 802 case DVACT_SUSPEND: 803 case DVACT_RESUME: 804 case DVACT_QUIESCE: 805 rv = config_suspend(d, act); 806 break; 807 case DVACT_DEACTIVATE: 808 rv = config_deactivate(d); 809 break; 810 } 811 if (rv == 0) 812 continue; 813 814 /* 815 * Found a device that refuses the action. 816 * If we were being asked to suspend, we can 817 * try to resume all previous devices. 818 */ 819 #ifdef DIAGNOSTIC 820 printf("config_activate_children: device %s failed %d\n", 821 d->dv_xname, act); 822 #endif 823 if (act == DVACT_RESUME) 824 printf("failing resume cannot be handled\n"); 825 if (act != DVACT_SUSPEND) 826 return (rv); 827 828 d = TAILQ_PREV(d, devicelist, dv_list); 829 for (; d != NULL && d != parent; 830 d = TAILQ_PREV(d, devicelist, dv_list)) { 831 if (d->dv_parent != parent) 832 continue; 833 printf("resume %s\n", d->dv_xname); 834 config_suspend(d, DVACT_RESUME); 835 } 836 return (rv); 837 } 838 return (rv); 839 } 840 841 /* 842 * Lookup a device in the cfdriver device array. Does not return a 843 * device if it is not active. 844 * 845 * Increments ref count on the device by one, reflecting the 846 * new reference created on the stack. 847 * 848 * Context: process only 849 */ 850 struct device * 851 device_lookup(struct cfdriver *cd, int unit) 852 { 853 struct device *dv = NULL; 854 855 if (unit >= 0 && unit < cd->cd_ndevs) 856 dv = (struct device *)(cd->cd_devs[unit]); 857 858 if (!dv) 859 return (NULL); 860 861 if (!(dv->dv_flags & DVF_ACTIVE)) 862 dv = NULL; 863 864 if (dv != NULL) 865 device_ref(dv); 866 867 return (dv); 868 } 869 870 871 /* 872 * Increments the ref count on the device structure. The device 873 * structure is freed when the ref count hits 0. 874 * 875 * Context: process or interrupt 876 */ 877 void 878 device_ref(struct device *dv) 879 { 880 dv->dv_ref++; 881 } 882 883 /* 884 * Decrement the ref count on the device structure. 885 * 886 * free's the structure when the ref count hits zero. 887 * 888 * Context: process or interrupt 889 */ 890 void 891 device_unref(struct device *dv) 892 { 893 dv->dv_ref--; 894 if (dv->dv_ref == 0) { 895 free(dv, M_DEVBUF); 896 } 897 } 898