subr_autoconf.c revision 1.59
1/* $OpenBSD: subr_autoconf.c,v 1.59 2009/11/23 14:12:10 deraadt 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 */ 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 77struct cftable_head allcftables; 78 79static struct cftable staticcftable = { 80 cfdata 81}; 82 83#ifndef AUTOCONF_VERBOSE 84#define AUTOCONF_VERBOSE 0 85#endif /* AUTOCONF_VERBOSE */ 86int autoconf_verbose = AUTOCONF_VERBOSE; /* trace probe calls */ 87 88static void mapply(struct matchinfo *, struct cfdata *); 89 90struct deferred_config { 91 TAILQ_ENTRY(deferred_config) dc_queue; 92 struct device *dc_dev; 93 void (*dc_func)(struct device *); 94}; 95 96TAILQ_HEAD(, deferred_config) deferred_config_queue; 97 98void config_process_deferred_children(struct device *); 99 100struct 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 */ 109void 110config_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 */ 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 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 */ 228void 229config_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 */ 265void * 266config_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 294char *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 */ 304struct device * 305config_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 */ 320struct device * 321config_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 */ 334struct device * 335config_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 402struct device * 403config_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 */ 482int 483config_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 608int 609config_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 626int 627config_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 */ 648void 649config_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 */ 676void 677config_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 */ 696void 697config_pending_incr(void) 698{ 699 700 config_pending++; 701} 702 703void 704config_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 716int 717config_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 748int 749config_suspend(struct device *dev, int act) 750{ 751 struct cfattach *ca = dev->dv_cfdata->cf_attach; 752 753 if (ca->ca_activate) { 754 printf("activate: %s %d\n", dev->dv_xname, act); 755 return (*ca->ca_activate)(dev, act); 756 } 757 return (0); 758} 759 760/* 761 * Call the ca_activate for each of our children, letting each 762 * decide whether they wish to do the same for their children 763 * and more. 764 */ 765int 766config_activate_children(struct device *parent, int act) 767{ 768 struct device *d; 769 int rv = 0; 770 771 for (d = TAILQ_NEXT(parent, dv_list); d != NULL; 772 d = TAILQ_NEXT(d, dv_list)) { 773 if (d->dv_parent != parent) 774 continue; 775 if (d->dv_cfdata->cf_attach->ca_activate) 776 printf("device %s act %d\n", d->dv_xname, act); 777 switch (act) { 778 case DVACT_ACTIVATE: 779 rv = config_activate(d); 780 break; 781 case DVACT_DEACTIVATE: 782 rv = config_deactivate(d); 783 break; 784 case DVACT_SUSPEND: 785 case DVACT_RESUME: 786 rv = config_suspend(d, act); 787 break; 788 } 789 if (rv == 0) 790 continue; 791 792 /* 793 * Found a device that refuses the action. 794 * If we were being asked to suspend, we can 795 * try to resume all previous devices. 796 */ 797#ifdef DIAGNOSTIC 798 printf("config_activate_children: device %s failed %d\n", 799 d->dv_xname, act); 800#endif 801 if (act == DVACT_RESUME) 802 printf("failing resume cannot be handled\n"); 803 if (act != DVACT_SUSPEND) 804 return (rv); 805 806 d = TAILQ_PREV(d, devicelist, dv_list); 807 for (; d != NULL && d != parent; 808 d = TAILQ_PREV(d, devicelist, dv_list)) { 809 if (d->dv_parent != parent) 810 continue; 811 printf("resume %s\n", d->dv_xname); 812 config_suspend(d, DVACT_RESUME); 813 } 814 return (rv); 815 } 816 return (rv); 817} 818 819/* 820 * Lookup a device in the cfdriver device array. Does not return a 821 * device if it is not active. 822 * 823 * Increments ref count on the device by one, reflecting the 824 * new reference created on the stack. 825 * 826 * Context: process only 827 */ 828struct device * 829device_lookup(struct cfdriver *cd, int unit) 830{ 831 struct device *dv = NULL; 832 833 if (unit >= 0 && unit < cd->cd_ndevs) 834 dv = (struct device *)(cd->cd_devs[unit]); 835 836 if (!dv) 837 return (NULL); 838 839 if (!(dv->dv_flags & DVF_ACTIVE)) 840 dv = NULL; 841 842 if (dv != NULL) 843 device_ref(dv); 844 845 return (dv); 846} 847 848 849/* 850 * Increments the ref count on the device structure. The device 851 * structure is freed when the ref count hits 0. 852 * 853 * Context: process or interrupt 854 */ 855void 856device_ref(struct device *dv) 857{ 858 dv->dv_ref++; 859} 860 861/* 862 * Decrement the ref count on the device structure. 863 * 864 * free's the structure when the ref count hits zero. 865 * 866 * Context: process or interrupt 867 */ 868void 869device_unref(struct device *dv) 870{ 871 dv->dv_ref--; 872 if (dv->dv_ref == 0) { 873 free(dv, M_DEVBUF); 874 } 875} 876