xref: /openbsd/sys/kern/subr_autoconf.c (revision 78b63d65)
1 /*	$OpenBSD: subr_autoconf.c,v 1.29 2001/09/01 05:48:18 jason 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. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:
27  *	This product includes software developed by the University of
28  *	California, Berkeley and its contributors.
29  * 4. Neither the name of the University nor the names of its contributors
30  *    may be used to endorse or promote products derived from this software
31  *    without specific prior written permission.
32  *
33  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43  * SUCH DAMAGE.
44  *
45  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
46  *
47  *	@(#)subr_autoconf.c	8.1 (Berkeley) 6/10/93
48  */
49 
50 #include <sys/param.h>
51 #include <sys/device.h>
52 #include <sys/malloc.h>
53 #include <sys/systm.h>
54 #include <machine/limits.h>
55 /* Extra stuff from Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de> */
56 #include <sys/queue.h>
57 
58 /*
59  * Autoconfiguration subroutines.
60  */
61 
62 typedef int (*cond_predicate_t) __P((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 char *number __P((char *, int));
91 static void mapply __P((struct matchinfo *, struct cfdata *));
92 
93 struct deferred_config {
94 	TAILQ_ENTRY(deferred_config) dc_queue;
95 	struct device *dc_dev;
96 	void (*dc_func) __P((struct device *));
97 };
98 
99 TAILQ_HEAD(, deferred_config) deferred_config_queue;
100 
101 void config_process_deferred_children __P((struct device *));
102 
103 struct devicelist alldevs;		/* list of all devices */
104 struct evcntlist allevents;		/* list of all event counters */
105 
106 /*
107  * Initialize autoconfiguration data structures.  This occurs before console
108  * initialization as that might require use of this subsystem.  Furthermore
109  * this means that malloc et al. isn't yet available.
110  */
111 void
112 config_init()
113 {
114 	TAILQ_INIT(&deferred_config_queue);
115 	TAILQ_INIT(&alldevs);
116 	TAILQ_INIT(&allevents);
117 	TAILQ_INIT(&allcftables);
118 	TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
119 }
120 
121 /*
122  * Apply the matching function and choose the best.  This is used
123  * a few times and we want to keep the code small.
124  */
125 void
126 mapply(m, cf)
127 	register struct matchinfo *m;
128 	register struct cfdata *cf;
129 {
130 	register int pri;
131 	void *match;
132 
133 	if (m->indirect)
134 		match = config_make_softc(m->parent, cf);
135 	else
136 		match = cf;
137 
138 	if (autoconf_verbose) {
139 		printf(">>> probing for %s", cf->cf_driver->cd_name);
140 		if (cf->cf_fstate == FSTATE_STAR)
141 			printf("*\n");
142 		else
143 			printf("%d\n", cf->cf_unit);
144 	}
145 	if (m->fn != NULL)
146 		pri = (*m->fn)(m->parent, match, m->aux);
147 	else {
148 	        if (cf->cf_attach->ca_match == NULL) {
149 			panic("mapply: no match function for '%s' device",
150 			    cf->cf_driver->cd_name);
151 		}
152 		pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
153 	}
154 	if (autoconf_verbose)
155 		printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
156 		    pri);
157 
158 	if (pri > m->pri) {
159 		if (m->indirect && m->match)
160 			free(m->match, M_DEVBUF);
161 		m->match = match;
162 		m->pri = pri;
163 	} else {
164 		if (m->indirect)
165 			free(match, M_DEVBUF);
166 	}
167 }
168 
169 /*
170  * Iterate over all potential children of some device, calling the given
171  * function (default being the child's match function) for each one.
172  * Nonzero returns are matches; the highest value returned is considered
173  * the best match.  Return the `found child' if we got a match, or NULL
174  * otherwise.  The `aux' pointer is simply passed on through.
175  *
176  * Note that this function is designed so that it can be used to apply
177  * an arbitrary function to all potential children (its return value
178  * can be ignored).
179  */
180 void *
181 config_search(fn, parent, aux)
182 	cfmatch_t fn;
183 	register struct device *parent;
184 	void *aux;
185 {
186 	register struct cfdata *cf;
187 	register short *p;
188 	struct matchinfo m;
189 	struct cftable *t;
190 
191 	m.fn = fn;
192 	m.parent = parent;
193 	m.match = NULL;
194 	m.aux = aux;
195 	m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
196 	m.pri = 0;
197 	for(t = allcftables.tqh_first; t; t = t->list.tqe_next) {
198 		for (cf = t->tab; cf->cf_driver; cf++) {
199 			/*
200 			 * Skip cf if no longer eligible, otherwise scan
201 			 * through parents for one matching `parent',
202 			 * and try match function.
203 			 */
204 			if (cf->cf_fstate == FSTATE_FOUND)
205 				continue;
206 			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
207 			    cf->cf_fstate == FSTATE_DSTAR)
208 				continue;
209 			for (p = cf->cf_parents; *p >= 0; p++)
210 				if (parent->dv_cfdata == &(t->tab)[*p])
211 					mapply(&m, cf);
212 		}
213 	}
214 	if (autoconf_verbose) {
215 		if (m.match)
216 			printf(">>> %s probe won\n",
217 			    ((struct cfdata *)m.match)->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(fn, parent)
234 	cfscan_t fn;
235 	register struct device *parent;
236 {
237 	register struct cfdata *cf;
238 	register short *p;
239 	void *match;
240 	int indirect;
241 	struct cftable *t;
242 
243 	indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
244 	for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
245 		for (cf = t->tab; cf->cf_driver; cf++) {
246 			/*
247 			 * Skip cf if no longer eligible, otherwise scan
248 			 * through parents for one matching `parent',
249 			 * and try match function.
250 			 */
251 			if (cf->cf_fstate == FSTATE_FOUND)
252 				continue;
253 			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
254 			    cf->cf_fstate == FSTATE_DSTAR)
255 				continue;
256 			for (p = cf->cf_parents; *p >= 0; p++)
257 				if (parent->dv_cfdata == &(t->tab)[*p]) {
258 					match = indirect?
259 					    config_make_softc(parent, cf) :
260 					    (void *)cf;
261 					(*fn)(parent, match);
262 				}
263 		}
264 	}
265 }
266 
267 /*
268  * Find the given root device.
269  * This is much like config_search, but there is no parent.
270  */
271 void *
272 config_rootsearch(fn, rootname, aux)
273 	register cfmatch_t fn;
274 	register char *rootname;
275 	register void *aux;
276 {
277 	register struct cfdata *cf;
278 	register short *p;
279 	struct matchinfo m;
280 
281 	m.fn = fn;
282 	m.parent = ROOT;
283 	m.match = NULL;
284 	m.aux = aux;
285 	m.indirect = 0;
286 	m.pri = 0;
287 	/*
288 	 * Look at root entries for matching name.  We do not bother
289 	 * with found-state here since only one root should ever be
290 	 * searched (and it must be done first).
291 	 */
292 	for (p = cfroots; *p >= 0; p++) {
293 		cf = &cfdata[*p];
294 		if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
295 			mapply(&m, cf);
296 	}
297 	return (m.match);
298 }
299 
300 char *msgs[3] = { "", " not configured\n", " unsupported\n" };
301 
302 /*
303  * The given `aux' argument describes a device that has been found
304  * on the given parent, but not necessarily configured.  Locate the
305  * configuration data for that device (using the submatch function
306  * provided, or using candidates' cd_match configuration driver
307  * functions) and attach it, and return true.  If the device was
308  * not configured, call the given `print' function and return 0.
309  */
310 struct device *
311 config_found_sm(parent, aux, print, submatch)
312 	struct device *parent;
313 	void *aux;
314 	cfprint_t print;
315 	cfmatch_t submatch;
316 {
317 	void *match;
318 
319 	if ((match = config_search(submatch, parent, aux)) != NULL)
320 		return (config_attach(parent, match, aux, print));
321 	if (print)
322 		printf(msgs[(*print)(aux, parent->dv_xname)]);
323 	return (NULL);
324 }
325 
326 /*
327  * As above, but for root devices.
328  */
329 struct device *
330 config_rootfound(rootname, aux)
331 	char *rootname;
332 	void *aux;
333 {
334 	void *match;
335 
336 	if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
337 		return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
338 	printf("root device %s not configured\n", rootname);
339 	return (NULL);
340 }
341 
342 /* just like sprintf(buf, "%d") except that it works from the end */
343 char *
344 number(ep, n)
345 	register char *ep;
346 	register int n;
347 {
348 
349 	*--ep = 0;
350 	while (n >= 10) {
351 		*--ep = (n % 10) + '0';
352 		n /= 10;
353 	}
354 	*--ep = n + '0';
355 	return (ep);
356 }
357 
358 /*
359  * Attach a found device.  Allocates memory for device variables.
360  */
361 struct device *
362 config_attach(parent, match, aux, print)
363 	register struct device *parent;
364 	void *match;
365 	register void *aux;
366 	cfprint_t print;
367 {
368 	register struct cfdata *cf;
369 	register struct device *dev;
370 	register struct cfdriver *cd;
371 	register struct cfattach *ca;
372 	struct cftable *t;
373 
374 	if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
375 		dev = match;
376 		cf = dev->dv_cfdata;
377 	} else {
378 		cf = match;
379 		dev = config_make_softc(parent, cf);
380 	}
381 
382 	cd = cf->cf_driver;
383 	ca = cf->cf_attach;
384 
385 	cd->cd_devs[dev->dv_unit] = dev;
386 
387 	/*
388 	 * If this is a "STAR" device and we used the last unit, prepare for
389 	 * another one.
390 	 */
391 	if (cf->cf_fstate == FSTATE_STAR) {
392 		if (dev->dv_unit == cf->cf_unit)
393 			cf->cf_unit++;
394 	} else
395 		cf->cf_fstate = FSTATE_FOUND;
396 
397 	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
398 	device_ref(dev);
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 (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
414 		for (cf = t->tab; cf->cf_driver; cf++)
415 			if (cf->cf_driver == cd &&
416 			    cf->cf_unit == dev->dv_unit) {
417 				if (cf->cf_fstate == FSTATE_NOTFOUND)
418 					cf->cf_fstate = FSTATE_FOUND;
419 				if (cf->cf_fstate == FSTATE_STAR)
420 					cf->cf_unit++;
421 			}
422 	}
423 #ifdef __HAVE_DEVICE_REGISTER
424 	device_register(dev, aux);
425 #endif
426 	(*ca->ca_attach)(parent, dev, aux);
427 	config_process_deferred_children(dev);
428 	return (dev);
429 }
430 
431 struct device *
432 config_make_softc(parent, cf)
433 	struct device *parent;
434 	struct cfdata *cf;
435 {
436 	register struct device *dev;
437 	register struct cfdriver *cd;
438 	register struct cfattach *ca;
439 	register size_t lname, lunit;
440 	register char *xunit;
441 	char num[10];
442 
443 	cd = cf->cf_driver;
444 	ca = cf->cf_attach;
445 	if (ca->ca_devsize < sizeof(struct device))
446 		panic("config_make_softc");
447 
448 	/* get memory for all device vars */
449 	dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
450 	if (!dev)
451 		panic("config_make_softc: allocation for device softc failed");
452 	bzero(dev, ca->ca_devsize);
453 	dev->dv_class = cd->cd_class;
454 	dev->dv_cfdata = cf;
455 	dev->dv_flags = DVF_ACTIVE;	/* always initially active */
456 
457 	/* If this is a STAR device, search for a free unit number */
458 	if (cf->cf_fstate == FSTATE_STAR) {
459 		for (dev->dv_unit = cf->cf_starunit1;
460 		    dev->dv_unit < cf->cf_unit; dev->dv_unit++)
461 			if (cd->cd_ndevs == 0 ||
462 			    cd->cd_devs[dev->dv_unit] == NULL)
463 				break;
464 	} else
465 		dev->dv_unit = cf->cf_unit;
466 
467 	/* compute length of name and decimal expansion of unit number */
468 	lname = strlen(cd->cd_name);
469 	xunit = number(&num[sizeof num], dev->dv_unit);
470 	lunit = &num[sizeof num] - xunit;
471 	if (lname + lunit >= sizeof(dev->dv_xname))
472 		panic("config_make_softc: device name too long");
473 
474 	bcopy(cd->cd_name, dev->dv_xname, lname);
475 	bcopy(xunit, dev->dv_xname + lname, lunit);
476 	dev->dv_parent = parent;
477 
478 	/* put this device in the devices array */
479 	if (dev->dv_unit >= cd->cd_ndevs) {
480 		/*
481 		 * Need to expand the array.
482 		 */
483 		int old = cd->cd_ndevs, new;
484 		void **nsp;
485 
486 		if (old == 0)
487 			new = MINALLOCSIZE / sizeof(void *);
488 		else
489 			new = old * 2;
490 		while (new <= dev->dv_unit)
491 			new *= 2;
492 		cd->cd_ndevs = new;
493 		nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
494 		if (nsp == 0)
495 			panic("config_make_softc: %sing dev array",
496 			    old != 0 ? "expand" : "creat");
497 		bzero(nsp + old, (new - old) * sizeof(void *));
498 		if (old != 0) {
499 			bcopy(cd->cd_devs, nsp, old * sizeof(void *));
500 			free(cd->cd_devs, M_DEVBUF);
501 		}
502 		cd->cd_devs = nsp;
503 	}
504 	if (cd->cd_devs[dev->dv_unit])
505 		panic("config_make_softc: duplicate %s", dev->dv_xname);
506 
507 	dev->dv_ref = 1;
508 
509 	return (dev);
510 }
511 
512 /*
513  * Detach a device.  Optionally forced (e.g. because of hardware
514  * removal) and quiet.  Returns zero if successful, non-zero
515  * (an error code) otherwise.
516  *
517  * Note that this code wants to be run from a process context, so
518  * that the detach can sleep to allow processes which have a device
519  * open to run and unwind their stacks.
520  */
521 int
522 config_detach(dev, flags)
523 	struct device *dev;
524 	int flags;
525 {
526 	struct cfdata *cf;
527 	struct cfattach *ca;
528 	struct cfdriver *cd;
529 #ifdef DIAGNOSTIC
530 	struct device *d;
531 #endif
532 	int rv = 0, i;
533 
534 	cf = dev->dv_cfdata;
535 #ifdef DIAGNOSTIC
536 	if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
537 		panic("config_detach: bad device fstate");
538 #endif
539 	ca = cf->cf_attach;
540 	cd = cf->cf_driver;
541 
542 	/*
543 	 * Ensure the device is deactivated.  If the device doesn't
544 	 * have an activation entry point, we allow DVF_ACTIVE to
545 	 * remain set.  Otherwise, if DVF_ACTIVE is still set, the
546 	 * device is busy, and the detach fails.
547 	 */
548 	if (ca->ca_activate != NULL)
549 		rv = config_deactivate(dev);
550 
551 	/*
552 	 * Try to detach the device.  If that's not possible, then
553 	 * we either panic() (for the forced but failed case), or
554 	 * return an error.
555 	 */
556 	if (rv == 0) {
557 		if (ca->ca_detach != NULL)
558 			rv = (*ca->ca_detach)(dev, flags);
559 		else
560 			rv = EOPNOTSUPP;
561 	}
562 	if (rv != 0) {
563 		if ((flags & DETACH_FORCE) == 0)
564 			return (rv);
565 		else
566 			panic("config_detach: forced detach of %s failed (%d)",
567 			    dev->dv_xname, rv);
568 	}
569 
570 	/*
571 	 * The device has now been successfully detached.
572 	 */
573 
574 #ifdef DIAGNOSTIC
575 	/*
576 	 * Sanity: If you're successfully detached, you should have no
577 	 * children.  (Note that because children must be attached
578 	 * after parents, we only need to search the latter part of
579 	 * the list.)
580 	 */
581 	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
582 	     d = TAILQ_NEXT(d, dv_list)) {
583 		if (d->dv_parent == dev)
584 			panic("config_detach: detached device has children");
585 	}
586 #endif
587 
588 	/*
589 	 * Mark cfdata to show that the unit can be reused, if possible.
590 	 * Note that we can only re-use a starred unit number if the unit
591 	 * being detached had the last assigned unit number.
592 	 */
593 	for (cf = cfdata; cf->cf_driver; cf++) {
594 		if (cf->cf_driver == cd) {
595 			if (cf->cf_fstate == FSTATE_FOUND &&
596 			    cf->cf_unit == dev->dv_unit)
597 				cf->cf_fstate = FSTATE_NOTFOUND;
598 			if (cf->cf_fstate == FSTATE_STAR &&
599 			    cf->cf_unit == dev->dv_unit + 1)
600 				cf->cf_unit--;
601 		}
602 	}
603 
604 	/*
605 	 * Unlink from device list.
606 	 */
607 	TAILQ_REMOVE(&alldevs, dev, dv_list);
608 	device_unref(dev);
609 
610 	/*
611 	 * Remove from cfdriver's array, tell the world, and free softc.
612 	 */
613 	cd->cd_devs[dev->dv_unit] = NULL;
614 	if ((flags & DETACH_QUIET) == 0)
615 		printf("%s detached\n", dev->dv_xname);
616 
617 	device_unref(dev);
618 	/*
619 	 * If the device now has no units in use, deallocate its softc array.
620 	 */
621 	for (i = 0; i < cd->cd_ndevs; i++)
622 		if (cd->cd_devs[i] != NULL)
623 			break;
624 	if (i == cd->cd_ndevs) {		/* nothing found; deallocate */
625 		free(cd->cd_devs, M_DEVBUF);
626 		cd->cd_devs = NULL;
627 		cd->cd_ndevs = 0;
628 	}
629 
630 	/*
631 	 * Return success.
632 	 */
633 	return (0);
634 }
635 
636 int
637 config_activate(dev)
638 	struct device *dev;
639 {
640 	struct cfattach *ca = dev->dv_cfdata->cf_attach;
641 	int rv = 0, oflags = dev->dv_flags;
642 
643 	if (ca->ca_activate == NULL)
644 		return (EOPNOTSUPP);
645 
646 	if ((dev->dv_flags & DVF_ACTIVE) == 0) {
647 		dev->dv_flags |= DVF_ACTIVE;
648 		rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
649 		if (rv)
650 			dev->dv_flags = oflags;
651 	}
652 	return (rv);
653 }
654 
655 int
656 config_deactivate(dev)
657 	struct device *dev;
658 {
659 	struct cfattach *ca = dev->dv_cfdata->cf_attach;
660 	int rv = 0, oflags = dev->dv_flags;
661 
662 	if (ca->ca_activate == NULL)
663 		return (EOPNOTSUPP);
664 
665 	if (dev->dv_flags & DVF_ACTIVE) {
666 		dev->dv_flags &= ~DVF_ACTIVE;
667 		rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
668 		if (rv)
669 			dev->dv_flags = oflags;
670 	}
671 	return (rv);
672 }
673 
674 /*
675  * Defer the configuration of the specified device until all
676  * of its parent's devices have been attached.
677  */
678 void
679 config_defer(dev, func)
680 	struct device *dev;
681 	void (*func) __P((struct device *));
682 {
683 	struct deferred_config *dc;
684 
685 	if (dev->dv_parent == NULL)
686 		panic("config_defer: can't defer config of a root device");
687 
688 #ifdef DIAGNOSTIC
689 	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
690 	     dc = TAILQ_NEXT(dc, dc_queue)) {
691 		if (dc->dc_dev == dev)
692 			panic("config_defer: deferred twice");
693 	}
694 #endif
695 
696 	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
697 		panic("config_defer: can't allocate defer structure");
698 
699 	dc->dc_dev = dev;
700 	dc->dc_func = func;
701 	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
702 }
703 
704 /*
705  * Process the deferred configuration queue for a device.
706  */
707 void
708 config_process_deferred_children(parent)
709 	struct device *parent;
710 {
711 	struct deferred_config *dc, *ndc;
712 
713 	for (dc = TAILQ_FIRST(&deferred_config_queue);
714 	     dc != NULL; dc = ndc) {
715 		ndc = TAILQ_NEXT(dc, dc_queue);
716 		if (dc->dc_dev->dv_parent == parent) {
717 			TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
718 			(*dc->dc_func)(dc->dc_dev);
719 			free(dc, M_DEVBUF);
720 		}
721 	}
722 }
723 
724 int
725 config_detach_children(parent, flags)
726 	struct device *parent;
727 	int flags;
728 {
729 	struct device *dev, *next_dev;
730 	int  rv = 0;
731 
732 	/* The config_detach routine may sleep, meaning devices
733 	   may be added to the queue. However, all devices will
734 	   be added to the tail of the queue, the queue won't
735 	   be re-organized, and the subtree of parent here should be locked
736 	   for purposes of adding/removing children.
737 	*/
738 	for (dev  = TAILQ_FIRST(&alldevs);
739 	     dev != NULL; dev = next_dev) {
740 		next_dev = TAILQ_NEXT(dev, dv_list);
741 		if (dev->dv_parent == parent &&
742 		    (rv = config_detach(dev, flags)))
743 			return (rv);
744 	}
745 
746 	return  (rv);
747 }
748 
749 int
750 config_activate_children(parent, act)
751 	struct device *parent;
752 	enum devact act;
753 {
754 	struct device *dev, *next_dev;
755 	int  rv = 0;
756 
757 	/* The config_deactivate routine may sleep, meaning devices
758 	   may be added to the queue. However, all devices will
759 	   be added to the tail of the queue, the queue won't
760 	   be re-organized, and the subtree of parent here should be locked
761 	   for purposes of adding/removing children.
762 	*/
763 	for (dev = TAILQ_FIRST(&alldevs);
764 	     dev != NULL; dev = next_dev) {
765 		next_dev = TAILQ_NEXT(dev, dv_list);
766 		if (dev->dv_parent == parent) {
767 			switch (act) {
768 			case DVACT_ACTIVATE:
769 				rv = config_activate(dev);
770 				break;
771 			case DVACT_DEACTIVATE:
772 				rv = config_deactivate(dev);
773 				break;
774 			default:
775 #ifdef DIAGNOSTIC
776 				printf ("config_activate_children: shouldn't get here");
777 #endif
778 				rv = EOPNOTSUPP;
779 				break;
780 
781 			}
782 
783 			if (rv)
784 				break;
785 		}
786 	}
787 
788 	return  (rv);
789 }
790 
791 /*
792  * Lookup a device in the cfdriver device array.  Does not return a
793  * device if it is not active.
794  *
795  * Increments ref count on the device by one, reflecting the
796  * new reference created on the stack.
797  *
798  * Context: process only
799  */
800 struct device *
801 device_lookup(cd, unit)
802 	struct cfdriver *cd;
803 	int unit;
804 {
805 	struct device *dv = NULL;
806 
807 	if (unit >= 0 && unit < cd->cd_ndevs)
808 		dv = (struct device *)(cd->cd_devs[unit]);
809 
810 	if (!dv)
811 		return (NULL);
812 
813 	if (!(dv->dv_flags & DVF_ACTIVE))
814 		dv = NULL;
815 
816 	if (dv != NULL)
817 		device_ref(dv);
818 
819 	return (dv);
820 }
821 
822 
823 /*
824  * Increments the ref count on the device structure. The device
825  * structure is freed when the ref count hits 0.
826  *
827  * Context: process or interrupt
828  */
829 void
830 device_ref(dv)
831 	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 and calls the zeroref
840  * function.
841  *
842  * Context: process or interrupt
843  */
844 void
845 device_unref(dv)
846 	struct device *dv;
847 {
848 	dv->dv_ref--;
849 	if (dv->dv_ref == 0) {
850 		if (dv->dv_cfdata->cf_attach->ca_zeroref)
851 			(*dv->dv_cfdata->cf_attach->ca_zeroref)(dv);
852 
853 		free(dv, M_DEVBUF);
854 	}
855 }
856 
857 /*
858  * Attach an event.  These must come from initially-zero space (see
859  * commented-out assignments below), but that occurs naturally for
860  * device instance variables.
861  */
862 void
863 evcnt_attach(dev, name, ev)
864 	struct device *dev;
865 	const char *name;
866 	struct evcnt *ev;
867 {
868 
869 #ifdef DIAGNOSTIC
870 	if (strlen(name) >= sizeof(ev->ev_name))
871 		panic("evcnt_attach");
872 #endif
873 	/* ev->ev_next = NULL; */
874 	ev->ev_dev = dev;
875 	/* ev->ev_count = 0; */
876 	strcpy(ev->ev_name, name);
877 	TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
878 }
879 
880 #if 0
881 int
882 attach_loadable(parentname, parentunit, cftable)
883 	char *parentname;
884 	int parentunit;
885 	struct cftable *cftable;
886 {
887 	int found = 0;
888 	struct device *d;
889 
890 	TAILQ_INSERT_TAIL(&allcftables, cftable, list);
891 
892 	for(d = alldevs.tqh_first; d != NULL; d = d->dv_list.tqe_next) {
893 		struct cfdriver *drv = d->dv_cfdata->cf_driver;
894 
895 		if (strcmp(parentname, drv->cd_name) == NULL &&
896 		    (parentunit == -1 || parentunit == d->dv_unit)) {
897 			int s;
898 
899 			s = splhigh(); /* ??? */
900 			found |= (*d->dv_cfdata->cf_attach->ca_reprobe)(d,
901 			    &(cftable->tab[0]));
902 			splx(s);
903 		}
904 	}
905 	if (!found)
906 		TAILQ_REMOVE(&allcftables, cftable, list);
907 	return(found);
908 }
909 
910 int
911 devcf_intable __P((struct device *, void *));
912 
913 int
914 devcf_intable(dev, arg)
915 	struct device *dev;
916 	void *arg;
917 {
918 	struct cftable *tbl = arg;
919 	struct cfdata *cf;
920 
921 	for(cf = tbl->tab; cf->cf_driver; cf++) {
922 		if (dev->dv_cfdata == cf)
923 			return(1);
924 	}
925 	return(0);
926 }
927 
928 int
929 detach_loadable(cftable)
930 	struct cftable *cftable;
931 {
932 	if (!detach_devices(devcf_intable, cftable, 0, 0))
933 		return(0);
934 	TAILQ_REMOVE(&allcftables, cftable, list);
935 	return(1);
936 }
937 #endif
938