1 /* $NetBSD: subr_autoconf.c,v 1.53 2000/06/04 19:15:19 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 2000 Christopher G. Demetriou 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1992, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This software was developed by the Computer Systems Engineering group 39 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 40 * contributed to Berkeley. 41 * 42 * All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Lawrence Berkeley Laboratories. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL) 76 * 77 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94 78 */ 79 80 #include <sys/cdefs.h> 81 82 __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.53 2000/06/04 19:15:19 cgd Exp $"); 83 84 #include <sys/param.h> 85 #include <sys/device.h> 86 #include <sys/malloc.h> 87 #include <sys/systm.h> 88 #include <sys/kernel.h> 89 #include <sys/errno.h> 90 #include <sys/proc.h> 91 #include <machine/limits.h> 92 93 /* 94 * Autoconfiguration subroutines. 95 */ 96 97 /* 98 * ioconf.c exports exactly two names: cfdata and cfroots. All system 99 * devices and drivers are found via these tables. 100 */ 101 extern struct cfdata cfdata[]; 102 extern short cfroots[]; 103 104 #define ROOT ((struct device *)NULL) 105 106 struct matchinfo { 107 cfmatch_t fn; 108 struct device *parent; 109 void *aux; 110 struct cfdata *match; 111 int pri; 112 }; 113 114 static char *number(char *, int); 115 static void mapply(struct matchinfo *, struct cfdata *); 116 117 struct deferred_config { 118 TAILQ_ENTRY(deferred_config) dc_queue; 119 struct device *dc_dev; 120 void (*dc_func)(struct device *); 121 }; 122 123 TAILQ_HEAD(deferred_config_head, deferred_config); 124 125 struct deferred_config_head deferred_config_queue; 126 struct deferred_config_head interrupt_config_queue; 127 128 static void config_process_deferred(struct deferred_config_head *, 129 struct device *); 130 131 struct devicelist alldevs; /* list of all devices */ 132 struct evcntlist allevents; /* list of all event counters */ 133 134 __volatile int config_pending; /* semaphore for mountroot */ 135 136 /* 137 * Configure the system's hardware. 138 */ 139 void 140 configure(void) 141 { 142 143 TAILQ_INIT(&deferred_config_queue); 144 TAILQ_INIT(&interrupt_config_queue); 145 TAILQ_INIT(&alldevs); 146 TAILQ_INIT(&allevents); 147 148 /* 149 * Do the machine-dependent portion of autoconfiguration. This 150 * sets the configuration machinery here in motion by "finding" 151 * the root bus. When this function returns, we expect interrupts 152 * to be enabled. 153 */ 154 cpu_configure(); 155 156 /* 157 * Now that we've found all the hardware, start the real time 158 * and statistics clocks. 159 */ 160 initclocks(); 161 162 cold = 0; /* clocks are running, we're warm now! */ 163 164 /* 165 * Now callback to finish configuration for devices which want 166 * to do this once interrupts are enabled. 167 */ 168 config_process_deferred(&interrupt_config_queue, NULL); 169 } 170 171 /* 172 * Apply the matching function and choose the best. This is used 173 * a few times and we want to keep the code small. 174 */ 175 static void 176 mapply(struct matchinfo *m, struct cfdata *cf) 177 { 178 int pri; 179 180 if (m->fn != NULL) 181 pri = (*m->fn)(m->parent, cf, m->aux); 182 else { 183 if (cf->cf_attach->ca_match == NULL) { 184 panic("mapply: no match function for '%s' device\n", 185 cf->cf_driver->cd_name); 186 } 187 pri = (*cf->cf_attach->ca_match)(m->parent, cf, m->aux); 188 } 189 if (pri > m->pri) { 190 m->match = cf; 191 m->pri = pri; 192 } 193 } 194 195 /* 196 * Iterate over all potential children of some device, calling the given 197 * function (default being the child's match function) for each one. 198 * Nonzero returns are matches; the highest value returned is considered 199 * the best match. Return the `found child' if we got a match, or NULL 200 * otherwise. The `aux' pointer is simply passed on through. 201 * 202 * Note that this function is designed so that it can be used to apply 203 * an arbitrary function to all potential children (its return value 204 * can be ignored). 205 */ 206 struct cfdata * 207 config_search(cfmatch_t fn, struct device *parent, void *aux) 208 { 209 struct cfdata *cf; 210 short *p; 211 struct matchinfo m; 212 213 m.fn = fn; 214 m.parent = parent; 215 m.aux = aux; 216 m.match = NULL; 217 m.pri = 0; 218 for (cf = cfdata; cf->cf_driver; cf++) { 219 /* 220 * Skip cf if no longer eligible, otherwise scan through 221 * parents for one matching `parent', and try match function. 222 */ 223 if (cf->cf_fstate == FSTATE_FOUND) 224 continue; 225 for (p = cf->cf_parents; *p >= 0; p++) 226 if (parent->dv_cfdata == &cfdata[*p]) 227 mapply(&m, cf); 228 } 229 return (m.match); 230 } 231 232 /* 233 * Find the given root device. 234 * This is much like config_search, but there is no parent. 235 */ 236 struct cfdata * 237 config_rootsearch(cfmatch_t fn, const char *rootname, void *aux) 238 { 239 struct cfdata *cf; 240 short *p; 241 struct matchinfo m; 242 243 m.fn = fn; 244 m.parent = ROOT; 245 m.aux = aux; 246 m.match = NULL; 247 m.pri = 0; 248 /* 249 * Look at root entries for matching name. We do not bother 250 * with found-state here since only one root should ever be 251 * searched (and it must be done first). 252 */ 253 for (p = cfroots; *p >= 0; p++) { 254 cf = &cfdata[*p]; 255 if (strcmp(cf->cf_driver->cd_name, rootname) == 0) 256 mapply(&m, cf); 257 } 258 return (m.match); 259 } 260 261 static const char *msgs[3] = { "", " not configured\n", " unsupported\n" }; 262 263 /* 264 * The given `aux' argument describes a device that has been found 265 * on the given parent, but not necessarily configured. Locate the 266 * configuration data for that device (using the submatch function 267 * provided, or using candidates' cd_match configuration driver 268 * functions) and attach it, and return true. If the device was 269 * not configured, call the given `print' function and return 0. 270 */ 271 struct device * 272 config_found_sm(struct device *parent, void *aux, cfprint_t print, 273 cfmatch_t submatch) 274 { 275 struct cfdata *cf; 276 277 if ((cf = config_search(submatch, parent, aux)) != NULL) 278 return (config_attach(parent, cf, aux, print)); 279 if (print) 280 printf(msgs[(*print)(aux, parent->dv_xname)]); 281 return (NULL); 282 } 283 284 /* 285 * As above, but for root devices. 286 */ 287 struct device * 288 config_rootfound(const char *rootname, void *aux) 289 { 290 struct cfdata *cf; 291 292 if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) 293 return (config_attach(ROOT, cf, aux, (cfprint_t)NULL)); 294 printf("root device %s not configured\n", rootname); 295 return (NULL); 296 } 297 298 /* just like sprintf(buf, "%d") except that it works from the end */ 299 static char * 300 number(char *ep, int n) 301 { 302 303 *--ep = 0; 304 while (n >= 10) { 305 *--ep = (n % 10) + '0'; 306 n /= 10; 307 } 308 *--ep = n + '0'; 309 return (ep); 310 } 311 312 /* 313 * Attach a found device. Allocates memory for device variables. 314 */ 315 struct device * 316 config_attach(struct device *parent, struct cfdata *cf, void *aux, 317 cfprint_t print) 318 { 319 struct device *dev; 320 struct cfdriver *cd; 321 struct cfattach *ca; 322 size_t lname, lunit; 323 const char *xunit; 324 int myunit; 325 char num[10]; 326 327 cd = cf->cf_driver; 328 ca = cf->cf_attach; 329 if (ca->ca_devsize < sizeof(struct device)) 330 panic("config_attach"); 331 #ifndef __BROKEN_CONFIG_UNIT_USAGE 332 if (cf->cf_fstate == FSTATE_STAR) { 333 for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++) 334 if (cd->cd_devs[myunit] == NULL) 335 break; 336 /* 337 * myunit is now the unit of the first NULL device pointer, 338 * or max(cd->cd_ndevs,cf->cf_unit). 339 */ 340 } else { 341 myunit = cf->cf_unit; 342 #else /* __BROKEN_CONFIG_UNIT_USAGE */ 343 myunit = cf->cf_unit; 344 if (cf->cf_fstate == FSTATE_STAR) 345 cf->cf_unit++; 346 else { 347 #endif /* __BROKEN_CONFIG_UNIT_USAGE */ 348 KASSERT(cf->cf_fstate == FSTATE_NOTFOUND); 349 cf->cf_fstate = FSTATE_FOUND; 350 } 351 352 /* compute length of name and decimal expansion of unit number */ 353 lname = strlen(cd->cd_name); 354 xunit = number(&num[sizeof(num)], myunit); 355 lunit = &num[sizeof(num)] - xunit; 356 if (lname + lunit >= sizeof(dev->dv_xname)) 357 panic("config_attach: device name too long"); 358 359 /* get memory for all device vars */ 360 dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, 361 cold ? M_NOWAIT : M_WAITOK); 362 if (!dev) 363 panic("config_attach: memory allocation for device softc failed"); 364 memset(dev, 0, ca->ca_devsize); 365 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */ 366 dev->dv_class = cd->cd_class; 367 dev->dv_cfdata = cf; 368 dev->dv_unit = myunit; 369 memcpy(dev->dv_xname, cd->cd_name, lname); 370 memcpy(dev->dv_xname + lname, xunit, lunit); 371 dev->dv_parent = parent; 372 dev->dv_flags = DVF_ACTIVE; /* always initially active */ 373 374 if (parent == ROOT) 375 printf("%s (root)", dev->dv_xname); 376 else { 377 printf("%s at %s", dev->dv_xname, parent->dv_xname); 378 if (print) 379 (void) (*print)(aux, NULL); 380 } 381 382 /* put this device in the devices array */ 383 if (dev->dv_unit >= cd->cd_ndevs) { 384 /* 385 * Need to expand the array. 386 */ 387 int old = cd->cd_ndevs, new; 388 void **nsp; 389 390 if (old == 0) 391 new = MINALLOCSIZE / sizeof(void *); 392 else 393 new = old * 2; 394 while (new <= dev->dv_unit) 395 new *= 2; 396 cd->cd_ndevs = new; 397 nsp = malloc(new * sizeof(void *), M_DEVBUF, 398 cold ? M_NOWAIT : M_WAITOK); 399 if (nsp == 0) 400 panic("config_attach: %sing dev array", 401 old != 0 ? "expand" : "creat"); 402 memset(nsp + old, 0, (new - old) * sizeof(void *)); 403 if (old != 0) { 404 memcpy(nsp, cd->cd_devs, old * sizeof(void *)); 405 free(cd->cd_devs, M_DEVBUF); 406 } 407 cd->cd_devs = nsp; 408 } 409 if (cd->cd_devs[dev->dv_unit]) 410 panic("config_attach: duplicate %s", dev->dv_xname); 411 cd->cd_devs[dev->dv_unit] = dev; 412 413 /* 414 * Before attaching, clobber any unfound devices that are 415 * otherwise identical. 416 */ 417 #ifdef __BROKEN_CONFIG_UNIT_USAGE 418 /* bump the unit number on all starred cfdata for this device. */ 419 #endif /* __BROKEN_CONFIG_UNIT_USAGE */ 420 for (cf = cfdata; cf->cf_driver; cf++) 421 if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) { 422 if (cf->cf_fstate == FSTATE_NOTFOUND) 423 cf->cf_fstate = FSTATE_FOUND; 424 #ifdef __BROKEN_CONFIG_UNIT_USAGE 425 if (cf->cf_fstate == FSTATE_STAR) 426 cf->cf_unit++; 427 #endif /* __BROKEN_CONFIG_UNIT_USAGE */ 428 } 429 #ifdef __HAVE_DEVICE_REGISTER 430 device_register(dev, aux); 431 #endif 432 (*ca->ca_attach)(parent, dev, aux); 433 config_process_deferred(&deferred_config_queue, dev); 434 return (dev); 435 } 436 437 /* 438 * Detach a device. Optionally forced (e.g. because of hardware 439 * removal) and quiet. Returns zero if successful, non-zero 440 * (an error code) otherwise. 441 * 442 * Note that this code wants to be run from a process context, so 443 * that the detach can sleep to allow processes which have a device 444 * open to run and unwind their stacks. 445 */ 446 int 447 config_detach(struct device *dev, int flags) 448 { 449 struct cfdata *cf; 450 struct cfattach *ca; 451 struct cfdriver *cd; 452 #ifdef DIAGNOSTIC 453 struct device *d; 454 #endif 455 int rv = 0, i; 456 457 cf = dev->dv_cfdata; 458 #ifdef DIAGNOSTIC 459 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR) 460 panic("config_detach: bad device fstate"); 461 #endif 462 ca = cf->cf_attach; 463 cd = cf->cf_driver; 464 465 /* 466 * Ensure the device is deactivated. If the device doesn't 467 * have an activation entry point, we allow DVF_ACTIVE to 468 * remain set. Otherwise, if DVF_ACTIVE is still set, the 469 * device is busy, and the detach fails. 470 */ 471 if (ca->ca_activate != NULL) 472 rv = config_deactivate(dev); 473 474 /* 475 * Try to detach the device. If that's not possible, then 476 * we either panic() (for the forced but failed case), or 477 * return an error. 478 */ 479 if (rv == 0) { 480 if (ca->ca_detach != NULL) 481 rv = (*ca->ca_detach)(dev, flags); 482 else 483 rv = EOPNOTSUPP; 484 } 485 if (rv != 0) { 486 if ((flags & DETACH_FORCE) == 0) 487 return (rv); 488 else 489 panic("config_detach: forced detach of %s failed (%d)", 490 dev->dv_xname, rv); 491 } 492 493 /* 494 * The device has now been successfully detached. 495 */ 496 497 #ifdef DIAGNOSTIC 498 /* 499 * Sanity: If you're successfully detached, you should have no 500 * children. (Note that because children must be attached 501 * after parents, we only need to search the latter part of 502 * the list.) 503 */ 504 for (d = TAILQ_NEXT(dev, dv_list); d != NULL; 505 d = TAILQ_NEXT(d, dv_list)) { 506 if (d->dv_parent == dev) { 507 printf("config_detach: detached device %s" 508 " has children %s\n", dev->dv_xname, d->dv_xname); 509 panic("config_detach"); 510 } 511 } 512 #endif 513 514 /* 515 * Mark cfdata to show that the unit can be reused, if possible. 516 */ 517 #ifdef __BROKEN_CONFIG_UNIT_USAGE 518 /* 519 * Note that we can only re-use a starred unit number if the unit 520 * being detached had the last assigned unit number. 521 */ 522 #endif /* __BROKEN_CONFIG_UNIT_USAGE */ 523 for (cf = cfdata; cf->cf_driver; cf++) { 524 if (cf->cf_driver == cd) { 525 if (cf->cf_fstate == FSTATE_FOUND && 526 cf->cf_unit == dev->dv_unit) 527 cf->cf_fstate = FSTATE_NOTFOUND; 528 #ifdef __BROKEN_CONFIG_UNIT_USAGE 529 if (cf->cf_fstate == FSTATE_STAR && 530 cf->cf_unit == dev->dv_unit + 1) 531 cf->cf_unit--; 532 #endif /* __BROKEN_CONFIG_UNIT_USAGE */ 533 } 534 } 535 536 /* 537 * Unlink from device list. 538 */ 539 TAILQ_REMOVE(&alldevs, dev, dv_list); 540 541 /* 542 * Remove from cfdriver's array, tell the world, and free softc. 543 */ 544 cd->cd_devs[dev->dv_unit] = NULL; 545 if ((flags & DETACH_QUIET) == 0) 546 printf("%s detached\n", dev->dv_xname); 547 free(dev, M_DEVBUF); 548 549 /* 550 * If the device now has no units in use, deallocate its softc array. 551 */ 552 for (i = 0; i < cd->cd_ndevs; i++) 553 if (cd->cd_devs[i] != NULL) 554 break; 555 if (i == cd->cd_ndevs) { /* nothing found; deallocate */ 556 free(cd->cd_devs, M_DEVBUF); 557 cd->cd_devs = NULL; 558 cd->cd_ndevs = 0; 559 } 560 561 /* 562 * Return success. 563 */ 564 return (0); 565 } 566 567 int 568 config_activate(struct device *dev) 569 { 570 struct cfattach *ca = dev->dv_cfdata->cf_attach; 571 int rv = 0, oflags = dev->dv_flags; 572 573 if (ca->ca_activate == NULL) 574 return (EOPNOTSUPP); 575 576 if ((dev->dv_flags & DVF_ACTIVE) == 0) { 577 dev->dv_flags |= DVF_ACTIVE; 578 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE); 579 if (rv) 580 dev->dv_flags = oflags; 581 } 582 return (rv); 583 } 584 585 int 586 config_deactivate(struct device *dev) 587 { 588 struct cfattach *ca = dev->dv_cfdata->cf_attach; 589 int rv = 0, oflags = dev->dv_flags; 590 591 if (ca->ca_activate == NULL) 592 return (EOPNOTSUPP); 593 594 if (dev->dv_flags & DVF_ACTIVE) { 595 dev->dv_flags &= ~DVF_ACTIVE; 596 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE); 597 if (rv) 598 dev->dv_flags = oflags; 599 } 600 return (rv); 601 } 602 603 /* 604 * Defer the configuration of the specified device until all 605 * of its parent's devices have been attached. 606 */ 607 void 608 config_defer(struct device *dev, void (*func)(struct device *)) 609 { 610 struct deferred_config *dc; 611 612 if (dev->dv_parent == NULL) 613 panic("config_defer: can't defer config of a root device"); 614 615 #ifdef DIAGNOSTIC 616 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL; 617 dc = TAILQ_NEXT(dc, dc_queue)) { 618 if (dc->dc_dev == dev) 619 panic("config_defer: deferred twice"); 620 } 621 #endif 622 623 dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 624 if (dc == NULL) 625 panic("config_defer: unable to allocate callback"); 626 627 dc->dc_dev = dev; 628 dc->dc_func = func; 629 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue); 630 config_pending_incr(); 631 } 632 633 /* 634 * Defer some autoconfiguration for a device until after interrupts 635 * are enabled. 636 */ 637 void 638 config_interrupts(struct device *dev, void (*func)(struct device *)) 639 { 640 struct deferred_config *dc; 641 642 /* 643 * If interrupts are enabled, callback now. 644 */ 645 if (cold == 0) { 646 (*func)(dev); 647 return; 648 } 649 650 #ifdef DIAGNOSTIC 651 for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL; 652 dc = TAILQ_NEXT(dc, dc_queue)) { 653 if (dc->dc_dev == dev) 654 panic("config_interrupts: deferred twice"); 655 } 656 #endif 657 658 dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 659 if (dc == NULL) 660 panic("config_interrupts: unable to allocate callback"); 661 662 dc->dc_dev = dev; 663 dc->dc_func = func; 664 TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue); 665 config_pending_incr(); 666 } 667 668 /* 669 * Process a deferred configuration queue. 670 */ 671 static void 672 config_process_deferred(struct deferred_config_head *queue, 673 struct device *parent) 674 { 675 struct deferred_config *dc, *ndc; 676 677 for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) { 678 ndc = TAILQ_NEXT(dc, dc_queue); 679 if (parent == NULL || dc->dc_dev->dv_parent == parent) { 680 TAILQ_REMOVE(queue, dc, dc_queue); 681 (*dc->dc_func)(dc->dc_dev); 682 free(dc, M_DEVBUF); 683 config_pending_decr(); 684 } 685 } 686 } 687 688 /* 689 * Manipulate the config_pending semaphore. 690 */ 691 void 692 config_pending_incr(void) 693 { 694 695 config_pending++; 696 } 697 698 void 699 config_pending_decr(void) 700 { 701 702 #ifdef DIAGNOSTIC 703 if (config_pending == 0) 704 panic("config_pending_decr: config_pending == 0"); 705 #endif 706 config_pending--; 707 if (config_pending == 0) 708 wakeup((void *)&config_pending); 709 } 710 711 /* 712 * Attach a statically-initialized event. The type and string pointers 713 * are already set up. 714 */ 715 void 716 evcnt_attach_static(struct evcnt *ev) 717 { 718 int len; 719 720 len = strlen(ev->ev_group); 721 #ifdef DIAGNOSTIC 722 if (len >= EVCNT_STRING_MAX) /* ..._MAX includes NUL */ 723 panic("evcnt_attach_static: group length (%s)", ev->ev_group); 724 #endif 725 ev->ev_grouplen = len; 726 727 len = strlen(ev->ev_name); 728 #ifdef DIAGNOSTIC 729 if (len >= EVCNT_STRING_MAX) /* ..._MAX includes NUL */ 730 panic("evcnt_attach_static: name length (%s)", ev->ev_name); 731 #endif 732 ev->ev_namelen = len; 733 734 TAILQ_INSERT_TAIL(&allevents, ev, ev_list); 735 } 736 737 /* 738 * Attach a dynamically-initialized event. Zero it, set up the type 739 * and string pointers and then act like it was statically initialized. 740 */ 741 void 742 evcnt_attach_dynamic(struct evcnt *ev, int type, const struct evcnt *parent, 743 const char *group, const char *name) 744 { 745 746 memset(ev, 0, sizeof *ev); 747 ev->ev_type = type; 748 ev->ev_parent = parent; 749 ev->ev_group = group; 750 ev->ev_name = name; 751 evcnt_attach_static(ev); 752 } 753 754 /* 755 * Detach an event. 756 */ 757 void 758 evcnt_detach(struct evcnt *ev) 759 { 760 761 TAILQ_REMOVE(&allevents, ev, ev_list); 762 } 763