subr_autoconf.c revision 1.59
1/*	$OpenBSD: subr_autoconf.c,v 1.59 2009/11/23 14:12:10 deraadt 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 */
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
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 */
109void
110config_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 */
122void
123mapply(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 */
175void *
176config_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 */
228void
229config_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 */
265void *
266config_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
294char *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 */
304struct device *
305config_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 */
320struct device *
321config_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 */
334struct device *
335config_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
402struct device *
403config_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 */
482int
483config_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
608int
609config_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
626int
627config_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 */
648void
649config_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 */
676void
677config_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 */
696void
697config_pending_incr(void)
698{
699
700	config_pending++;
701}
702
703void
704config_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
716int
717config_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
748int
749config_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 */
765int
766config_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		if (d->dv_cfdata->cf_attach->ca_activate)
776			printf("device %s act %d\n", d->dv_xname, act);
777		switch (act) {
778		case DVACT_ACTIVATE:
779			rv = config_activate(d);
780			break;
781		case DVACT_DEACTIVATE:
782			rv = config_deactivate(d);
783			break;
784		case DVACT_SUSPEND:
785		case DVACT_RESUME:
786			rv = config_suspend(d, act);
787			break;
788		}
789		if (rv == 0)
790			continue;
791
792		/*
793		 * Found a device that refuses the action.
794		 * If we were being asked to suspend, we can
795		 * try to resume all previous devices.
796		 */
797#ifdef DIAGNOSTIC
798		printf("config_activate_children: device %s failed %d\n",
799		    d->dv_xname, act);
800#endif
801		if (act == DVACT_RESUME)
802			printf("failing resume cannot be handled\n");
803		if (act != DVACT_SUSPEND)
804			return (rv);
805
806		d = TAILQ_PREV(d, devicelist, dv_list);
807		for (; d != NULL && d != parent;
808		    d = TAILQ_PREV(d, devicelist, dv_list)) {
809			if (d->dv_parent != parent)
810				continue;
811			printf("resume %s\n", d->dv_xname);
812			config_suspend(d, DVACT_RESUME);
813		}
814		return (rv);
815	}
816	return (rv);
817}
818
819/*
820 * Lookup a device in the cfdriver device array.  Does not return a
821 * device if it is not active.
822 *
823 * Increments ref count on the device by one, reflecting the
824 * new reference created on the stack.
825 *
826 * Context: process only
827 */
828struct device *
829device_lookup(struct cfdriver *cd, int unit)
830{
831	struct device *dv = NULL;
832
833	if (unit >= 0 && unit < cd->cd_ndevs)
834		dv = (struct device *)(cd->cd_devs[unit]);
835
836	if (!dv)
837		return (NULL);
838
839	if (!(dv->dv_flags & DVF_ACTIVE))
840		dv = NULL;
841
842	if (dv != NULL)
843		device_ref(dv);
844
845	return (dv);
846}
847
848
849/*
850 * Increments the ref count on the device structure. The device
851 * structure is freed when the ref count hits 0.
852 *
853 * Context: process or interrupt
854 */
855void
856device_ref(struct device *dv)
857{
858	dv->dv_ref++;
859}
860
861/*
862 * Decrement the ref count on the device structure.
863 *
864 * free's the structure when the ref count hits zero.
865 *
866 * Context: process or interrupt
867 */
868void
869device_unref(struct device *dv)
870{
871	dv->dv_ref--;
872	if (dv->dv_ref == 0) {
873		free(dv, M_DEVBUF);
874	}
875}
876