Home | History | Annotate | Line # | Download | only in kern
subr_autoconf.c revision 1.29
      1 /*	$NetBSD: subr_autoconf.c,v 1.29 1998/06/09 18:46:12 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This software was developed by the Computer Systems Engineering group
      8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
      9  * contributed to Berkeley.
     10  *
     11  * All advertising materials mentioning features or use of this software
     12  * must display the following acknowledgement:
     13  *	This product includes software developed by the University of
     14  *	California, Lawrence Berkeley Laboratories.
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in the
     23  *    documentation and/or other materials provided with the distribution.
     24  * 3. All advertising materials mentioning features or use of this software
     25  *    must display the following acknowledgement:
     26  *	This product includes software developed by the University of
     27  *	California, Berkeley and its contributors.
     28  * 4. Neither the name of the University nor the names of its contributors
     29  *    may be used to endorse or promote products derived from this software
     30  *    without specific prior written permission.
     31  *
     32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     42  * SUCH DAMAGE.
     43  *
     44  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
     45  *
     46  *	@(#)subr_autoconf.c	8.3 (Berkeley) 5/17/94
     47  */
     48 
     49 #include <sys/param.h>
     50 #include <sys/device.h>
     51 #include <sys/malloc.h>
     52 #include <sys/systm.h>
     53 #include <machine/limits.h>
     54 
     55 /*
     56  * Autoconfiguration subroutines.
     57  */
     58 
     59 /*
     60  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
     61  * devices and drivers are found via these tables.
     62  */
     63 extern struct cfdata cfdata[];
     64 extern short cfroots[];
     65 
     66 #define	ROOT ((struct device *)NULL)
     67 
     68 #ifdef __BROKEN_INDIRECT_CONFIG
     69 struct device *config_make_softc __P((struct device *, struct cfdata *));
     70 #endif
     71 
     72 struct matchinfo {
     73 	cfmatch_t fn;
     74 	struct	device *parent;
     75 	void	*aux;
     76 #ifdef __BROKEN_INDIRECT_CONFIG
     77 	void	*match;
     78 	int	indirect;
     79 #else
     80 	struct	cfdata *match;
     81 #endif
     82 	int	pri;
     83 };
     84 
     85 static char *number __P((char *, int));
     86 static void mapply __P((struct matchinfo *, struct cfdata *));
     87 
     88 struct deferred_config {
     89 	TAILQ_ENTRY(deferred_config) dc_queue;
     90 	struct device *dc_dev;
     91 	void (*dc_func) __P((struct device *));
     92 };
     93 
     94 TAILQ_HEAD(, deferred_config) deferred_config_queue;
     95 
     96 static void config_process_deferred_children __P((struct device *));
     97 
     98 struct devicelist alldevs;		/* list of all devices */
     99 struct evcntlist allevents;		/* list of all event counters */
    100 
    101 /*
    102  * Initialize autoconfiguration data structures.
    103  */
    104 void
    105 config_init()
    106 {
    107 
    108 	TAILQ_INIT(&deferred_config_queue);
    109 	TAILQ_INIT(&alldevs);
    110 	TAILQ_INIT(&allevents);
    111 }
    112 
    113 /*
    114  * Apply the matching function and choose the best.  This is used
    115  * a few times and we want to keep the code small.
    116  */
    117 static void
    118 mapply(m, cf)
    119 	register struct matchinfo *m;
    120 	register struct cfdata *cf;
    121 {
    122 	register int pri;
    123 #ifdef __BROKEN_INDIRECT_CONFIG
    124 	void *match;
    125 
    126 	if (m->indirect)
    127 		match = config_make_softc(m->parent, cf);
    128 	else
    129 		match = cf;
    130 #endif
    131 
    132 	if (m->fn != NULL)
    133 #ifdef __BROKEN_INDIRECT_CONFIG
    134 		pri = (*m->fn)(m->parent, match, m->aux);
    135 #else
    136 		pri = (*m->fn)(m->parent, cf, m->aux);
    137 #endif
    138 	else {
    139 	        if (cf->cf_attach->ca_match == NULL) {
    140 			panic("mapply: no match function for '%s' device\n",
    141 			    cf->cf_driver->cd_name);
    142 		}
    143 #ifdef __BROKEN_INDIRECT_CONFIG
    144 		pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
    145 #else
    146 		pri = (*cf->cf_attach->ca_match)(m->parent, cf, m->aux);
    147 #endif
    148 	}
    149 	if (pri > m->pri) {
    150 #ifdef __BROKEN_INDIRECT_CONFIG
    151 		if (m->indirect && m->match)
    152 			free(m->match, M_DEVBUF);
    153 		m->match = match;
    154 #else
    155 		m->match = cf;
    156 #endif
    157 		m->pri = pri;
    158 #ifdef __BROKEN_INDIRECT_CONFIG
    159 	} else {
    160 		if (m->indirect)
    161 			free(match, M_DEVBUF);
    162 #endif
    163 	}
    164 }
    165 
    166 /*
    167  * Iterate over all potential children of some device, calling the given
    168  * function (default being the child's match function) for each one.
    169  * Nonzero returns are matches; the highest value returned is considered
    170  * the best match.  Return the `found child' if we got a match, or NULL
    171  * otherwise.  The `aux' pointer is simply passed on through.
    172  *
    173  * Note that this function is designed so that it can be used to apply
    174  * an arbitrary function to all potential children (its return value
    175  * can be ignored).
    176  */
    177 #ifdef __BROKEN_INDIRECT_CONFIG
    178 void *
    179 #else
    180 struct cfdata *
    181 #endif
    182 config_search(fn, parent, aux)
    183 	cfmatch_t fn;
    184 	register struct device *parent;
    185 	void *aux;
    186 {
    187 	register struct cfdata *cf;
    188 	register short *p;
    189 	struct matchinfo m;
    190 
    191 	m.fn = fn;
    192 	m.parent = parent;
    193 	m.aux = aux;
    194 	m.match = NULL;
    195 #ifdef __BROKEN_INDIRECT_CONFIG
    196 	m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
    197 #endif
    198 	m.pri = 0;
    199 	for (cf = cfdata; cf->cf_driver; cf++) {
    200 		/*
    201 		 * Skip cf if no longer eligible, otherwise scan through
    202 		 * parents for one matching `parent', and try match function.
    203 		 */
    204 		if (cf->cf_fstate == FSTATE_FOUND)
    205 			continue;
    206 		for (p = cf->cf_parents; *p >= 0; p++)
    207 			if (parent->dv_cfdata == &cfdata[*p])
    208 				mapply(&m, cf);
    209 	}
    210 	return (m.match);
    211 }
    212 
    213 #ifdef __BROKEN_INDIRECT_CONFIG
    214 /*
    215  * Iterate over all potential children of some device, calling the given
    216  * function for each one.
    217  *
    218  * Note that this function is designed so that it can be used to apply
    219  * an arbitrary function to all potential children (its return value
    220  * can be ignored).
    221  */
    222 void
    223 config_scan(fn, parent)
    224 	cfscan_t fn;
    225 	register struct device *parent;
    226 {
    227 	register struct cfdata *cf;
    228 	register short *p;
    229 	void *match;
    230 	int indirect;
    231 
    232 	indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
    233 	for (cf = cfdata; cf->cf_driver; cf++) {
    234 		/*
    235 		 * Skip cf if no longer eligible, otherwise scan through
    236 		 * parents for one matching `parent', and try match function.
    237 		 */
    238 		if (cf->cf_fstate == FSTATE_FOUND)
    239 			continue;
    240 		for (p = cf->cf_parents; *p >= 0; p++)
    241 			if (parent->dv_cfdata == &cfdata[*p]) {
    242 				if (indirect)
    243 					match = config_make_softc(parent, cf);
    244 				else
    245 					match = cf;
    246 				(*fn)(parent, match);
    247 			}
    248 	}
    249 }
    250 #endif /* __BROKEN_INDIRECT_CONFIG */
    251 
    252 /*
    253  * Find the given root device.
    254  * This is much like config_search, but there is no parent.
    255  */
    256 #ifdef __BROKEN_INDIRECT_CONFIG
    257 void *
    258 #else
    259 struct cfdata *
    260 #endif
    261 config_rootsearch(fn, rootname, aux)
    262 	register cfmatch_t fn;
    263 	register char *rootname;
    264 	register void *aux;
    265 {
    266 	register struct cfdata *cf;
    267 	register short *p;
    268 	struct matchinfo m;
    269 
    270 	m.fn = fn;
    271 	m.parent = ROOT;
    272 	m.aux = aux;
    273 	m.match = NULL;
    274 #ifdef __BROKEN_INDIRECT_CONFIG
    275 	m.indirect = 0;
    276 #endif
    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 root should ever be
    281 	 * searched (and it must be done first).
    282 	 */
    283 	for (p = cfroots; *p >= 0; p++) {
    284 		cf = &cfdata[*p];
    285 		if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
    286 			mapply(&m, cf);
    287 	}
    288 	return (m.match);
    289 }
    290 
    291 static char *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  */
    301 struct device *
    302 config_found_sm(parent, aux, print, submatch)
    303 	struct device *parent;
    304 	void *aux;
    305 	cfprint_t print;
    306 	cfmatch_t submatch;
    307 {
    308 #ifdef __BROKEN_INDIRECT_CONFIG
    309 	void *match;
    310 
    311 	if ((match = config_search(submatch, parent, aux)) != NULL)
    312 		return (config_attach(parent, match, aux, print));
    313 #else
    314 	struct cfdata *cf;
    315 
    316 	if ((cf = config_search(submatch, parent, aux)) != NULL)
    317 		return (config_attach(parent, cf, aux, print));
    318 #endif
    319 	if (print)
    320 		printf(msgs[(*print)(aux, parent->dv_xname)]);
    321 	return (NULL);
    322 }
    323 
    324 /*
    325  * As above, but for root devices.
    326  */
    327 struct device *
    328 config_rootfound(rootname, aux)
    329 	char *rootname;
    330 	void *aux;
    331 {
    332 #ifdef __BROKEN_INDIRECT_CONFIG
    333 	void *match;
    334 
    335 	if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
    336 		return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
    337 #else
    338 	struct cfdata *cf;
    339 
    340 	if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
    341 		return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
    342 #endif
    343 	printf("root device %s not configured\n", rootname);
    344 	return (NULL);
    345 }
    346 
    347 /* just like sprintf(buf, "%d") except that it works from the end */
    348 static char *
    349 number(ep, n)
    350 	register char *ep;
    351 	register int n;
    352 {
    353 
    354 	*--ep = 0;
    355 	while (n >= 10) {
    356 		*--ep = (n % 10) + '0';
    357 		n /= 10;
    358 	}
    359 	*--ep = n + '0';
    360 	return (ep);
    361 }
    362 
    363 /*
    364  * Attach a found device.  Allocates memory for device variables.
    365  */
    366 #ifdef __BROKEN_INDIRECT_CONFIG
    367 struct device *
    368 config_attach(parent, match, aux, print)
    369 	register struct device *parent;
    370 	void *match;
    371 	register void *aux;
    372 	cfprint_t print;
    373 {
    374 	register struct cfdata *cf;
    375 	register struct device *dev;
    376 	register struct cfdriver *cd;
    377 	register struct cfattach *ca;
    378 
    379 	if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
    380 		dev = match;
    381 		cf = dev->dv_cfdata;
    382 	} else {
    383 		cf = match;
    384 		dev = config_make_softc(parent, cf);
    385 	}
    386 
    387 	cd = cf->cf_driver;
    388 	ca = cf->cf_attach;
    389 	cd->cd_devs[cf->cf_unit] = dev;
    390 
    391 	if (cf->cf_fstate == FSTATE_STAR)
    392 		cf->cf_unit++;
    393 	else {
    394 		KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
    395 		cf->cf_fstate = FSTATE_FOUND;
    396 	}
    397 
    398 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
    399 
    400 	if (parent == ROOT)
    401 		printf("%s (root)", dev->dv_xname);
    402 	else {
    403 		printf("%s at %s", dev->dv_xname, parent->dv_xname);
    404 		if (print)
    405 			(void) (*print)(aux, (char *)0);
    406 	}
    407 
    408 	/*
    409 	 * Before attaching, clobber any unfound devices that are
    410 	 * otherwise identical, or bump the unit number on all starred
    411 	 * cfdata for this device.
    412 	 */
    413 	for (cf = cfdata; cf->cf_driver; cf++)
    414 		if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
    415 			if (cf->cf_fstate == FSTATE_NOTFOUND)
    416 				cf->cf_fstate = FSTATE_FOUND;
    417 			if (cf->cf_fstate == FSTATE_STAR)
    418 				cf->cf_unit++;
    419 		}
    420 #if defined(__alpha__) || defined(hp300) || defined(__i386__)
    421 	device_register(dev, aux);
    422 #endif
    423 	(*ca->ca_attach)(parent, dev, aux);
    424 	config_process_deferred_children(dev);
    425 	return (dev);
    426 }
    427 
    428 struct device *
    429 config_make_softc(parent, cf)
    430 	struct device *parent;
    431 	struct cfdata *cf;
    432 {
    433 	register struct device *dev;
    434 	register struct cfdriver *cd;
    435 	register struct cfattach *ca;
    436 	register size_t lname, lunit;
    437 	register char *xunit;
    438 	char num[10];
    439 
    440 	cd = cf->cf_driver;
    441 	ca = cf->cf_attach;
    442 	if (ca->ca_devsize < sizeof(struct device))
    443 		panic("config_make_softc");
    444 
    445 	/* compute length of name and decimal expansion of unit number */
    446 	lname = strlen(cd->cd_name);
    447 	xunit = number(&num[sizeof num], cf->cf_unit);
    448 	lunit = &num[sizeof num] - xunit;
    449 	if (lname + lunit >= sizeof(dev->dv_xname))
    450 		panic("config_attach: device name too long");
    451 
    452 	/* get memory for all device vars */
    453 	dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
    454 	if (!dev)
    455 	    panic("config_attach: memory allocation for device softc failed");
    456 	bzero(dev, ca->ca_devsize);
    457 	dev->dv_class = cd->cd_class;
    458 	dev->dv_cfdata = cf;
    459 	dev->dv_unit = cf->cf_unit;
    460 	bcopy(cd->cd_name, dev->dv_xname, lname);
    461 	bcopy(xunit, dev->dv_xname + lname, lunit);
    462 	dev->dv_parent = parent;
    463 
    464 	/* put this device in the devices array */
    465 	if (dev->dv_unit >= cd->cd_ndevs) {
    466 		/*
    467 		 * Need to expand the array.
    468 		 */
    469 		int old = cd->cd_ndevs, new;
    470 		void **nsp;
    471 
    472 		if (old == 0)
    473 			new = MINALLOCSIZE / sizeof(void *);
    474 		else
    475 			new = old * 2;
    476 		while (new <= dev->dv_unit)
    477 			new *= 2;
    478 		cd->cd_ndevs = new;
    479 		nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
    480 		if (nsp == 0)
    481 			panic("config_attach: %sing dev array",
    482 			    old != 0 ? "expand" : "creat");
    483 		bzero(nsp + old, (new - old) * sizeof(void *));
    484 		if (old != 0) {
    485 			bcopy(cd->cd_devs, nsp, old * sizeof(void *));
    486 			free(cd->cd_devs, M_DEVBUF);
    487 		}
    488 		cd->cd_devs = nsp;
    489 	}
    490 	if (cd->cd_devs[dev->dv_unit])
    491 		panic("config_attach: duplicate %s", dev->dv_xname);
    492 
    493 	return (dev);
    494 }
    495 #else /* __BROKEN_INDIRECT_CONFIG */
    496 struct device *
    497 config_attach(parent, cf, aux, print)
    498 	register struct device *parent;
    499 	register struct cfdata *cf;
    500 	register void *aux;
    501 	cfprint_t print;
    502 {
    503 	register struct device *dev;
    504 	register struct cfdriver *cd;
    505 	register struct cfattach *ca;
    506 	register size_t lname, lunit;
    507 	register char *xunit;
    508 	int myunit;
    509 	char num[10];
    510 
    511 	cd = cf->cf_driver;
    512 	ca = cf->cf_attach;
    513 	if (ca->ca_devsize < sizeof(struct device))
    514 		panic("config_attach");
    515 	myunit = cf->cf_unit;
    516 	if (cf->cf_fstate == FSTATE_STAR)
    517 		cf->cf_unit++;
    518 	else {
    519 		KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
    520 		cf->cf_fstate = FSTATE_FOUND;
    521 	}
    522 
    523 	/* compute length of name and decimal expansion of unit number */
    524 	lname = strlen(cd->cd_name);
    525 	xunit = number(&num[sizeof num], myunit);
    526 	lunit = &num[sizeof num] - xunit;
    527 	if (lname + lunit >= sizeof(dev->dv_xname))
    528 		panic("config_attach: device name too long");
    529 
    530 	/* get memory for all device vars */
    531 	dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
    532 	if (!dev)
    533 	    panic("config_attach: memory allocation for device softc failed");
    534 	bzero(dev, ca->ca_devsize);
    535 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);	/* link up */
    536 	dev->dv_class = cd->cd_class;
    537 	dev->dv_cfdata = cf;
    538 	dev->dv_unit = myunit;
    539 	bcopy(cd->cd_name, dev->dv_xname, lname);
    540 	bcopy(xunit, dev->dv_xname + lname, lunit);
    541 	dev->dv_parent = parent;
    542 
    543 	if (parent == ROOT)
    544 		printf("%s (root)", dev->dv_xname);
    545 	else {
    546 		printf("%s at %s", dev->dv_xname, parent->dv_xname);
    547 		if (print)
    548 			(void) (*print)(aux, (char *)0);
    549 	}
    550 
    551 	/* put this device in the devices array */
    552 	if (dev->dv_unit >= cd->cd_ndevs) {
    553 		/*
    554 		 * Need to expand the array.
    555 		 */
    556 		int old = cd->cd_ndevs, new;
    557 		void **nsp;
    558 
    559 		if (old == 0)
    560 			new = MINALLOCSIZE / sizeof(void *);
    561 		else
    562 			new = old * 2;
    563 		while (new <= dev->dv_unit)
    564 			new *= 2;
    565 		cd->cd_ndevs = new;
    566 		nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
    567 		if (nsp == 0)
    568 			panic("config_attach: %sing dev array",
    569 			    old != 0 ? "expand" : "creat");
    570 		bzero(nsp + old, (new - old) * sizeof(void *));
    571 		if (old != 0) {
    572 			bcopy(cd->cd_devs, nsp, old * sizeof(void *));
    573 			free(cd->cd_devs, M_DEVBUF);
    574 		}
    575 		cd->cd_devs = nsp;
    576 	}
    577 	if (cd->cd_devs[dev->dv_unit])
    578 		panic("config_attach: duplicate %s", dev->dv_xname);
    579 	cd->cd_devs[dev->dv_unit] = dev;
    580 
    581 	/*
    582 	 * Before attaching, clobber any unfound devices that are
    583 	 * otherwise identical, or bump the unit number on all starred
    584 	 * cfdata for this device.
    585 	 */
    586 	for (cf = cfdata; cf->cf_driver; cf++)
    587 		if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
    588 			if (cf->cf_fstate == FSTATE_NOTFOUND)
    589 				cf->cf_fstate = FSTATE_FOUND;
    590 			if (cf->cf_fstate == FSTATE_STAR)
    591 				cf->cf_unit++;
    592 		}
    593 #if defined(__alpha__) || defined(hp300) || defined(__i386__)
    594 	device_register(dev, aux);
    595 #endif
    596 	(*ca->ca_attach)(parent, dev, aux);
    597 	config_process_deferred_children(dev);
    598 	return (dev);
    599 }
    600 #endif /* __BROKEN_INDIRECT_CONFIG */
    601 
    602 /*
    603  * Defer the configuration of the specified device until all
    604  * of its parent's devices have been attached.
    605  */
    606 void
    607 config_defer(dev, func)
    608 	struct device *dev;
    609 	void (*func) __P((struct device *));
    610 {
    611 	struct deferred_config *dc;
    612 
    613 	if (dev->dv_parent == NULL)
    614 		panic("config_defer: can't defer config of a root device");
    615 
    616 #ifdef DIAGNOSTIC
    617 	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
    618 	     dc = TAILQ_NEXT(dc, dc_queue)) {
    619 		if (dc->dc_dev == dev)
    620 			panic("config_defer: deferred twice");
    621 	}
    622 #endif
    623 
    624 	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
    625 		panic("config_defer: can't allocate defer structure");
    626 
    627 	dc->dc_dev = dev;
    628 	dc->dc_func = func;
    629 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
    630 }
    631 
    632 /*
    633  * Process the deferred configuration queue for a device.
    634  */
    635 static void
    636 config_process_deferred_children(parent)
    637 	struct device *parent;
    638 {
    639 	struct deferred_config *dc, *ndc;
    640 
    641 	for (dc = TAILQ_FIRST(&deferred_config_queue);
    642 	     dc != NULL; dc = ndc) {
    643 		ndc = TAILQ_NEXT(dc, dc_queue);
    644 		if (dc->dc_dev->dv_parent == parent) {
    645 			TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
    646 			(*dc->dc_func)(dc->dc_dev);
    647 			free(dc, M_DEVBUF);
    648 		}
    649 	}
    650 }
    651 
    652 /*
    653  * Attach an event.  These must come from initially-zero space (see
    654  * commented-out assignments below), but that occurs naturally for
    655  * device instance variables.
    656  */
    657 void
    658 evcnt_attach(dev, name, ev)
    659 	struct device *dev;
    660 	const char *name;
    661 	struct evcnt *ev;
    662 {
    663 
    664 #ifdef DIAGNOSTIC
    665 	if (strlen(name) >= sizeof(ev->ev_name))
    666 		panic("evcnt_attach");
    667 #endif
    668 	/* ev->ev_next = NULL; */
    669 	ev->ev_dev = dev;
    670 	/* ev->ev_count = 0; */
    671 	strcpy(ev->ev_name, name);
    672 	TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
    673 }
    674