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