1 /* $OpenBSD: subr_autoconf.c,v 1.39 2004/11/23 19:08:55 miod 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/limits.h>
49 #include <sys/malloc.h>
50 #include <sys/systm.h>
51 /* Extra stuff from Matthias Drochner <drochner@zelux6.zel.kfa-juelich.de> */
52 #include <sys/queue.h>
53 #include <sys/proc.h>
54
55 /*
56 * Autoconfiguration subroutines.
57 */
58
59 typedef int (*cond_predicate_t)(struct device *, void *);
60
61 /*
62 * ioconf.c exports exactly two names: cfdata and cfroots. All system
63 * devices and drivers are found via these tables.
64 */
65 extern short cfroots[];
66
67 #define ROOT ((struct device *)NULL)
68
69 struct matchinfo {
70 cfmatch_t fn;
71 struct device *parent;
72 void *match, *aux;
73 int indirect, pri;
74 };
75
76 struct cftable_head allcftables;
77
78 static struct cftable staticcftable = {
79 cfdata
80 };
81
82 #ifndef AUTOCONF_VERBOSE
83 #define AUTOCONF_VERBOSE 0
84 #endif /* AUTOCONF_VERBOSE */
85 int autoconf_verbose = AUTOCONF_VERBOSE; /* trace probe calls */
86
87 static void mapply(struct matchinfo *, struct cfdata *);
88
89 struct deferred_config {
90 TAILQ_ENTRY(deferred_config) dc_queue;
91 struct device *dc_dev;
92 void (*dc_func)(struct device *);
93 };
94
95 TAILQ_HEAD(, deferred_config) deferred_config_queue;
96
97 void config_process_deferred_children(struct device *);
98
99 struct devicelist alldevs; /* list of all devices */
100 struct evcntlist allevents; /* list of all event counters */
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 */
109 void
config_init()110 config_init()
111 {
112 TAILQ_INIT(&deferred_config_queue);
113 TAILQ_INIT(&alldevs);
114 TAILQ_INIT(&allevents);
115 TAILQ_INIT(&allcftables);
116 TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
117 }
118
119 /*
120 * Apply the matching function and choose the best. This is used
121 * a few times and we want to keep the code small.
122 */
123 void
mapply(m,cf)124 mapply(m, cf)
125 register struct matchinfo *m;
126 register struct cfdata *cf;
127 {
128 register int pri;
129 void *match;
130
131 if (m->indirect)
132 match = config_make_softc(m->parent, cf);
133 else
134 match = cf;
135
136 if (autoconf_verbose) {
137 printf(">>> probing for %s", cf->cf_driver->cd_name);
138 if (cf->cf_fstate == FSTATE_STAR)
139 printf("*\n");
140 else
141 printf("%d\n", cf->cf_unit);
142 }
143 if (m->fn != NULL)
144 pri = (*m->fn)(m->parent, match, m->aux);
145 else {
146 if (cf->cf_attach->ca_match == NULL) {
147 panic("mapply: no match function for '%s' device",
148 cf->cf_driver->cd_name);
149 }
150 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
151 }
152 if (autoconf_verbose)
153 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
154 pri);
155
156 if (pri > m->pri) {
157 if (m->indirect && m->match)
158 free(m->match, M_DEVBUF);
159 m->match = match;
160 m->pri = pri;
161 } else {
162 if (m->indirect)
163 free(match, M_DEVBUF);
164 }
165 }
166
167 /*
168 * Iterate over all potential children of some device, calling the given
169 * function (default being the child's match function) for each one.
170 * Nonzero returns are matches; the highest value returned is considered
171 * the best match. Return the `found child' if we got a match, or NULL
172 * otherwise. The `aux' pointer is simply passed on through.
173 *
174 * Note that this function is designed so that it can be used to apply
175 * an arbitrary function to all potential children (its return value
176 * can be ignored).
177 */
178 void *
config_search(fn,parent,aux)179 config_search(fn, parent, aux)
180 cfmatch_t fn;
181 register struct device *parent;
182 void *aux;
183 {
184 register struct cfdata *cf;
185 register short *p;
186 struct matchinfo m;
187 struct cftable *t;
188
189 m.fn = fn;
190 m.parent = parent;
191 m.match = NULL;
192 m.aux = aux;
193 m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
194 m.pri = 0;
195 for(t = allcftables.tqh_first; t; t = t->list.tqe_next) {
196 for (cf = t->tab; cf->cf_driver; cf++) {
197 /*
198 * Skip cf if no longer eligible, otherwise scan
199 * through parents for one matching `parent',
200 * and try match function.
201 */
202 if (cf->cf_fstate == FSTATE_FOUND)
203 continue;
204 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
205 cf->cf_fstate == FSTATE_DSTAR)
206 continue;
207 for (p = cf->cf_parents; *p >= 0; p++)
208 if (parent->dv_cfdata == &(t->tab)[*p])
209 mapply(&m, cf);
210 }
211 }
212 if (autoconf_verbose) {
213 if (m.match)
214 printf(">>> %s probe won\n",
215 ((struct cfdata *)m.match)->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
config_scan(fn,parent)231 config_scan(fn, parent)
232 cfscan_t fn;
233 register struct device *parent;
234 {
235 register struct cfdata *cf;
236 register short *p;
237 void *match;
238 int indirect;
239 struct cftable *t;
240
241 indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
242 for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
243 for (cf = t->tab; cf->cf_driver; cf++) {
244 /*
245 * Skip cf if no longer eligible, otherwise scan
246 * through parents for one matching `parent',
247 * and try match function.
248 */
249 if (cf->cf_fstate == FSTATE_FOUND)
250 continue;
251 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
252 cf->cf_fstate == FSTATE_DSTAR)
253 continue;
254 for (p = cf->cf_parents; *p >= 0; p++)
255 if (parent->dv_cfdata == &(t->tab)[*p]) {
256 match = indirect?
257 config_make_softc(parent, cf) :
258 (void *)cf;
259 (*fn)(parent, match);
260 }
261 }
262 }
263 }
264
265 /*
266 * Find the given root device.
267 * This is much like config_search, but there is no parent.
268 */
269 void *
config_rootsearch(fn,rootname,aux)270 config_rootsearch(fn, rootname, aux)
271 register cfmatch_t fn;
272 register char *rootname;
273 register void *aux;
274 {
275 register struct cfdata *cf;
276 register short *p;
277 struct matchinfo m;
278
279 m.fn = fn;
280 m.parent = ROOT;
281 m.match = NULL;
282 m.aux = aux;
283 m.indirect = 0;
284 m.pri = 0;
285 /*
286 * Look at root entries for matching name. We do not bother
287 * with found-state here since only one root should ever be
288 * searched (and it must be done first).
289 */
290 for (p = cfroots; *p >= 0; p++) {
291 cf = &cfdata[*p];
292 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
293 mapply(&m, cf);
294 }
295 return (m.match);
296 }
297
298 char *msgs[3] = { "", " not configured\n", " unsupported\n" };
299
300 /*
301 * The given `aux' argument describes a device that has been found
302 * on the given parent, but not necessarily configured. Locate the
303 * configuration data for that device (using the submatch function
304 * provided, or using candidates' cd_match configuration driver
305 * functions) and attach it, and return true. If the device was
306 * not configured, call the given `print' function and return 0.
307 */
308 struct device *
config_found_sm(parent,aux,print,submatch)309 config_found_sm(parent, aux, print, submatch)
310 struct device *parent;
311 void *aux;
312 cfprint_t print;
313 cfmatch_t submatch;
314 {
315 void *match;
316
317 if ((match = config_search(submatch, parent, aux)) != NULL)
318 return (config_attach(parent, match, aux, print));
319 if (print)
320 printf(msgs[(*print)(aux, parent->dv_xname)]);
321 return (NULL);
322 }
323
324 /*
325 * As above, but for root devices.
326 */
327 struct device *
config_rootfound(rootname,aux)328 config_rootfound(rootname, aux)
329 char *rootname;
330 void *aux;
331 {
332 void *match;
333
334 if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
335 return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
336 printf("root device %s not configured\n", rootname);
337 return (NULL);
338 }
339
340 /*
341 * Attach a found device. Allocates memory for device variables.
342 */
343 struct device *
config_attach(parent,match,aux,print)344 config_attach(parent, match, aux, print)
345 register struct device *parent;
346 void *match;
347 register void *aux;
348 cfprint_t print;
349 {
350 register struct cfdata *cf;
351 register struct device *dev;
352 register struct cfdriver *cd;
353 register struct cfattach *ca;
354 struct cftable *t;
355
356 if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
357 dev = match;
358 cf = dev->dv_cfdata;
359 } else {
360 cf = match;
361 dev = config_make_softc(parent, cf);
362 }
363
364 cd = cf->cf_driver;
365 ca = cf->cf_attach;
366
367 cd->cd_devs[dev->dv_unit] = dev;
368
369 /*
370 * If this is a "STAR" device and we used the last unit, prepare for
371 * another one.
372 */
373 if (cf->cf_fstate == FSTATE_STAR) {
374 if (dev->dv_unit == cf->cf_unit)
375 cf->cf_unit++;
376 } else
377 cf->cf_fstate = FSTATE_FOUND;
378
379 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
380 device_ref(dev);
381
382 if (parent == ROOT)
383 printf("%s (root)", dev->dv_xname);
384 else {
385 printf("%s at %s", dev->dv_xname, parent->dv_xname);
386 if (print)
387 (void) (*print)(aux, (char *)0);
388 }
389
390 /*
391 * Before attaching, clobber any unfound devices that are
392 * otherwise identical, or bump the unit number on all starred
393 * cfdata for this device.
394 */
395 for (t = allcftables.tqh_first; t; t = t->list.tqe_next) {
396 for (cf = t->tab; cf->cf_driver; cf++)
397 if (cf->cf_driver == cd &&
398 cf->cf_unit == dev->dv_unit) {
399 if (cf->cf_fstate == FSTATE_NOTFOUND)
400 cf->cf_fstate = FSTATE_FOUND;
401 if (cf->cf_fstate == FSTATE_STAR)
402 cf->cf_unit++;
403 }
404 }
405 #ifdef __HAVE_DEVICE_REGISTER
406 device_register(dev, aux);
407 #endif
408 (*ca->ca_attach)(parent, dev, aux);
409 config_process_deferred_children(dev);
410 return (dev);
411 }
412
413 struct device *
config_make_softc(parent,cf)414 config_make_softc(parent, cf)
415 struct device *parent;
416 struct cfdata *cf;
417 {
418 register struct device *dev;
419 register struct cfdriver *cd;
420 register struct cfattach *ca;
421
422 cd = cf->cf_driver;
423 ca = cf->cf_attach;
424 if (ca->ca_devsize < sizeof(struct device))
425 panic("config_make_softc");
426
427 /* get memory for all device vars */
428 dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
429 if (!dev)
430 panic("config_make_softc: allocation for device softc failed");
431 bzero(dev, ca->ca_devsize);
432 dev->dv_class = cd->cd_class;
433 dev->dv_cfdata = cf;
434 dev->dv_flags = DVF_ACTIVE; /* always initially active */
435
436 /* If this is a STAR device, search for a free unit number */
437 if (cf->cf_fstate == FSTATE_STAR) {
438 for (dev->dv_unit = cf->cf_starunit1;
439 dev->dv_unit < cf->cf_unit; dev->dv_unit++)
440 if (cd->cd_ndevs == 0 ||
441 cd->cd_devs[dev->dv_unit] == NULL)
442 break;
443 } else
444 dev->dv_unit = cf->cf_unit;
445
446 /* Build the device name into dv_xname. */
447 if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
448 cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
449 panic("config_make_softc: device name too long");
450 dev->dv_parent = parent;
451
452 /* put this device in the devices array */
453 if (dev->dv_unit >= cd->cd_ndevs) {
454 /*
455 * Need to expand the array.
456 */
457 int old = cd->cd_ndevs, new;
458 void **nsp;
459
460 if (old == 0)
461 new = MINALLOCSIZE / sizeof(void *);
462 else
463 new = old * 2;
464 while (new <= dev->dv_unit)
465 new *= 2;
466 cd->cd_ndevs = new;
467 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
468 if (nsp == 0)
469 panic("config_make_softc: %sing dev array",
470 old != 0 ? "expand" : "creat");
471 bzero(nsp + old, (new - old) * sizeof(void *));
472 if (old != 0) {
473 bcopy(cd->cd_devs, nsp, old * sizeof(void *));
474 free(cd->cd_devs, M_DEVBUF);
475 }
476 cd->cd_devs = nsp;
477 }
478 if (cd->cd_devs[dev->dv_unit])
479 panic("config_make_softc: duplicate %s", dev->dv_xname);
480
481 dev->dv_ref = 1;
482
483 return (dev);
484 }
485
486 /*
487 * Detach a device. Optionally forced (e.g. because of hardware
488 * removal) and quiet. Returns zero if successful, non-zero
489 * (an error code) otherwise.
490 *
491 * Note that this code wants to be run from a process context, so
492 * that the detach can sleep to allow processes which have a device
493 * open to run and unwind their stacks.
494 */
495 int
config_detach(dev,flags)496 config_detach(dev, flags)
497 struct device *dev;
498 int flags;
499 {
500 struct cfdata *cf;
501 struct cfattach *ca;
502 struct cfdriver *cd;
503 #ifdef DIAGNOSTIC
504 struct device *d;
505 #endif
506 int rv = 0, i;
507
508 cf = dev->dv_cfdata;
509 #ifdef DIAGNOSTIC
510 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
511 panic("config_detach: bad device fstate");
512 #endif
513 ca = cf->cf_attach;
514 cd = cf->cf_driver;
515
516 /*
517 * Ensure the device is deactivated. If the device doesn't
518 * have an activation entry point, we allow DVF_ACTIVE to
519 * remain set. Otherwise, if DVF_ACTIVE is still set, the
520 * device is busy, and the detach fails.
521 */
522 if (ca->ca_activate != NULL)
523 rv = config_deactivate(dev);
524
525 /*
526 * Try to detach the device. If that's not possible, then
527 * we either panic() (for the forced but failed case), or
528 * return an error.
529 */
530 if (rv == 0) {
531 if (ca->ca_detach != NULL)
532 rv = (*ca->ca_detach)(dev, flags);
533 else
534 rv = EOPNOTSUPP;
535 }
536 if (rv != 0) {
537 if ((flags & DETACH_FORCE) == 0)
538 return (rv);
539 else
540 panic("config_detach: forced detach of %s failed (%d)",
541 dev->dv_xname, rv);
542 }
543
544 /*
545 * The device has now been successfully detached.
546 */
547
548 #ifdef DIAGNOSTIC
549 /*
550 * Sanity: If you're successfully detached, you should have no
551 * children. (Note that because children must be attached
552 * after parents, we only need to search the latter part of
553 * the list.)
554 */
555 for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
556 d = TAILQ_NEXT(d, dv_list)) {
557 if (d->dv_parent == dev)
558 panic("config_detach: detached device has children");
559 }
560 #endif
561
562 /*
563 * Mark cfdata to show that the unit can be reused, if possible.
564 * Note that we can only re-use a starred unit number if the unit
565 * being detached had the last assigned unit number.
566 */
567 for (cf = cfdata; cf->cf_driver; cf++) {
568 if (cf->cf_driver == cd) {
569 if (cf->cf_fstate == FSTATE_FOUND &&
570 cf->cf_unit == dev->dv_unit)
571 cf->cf_fstate = FSTATE_NOTFOUND;
572 if (cf->cf_fstate == FSTATE_STAR &&
573 cf->cf_unit == dev->dv_unit + 1)
574 cf->cf_unit--;
575 }
576 }
577
578 /*
579 * Unlink from device list.
580 */
581 TAILQ_REMOVE(&alldevs, dev, dv_list);
582 device_unref(dev);
583
584 /*
585 * Remove from cfdriver's array, tell the world, and free softc.
586 */
587 cd->cd_devs[dev->dv_unit] = NULL;
588 if ((flags & DETACH_QUIET) == 0)
589 printf("%s detached\n", dev->dv_xname);
590
591 device_unref(dev);
592 /*
593 * If the device now has no units in use, deallocate its softc array.
594 */
595 for (i = 0; i < cd->cd_ndevs; i++)
596 if (cd->cd_devs[i] != NULL)
597 break;
598 if (i == cd->cd_ndevs) { /* nothing found; deallocate */
599 free(cd->cd_devs, M_DEVBUF);
600 cd->cd_devs = NULL;
601 cd->cd_ndevs = 0;
602 }
603
604 /*
605 * Return success.
606 */
607 return (0);
608 }
609
610 int
config_activate(dev)611 config_activate(dev)
612 struct device *dev;
613 {
614 struct cfattach *ca = dev->dv_cfdata->cf_attach;
615 int rv = 0, oflags = dev->dv_flags;
616
617 if (ca->ca_activate == NULL)
618 return (EOPNOTSUPP);
619
620 if ((dev->dv_flags & DVF_ACTIVE) == 0) {
621 dev->dv_flags |= DVF_ACTIVE;
622 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
623 if (rv)
624 dev->dv_flags = oflags;
625 }
626 return (rv);
627 }
628
629 int
config_deactivate(dev)630 config_deactivate(dev)
631 struct device *dev;
632 {
633 struct cfattach *ca = dev->dv_cfdata->cf_attach;
634 int rv = 0, oflags = dev->dv_flags;
635
636 if (ca->ca_activate == NULL)
637 return (EOPNOTSUPP);
638
639 if (dev->dv_flags & DVF_ACTIVE) {
640 dev->dv_flags &= ~DVF_ACTIVE;
641 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
642 if (rv)
643 dev->dv_flags = oflags;
644 }
645 return (rv);
646 }
647
648 /*
649 * Defer the configuration of the specified device until all
650 * of its parent's devices have been attached.
651 */
652 void
config_defer(dev,func)653 config_defer(dev, func)
654 struct device *dev;
655 void (*func)(struct device *);
656 {
657 struct deferred_config *dc;
658
659 if (dev->dv_parent == NULL)
660 panic("config_defer: can't defer config of a root device");
661
662 #ifdef DIAGNOSTIC
663 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
664 dc = TAILQ_NEXT(dc, dc_queue)) {
665 if (dc->dc_dev == dev)
666 panic("config_defer: deferred twice");
667 }
668 #endif
669
670 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
671 panic("config_defer: can't allocate defer structure");
672
673 dc->dc_dev = dev;
674 dc->dc_func = func;
675 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
676 config_pending_incr();
677 }
678
679 /*
680 * Process the deferred configuration queue for a device.
681 */
682 void
config_process_deferred_children(parent)683 config_process_deferred_children(parent)
684 struct device *parent;
685 {
686 struct deferred_config *dc, *ndc;
687
688 for (dc = TAILQ_FIRST(&deferred_config_queue);
689 dc != NULL; dc = ndc) {
690 ndc = TAILQ_NEXT(dc, dc_queue);
691 if (dc->dc_dev->dv_parent == parent) {
692 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
693 (*dc->dc_func)(dc->dc_dev);
694 free(dc, M_DEVBUF);
695 config_pending_decr();
696 }
697 }
698 }
699
700 /*
701 * Manipulate the config_pending semaphore.
702 */
703 void
config_pending_incr(void)704 config_pending_incr(void)
705 {
706
707 config_pending++;
708 }
709
710 void
config_pending_decr(void)711 config_pending_decr(void)
712 {
713
714 #ifdef DIAGNOSTIC
715 if (config_pending == 0)
716 panic("config_pending_decr: config_pending == 0");
717 #endif
718 config_pending--;
719 if (config_pending == 0)
720 wakeup((void *)&config_pending);
721 }
722
723 int
config_detach_children(parent,flags)724 config_detach_children(parent, flags)
725 struct device *parent;
726 int flags;
727 {
728 struct device *dev, *next_dev;
729 int rv = 0;
730
731 /* The config_detach routine may sleep, meaning devices
732 may be added to the queue. However, all devices will
733 be added to the tail of the queue, the queue won't
734 be re-organized, and the subtree of parent here should be locked
735 for purposes of adding/removing children.
736 */
737 for (dev = TAILQ_FIRST(&alldevs);
738 dev != NULL; dev = next_dev) {
739 next_dev = TAILQ_NEXT(dev, dv_list);
740 if (dev->dv_parent == parent &&
741 (rv = config_detach(dev, flags)))
742 return (rv);
743 }
744
745 return (rv);
746 }
747
748 int
config_activate_children(parent,act)749 config_activate_children(parent, act)
750 struct device *parent;
751 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 *
device_lookup(cd,unit)800 device_lookup(cd, unit)
801 struct cfdriver *cd;
802 int unit;
803 {
804 struct device *dv = NULL;
805
806 if (unit >= 0 && unit < cd->cd_ndevs)
807 dv = (struct device *)(cd->cd_devs[unit]);
808
809 if (!dv)
810 return (NULL);
811
812 if (!(dv->dv_flags & DVF_ACTIVE))
813 dv = NULL;
814
815 if (dv != NULL)
816 device_ref(dv);
817
818 return (dv);
819 }
820
821
822 /*
823 * Increments the ref count on the device structure. The device
824 * structure is freed when the ref count hits 0.
825 *
826 * Context: process or interrupt
827 */
828 void
device_ref(dv)829 device_ref(dv)
830 struct device *dv;
831 {
832 dv->dv_ref++;
833 }
834
835 /*
836 * Decrement the ref count on the device structure.
837 *
838 * free's the structure when the ref count hits zero and calls the zeroref
839 * function.
840 *
841 * Context: process or interrupt
842 */
843 void
device_unref(dv)844 device_unref(dv)
845 struct device *dv;
846 {
847 dv->dv_ref--;
848 if (dv->dv_ref == 0) {
849 if (dv->dv_cfdata->cf_attach->ca_zeroref)
850 (*dv->dv_cfdata->cf_attach->ca_zeroref)(dv);
851
852 free(dv, M_DEVBUF);
853 }
854 }
855
856 /*
857 * Attach an event. These must come from initially-zero space (see
858 * commented-out assignments below), but that occurs naturally for
859 * device instance variables.
860 */
861 void
evcnt_attach(dev,name,ev)862 evcnt_attach(dev, name, ev)
863 struct device *dev;
864 const char *name;
865 struct evcnt *ev;
866 {
867
868 #ifdef DIAGNOSTIC
869 if (strlen(name) >= sizeof(ev->ev_name))
870 panic("evcnt_attach");
871 #endif
872 /* ev->ev_next = NULL; */
873 ev->ev_dev = dev;
874 /* ev->ev_count = 0; */
875 strlcpy(ev->ev_name, name, sizeof ev->ev_name);
876 TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
877 }
878