subr_autoconf.c revision 1.66
1/*	$OpenBSD: subr_autoconf.c,v 1.66 2011/07/03 15:47:16 matthew 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#include <sys/queue.h>
53#include <sys/proc.h>
54#include <sys/mutex.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 */
66extern short cfroots[];
67
68#define	ROOT ((struct device *)NULL)
69
70struct matchinfo {
71	cfmatch_t fn;
72	struct	device *parent;
73	void	*match, *aux;
74	int	indirect, pri;
75};
76
77struct cftable_head allcftables;
78
79static struct cftable staticcftable = {
80	cfdata
81};
82
83#ifndef AUTOCONF_VERBOSE
84#define AUTOCONF_VERBOSE 0
85#endif /* AUTOCONF_VERBOSE */
86int autoconf_verbose = AUTOCONF_VERBOSE;	/* trace probe calls */
87
88static void mapply(struct matchinfo *, struct cfdata *);
89
90struct deferred_config {
91	TAILQ_ENTRY(deferred_config) dc_queue;
92	struct device *dc_dev;
93	void (*dc_func)(struct device *);
94};
95
96TAILQ_HEAD(, deferred_config) deferred_config_queue;
97
98void config_process_deferred_children(struct device *);
99
100struct devicelist alldevs;		/* list of all devices */
101
102__volatile int config_pending;		/* semaphore for mountroot */
103
104struct mutex autoconf_attdet_mtx = MUTEX_INITIALIZER(IPL_HIGH);
105/*
106 * If > 0, devices are being attached and any thread which tries to
107 * detach will sleep; if < 0 devices are being detached and any
108 * thread which tries to attach will sleep.
109 */
110int	autoconf_attdet;
111
112/*
113 * Initialize autoconfiguration data structures.  This occurs before console
114 * initialization as that might require use of this subsystem.  Furthermore
115 * this means that malloc et al. isn't yet available.
116 */
117void
118config_init(void)
119{
120	TAILQ_INIT(&deferred_config_queue);
121	TAILQ_INIT(&alldevs);
122	TAILQ_INIT(&allcftables);
123	TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
124}
125
126/*
127 * Apply the matching function and choose the best.  This is used
128 * a few times and we want to keep the code small.
129 */
130void
131mapply(struct matchinfo *m, struct cfdata *cf)
132{
133	int pri;
134	void *match;
135
136	if (m->indirect)
137		match = config_make_softc(m->parent, cf);
138	else
139		match = cf;
140
141	if (autoconf_verbose) {
142		printf(">>> probing for %s", cf->cf_driver->cd_name);
143		if (cf->cf_fstate == FSTATE_STAR)
144			printf("*\n");
145		else
146			printf("%d\n", cf->cf_unit);
147	}
148	if (m->fn != NULL)
149		pri = (*m->fn)(m->parent, match, m->aux);
150	else {
151	        if (cf->cf_attach->ca_match == NULL) {
152			panic("mapply: no match function for '%s' device",
153			    cf->cf_driver->cd_name);
154		}
155		pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
156	}
157	if (autoconf_verbose)
158		printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
159		    pri);
160
161	if (pri > m->pri) {
162		if (m->indirect && m->match)
163			free(m->match, M_DEVBUF);
164		m->match = match;
165		m->pri = pri;
166	} else {
167		if (m->indirect)
168			free(match, M_DEVBUF);
169	}
170}
171
172/*
173 * Iterate over all potential children of some device, calling the given
174 * function (default being the child's match function) for each one.
175 * Nonzero returns are matches; the highest value returned is considered
176 * the best match.  Return the `found child' if we got a match, or NULL
177 * otherwise.  The `aux' pointer is simply passed on through.
178 *
179 * Note that this function is designed so that it can be used to apply
180 * an arbitrary function to all potential children (its return value
181 * can be ignored).
182 */
183void *
184config_search(cfmatch_t fn, struct device *parent, void *aux)
185{
186	struct cfdata *cf;
187	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	TAILQ_FOREACH(t, &allcftables, list) {
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			if (m.indirect)
217				cf = ((struct device *)m.match)->dv_cfdata;
218			else
219				cf = (struct cfdata *)m.match;
220			printf(">>> %s probe won\n",
221			    cf->cf_driver->cd_name);
222		} else
223			printf(">>> no winning probe\n");
224	}
225	return (m.match);
226}
227
228/*
229 * Iterate over all potential children of some device, calling the given
230 * function for each one.
231 *
232 * Note that this function is designed so that it can be used to apply
233 * an arbitrary function to all potential children (its return value
234 * can be ignored).
235 */
236void
237config_scan(cfscan_t fn, struct device *parent)
238{
239	struct cfdata *cf;
240	short *p;
241	void *match;
242	int indirect;
243	struct cftable *t;
244
245	indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
246	TAILQ_FOREACH(t, &allcftables, list) {
247		for (cf = t->tab; cf->cf_driver; cf++) {
248			/*
249			 * Skip cf if no longer eligible, otherwise scan
250			 * through parents for one matching `parent',
251			 * and try match function.
252			 */
253			if (cf->cf_fstate == FSTATE_FOUND)
254				continue;
255			if (cf->cf_fstate == FSTATE_DNOTFOUND ||
256			    cf->cf_fstate == FSTATE_DSTAR)
257				continue;
258			for (p = cf->cf_parents; *p >= 0; p++)
259				if (parent->dv_cfdata == &(t->tab)[*p]) {
260					match = indirect?
261					    config_make_softc(parent, cf) :
262					    (void *)cf;
263					(*fn)(parent, match);
264				}
265		}
266	}
267}
268
269/*
270 * Find the given root device.
271 * This is much like config_search, but there is no parent.
272 */
273void *
274config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
275{
276	struct cfdata *cf;
277	short *p;
278	struct matchinfo m;
279
280	m.fn = fn;
281	m.parent = ROOT;
282	m.match = NULL;
283	m.aux = aux;
284	m.indirect = 0;
285	m.pri = 0;
286	/*
287	 * Look at root entries for matching name.  We do not bother
288	 * with found-state here since only one instance of each possible
289	 * root child should ever be searched.
290	 */
291	for (p = cfroots; *p >= 0; p++) {
292		cf = &cfdata[*p];
293		if (cf->cf_fstate == FSTATE_DNOTFOUND ||
294		    cf->cf_fstate == FSTATE_DSTAR)
295			continue;
296		if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
297			mapply(&m, cf);
298	}
299	return (m.match);
300}
301
302char *msgs[3] = { "", " not configured\n", " unsupported\n" };
303
304/*
305 * The given `aux' argument describes a device that has been found
306 * on the given parent, but not necessarily configured.  Locate the
307 * configuration data for that device (using the submatch function
308 * provided, or using candidates' cd_match configuration driver
309 * functions) and attach it, and return true.  If the device was
310 * not configured, call the given `print' function and return 0.
311 */
312struct device *
313config_found_sm(struct device *parent, void *aux, cfprint_t print,
314    cfmatch_t submatch)
315{
316	void *match;
317
318	if ((match = config_search(submatch, parent, aux)) != NULL)
319		return (config_attach(parent, match, aux, print));
320	if (print)
321		printf(msgs[(*print)(aux, parent->dv_xname)]);
322	return (NULL);
323}
324
325/*
326 * As above, but for root devices.
327 */
328struct device *
329config_rootfound(char *rootname, void *aux)
330{
331	void *match;
332
333	if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
334		return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
335	printf("root device %s not configured\n", rootname);
336	return (NULL);
337}
338
339/*
340 * Attach a found device.  Allocates memory for device variables.
341 */
342struct device *
343config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
344{
345	struct cfdata *cf;
346	struct device *dev;
347	struct cfdriver *cd;
348	struct cfattach *ca;
349	struct cftable *t;
350
351	mtx_enter(&autoconf_attdet_mtx);
352	while (autoconf_attdet < 0)
353		msleep(&autoconf_attdet, &autoconf_attdet_mtx,
354		    PWAIT, "autoconf", 0);
355	autoconf_attdet++;
356	mtx_leave(&autoconf_attdet_mtx);
357
358	if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
359		dev = match;
360		cf = dev->dv_cfdata;
361	} else {
362		cf = match;
363		dev = config_make_softc(parent, cf);
364	}
365
366	cd = cf->cf_driver;
367	ca = cf->cf_attach;
368
369	KASSERT(cd->cd_devs != NULL);
370	KASSERT(dev->dv_unit < cd->cd_ndevs);
371	KASSERT(cd->cd_devs[dev->dv_unit] == NULL);
372	cd->cd_devs[dev->dv_unit] = dev;
373
374	/*
375	 * If this is a "STAR" device and we used the last unit, prepare for
376	 * another one.
377	 */
378	if (cf->cf_fstate == FSTATE_STAR) {
379		if (dev->dv_unit == cf->cf_unit)
380			cf->cf_unit++;
381	} else
382		cf->cf_fstate = FSTATE_FOUND;
383
384	TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
385	device_ref(dev);
386
387	if (parent == ROOT)
388		printf("%s at root", dev->dv_xname);
389	else {
390		printf("%s at %s", dev->dv_xname, parent->dv_xname);
391		if (print)
392			(void) (*print)(aux, (char *)0);
393	}
394
395	/*
396	 * Before attaching, clobber any unfound devices that are
397	 * otherwise identical, or bump the unit number on all starred
398	 * cfdata for this device.
399	 */
400	TAILQ_FOREACH(t, &allcftables, list) {
401		for (cf = t->tab; cf->cf_driver; cf++)
402			if (cf->cf_driver == cd &&
403			    cf->cf_unit == dev->dv_unit) {
404				if (cf->cf_fstate == FSTATE_NOTFOUND)
405					cf->cf_fstate = FSTATE_FOUND;
406				if (cf->cf_fstate == FSTATE_STAR)
407					cf->cf_unit++;
408			}
409	}
410	device_register(dev, aux);
411	(*ca->ca_attach)(parent, dev, aux);
412	config_process_deferred_children(dev);
413#if NHOTPLUG > 0
414	if (!cold)
415		hotplug_device_attach(cd->cd_class, dev->dv_xname);
416#endif
417
418	mtx_enter(&autoconf_attdet_mtx);
419	if (--autoconf_attdet == 0)
420		wakeup(&autoconf_attdet);
421	mtx_leave(&autoconf_attdet_mtx);
422	return (dev);
423}
424
425struct device *
426config_make_softc(struct device *parent, struct cfdata *cf)
427{
428	struct device *dev;
429	struct cfdriver *cd;
430	struct cfattach *ca;
431
432	cd = cf->cf_driver;
433	ca = cf->cf_attach;
434	if (ca->ca_devsize < sizeof(struct device))
435		panic("config_make_softc");
436
437	/* get memory for all device vars */
438	dev = malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT|M_ZERO);
439	if (!dev)
440		panic("config_make_softc: allocation for device softc failed");
441
442	dev->dv_class = cd->cd_class;
443	dev->dv_cfdata = cf;
444	dev->dv_flags = DVF_ACTIVE;	/* always initially active */
445
446	/* If this is a STAR device, search for a free unit number */
447	if (cf->cf_fstate == FSTATE_STAR) {
448		for (dev->dv_unit = cf->cf_starunit1;
449		    dev->dv_unit < cf->cf_unit; dev->dv_unit++)
450			if (cd->cd_ndevs == 0 ||
451			    dev->dv_unit >= cd->cd_ndevs ||
452			    cd->cd_devs[dev->dv_unit] == NULL)
453				break;
454	} else
455		dev->dv_unit = cf->cf_unit;
456
457	/* Build the device name into dv_xname. */
458	if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
459	    cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
460		panic("config_make_softc: device name too long");
461	dev->dv_parent = parent;
462
463	/* put this device in the devices array */
464	if (dev->dv_unit >= cd->cd_ndevs) {
465		/*
466		 * Need to expand the array.
467		 */
468		int old = cd->cd_ndevs, new;
469		void **nsp;
470
471		if (old == 0)
472			new = MINALLOCSIZE / sizeof(void *);
473		else
474			new = old * 2;
475		while (new <= dev->dv_unit)
476			new *= 2;
477		cd->cd_ndevs = new;
478		nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT|M_ZERO);
479		if (nsp == 0)
480			panic("config_make_softc: %sing dev array",
481			    old != 0 ? "expand" : "creat");
482		if (old != 0) {
483			bcopy(cd->cd_devs, nsp, old * sizeof(void *));
484			free(cd->cd_devs, M_DEVBUF);
485		}
486		cd->cd_devs = nsp;
487	}
488	if (cd->cd_devs[dev->dv_unit])
489		panic("config_make_softc: duplicate %s", dev->dv_xname);
490
491	dev->dv_ref = 1;
492
493	return (dev);
494}
495
496/*
497 * Detach a device.  Optionally forced (e.g. because of hardware
498 * removal) and quiet.  Returns zero if successful, non-zero
499 * (an error code) otherwise.
500 *
501 * Note that this code wants to be run from a process context, so
502 * that the detach can sleep to allow processes which have a device
503 * open to run and unwind their stacks.
504 */
505int
506config_detach(struct device *dev, int flags)
507{
508	struct cfdata *cf;
509	struct cfattach *ca;
510	struct cfdriver *cd;
511	int rv = 0, i;
512#ifdef DIAGNOSTIC
513	struct device *d;
514#endif
515#if NHOTPLUG > 0
516	char devname[16];
517#endif
518
519	mtx_enter(&autoconf_attdet_mtx);
520	while (autoconf_attdet > 0)
521		msleep(&autoconf_attdet, &autoconf_attdet_mtx,
522		    PWAIT, "autoconf", 0);
523	autoconf_attdet--;
524	mtx_leave(&autoconf_attdet_mtx);
525
526#if NHOTPLUG > 0
527	strlcpy(devname, dev->dv_xname, sizeof(devname));
528#endif
529
530	cf = dev->dv_cfdata;
531#ifdef DIAGNOSTIC
532	if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
533		panic("config_detach: bad device fstate");
534#endif
535	ca = cf->cf_attach;
536	cd = cf->cf_driver;
537
538	/*
539	 * Ensure the device is deactivated.  If the device doesn't
540	 * have an activation entry point, we allow DVF_ACTIVE to
541	 * remain set.  Otherwise, if DVF_ACTIVE is still set, the
542	 * device is busy, and the detach fails.
543	 */
544	if (ca->ca_activate != NULL)
545		rv = config_deactivate(dev);
546
547	/*
548	 * Try to detach the device.  If that's not possible, then
549	 * we either panic() (for the forced but failed case), or
550	 * return an error.
551	 */
552	if (rv == 0) {
553		if (ca->ca_detach != NULL)
554			rv = (*ca->ca_detach)(dev, flags);
555		else
556			rv = EOPNOTSUPP;
557	}
558	if (rv != 0) {
559		if ((flags & DETACH_FORCE) == 0)
560			goto done;
561		else
562			panic("config_detach: forced detach of %s failed (%d)",
563			    dev->dv_xname, rv);
564	}
565
566	/*
567	 * The device has now been successfully detached.
568	 */
569
570#ifdef DIAGNOSTIC
571	/*
572	 * Sanity: If you're successfully detached, you should have no
573	 * children.  (Note that because children must be attached
574	 * after parents, we only need to search the latter part of
575	 * the list.)
576	 */
577	i = 0;
578	for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
579	     d = TAILQ_NEXT(d, dv_list)) {
580		if (d->dv_parent == dev) {
581			printf("config_detach: %s attached at %s\n",
582			    d->dv_xname, dev->dv_xname);
583			i = 1;
584		}
585	}
586	if (i != 0)
587		panic("config_detach: detached device (%s) has children",
588		    dev->dv_xname);
589#endif
590
591	/*
592	 * Mark cfdata to show that the unit can be reused, if possible.
593	 * Note that we can only re-use a starred unit number if the unit
594	 * being detached had the last assigned unit number.
595	 */
596	for (cf = cfdata; cf->cf_driver; cf++) {
597		if (cf->cf_driver == cd) {
598			if (cf->cf_fstate == FSTATE_FOUND &&
599			    cf->cf_unit == dev->dv_unit)
600				cf->cf_fstate = FSTATE_NOTFOUND;
601			if (cf->cf_fstate == FSTATE_STAR &&
602			    cf->cf_unit == dev->dv_unit + 1)
603				cf->cf_unit--;
604		}
605	}
606
607	/*
608	 * Unlink from device list.
609	 */
610	TAILQ_REMOVE(&alldevs, dev, dv_list);
611	device_unref(dev);
612
613	/*
614	 * Remove from cfdriver's array, tell the world, and free softc.
615	 */
616	cd->cd_devs[dev->dv_unit] = NULL;
617	if ((flags & DETACH_QUIET) == 0)
618		printf("%s detached\n", dev->dv_xname);
619
620	device_unref(dev);
621	/*
622	 * If the device now has no units in use, deallocate its softc array.
623	 */
624	for (i = 0; i < cd->cd_ndevs; i++)
625		if (cd->cd_devs[i] != NULL)
626			break;
627	if (i == cd->cd_ndevs) {		/* nothing found; deallocate */
628		free(cd->cd_devs, M_DEVBUF);
629		cd->cd_devs = NULL;
630		cd->cd_ndevs = 0;
631		cf->cf_unit = 0;
632	}
633
634#if NHOTPLUG > 0
635	if (!cold)
636		hotplug_device_detach(cd->cd_class, devname);
637#endif
638
639	/*
640	 * Return success.
641	 */
642done:
643	mtx_enter(&autoconf_attdet_mtx);
644	if (++autoconf_attdet == 0)
645		wakeup(&autoconf_attdet);
646	mtx_leave(&autoconf_attdet_mtx);
647	return (rv);
648}
649
650int
651config_deactivate(struct device *dev)
652{
653	struct cfattach *ca = dev->dv_cfdata->cf_attach;
654	int rv = 0, oflags = dev->dv_flags;
655
656	if (ca->ca_activate == NULL)
657		return (EOPNOTSUPP);
658
659	if (dev->dv_flags & DVF_ACTIVE) {
660		dev->dv_flags &= ~DVF_ACTIVE;
661		rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
662		if (rv)
663			dev->dv_flags = oflags;
664	}
665	return (rv);
666}
667
668/*
669 * Defer the configuration of the specified device until all
670 * of its parent's devices have been attached.
671 */
672void
673config_defer(struct device *dev, void (*func)(struct device *))
674{
675	struct deferred_config *dc;
676
677	if (dev->dv_parent == NULL)
678		panic("config_defer: can't defer config of a root device");
679
680#ifdef DIAGNOSTIC
681	for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
682	     dc = TAILQ_NEXT(dc, dc_queue)) {
683		if (dc->dc_dev == dev)
684			panic("config_defer: deferred twice");
685	}
686#endif
687
688	if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
689		panic("config_defer: can't allocate defer structure");
690
691	dc->dc_dev = dev;
692	dc->dc_func = func;
693	TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
694	config_pending_incr();
695}
696
697/*
698 * Process the deferred configuration queue for a device.
699 */
700void
701config_process_deferred_children(struct device *parent)
702{
703	struct deferred_config *dc, *ndc;
704
705	for (dc = TAILQ_FIRST(&deferred_config_queue);
706	     dc != NULL; dc = ndc) {
707		ndc = TAILQ_NEXT(dc, dc_queue);
708		if (dc->dc_dev->dv_parent == parent) {
709			TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
710			(*dc->dc_func)(dc->dc_dev);
711			free(dc, M_DEVBUF);
712			config_pending_decr();
713		}
714	}
715}
716
717/*
718 * Manipulate the config_pending semaphore.
719 */
720void
721config_pending_incr(void)
722{
723
724	config_pending++;
725}
726
727void
728config_pending_decr(void)
729{
730
731#ifdef DIAGNOSTIC
732	if (config_pending == 0)
733		panic("config_pending_decr: config_pending == 0");
734#endif
735	config_pending--;
736	if (config_pending == 0)
737		wakeup((void *)&config_pending);
738}
739
740int
741config_detach_children(struct device *parent, int flags)
742{
743	struct device *dev, *next_dev;
744	int rv = 0;
745
746	/*
747	 * The config_detach routine may sleep, meaning devices
748	 * may be added to the queue. However, all devices will
749	 * be added to the tail of the queue, the queue won't
750	 * be re-organized, and the subtree of parent here should be locked
751	 * for purposes of adding/removing children.
752	 *
753	 * Note that we can not afford trying to walk the device list
754	 * once - our ``next'' device might be a child of the device
755	 * we are about to detach, so it would disappear.
756	 * Just play it safe and restart from the parent.
757	 */
758	for (dev = TAILQ_LAST(&alldevs, devicelist);
759	    dev != NULL; dev = next_dev) {
760		if (dev->dv_parent == parent) {
761			if ((rv = config_detach(dev, flags)) != 0)
762				return (rv);
763			next_dev = TAILQ_LAST(&alldevs, devicelist);
764		} else {
765			next_dev = TAILQ_PREV(dev, devicelist, dv_list);
766		}
767	}
768
769	return (0);
770}
771
772int
773config_suspend(struct device *dev, int act)
774{
775	struct cfattach *ca = dev->dv_cfdata->cf_attach;
776
777	if (ca->ca_activate) {
778#if 0
779		printf("activate: %s %d\n", dev->dv_xname, act);
780#endif
781		return (*ca->ca_activate)(dev, act);
782	}
783	return (0);
784}
785
786/*
787 * Call the ca_activate for each of our children, letting each
788 * decide whether they wish to do the same for their children
789 * and more.
790 */
791int
792config_activate_children(struct device *parent, int act)
793{
794	struct device *d;
795	int rv = 0;
796
797	for (d = TAILQ_NEXT(parent, dv_list); d != NULL;
798	    d = TAILQ_NEXT(d, dv_list)) {
799		if (d->dv_parent != parent)
800			continue;
801		switch (act) {
802		case DVACT_SUSPEND:
803		case DVACT_RESUME:
804		case DVACT_QUIESCE:
805			rv = config_suspend(d, act);
806			break;
807		case DVACT_DEACTIVATE:
808			rv = config_deactivate(d);
809			break;
810		}
811		if (rv == 0)
812			continue;
813
814		/*
815		 * Found a device that refuses the action.
816		 * If we were being asked to suspend, we can
817		 * try to resume all previous devices.
818		 */
819#ifdef DIAGNOSTIC
820		printf("config_activate_children: device %s failed %d\n",
821		    d->dv_xname, act);
822#endif
823		if (act == DVACT_RESUME)
824			printf("failing resume cannot be handled\n");
825		if (act != DVACT_SUSPEND)
826			return (rv);
827
828		d = TAILQ_PREV(d, devicelist, dv_list);
829		for (; d != NULL && d != parent;
830		    d = TAILQ_PREV(d, devicelist, dv_list)) {
831			if (d->dv_parent != parent)
832				continue;
833			printf("resume %s\n", d->dv_xname);
834			config_suspend(d, DVACT_RESUME);
835		}
836		return (rv);
837	}
838	return (rv);
839}
840
841/*
842 * Lookup a device in the cfdriver device array.  Does not return a
843 * device if it is not active.
844 *
845 * Increments ref count on the device by one, reflecting the
846 * new reference created on the stack.
847 *
848 * Context: process only
849 */
850struct device *
851device_lookup(struct cfdriver *cd, int unit)
852{
853	struct device *dv = NULL;
854
855	if (unit >= 0 && unit < cd->cd_ndevs)
856		dv = (struct device *)(cd->cd_devs[unit]);
857
858	if (!dv)
859		return (NULL);
860
861	if (!(dv->dv_flags & DVF_ACTIVE))
862		dv = NULL;
863
864	if (dv != NULL)
865		device_ref(dv);
866
867	return (dv);
868}
869
870
871/*
872 * Increments the ref count on the device structure. The device
873 * structure is freed when the ref count hits 0.
874 *
875 * Context: process or interrupt
876 */
877void
878device_ref(struct device *dv)
879{
880	dv->dv_ref++;
881}
882
883/*
884 * Decrement the ref count on the device structure.
885 *
886 * free's the structure when the ref count hits zero.
887 *
888 * Context: process or interrupt
889 */
890void
891device_unref(struct device *dv)
892{
893	dv->dv_ref--;
894	if (dv->dv_ref == 0) {
895		free(dv, M_DEVBUF);
896	}
897}
898