xref: /openbsd-src/sys/kern/subr_autoconf.c (revision cd1eb269cafb12c415be1749cd4a4b5422710415)
1 /*	$OpenBSD: subr_autoconf.c,v 1.60 2010/02/28 17:31:27 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_suspend(struct device *dev, int act)
750 {
751 	struct cfattach *ca = dev->dv_cfdata->cf_attach;
752 
753 	if (ca->ca_activate) {
754 		printf("activate: %s %d\n", dev->dv_xname, act);
755 		return (*ca->ca_activate)(dev, act);
756 	}
757 	return (0);
758 }
759 
760 /*
761  * Call the ca_activate for each of our children, letting each
762  * decide whether they wish to do the same for their children
763  * and more.
764  */
765 int
766 config_activate_children(struct device *parent, int act)
767 {
768 	struct device *d;
769 	int rv = 0;
770 
771 	for (d = TAILQ_NEXT(parent, dv_list); d != NULL;
772 	    d = TAILQ_NEXT(d, dv_list)) {
773 		if (d->dv_parent != parent)
774 			continue;
775 		switch (act) {
776 		case DVACT_ACTIVATE:
777 			rv = config_activate(d);
778 			break;
779 		case DVACT_DEACTIVATE:
780 			rv = config_deactivate(d);
781 			break;
782 		case DVACT_SUSPEND:
783 		case DVACT_RESUME:
784 			rv = config_suspend(d, act);
785 			break;
786 		}
787 		if (rv == 0)
788 			continue;
789 
790 		/*
791 		 * Found a device that refuses the action.
792 		 * If we were being asked to suspend, we can
793 		 * try to resume all previous devices.
794 		 */
795 #ifdef DIAGNOSTIC
796 		printf("config_activate_children: device %s failed %d\n",
797 		    d->dv_xname, act);
798 #endif
799 		if (act == DVACT_RESUME)
800 			printf("failing resume cannot be handled\n");
801 		if (act != DVACT_SUSPEND)
802 			return (rv);
803 
804 		d = TAILQ_PREV(d, devicelist, dv_list);
805 		for (; d != NULL && d != parent;
806 		    d = TAILQ_PREV(d, devicelist, dv_list)) {
807 			if (d->dv_parent != parent)
808 				continue;
809 			printf("resume %s\n", d->dv_xname);
810 			config_suspend(d, DVACT_RESUME);
811 		}
812 		return (rv);
813 	}
814 	return (rv);
815 }
816 
817 /*
818  * Lookup a device in the cfdriver device array.  Does not return a
819  * device if it is not active.
820  *
821  * Increments ref count on the device by one, reflecting the
822  * new reference created on the stack.
823  *
824  * Context: process only
825  */
826 struct device *
827 device_lookup(struct cfdriver *cd, int unit)
828 {
829 	struct device *dv = NULL;
830 
831 	if (unit >= 0 && unit < cd->cd_ndevs)
832 		dv = (struct device *)(cd->cd_devs[unit]);
833 
834 	if (!dv)
835 		return (NULL);
836 
837 	if (!(dv->dv_flags & DVF_ACTIVE))
838 		dv = NULL;
839 
840 	if (dv != NULL)
841 		device_ref(dv);
842 
843 	return (dv);
844 }
845 
846 
847 /*
848  * Increments the ref count on the device structure. The device
849  * structure is freed when the ref count hits 0.
850  *
851  * Context: process or interrupt
852  */
853 void
854 device_ref(struct device *dv)
855 {
856 	dv->dv_ref++;
857 }
858 
859 /*
860  * Decrement the ref count on the device structure.
861  *
862  * free's the structure when the ref count hits zero.
863  *
864  * Context: process or interrupt
865  */
866 void
867 device_unref(struct device *dv)
868 {
869 	dv->dv_ref--;
870 	if (dv->dv_ref == 0) {
871 		free(dv, M_DEVBUF);
872 	}
873 }
874