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