Annotation of sys/kern/subr_autoconf.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: subr_autoconf.c,v 1.52 2007/05/30 05:36:36 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: typedef int (*cond_predicate_t)(struct device *, void *);
63:
64: /*
65: * ioconf.c exports exactly two names: cfdata and cfroots. All system
66: * devices and drivers are found via these tables.
67: */
68: extern short cfroots[];
69:
70: #define ROOT ((struct device *)NULL)
71:
72: struct matchinfo {
73: cfmatch_t fn;
74: struct device *parent;
75: void *match, *aux;
76: int indirect, pri;
77: };
78:
79: struct cftable_head allcftables;
80:
81: static struct cftable staticcftable = {
82: cfdata
83: };
84:
85: #ifndef AUTOCONF_VERBOSE
86: #define AUTOCONF_VERBOSE 0
87: #endif /* AUTOCONF_VERBOSE */
88: int autoconf_verbose = AUTOCONF_VERBOSE; /* trace probe calls */
89:
90: static void mapply(struct matchinfo *, struct cfdata *);
91:
92: struct deferred_config {
93: TAILQ_ENTRY(deferred_config) dc_queue;
94: struct device *dc_dev;
95: void (*dc_func)(struct device *);
96: };
97:
98: TAILQ_HEAD(, deferred_config) deferred_config_queue;
99:
100: void config_process_deferred_children(struct device *);
101:
102: struct devicelist alldevs; /* list of all devices */
103:
104: __volatile int config_pending; /* semaphore for mountroot */
105:
106: /*
107: * Initialize autoconfiguration data structures. This occurs before console
108: * initialization as that might require use of this subsystem. Furthermore
109: * this means that malloc et al. isn't yet available.
110: */
111: void
112: config_init(void)
113: {
114: TAILQ_INIT(&deferred_config_queue);
115: TAILQ_INIT(&alldevs);
116: TAILQ_INIT(&allcftables);
117: TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
118: }
119:
120: /*
121: * Apply the matching function and choose the best. This is used
122: * a few times and we want to keep the code small.
123: */
124: void
125: mapply(struct matchinfo *m, struct cfdata *cf)
126: {
127: int pri;
128: void *match;
129:
130: if (m->indirect)
131: match = config_make_softc(m->parent, cf);
132: else
133: match = cf;
134:
135: if (autoconf_verbose) {
136: printf(">>> probing for %s", cf->cf_driver->cd_name);
137: if (cf->cf_fstate == FSTATE_STAR)
138: printf("*\n");
139: else
140: printf("%d\n", cf->cf_unit);
141: }
142: if (m->fn != NULL)
143: pri = (*m->fn)(m->parent, match, m->aux);
144: else {
145: if (cf->cf_attach->ca_match == NULL) {
146: panic("mapply: no match function for '%s' device",
147: cf->cf_driver->cd_name);
148: }
149: pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
150: }
151: if (autoconf_verbose)
152: printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
153: pri);
154:
155: if (pri > m->pri) {
156: if (m->indirect && m->match)
157: free(m->match, M_DEVBUF);
158: m->match = match;
159: m->pri = pri;
160: } else {
161: if (m->indirect)
162: free(match, M_DEVBUF);
163: }
164: }
165:
166: /*
167: * Iterate over all potential children of some device, calling the given
168: * function (default being the child's match function) for each one.
169: * Nonzero returns are matches; the highest value returned is considered
170: * the best match. Return the `found child' if we got a match, or NULL
171: * otherwise. The `aux' pointer is simply passed on through.
172: *
173: * Note that this function is designed so that it can be used to apply
174: * an arbitrary function to all potential children (its return value
175: * can be ignored).
176: */
177: void *
178: config_search(cfmatch_t fn, struct device *parent, void *aux)
179: {
180: struct cfdata *cf;
181: short *p;
182: struct matchinfo m;
183: struct cftable *t;
184:
185: m.fn = fn;
186: m.parent = parent;
187: m.match = NULL;
188: m.aux = aux;
189: m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
190: m.pri = 0;
191: TAILQ_FOREACH(t, &allcftables, list) {
192: for (cf = t->tab; cf->cf_driver; cf++) {
193: /*
194: * Skip cf if no longer eligible, otherwise scan
195: * through parents for one matching `parent',
196: * and try match function.
197: */
198: if (cf->cf_fstate == FSTATE_FOUND)
199: continue;
200: if (cf->cf_fstate == FSTATE_DNOTFOUND ||
201: cf->cf_fstate == FSTATE_DSTAR)
202: continue;
203: for (p = cf->cf_parents; *p >= 0; p++)
204: if (parent->dv_cfdata == &(t->tab)[*p])
205: mapply(&m, cf);
206: }
207: }
208: if (autoconf_verbose) {
209: if (m.match) {
210: if (m.indirect)
211: cf = ((struct device *)m.match)->dv_cfdata;
212: else
213: cf = (struct cfdata *)m.match;
214: printf(">>> %s probe won\n",
215: cf->cf_driver->cd_name);
216: } else
217: printf(">>> no winning probe\n");
218: }
219: return (m.match);
220: }
221:
222: /*
223: * Iterate over all potential children of some device, calling the given
224: * function for each one.
225: *
226: * Note that this function is designed so that it can be used to apply
227: * an arbitrary function to all potential children (its return value
228: * can be ignored).
229: */
230: void
231: config_scan(cfscan_t fn, struct device *parent)
232: {
233: struct cfdata *cf;
234: short *p;
235: void *match;
236: int indirect;
237: struct cftable *t;
238:
239: indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
240: TAILQ_FOREACH(t, &allcftables, list) {
241: for (cf = t->tab; cf->cf_driver; cf++) {
242: /*
243: * Skip cf if no longer eligible, otherwise scan
244: * through parents for one matching `parent',
245: * and try match function.
246: */
247: if (cf->cf_fstate == FSTATE_FOUND)
248: continue;
249: if (cf->cf_fstate == FSTATE_DNOTFOUND ||
250: cf->cf_fstate == FSTATE_DSTAR)
251: continue;
252: for (p = cf->cf_parents; *p >= 0; p++)
253: if (parent->dv_cfdata == &(t->tab)[*p]) {
254: match = indirect?
255: config_make_softc(parent, cf) :
256: (void *)cf;
257: (*fn)(parent, match);
258: }
259: }
260: }
261: }
262:
263: /*
264: * Find the given root device.
265: * This is much like config_search, but there is no parent.
266: */
267: void *
268: config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
269: {
270: struct cfdata *cf;
271: short *p;
272: struct matchinfo m;
273:
274: m.fn = fn;
275: m.parent = ROOT;
276: m.match = NULL;
277: m.aux = aux;
278: m.indirect = 0;
279: m.pri = 0;
280: /*
281: * Look at root entries for matching name. We do not bother
282: * with found-state here since only one root should ever be
283: * searched (and it must be done first).
284: */
285: for (p = cfroots; *p >= 0; p++) {
286: cf = &cfdata[*p];
287: if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
288: mapply(&m, cf);
289: }
290: return (m.match);
291: }
292:
293: char *msgs[3] = { "", " not configured\n", " unsupported\n" };
294:
295: /*
296: * The given `aux' argument describes a device that has been found
297: * on the given parent, but not necessarily configured. Locate the
298: * configuration data for that device (using the submatch function
299: * provided, or using candidates' cd_match configuration driver
300: * functions) and attach it, and return true. If the device was
301: * not configured, call the given `print' function and return 0.
302: */
303: struct device *
304: config_found_sm(struct device *parent, void *aux, cfprint_t print,
305: cfmatch_t submatch)
306: {
307: void *match;
308:
309: if ((match = config_search(submatch, parent, aux)) != NULL)
310: return (config_attach(parent, match, aux, print));
311: if (print)
312: printf(msgs[(*print)(aux, parent->dv_xname)]);
313: return (NULL);
314: }
315:
316: /*
317: * As above, but for root devices.
318: */
319: struct device *
320: config_rootfound(char *rootname, void *aux)
321: {
322: void *match;
323:
324: if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
325: return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
326: printf("root device %s not configured\n", rootname);
327: return (NULL);
328: }
329:
330: /*
331: * Attach a found device. Allocates memory for device variables.
332: */
333: struct device *
334: config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
335: {
336: struct cfdata *cf;
337: struct device *dev;
338: struct cfdriver *cd;
339: struct cfattach *ca;
340: struct cftable *t;
341:
342: if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
343: dev = match;
344: cf = dev->dv_cfdata;
345: } else {
346: cf = match;
347: dev = config_make_softc(parent, cf);
348: }
349:
350: cd = cf->cf_driver;
351: ca = cf->cf_attach;
352:
353: cd->cd_devs[dev->dv_unit] = dev;
354:
355: /*
356: * If this is a "STAR" device and we used the last unit, prepare for
357: * another one.
358: */
359: if (cf->cf_fstate == FSTATE_STAR) {
360: if (dev->dv_unit == cf->cf_unit)
361: cf->cf_unit++;
362: } else
363: cf->cf_fstate = FSTATE_FOUND;
364:
365: TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
366: device_ref(dev);
367:
368: if (parent == ROOT)
369: printf("%s at root", dev->dv_xname);
370: else {
371: printf("%s at %s", dev->dv_xname, parent->dv_xname);
372: if (print)
373: (void) (*print)(aux, (char *)0);
374: }
375:
376: /*
377: * Before attaching, clobber any unfound devices that are
378: * otherwise identical, or bump the unit number on all starred
379: * cfdata for this device.
380: */
381: TAILQ_FOREACH(t, &allcftables, list) {
382: for (cf = t->tab; cf->cf_driver; cf++)
383: if (cf->cf_driver == cd &&
384: cf->cf_unit == dev->dv_unit) {
385: if (cf->cf_fstate == FSTATE_NOTFOUND)
386: cf->cf_fstate = FSTATE_FOUND;
387: if (cf->cf_fstate == FSTATE_STAR)
388: cf->cf_unit++;
389: }
390: }
391: device_register(dev, aux);
392: (*ca->ca_attach)(parent, dev, aux);
393: config_process_deferred_children(dev);
394: #if NHOTPLUG > 0
395: if (!cold)
396: hotplug_device_attach(cd->cd_class, dev->dv_xname);
397: #endif
398: return (dev);
399: }
400:
401: struct device *
402: config_make_softc(struct device *parent, struct cfdata *cf)
403: {
404: struct device *dev;
405: struct cfdriver *cd;
406: struct cfattach *ca;
407:
408: cd = cf->cf_driver;
409: ca = cf->cf_attach;
410: if (ca->ca_devsize < sizeof(struct device))
411: panic("config_make_softc");
412:
413: /* get memory for all device vars */
414: dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
415: if (!dev)
416: panic("config_make_softc: allocation for device softc failed");
417: bzero(dev, ca->ca_devsize);
418: dev->dv_class = cd->cd_class;
419: dev->dv_cfdata = cf;
420: dev->dv_flags = DVF_ACTIVE; /* always initially active */
421:
422: /* If this is a STAR device, search for a free unit number */
423: if (cf->cf_fstate == FSTATE_STAR) {
424: for (dev->dv_unit = cf->cf_starunit1;
425: dev->dv_unit < cf->cf_unit; dev->dv_unit++)
426: if (cd->cd_ndevs == 0 ||
427: dev->dv_unit >= cd->cd_ndevs ||
428: cd->cd_devs[dev->dv_unit] == NULL)
429: break;
430: } else
431: dev->dv_unit = cf->cf_unit;
432:
433: /* Build the device name into dv_xname. */
434: if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
435: cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
436: panic("config_make_softc: device name too long");
437: dev->dv_parent = parent;
438:
439: /* put this device in the devices array */
440: if (dev->dv_unit >= cd->cd_ndevs) {
441: /*
442: * Need to expand the array.
443: */
444: int old = cd->cd_ndevs, new;
445: void **nsp;
446:
447: if (old == 0)
448: new = MINALLOCSIZE / sizeof(void *);
449: else
450: new = old * 2;
451: while (new <= dev->dv_unit)
452: new *= 2;
453: cd->cd_ndevs = new;
454: nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
455: if (nsp == 0)
456: panic("config_make_softc: %sing dev array",
457: old != 0 ? "expand" : "creat");
458: bzero(nsp + old, (new - old) * sizeof(void *));
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, *prev_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 (prev_dev = NULL, 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 = prev_dev ? prev_dev : TAILQ_LAST(&alldevs,
740: devicelist);
741: } else {
742: prev_dev = dev;
743: next_dev = TAILQ_PREV(dev, devicelist, dv_list);
744: }
745: }
746:
747: return (0);
748: }
749:
750: int
751: config_activate_children(struct device *parent, enum devact act)
752: {
753: struct device *dev, *next_dev;
754: int rv = 0;
755:
756: /* The config_deactivate routine may sleep, meaning devices
757: may be added to the queue. However, all devices will
758: be added to the tail of the queue, the queue won't
759: be re-organized, and the subtree of parent here should be locked
760: for purposes of adding/removing children.
761: */
762: for (dev = TAILQ_FIRST(&alldevs);
763: dev != NULL; dev = next_dev) {
764: next_dev = TAILQ_NEXT(dev, dv_list);
765: if (dev->dv_parent == parent) {
766: switch (act) {
767: case DVACT_ACTIVATE:
768: rv = config_activate(dev);
769: break;
770: case DVACT_DEACTIVATE:
771: rv = config_deactivate(dev);
772: break;
773: default:
774: #ifdef DIAGNOSTIC
775: printf ("config_activate_children: shouldn't get here");
776: #endif
777: rv = EOPNOTSUPP;
778: break;
779:
780: }
781:
782: if (rv)
783: break;
784: }
785: }
786:
787: return (rv);
788: }
789:
790: /*
791: * Lookup a device in the cfdriver device array. Does not return a
792: * device if it is not active.
793: *
794: * Increments ref count on the device by one, reflecting the
795: * new reference created on the stack.
796: *
797: * Context: process only
798: */
799: struct device *
800: device_lookup(struct cfdriver *cd, int unit)
801: {
802: struct device *dv = NULL;
803:
804: if (unit >= 0 && unit < cd->cd_ndevs)
805: dv = (struct device *)(cd->cd_devs[unit]);
806:
807: if (!dv)
808: return (NULL);
809:
810: if (!(dv->dv_flags & DVF_ACTIVE))
811: dv = NULL;
812:
813: if (dv != NULL)
814: device_ref(dv);
815:
816: return (dv);
817: }
818:
819:
820: /*
821: * Increments the ref count on the device structure. The device
822: * structure is freed when the ref count hits 0.
823: *
824: * Context: process or interrupt
825: */
826: void
827: device_ref(struct device *dv)
828: {
829: dv->dv_ref++;
830: }
831:
832: /*
833: * Decrement the ref count on the device structure.
834: *
835: * free's the structure when the ref count hits zero.
836: *
837: * Context: process or interrupt
838: */
839: void
840: device_unref(struct device *dv)
841: {
842: dv->dv_ref--;
843: if (dv->dv_ref == 0) {
844: free(dv, M_DEVBUF);
845: }
846: }
CVSweb