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