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 }