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