Annotation of src/sys/kern/subr_autoconf.c, Revision 1.292
1.292 ! riastrad 1: /* $NetBSD: subr_autoconf.c,v 1.291 2021/12/31 14:19:57 riastradh Exp $ */
1.53 cgd 2:
3: /*
4: * Copyright (c) 1996, 2000 Christopher G. Demetriou
5: * All rights reserved.
1.93 perry 6: *
1.53 cgd 7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
1.54 cgd 17: * This product includes software developed for the
1.88 keihan 18: * NetBSD Project. See http://www.NetBSD.org/ for
1.54 cgd 19: * information about NetBSD.
1.53 cgd 20: * 4. The name of the author may not be used to endorse or promote products
1.54 cgd 21: * derived from this software without specific prior written permission.
1.93 perry 22: *
1.53 cgd 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.93 perry 33: *
1.54 cgd 34: * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
1.53 cgd 35: */
1.9 cgd 36:
1.1 glass 37: /*
1.7 glass 38: * Copyright (c) 1992, 1993
39: * The Regents of the University of California. All rights reserved.
1.1 glass 40: *
41: * This software was developed by the Computer Systems Engineering group
42: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43: * contributed to Berkeley.
44: *
45: * All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the University of
48: * California, Lawrence Berkeley Laboratories.
49: *
1.7 glass 50: * Redistribution and use in source and binary forms, with or without
51: * modification, are permitted provided that the following conditions
52: * are met:
53: * 1. Redistributions of source code must retain the above copyright
54: * notice, this list of conditions and the following disclaimer.
55: * 2. Redistributions in binary form must reproduce the above copyright
56: * notice, this list of conditions and the following disclaimer in the
57: * documentation and/or other materials provided with the distribution.
1.87 agc 58: * 3. Neither the name of the University nor the names of its contributors
1.7 glass 59: * may be used to endorse or promote products derived from this software
60: * without specific prior written permission.
1.1 glass 61: *
1.7 glass 62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
1.1 glass 73: *
1.8 cgd 74: * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
1.9 cgd 75: *
1.28 fvdl 76: * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
1.1 glass 77: */
78:
1.51 cgd 79: #include <sys/cdefs.h>
1.292 ! riastrad 80: __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.291 2021/12/31 14:19:57 riastradh Exp $");
1.62 simonb 81:
1.180 pooka 82: #ifdef _KERNEL_OPT
1.62 simonb 83: #include "opt_ddb.h"
1.217 jmcneill 84: #include "drvctl.h"
1.180 pooka 85: #endif
1.51 cgd 86:
1.4 mycroft 87: #include <sys/param.h>
88: #include <sys/device.h>
1.118 dyoung 89: #include <sys/disklabel.h>
90: #include <sys/conf.h>
91: #include <sys/kauth.h>
1.159 matt 92: #include <sys/kmem.h>
1.17 christos 93: #include <sys/systm.h>
1.43 thorpej 94: #include <sys/kernel.h>
1.33 thorpej 95: #include <sys/errno.h>
1.47 thorpej 96: #include <sys/proc.h>
1.82 mrg 97: #include <sys/reboot.h>
1.142 ad 98: #include <sys/kthread.h>
1.118 dyoung 99: #include <sys/buf.h>
100: #include <sys/dirent.h>
101: #include <sys/mount.h>
102: #include <sys/namei.h>
103: #include <sys/unistd.h>
104: #include <sys/fcntl.h>
105: #include <sys/lockf.h>
1.124 jmcneill 106: #include <sys/callout.h>
1.149 jmcneill 107: #include <sys/devmon.h>
1.153 cegger 108: #include <sys/cpu.h>
1.174 dyoung 109: #include <sys/sysctl.h>
1.278 thorpej 110: #include <sys/stdarg.h>
1.118 dyoung 111:
112: #include <sys/disk.h>
113:
1.235 riastrad 114: #include <sys/rndsource.h>
1.231 tls 115:
1.16 mycroft 116: #include <machine/limits.h>
1.1 glass 117:
118: /*
119: * Autoconfiguration subroutines.
120: */
121:
122: /*
1.231 tls 123: * Device autoconfiguration timings are mixed into the entropy pool.
124: */
1.270 riastrad 125: static krndsource_t rnd_autoconf_source;
1.231 tls 126:
127: /*
1.1 glass 128: * ioconf.c exports exactly two names: cfdata and cfroots. All system
129: * devices and drivers are found via these tables.
130: */
131: extern struct cfdata cfdata[];
1.84 matt 132: extern const short cfroots[];
1.1 glass 133:
1.65 thorpej 134: /*
1.67 thorpej 135: * List of all cfdriver structures. We use this to detect duplicates
136: * when other cfdrivers are loaded.
137: */
1.69 thorpej 138: struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
139: extern struct cfdriver * const cfdriver_list_initial[];
1.67 thorpej 140:
141: /*
1.76 thorpej 142: * Initial list of cfattach's.
143: */
144: extern const struct cfattachinit cfattachinit[];
145:
146: /*
1.65 thorpej 147: * List of cfdata tables. We always have one such list -- the one
148: * built statically when the kernel was configured.
149: */
1.121 matt 150: struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
1.65 thorpej 151: static struct cftable initcftable;
152:
1.102 thorpej 153: #define ROOT ((device_t)NULL)
1.1 glass 154:
1.16 mycroft 155: struct matchinfo {
1.99 drochner 156: cfsubmatch_t fn;
1.224 chs 157: device_t parent;
1.99 drochner 158: const int *locs;
1.25 cgd 159: void *aux;
160: struct cfdata *match;
161: int pri;
1.16 mycroft 162: };
1.17 christos 163:
1.198 dyoung 164: struct alldevs_foray {
165: int af_s;
166: struct devicelist af_garbage;
167: };
168:
1.289 thorpej 169: /*
170: * Internal version of the cfargs structure; all versions are
171: * canonicalized to this.
172: */
173: struct cfargs_internal {
174: union {
175: cfsubmatch_t submatch;/* submatch function (direct config) */
176: cfsearch_t search; /* search function (indirect config) */
177: };
178: const char * iattr; /* interface attribute */
179: const int * locators; /* locators array */
180: devhandle_t devhandle; /* devhandle_t (by value) */
181: };
182:
1.51 cgd 183: static char *number(char *, int);
1.102 thorpej 184: static void mapply(struct matchinfo *, cfdata_t);
1.187 dyoung 185: static void config_devdelete(device_t);
1.190 dyoung 186: static void config_devunlink(device_t, struct devicelist *);
1.117 drochner 187: static void config_makeroom(int, struct cfdriver *);
188: static void config_devlink(device_t);
1.198 dyoung 189: static void config_alldevs_enter(struct alldevs_foray *);
190: static void config_alldevs_exit(struct alldevs_foray *);
1.221 pgoyette 191: static void config_add_attrib_dict(device_t);
1.289 thorpej 192: static device_t config_attach_internal(device_t, cfdata_t, void *,
193: cfprint_t, const struct cfargs_internal *);
1.197 rmind 194:
195: static void config_collect_garbage(struct devicelist *);
196: static void config_dump_garbage(struct devicelist *);
197:
1.139 dyoung 198: static void pmflock_debug(device_t, const char *, int);
199:
1.136 dyoung 200: static device_t deviter_next1(deviter_t *);
201: static void deviter_reinit(deviter_t *);
202:
1.29 thorpej 203: struct deferred_config {
204: TAILQ_ENTRY(deferred_config) dc_queue;
1.102 thorpej 205: device_t dc_dev;
206: void (*dc_func)(device_t);
1.29 thorpej 207: };
208:
1.42 thorpej 209: TAILQ_HEAD(deferred_config_head, deferred_config);
1.29 thorpej 210:
1.263 mrg 211: static struct deferred_config_head deferred_config_queue =
1.121 matt 212: TAILQ_HEAD_INITIALIZER(deferred_config_queue);
1.263 mrg 213: static struct deferred_config_head interrupt_config_queue =
1.121 matt 214: TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
1.263 mrg 215: static int interrupt_config_threads = 8;
216: static struct deferred_config_head mountroot_config_queue =
1.207 tsutsui 217: TAILQ_HEAD_INITIALIZER(mountroot_config_queue);
1.263 mrg 218: static int mountroot_config_threads = 2;
1.234 mrg 219: static lwp_t **mountroot_config_lwpids;
220: static size_t mountroot_config_lwpids_size;
1.263 mrg 221: bool root_is_mounted = false;
1.42 thorpej 222:
1.102 thorpej 223: static void config_process_deferred(struct deferred_config_head *, device_t);
1.29 thorpej 224:
1.75 thorpej 225: /* Hooks to finalize configuration once all real devices have been found. */
226: struct finalize_hook {
227: TAILQ_ENTRY(finalize_hook) f_list;
1.102 thorpej 228: int (*f_func)(device_t);
229: device_t f_dev;
1.75 thorpej 230: };
1.121 matt 231: static TAILQ_HEAD(, finalize_hook) config_finalize_list =
232: TAILQ_HEAD_INITIALIZER(config_finalize_list);
1.75 thorpej 233: static int config_finalize_done;
234:
1.56 thorpej 235: /* list of all devices */
1.257 mlelstv 236: static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
237: static kmutex_t alldevs_lock __cacheline_aligned;
238: static devgen_t alldevs_gen = 1;
239: static int alldevs_nread = 0;
240: static int alldevs_nwrite = 0;
241: static bool alldevs_garbage = false;
1.56 thorpej 242:
1.274 riastrad 243: static struct devicelist config_pending =
244: TAILQ_HEAD_INITIALIZER(config_pending);
1.151 ad 245: static kmutex_t config_misc_lock;
246: static kcondvar_t config_misc_cv;
1.47 thorpej 247:
1.210 martin 248: static bool detachall = false;
1.174 dyoung 249:
1.67 thorpej 250: #define STREQ(s1, s2) \
1.70 thorpej 251: (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
1.67 thorpej 252:
1.185 pooka 253: static bool config_initialized = false; /* config_init() has been called. */
1.74 thorpej 254:
1.80 thorpej 255: static int config_do_twiddle;
1.176 ad 256: static callout_t config_twiddle_ch;
1.80 thorpej 257:
1.182 pooka 258: static void sysctl_detach_setup(struct sysctllog **);
259:
1.237 pgoyette 260: int no_devmon_insert(const char *, prop_dictionary_t);
261: int (*devmon_insert_vec)(const char *, prop_dictionary_t) = no_devmon_insert;
262:
1.204 pooka 263: typedef int (*cfdriver_fn)(struct cfdriver *);
264: static int
265: frob_cfdrivervec(struct cfdriver * const *cfdriverv,
266: cfdriver_fn drv_do, cfdriver_fn drv_undo,
267: const char *style, bool dopanic)
268: {
1.226 christos 269: void (*pr)(const char *, ...) __printflike(1, 2) =
1.255 joerg 270: dopanic ? panic : printf;
1.229 martin 271: int i, error = 0, e2 __diagused;
1.204 pooka 272:
273: for (i = 0; cfdriverv[i] != NULL; i++) {
274: if ((error = drv_do(cfdriverv[i])) != 0) {
275: pr("configure: `%s' driver %s failed: %d",
276: cfdriverv[i]->cd_name, style, error);
277: goto bad;
278: }
279: }
280:
281: KASSERT(error == 0);
282: return 0;
283:
284: bad:
285: printf("\n");
286: for (i--; i >= 0; i--) {
287: e2 = drv_undo(cfdriverv[i]);
288: KASSERT(e2 == 0);
289: }
290:
291: return error;
292: }
293:
294: typedef int (*cfattach_fn)(const char *, struct cfattach *);
295: static int
296: frob_cfattachvec(const struct cfattachinit *cfattachv,
297: cfattach_fn att_do, cfattach_fn att_undo,
298: const char *style, bool dopanic)
299: {
300: const struct cfattachinit *cfai = NULL;
1.226 christos 301: void (*pr)(const char *, ...) __printflike(1, 2) =
1.255 joerg 302: dopanic ? panic : printf;
1.229 martin 303: int j = 0, error = 0, e2 __diagused;
1.204 pooka 304:
305: for (cfai = &cfattachv[0]; cfai->cfai_name != NULL; cfai++) {
306: for (j = 0; cfai->cfai_list[j] != NULL; j++) {
307: if ((error = att_do(cfai->cfai_name,
1.214 mbalmer 308: cfai->cfai_list[j])) != 0) {
1.204 pooka 309: pr("configure: attachment `%s' "
310: "of `%s' driver %s failed: %d",
311: cfai->cfai_list[j]->ca_name,
312: cfai->cfai_name, style, error);
313: goto bad;
314: }
315: }
316: }
317:
318: KASSERT(error == 0);
319: return 0;
320:
321: bad:
322: /*
323: * Rollback in reverse order. dunno if super-important, but
324: * do that anyway. Although the code looks a little like
325: * someone did a little integration (in the math sense).
326: */
327: printf("\n");
328: if (cfai) {
329: bool last;
330:
331: for (last = false; last == false; ) {
332: if (cfai == &cfattachv[0])
333: last = true;
334: for (j--; j >= 0; j--) {
335: e2 = att_undo(cfai->cfai_name,
336: cfai->cfai_list[j]);
337: KASSERT(e2 == 0);
338: }
339: if (!last) {
340: cfai--;
341: for (j = 0; cfai->cfai_list[j] != NULL; j++)
342: ;
343: }
344: }
345: }
346:
347: return error;
348: }
349:
1.20 cgd 350: /*
1.74 thorpej 351: * Initialize the autoconfiguration data structures. Normally this
352: * is done by configure(), but some platforms need to do this very
353: * early (to e.g. initialize the console).
1.20 cgd 354: */
355: void
1.74 thorpej 356: config_init(void)
1.20 cgd 357: {
1.67 thorpej 358:
1.185 pooka 359: KASSERT(config_initialized == false);
1.74 thorpej 360:
1.257 mlelstv 361: mutex_init(&alldevs_lock, MUTEX_DEFAULT, IPL_VM);
1.136 dyoung 362:
1.151 ad 363: mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
364: cv_init(&config_misc_cv, "cfgmisc");
365:
1.176 ad 366: callout_init(&config_twiddle_ch, CALLOUT_MPSAFE);
367:
1.204 pooka 368: frob_cfdrivervec(cfdriver_list_initial,
369: config_cfdriver_attach, NULL, "bootstrap", true);
370: frob_cfattachvec(cfattachinit,
371: config_cfattach_attach, NULL, "bootstrap", true);
1.20 cgd 372:
1.65 thorpej 373: initcftable.ct_cfdata = cfdata;
374: TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
1.185 pooka 375:
1.270 riastrad 376: rnd_attach_source(&rnd_autoconf_source, "autoconf", RND_TYPE_UNKNOWN,
377: RND_FLAG_COLLECT_TIME);
378:
1.185 pooka 379: config_initialized = true;
380: }
381:
1.204 pooka 382: /*
383: * Init or fini drivers and attachments. Either all or none
384: * are processed (via rollback). It would be nice if this were
385: * atomic to outside consumers, but with the current state of
386: * locking ...
387: */
388: int
389: config_init_component(struct cfdriver * const *cfdriverv,
390: const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
391: {
392: int error;
393:
1.285 riastrad 394: KERNEL_LOCK(1, NULL);
1.282 riastrad 395:
1.204 pooka 396: if ((error = frob_cfdrivervec(cfdriverv,
397: config_cfdriver_attach, config_cfdriver_detach, "init", false))!= 0)
1.285 riastrad 398: goto out;
1.204 pooka 399: if ((error = frob_cfattachvec(cfattachv,
400: config_cfattach_attach, config_cfattach_detach,
401: "init", false)) != 0) {
402: frob_cfdrivervec(cfdriverv,
403: config_cfdriver_detach, NULL, "init rollback", true);
1.285 riastrad 404: goto out;
1.204 pooka 405: }
406: if ((error = config_cfdata_attach(cfdatav, 1)) != 0) {
407: frob_cfattachvec(cfattachv,
408: config_cfattach_detach, NULL, "init rollback", true);
409: frob_cfdrivervec(cfdriverv,
410: config_cfdriver_detach, NULL, "init rollback", true);
1.285 riastrad 411: goto out;
1.204 pooka 412: }
413:
1.285 riastrad 414: /* Success! */
415: error = 0;
416:
417: out: KERNEL_UNLOCK_ONE(NULL);
418: return error;
1.204 pooka 419: }
420:
421: int
422: config_fini_component(struct cfdriver * const *cfdriverv,
423: const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
424: {
425: int error;
426:
1.285 riastrad 427: KERNEL_LOCK(1, NULL);
1.282 riastrad 428:
1.204 pooka 429: if ((error = config_cfdata_detach(cfdatav)) != 0)
1.285 riastrad 430: goto out;
1.204 pooka 431: if ((error = frob_cfattachvec(cfattachv,
432: config_cfattach_detach, config_cfattach_attach,
433: "fini", false)) != 0) {
434: if (config_cfdata_attach(cfdatav, 0) != 0)
435: panic("config_cfdata fini rollback failed");
1.285 riastrad 436: goto out;
1.204 pooka 437: }
438: if ((error = frob_cfdrivervec(cfdriverv,
439: config_cfdriver_detach, config_cfdriver_attach,
440: "fini", false)) != 0) {
441: frob_cfattachvec(cfattachv,
442: config_cfattach_attach, NULL, "fini rollback", true);
443: if (config_cfdata_attach(cfdatav, 0) != 0)
444: panic("config_cfdata fini rollback failed");
1.285 riastrad 445: goto out;
1.204 pooka 446: }
447:
1.285 riastrad 448: /* Success! */
449: error = 0;
450:
451: out: KERNEL_UNLOCK_ONE(NULL);
452: return error;
1.204 pooka 453: }
454:
1.185 pooka 455: void
456: config_init_mi(void)
457: {
458:
459: if (!config_initialized)
460: config_init();
461:
1.182 pooka 462: sysctl_detach_setup(NULL);
1.74 thorpej 463: }
464:
1.126 dyoung 465: void
466: config_deferred(device_t dev)
467: {
1.282 riastrad 468:
469: KASSERT(KERNEL_LOCKED_P());
470:
1.126 dyoung 471: config_process_deferred(&deferred_config_queue, dev);
472: config_process_deferred(&interrupt_config_queue, dev);
1.207 tsutsui 473: config_process_deferred(&mountroot_config_queue, dev);
1.126 dyoung 474: }
475:
1.142 ad 476: static void
477: config_interrupts_thread(void *cookie)
478: {
479: struct deferred_config *dc;
1.267 jdolecek 480: device_t dev;
1.142 ad 481:
1.266 jdolecek 482: mutex_enter(&config_misc_lock);
1.142 ad 483: while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
484: TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
1.266 jdolecek 485: mutex_exit(&config_misc_lock);
486:
1.267 jdolecek 487: dev = dc->dc_dev;
488: (*dc->dc_func)(dev);
489: if (!device_pmf_is_registered(dev))
490: aprint_debug_dev(dev,
1.265 msaitoh 491: "WARNING: power management not supported\n");
1.267 jdolecek 492: config_pending_decr(dev);
1.159 matt 493: kmem_free(dc, sizeof(*dc));
1.266 jdolecek 494:
495: mutex_enter(&config_misc_lock);
1.142 ad 496: }
1.266 jdolecek 497: mutex_exit(&config_misc_lock);
498:
1.142 ad 499: kthread_exit(0);
500: }
501:
1.74 thorpej 502: void
1.222 matt 503: config_create_interruptthreads(void)
1.74 thorpej 504: {
1.180 pooka 505: int i;
1.144 ad 506:
1.142 ad 507: for (i = 0; i < interrupt_config_threads; i++) {
1.266 jdolecek 508: (void)kthread_create(PRI_NONE, 0/*XXXSMP */, NULL,
1.223 matt 509: config_interrupts_thread, NULL, NULL, "configintr");
1.142 ad 510: }
1.20 cgd 511: }
512:
1.207 tsutsui 513: static void
514: config_mountroot_thread(void *cookie)
515: {
516: struct deferred_config *dc;
517:
1.266 jdolecek 518: mutex_enter(&config_misc_lock);
1.207 tsutsui 519: while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
520: TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
1.266 jdolecek 521: mutex_exit(&config_misc_lock);
522:
1.207 tsutsui 523: (*dc->dc_func)(dc->dc_dev);
524: kmem_free(dc, sizeof(*dc));
1.266 jdolecek 525:
526: mutex_enter(&config_misc_lock);
1.207 tsutsui 527: }
1.266 jdolecek 528: mutex_exit(&config_misc_lock);
529:
1.207 tsutsui 530: kthread_exit(0);
531: }
532:
533: void
1.222 matt 534: config_create_mountrootthreads(void)
1.207 tsutsui 535: {
536: int i;
537:
1.208 tsutsui 538: if (!root_is_mounted)
539: root_is_mounted = true;
540:
1.234 mrg 541: mountroot_config_lwpids_size = sizeof(mountroot_config_lwpids) *
542: mountroot_config_threads;
543: mountroot_config_lwpids = kmem_alloc(mountroot_config_lwpids_size,
544: KM_NOSLEEP);
545: KASSERT(mountroot_config_lwpids);
1.207 tsutsui 546: for (i = 0; i < mountroot_config_threads; i++) {
1.234 mrg 547: mountroot_config_lwpids[i] = 0;
1.266 jdolecek 548: (void)kthread_create(PRI_NONE, KTHREAD_MUSTJOIN/* XXXSMP */,
549: NULL, config_mountroot_thread, NULL,
1.234 mrg 550: &mountroot_config_lwpids[i],
551: "configroot");
552: }
553: }
554:
555: void
556: config_finalize_mountroot(void)
557: {
558: int i, error;
559:
560: for (i = 0; i < mountroot_config_threads; i++) {
561: if (mountroot_config_lwpids[i] == 0)
562: continue;
563:
564: error = kthread_join(mountroot_config_lwpids[i]);
565: if (error)
566: printf("%s: thread %x joined with error %d\n",
567: __func__, i, error);
1.207 tsutsui 568: }
1.234 mrg 569: kmem_free(mountroot_config_lwpids, mountroot_config_lwpids_size);
1.207 tsutsui 570: }
571:
1.1 glass 572: /*
1.149 jmcneill 573: * Announce device attach/detach to userland listeners.
574: */
1.237 pgoyette 575:
576: int
577: no_devmon_insert(const char *name, prop_dictionary_t p)
578: {
579:
580: return ENODEV;
581: }
582:
1.149 jmcneill 583: static void
584: devmon_report_device(device_t dev, bool isattach)
585: {
1.269 macallan 586: prop_dictionary_t ev, dict = device_properties(dev);
1.149 jmcneill 587: const char *parent;
588: const char *what;
1.269 macallan 589: const char *where;
1.149 jmcneill 590: device_t pdev = device_parent(dev);
591:
1.237 pgoyette 592: /* If currently no drvctl device, just return */
593: if (devmon_insert_vec == no_devmon_insert)
594: return;
595:
1.149 jmcneill 596: ev = prop_dictionary_create();
597: if (ev == NULL)
598: return;
599:
600: what = (isattach ? "device-attach" : "device-detach");
601: parent = (pdev == NULL ? "root" : device_xname(pdev));
1.272 jmcneill 602: if (prop_dictionary_get_string(dict, "location", &where)) {
603: prop_dictionary_set_string(ev, "location", where);
1.269 macallan 604: aprint_debug("ev: %s %s at %s in [%s]\n",
605: what, device_xname(dev), parent, where);
606: }
1.272 jmcneill 607: if (!prop_dictionary_set_string(ev, "device", device_xname(dev)) ||
608: !prop_dictionary_set_string(ev, "parent", parent)) {
1.149 jmcneill 609: prop_object_release(ev);
610: return;
611: }
612:
1.237 pgoyette 613: if ((*devmon_insert_vec)(what, ev) != 0)
614: prop_object_release(ev);
1.149 jmcneill 615: }
616:
617: /*
1.67 thorpej 618: * Add a cfdriver to the system.
619: */
620: int
621: config_cfdriver_attach(struct cfdriver *cd)
622: {
623: struct cfdriver *lcd;
624:
625: /* Make sure this driver isn't already in the system. */
626: LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
627: if (STREQ(lcd->cd_name, cd->cd_name))
1.175 cegger 628: return EEXIST;
1.67 thorpej 629: }
630:
1.76 thorpej 631: LIST_INIT(&cd->cd_attach);
1.67 thorpej 632: LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
633:
1.175 cegger 634: return 0;
1.67 thorpej 635: }
636:
637: /*
638: * Remove a cfdriver from the system.
639: */
640: int
641: config_cfdriver_detach(struct cfdriver *cd)
642: {
1.198 dyoung 643: struct alldevs_foray af;
644: int i, rc = 0;
1.67 thorpej 645:
1.198 dyoung 646: config_alldevs_enter(&af);
1.67 thorpej 647: /* Make sure there are no active instances. */
648: for (i = 0; i < cd->cd_ndevs; i++) {
1.187 dyoung 649: if (cd->cd_devs[i] != NULL) {
650: rc = EBUSY;
651: break;
652: }
1.67 thorpej 653: }
1.198 dyoung 654: config_alldevs_exit(&af);
1.187 dyoung 655:
656: if (rc != 0)
657: return rc;
1.67 thorpej 658:
1.76 thorpej 659: /* ...and no attachments loaded. */
660: if (LIST_EMPTY(&cd->cd_attach) == 0)
1.175 cegger 661: return EBUSY;
1.76 thorpej 662:
1.67 thorpej 663: LIST_REMOVE(cd, cd_list);
664:
665: KASSERT(cd->cd_devs == NULL);
666:
1.175 cegger 667: return 0;
1.67 thorpej 668: }
669:
670: /*
671: * Look up a cfdriver by name.
672: */
1.78 isaki 673: struct cfdriver *
1.67 thorpej 674: config_cfdriver_lookup(const char *name)
675: {
676: struct cfdriver *cd;
1.69 thorpej 677:
1.67 thorpej 678: LIST_FOREACH(cd, &allcfdrivers, cd_list) {
679: if (STREQ(cd->cd_name, name))
1.175 cegger 680: return cd;
1.67 thorpej 681: }
682:
1.175 cegger 683: return NULL;
1.67 thorpej 684: }
685:
686: /*
1.76 thorpej 687: * Add a cfattach to the specified driver.
688: */
689: int
690: config_cfattach_attach(const char *driver, struct cfattach *ca)
691: {
692: struct cfattach *lca;
693: struct cfdriver *cd;
694:
695: cd = config_cfdriver_lookup(driver);
696: if (cd == NULL)
1.175 cegger 697: return ESRCH;
1.76 thorpej 698:
699: /* Make sure this attachment isn't already on this driver. */
700: LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
701: if (STREQ(lca->ca_name, ca->ca_name))
1.175 cegger 702: return EEXIST;
1.76 thorpej 703: }
704:
705: LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
706:
1.175 cegger 707: return 0;
1.76 thorpej 708: }
709:
710: /*
711: * Remove a cfattach from the specified driver.
712: */
713: int
714: config_cfattach_detach(const char *driver, struct cfattach *ca)
715: {
1.198 dyoung 716: struct alldevs_foray af;
1.76 thorpej 717: struct cfdriver *cd;
1.102 thorpej 718: device_t dev;
1.198 dyoung 719: int i, rc = 0;
1.76 thorpej 720:
721: cd = config_cfdriver_lookup(driver);
722: if (cd == NULL)
1.175 cegger 723: return ESRCH;
1.76 thorpej 724:
1.198 dyoung 725: config_alldevs_enter(&af);
1.76 thorpej 726: /* Make sure there are no active instances. */
727: for (i = 0; i < cd->cd_ndevs; i++) {
728: if ((dev = cd->cd_devs[i]) == NULL)
729: continue;
1.187 dyoung 730: if (dev->dv_cfattach == ca) {
731: rc = EBUSY;
732: break;
733: }
1.76 thorpej 734: }
1.198 dyoung 735: config_alldevs_exit(&af);
1.187 dyoung 736:
737: if (rc != 0)
738: return rc;
1.76 thorpej 739:
740: LIST_REMOVE(ca, ca_list);
741:
1.175 cegger 742: return 0;
1.76 thorpej 743: }
744:
745: /*
746: * Look up a cfattach by name.
747: */
748: static struct cfattach *
749: config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
750: {
751: struct cfattach *ca;
752:
753: LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
754: if (STREQ(ca->ca_name, atname))
1.175 cegger 755: return ca;
1.76 thorpej 756: }
757:
1.175 cegger 758: return NULL;
1.76 thorpej 759: }
760:
761: /*
762: * Look up a cfattach by driver/attachment name.
763: */
764: struct cfattach *
765: config_cfattach_lookup(const char *name, const char *atname)
766: {
767: struct cfdriver *cd;
768:
769: cd = config_cfdriver_lookup(name);
770: if (cd == NULL)
1.175 cegger 771: return NULL;
1.76 thorpej 772:
1.175 cegger 773: return config_cfattach_lookup_cd(cd, atname);
1.76 thorpej 774: }
775:
776: /*
1.1 glass 777: * Apply the matching function and choose the best. This is used
778: * a few times and we want to keep the code small.
779: */
1.16 mycroft 780: static void
1.102 thorpej 781: mapply(struct matchinfo *m, cfdata_t cf)
1.1 glass 782: {
1.50 augustss 783: int pri;
1.1 glass 784:
1.99 drochner 785: if (m->fn != NULL) {
786: pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
1.90 drochner 787: } else {
1.100 drochner 788: pri = config_match(m->parent, cf, m->aux);
1.3 glass 789: }
1.1 glass 790: if (pri > m->pri) {
1.25 cgd 791: m->match = cf;
1.1 glass 792: m->pri = pri;
793: }
794: }
795:
1.98 drochner 796: int
1.102 thorpej 797: config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
1.98 drochner 798: {
799: const struct cfiattrdata *ci;
800: const struct cflocdesc *cl;
801: int nlocs, i;
802:
1.201 dyoung 803: ci = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
1.98 drochner 804: KASSERT(ci);
805: nlocs = ci->ci_loclen;
1.154 drochner 806: KASSERT(!nlocs || locs);
1.98 drochner 807: for (i = 0; i < nlocs; i++) {
808: cl = &ci->ci_locdesc[i];
1.233 uebayasi 809: if (cl->cld_defaultstr != NULL &&
810: cf->cf_loc[i] == cl->cld_default)
811: continue;
812: if (cf->cf_loc[i] == locs[i])
813: continue;
814: return 0;
1.98 drochner 815: }
816:
1.175 cegger 817: return config_match(parent, cf, aux);
1.98 drochner 818: }
819:
1.1 glass 820: /*
1.96 drochner 821: * Helper function: check whether the driver supports the interface attribute
822: * and return its descriptor structure.
1.91 drochner 823: */
1.96 drochner 824: static const struct cfiattrdata *
825: cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
1.91 drochner 826: {
1.96 drochner 827: const struct cfiattrdata * const *cpp;
1.91 drochner 828:
829: if (cd->cd_attrs == NULL)
1.175 cegger 830: return 0;
1.91 drochner 831:
832: for (cpp = cd->cd_attrs; *cpp; cpp++) {
1.96 drochner 833: if (STREQ((*cpp)->ci_name, ia)) {
1.91 drochner 834: /* Match. */
1.175 cegger 835: return *cpp;
1.91 drochner 836: }
837: }
1.175 cegger 838: return 0;
1.91 drochner 839: }
840:
1.278 thorpej 841: static int
842: cfdriver_iattr_count(const struct cfdriver *cd)
843: {
844: const struct cfiattrdata * const *cpp;
845: int i;
846:
847: if (cd->cd_attrs == NULL)
848: return 0;
849:
850: for (i = 0, cpp = cd->cd_attrs; *cpp; cpp++) {
851: i++;
852: }
853: return i;
854: }
855:
1.91 drochner 856: /*
1.96 drochner 857: * Lookup an interface attribute description by name.
858: * If the driver is given, consider only its supported attributes.
859: */
860: const struct cfiattrdata *
861: cfiattr_lookup(const char *name, const struct cfdriver *cd)
862: {
863: const struct cfdriver *d;
864: const struct cfiattrdata *ia;
865:
866: if (cd)
1.175 cegger 867: return cfdriver_get_iattr(cd, name);
1.96 drochner 868:
869: LIST_FOREACH(d, &allcfdrivers, cd_list) {
870: ia = cfdriver_get_iattr(d, name);
871: if (ia)
1.175 cegger 872: return ia;
1.96 drochner 873: }
1.175 cegger 874: return 0;
1.96 drochner 875: }
876:
877: /*
1.66 thorpej 878: * Determine if `parent' is a potential parent for a device spec based
879: * on `cfp'.
880: */
881: static int
1.102 thorpej 882: cfparent_match(const device_t parent, const struct cfparent *cfp)
1.66 thorpej 883: {
1.67 thorpej 884: struct cfdriver *pcd;
1.70 thorpej 885:
886: /* We don't match root nodes here. */
887: if (cfp == NULL)
1.175 cegger 888: return 0;
1.66 thorpej 889:
1.77 thorpej 890: pcd = parent->dv_cfdriver;
1.67 thorpej 891: KASSERT(pcd != NULL);
892:
1.66 thorpej 893: /*
894: * First, ensure this parent has the correct interface
895: * attribute.
896: */
1.96 drochner 897: if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
1.175 cegger 898: return 0;
1.66 thorpej 899:
900: /*
901: * If no specific parent device instance was specified (i.e.
902: * we're attaching to the attribute only), we're done!
903: */
904: if (cfp->cfp_parent == NULL)
1.175 cegger 905: return 1;
1.66 thorpej 906:
907: /*
908: * Check the parent device's name.
909: */
1.71 thorpej 910: if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
1.175 cegger 911: return 0; /* not the same parent */
1.66 thorpej 912:
913: /*
914: * Make sure the unit number matches.
915: */
1.77 thorpej 916: if (cfp->cfp_unit == DVUNIT_ANY || /* wildcard */
1.66 thorpej 917: cfp->cfp_unit == parent->dv_unit)
1.175 cegger 918: return 1;
1.66 thorpej 919:
920: /* Unit numbers don't match. */
1.175 cegger 921: return 0;
1.68 thorpej 922: }
923:
924: /*
1.90 drochner 925: * Helper for config_cfdata_attach(): check all devices whether it could be
926: * parent any attachment in the config data table passed, and rescan.
927: */
928: static void
929: rescan_with_cfdata(const struct cfdata *cf)
930: {
1.102 thorpej 931: device_t d;
1.90 drochner 932: const struct cfdata *cf1;
1.136 dyoung 933: deviter_t di;
1.243 msaitoh 934:
1.282 riastrad 935: KASSERT(KERNEL_LOCKED_P());
1.90 drochner 936:
937: /*
1.164 ad 938: * "alldevs" is likely longer than a modules's cfdata, so make it
1.90 drochner 939: * the outer loop.
940: */
1.136 dyoung 941: for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) {
1.90 drochner 942:
943: if (!(d->dv_cfattach->ca_rescan))
944: continue;
945:
946: for (cf1 = cf; cf1->cf_name; cf1++) {
947:
948: if (!cfparent_match(d, cf1->cf_pspec))
949: continue;
950:
951: (*d->dv_cfattach->ca_rescan)(d,
1.201 dyoung 952: cfdata_ifattr(cf1), cf1->cf_loc);
1.209 jruoho 953:
954: config_deferred(d);
1.90 drochner 955: }
956: }
1.136 dyoung 957: deviter_release(&di);
1.90 drochner 958: }
959:
960: /*
961: * Attach a supplemental config data table and rescan potential
962: * parent devices if required.
963: */
964: int
1.102 thorpej 965: config_cfdata_attach(cfdata_t cf, int scannow)
1.90 drochner 966: {
967: struct cftable *ct;
968:
1.285 riastrad 969: KERNEL_LOCK(1, NULL);
1.282 riastrad 970:
1.159 matt 971: ct = kmem_alloc(sizeof(*ct), KM_SLEEP);
1.90 drochner 972: ct->ct_cfdata = cf;
973: TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
974:
975: if (scannow)
976: rescan_with_cfdata(cf);
977:
1.288 skrll 978: KERNEL_UNLOCK_ONE(NULL);
1.285 riastrad 979:
1.175 cegger 980: return 0;
1.90 drochner 981: }
982:
983: /*
984: * Helper for config_cfdata_detach: check whether a device is
985: * found through any attachment in the config data table.
986: */
987: static int
1.224 chs 988: dev_in_cfdata(device_t d, cfdata_t cf)
1.90 drochner 989: {
990: const struct cfdata *cf1;
991:
992: for (cf1 = cf; cf1->cf_name; cf1++)
993: if (d->dv_cfdata == cf1)
1.175 cegger 994: return 1;
1.90 drochner 995:
1.175 cegger 996: return 0;
1.90 drochner 997: }
998:
999: /*
1000: * Detach a supplemental config data table. Detach all devices found
1001: * through that table (and thus keeping references to it) before.
1002: */
1003: int
1.102 thorpej 1004: config_cfdata_detach(cfdata_t cf)
1.90 drochner 1005: {
1.102 thorpej 1006: device_t d;
1.136 dyoung 1007: int error = 0;
1.90 drochner 1008: struct cftable *ct;
1.136 dyoung 1009: deviter_t di;
1.90 drochner 1010:
1.285 riastrad 1011: KERNEL_LOCK(1, NULL);
1012:
1.136 dyoung 1013: for (d = deviter_first(&di, DEVITER_F_RW); d != NULL;
1014: d = deviter_next(&di)) {
1015: if (!dev_in_cfdata(d, cf))
1016: continue;
1017: if ((error = config_detach(d, 0)) != 0)
1018: break;
1019: }
1020: deviter_release(&di);
1021: if (error) {
1022: aprint_error_dev(d, "unable to detach instance\n");
1.285 riastrad 1023: goto out;
1.90 drochner 1024: }
1025:
1026: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1027: if (ct->ct_cfdata == cf) {
1028: TAILQ_REMOVE(&allcftables, ct, ct_list);
1.159 matt 1029: kmem_free(ct, sizeof(*ct));
1.285 riastrad 1030: error = 0;
1031: goto out;
1.90 drochner 1032: }
1033: }
1034:
1035: /* not found -- shouldn't happen */
1.285 riastrad 1036: error = EINVAL;
1037:
1038: out: KERNEL_UNLOCK_ONE(NULL);
1039: return error;
1.90 drochner 1040: }
1041:
1042: /*
1.68 thorpej 1043: * Invoke the "match" routine for a cfdata entry on behalf of
1.278 thorpej 1044: * an external caller, usually a direct config "submatch" routine.
1.68 thorpej 1045: */
1046: int
1.102 thorpej 1047: config_match(device_t parent, cfdata_t cf, void *aux)
1.68 thorpej 1048: {
1.76 thorpej 1049: struct cfattach *ca;
1050:
1.282 riastrad 1051: KASSERT(KERNEL_LOCKED_P());
1052:
1.76 thorpej 1053: ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
1054: if (ca == NULL) {
1055: /* No attachment for this entry, oh well. */
1.175 cegger 1056: return 0;
1.76 thorpej 1057: }
1.68 thorpej 1058:
1.175 cegger 1059: return (*ca->ca_match)(parent, cf, aux);
1.66 thorpej 1060: }
1061:
1062: /*
1.278 thorpej 1063: * Invoke the "probe" routine for a cfdata entry on behalf of
1064: * an external caller, usually an indirect config "search" routine.
1065: */
1066: int
1067: config_probe(device_t parent, cfdata_t cf, void *aux)
1068: {
1069: /*
1070: * This is currently a synonym for config_match(), but this
1071: * is an implementation detail; "match" and "probe" routines
1072: * have different behaviors.
1073: *
1074: * XXX config_probe() should return a bool, because there is
1075: * XXX no match score for probe -- it's either there or it's
1076: * XXX not, but some ports abuse the return value as a way
1077: * XXX to attach "critical" devices before "non-critical"
1078: * XXX devices.
1079: */
1080: return config_match(parent, cf, aux);
1081: }
1082:
1.289 thorpej 1083: static struct cfargs_internal *
1084: cfargs_canonicalize(const struct cfargs * const cfargs,
1085: struct cfargs_internal * const store)
1086: {
1087: struct cfargs_internal *args = store;
1.278 thorpej 1088:
1.289 thorpej 1089: memset(args, 0, sizeof(*args));
1.278 thorpej 1090:
1.289 thorpej 1091: /* If none specified, are all-NULL pointers are good. */
1092: if (cfargs == NULL) {
1093: return args;
1094: }
1.278 thorpej 1095:
1.289 thorpej 1096: /*
1097: * Only one arguments version is recognized at this time.
1098: */
1099: if (cfargs->cfargs_version != CFARGS_VERSION) {
1100: panic("cfargs_canonicalize: unknown version %lu\n",
1101: (unsigned long)cfargs->cfargs_version);
1102: }
1.278 thorpej 1103:
1.289 thorpej 1104: /*
1105: * submatch and search are mutually-exclusive.
1106: */
1107: if (cfargs->submatch != NULL && cfargs->search != NULL) {
1108: panic("cfargs_canonicalize: submatch and search are "
1109: "mutually-exclusive");
1110: }
1111: if (cfargs->submatch != NULL) {
1112: args->submatch = cfargs->submatch;
1113: } else if (cfargs->search != NULL) {
1114: args->search = cfargs->search;
1115: }
1.278 thorpej 1116:
1.289 thorpej 1117: args->iattr = cfargs->iattr;
1118: args->locators = cfargs->locators;
1119: args->devhandle = cfargs->devhandle;
1.278 thorpej 1120:
1.289 thorpej 1121: return args;
1.278 thorpej 1122: }
1123:
1124: /*
1.1 glass 1125: * Iterate over all potential children of some device, calling the given
1126: * function (default being the child's match function) for each one.
1127: * Nonzero returns are matches; the highest value returned is considered
1128: * the best match. Return the `found child' if we got a match, or NULL
1129: * otherwise. The `aux' pointer is simply passed on through.
1130: *
1131: * Note that this function is designed so that it can be used to apply
1132: * an arbitrary function to all potential children (its return value
1133: * can be ignored).
1134: */
1.289 thorpej 1135: static cfdata_t
1136: config_search_internal(device_t parent, void *aux,
1137: const struct cfargs_internal * const args)
1.90 drochner 1138: {
1139: struct cftable *ct;
1.102 thorpej 1140: cfdata_t cf;
1.90 drochner 1141: struct matchinfo m;
1142:
1143: KASSERT(config_initialized);
1.289 thorpej 1144: KASSERT(!args->iattr ||
1145: cfdriver_get_iattr(parent->dv_cfdriver, args->iattr));
1146: KASSERT(args->iattr ||
1147: cfdriver_iattr_count(parent->dv_cfdriver) < 2);
1.90 drochner 1148:
1.289 thorpej 1149: m.fn = args->submatch; /* N.B. union */
1.1 glass 1150: m.parent = parent;
1.289 thorpej 1151: m.locs = args->locators;
1.25 cgd 1152: m.aux = aux;
1.14 mycroft 1153: m.match = NULL;
1.1 glass 1154: m.pri = 0;
1.65 thorpej 1155:
1156: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1157: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.90 drochner 1158:
1159: /* We don't match root nodes here. */
1160: if (!cf->cf_pspec)
1161: continue;
1162:
1.65 thorpej 1163: /*
1164: * Skip cf if no longer eligible, otherwise scan
1165: * through parents for one matching `parent', and
1166: * try match function.
1167: */
1168: if (cf->cf_fstate == FSTATE_FOUND)
1169: continue;
1170: if (cf->cf_fstate == FSTATE_DNOTFOUND ||
1171: cf->cf_fstate == FSTATE_DSTAR)
1172: continue;
1.90 drochner 1173:
1174: /*
1175: * If an interface attribute was specified,
1176: * consider only children which attach to
1177: * that attribute.
1178: */
1.289 thorpej 1179: if (args->iattr != NULL &&
1180: !STREQ(args->iattr, cfdata_ifattr(cf)))
1.90 drochner 1181: continue;
1182:
1.66 thorpej 1183: if (cfparent_match(parent, cf->cf_pspec))
1184: mapply(&m, cf);
1.65 thorpej 1185: }
1.1 glass 1186: }
1.175 cegger 1187: return m.match;
1.1 glass 1188: }
1189:
1.102 thorpej 1190: cfdata_t
1.289 thorpej 1191: config_search(device_t parent, void *aux, const struct cfargs *cfargs)
1.102 thorpej 1192: {
1.278 thorpej 1193: cfdata_t cf;
1.289 thorpej 1194: struct cfargs_internal store;
1.102 thorpej 1195:
1.289 thorpej 1196: cf = config_search_internal(parent, aux,
1197: cfargs_canonicalize(cfargs, &store));
1.278 thorpej 1198:
1199: return cf;
1.102 thorpej 1200: }
1201:
1.16 mycroft 1202: /*
1.1 glass 1203: * Find the given root device.
1204: * This is much like config_search, but there is no parent.
1.65 thorpej 1205: * Don't bother with multiple cfdata tables; the root node
1206: * must always be in the initial table.
1.1 glass 1207: */
1.102 thorpej 1208: cfdata_t
1.95 drochner 1209: config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
1.1 glass 1210: {
1.102 thorpej 1211: cfdata_t cf;
1.84 matt 1212: const short *p;
1.1 glass 1213: struct matchinfo m;
1214:
1.99 drochner 1215: m.fn = fn;
1.1 glass 1216: m.parent = ROOT;
1.25 cgd 1217: m.aux = aux;
1.14 mycroft 1218: m.match = NULL;
1.1 glass 1219: m.pri = 0;
1.114 christos 1220: m.locs = 0;
1.1 glass 1221: /*
1222: * Look at root entries for matching name. We do not bother
1223: * with found-state here since only one root should ever be
1224: * searched (and it must be done first).
1225: */
1226: for (p = cfroots; *p >= 0; p++) {
1227: cf = &cfdata[*p];
1.67 thorpej 1228: if (strcmp(cf->cf_name, rootname) == 0)
1.16 mycroft 1229: mapply(&m, cf);
1.1 glass 1230: }
1.175 cegger 1231: return m.match;
1.1 glass 1232: }
1233:
1.280 thorpej 1234: static const char * const msgs[] = {
1235: [QUIET] = "",
1236: [UNCONF] = " not configured\n",
1237: [UNSUPP] = " unsupported\n",
1238: };
1.1 glass 1239:
1240: /*
1241: * The given `aux' argument describes a device that has been found
1242: * on the given parent, but not necessarily configured. Locate the
1.18 cgd 1243: * configuration data for that device (using the submatch function
1244: * provided, or using candidates' cd_match configuration driver
1.218 dyoung 1245: * functions) and attach it, and return its device_t. If the device was
1246: * not configured, call the given `print' function and return NULL.
1.1 glass 1247: */
1.279 thorpej 1248: device_t
1.289 thorpej 1249: config_found(device_t parent, void *aux, cfprint_t print,
1250: const struct cfargs * const cfargs)
1.90 drochner 1251: {
1.102 thorpej 1252: cfdata_t cf;
1.289 thorpej 1253: struct cfargs_internal store;
1254: const struct cfargs_internal * const args =
1255: cfargs_canonicalize(cfargs, &store);
1.278 thorpej 1256:
1.289 thorpej 1257: cf = config_search_internal(parent, aux, args);
1.278 thorpej 1258: if (cf != NULL) {
1.289 thorpej 1259: return config_attach_internal(parent, cf, aux, print, args);
1.278 thorpej 1260: }
1.90 drochner 1261:
1262: if (print) {
1.176 ad 1263: if (config_do_twiddle && cold)
1.90 drochner 1264: twiddle();
1.280 thorpej 1265:
1266: const int pret = (*print)(aux, device_xname(parent));
1267: KASSERT(pret >= 0);
1268: KASSERT(pret < __arraycount(msgs));
1269: KASSERT(msgs[pret] != NULL);
1270: aprint_normal("%s", msgs[pret]);
1.90 drochner 1271: }
1.105 jmcneill 1272:
1.231 tls 1273: /*
1274: * This has the effect of mixing in a single timestamp to the
1275: * entropy pool. Experiments indicate the estimator will almost
1276: * always attribute one bit of entropy to this sample; analysis
1277: * of device attach/detach timestamps on FreeBSD indicates 4
1278: * bits of entropy/sample so this seems appropriately conservative.
1279: */
1280: rnd_add_uint32(&rnd_autoconf_source, 0);
1.175 cegger 1281: return NULL;
1.90 drochner 1282: }
1283:
1.1 glass 1284: /*
1285: * As above, but for root devices.
1286: */
1.102 thorpej 1287: device_t
1.52 cgd 1288: config_rootfound(const char *rootname, void *aux)
1.1 glass 1289: {
1.102 thorpej 1290: cfdata_t cf;
1.281 riastrad 1291: device_t dev = NULL;
1.25 cgd 1292:
1.281 riastrad 1293: KERNEL_LOCK(1, NULL);
1.220 plunky 1294: if ((cf = config_rootsearch(NULL, rootname, aux)) != NULL)
1.289 thorpej 1295: dev = config_attach(ROOT, cf, aux, NULL, CFARGS_NONE);
1.281 riastrad 1296: else
1297: aprint_error("root device %s not configured\n", rootname);
1298: KERNEL_UNLOCK_ONE(NULL);
1299: return dev;
1.1 glass 1300: }
1301:
1302: /* just like sprintf(buf, "%d") except that it works from the end */
1303: static char *
1.51 cgd 1304: number(char *ep, int n)
1.1 glass 1305: {
1306:
1307: *--ep = 0;
1308: while (n >= 10) {
1309: *--ep = (n % 10) + '0';
1310: n /= 10;
1311: }
1312: *--ep = n + '0';
1.175 cegger 1313: return ep;
1.1 glass 1314: }
1315:
1316: /*
1.59 augustss 1317: * Expand the size of the cd_devs array if necessary.
1.187 dyoung 1318: *
1.257 mlelstv 1319: * The caller must hold alldevs_lock. config_makeroom() may release and
1320: * re-acquire alldevs_lock, so callers should re-check conditions such
1321: * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom()
1.187 dyoung 1322: * returns.
1.59 augustss 1323: */
1.117 drochner 1324: static void
1.59 augustss 1325: config_makeroom(int n, struct cfdriver *cd)
1326: {
1.232 matt 1327: int ondevs, nndevs;
1.190 dyoung 1328: device_t *osp, *nsp;
1.59 augustss 1329:
1.257 mlelstv 1330: KASSERT(mutex_owned(&alldevs_lock));
1331: alldevs_nwrite++;
1.187 dyoung 1332:
1.232 matt 1333: for (nndevs = MAX(4, cd->cd_ndevs); nndevs <= n; nndevs += nndevs)
1.190 dyoung 1334: ;
1335:
1336: while (n >= cd->cd_ndevs) {
1337: /*
1338: * Need to expand the array.
1339: */
1.232 matt 1340: ondevs = cd->cd_ndevs;
1.190 dyoung 1341: osp = cd->cd_devs;
1342:
1.251 riastrad 1343: /*
1.257 mlelstv 1344: * Release alldevs_lock around allocation, which may
1.190 dyoung 1345: * sleep.
1346: */
1.257 mlelstv 1347: mutex_exit(&alldevs_lock);
1.273 jdolecek 1348: nsp = kmem_alloc(sizeof(device_t) * nndevs, KM_SLEEP);
1.257 mlelstv 1349: mutex_enter(&alldevs_lock);
1.190 dyoung 1350:
1.251 riastrad 1351: /*
1352: * If another thread moved the array while we did
1.257 mlelstv 1353: * not hold alldevs_lock, try again.
1.190 dyoung 1354: */
1355: if (cd->cd_devs != osp) {
1.257 mlelstv 1356: mutex_exit(&alldevs_lock);
1.273 jdolecek 1357: kmem_free(nsp, sizeof(device_t) * nndevs);
1.257 mlelstv 1358: mutex_enter(&alldevs_lock);
1.190 dyoung 1359: continue;
1360: }
1.59 augustss 1361:
1.273 jdolecek 1362: memset(nsp + ondevs, 0, sizeof(device_t) * (nndevs - ondevs));
1.232 matt 1363: if (ondevs != 0)
1.273 jdolecek 1364: memcpy(nsp, cd->cd_devs, sizeof(device_t) * ondevs);
1.190 dyoung 1365:
1.232 matt 1366: cd->cd_ndevs = nndevs;
1.190 dyoung 1367: cd->cd_devs = nsp;
1.232 matt 1368: if (ondevs != 0) {
1.257 mlelstv 1369: mutex_exit(&alldevs_lock);
1.273 jdolecek 1370: kmem_free(osp, sizeof(device_t) * ondevs);
1.257 mlelstv 1371: mutex_enter(&alldevs_lock);
1.206 dyoung 1372: }
1.59 augustss 1373: }
1.257 mlelstv 1374: KASSERT(mutex_owned(&alldevs_lock));
1375: alldevs_nwrite--;
1.59 augustss 1376: }
1377:
1.190 dyoung 1378: /*
1379: * Put dev into the devices list.
1380: */
1.117 drochner 1381: static void
1382: config_devlink(device_t dev)
1383: {
1384:
1.257 mlelstv 1385: mutex_enter(&alldevs_lock);
1.117 drochner 1386:
1.190 dyoung 1387: KASSERT(device_cfdriver(dev)->cd_devs[dev->dv_unit] == dev);
1388:
1.257 mlelstv 1389: dev->dv_add_gen = alldevs_gen;
1.136 dyoung 1390: /* It is safe to add a device to the tail of the list while
1.187 dyoung 1391: * readers and writers are in the list.
1.136 dyoung 1392: */
1.257 mlelstv 1393: TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
1394: mutex_exit(&alldevs_lock);
1.117 drochner 1395: }
1396:
1.190 dyoung 1397: static void
1398: config_devfree(device_t dev)
1399: {
1.286 riastrad 1400:
1.271 thorpej 1401: KASSERT(dev->dv_flags & DVF_PRIV_ALLOC);
1.286 riastrad 1402: KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending);
1.190 dyoung 1403:
1404: if (dev->dv_cfattach->ca_devsize > 0)
1405: kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
1.271 thorpej 1406: kmem_free(dev, sizeof(*dev));
1.190 dyoung 1407: }
1408:
1.187 dyoung 1409: /*
1.257 mlelstv 1410: * Caller must hold alldevs_lock.
1.187 dyoung 1411: */
1.117 drochner 1412: static void
1.190 dyoung 1413: config_devunlink(device_t dev, struct devicelist *garbage)
1.117 drochner 1414: {
1.190 dyoung 1415: struct device_garbage *dg = &dev->dv_garbage;
1416: cfdriver_t cd = device_cfdriver(dev);
1417: int i;
1.187 dyoung 1418:
1.257 mlelstv 1419: KASSERT(mutex_owned(&alldevs_lock));
1.286 riastrad 1420: KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending);
1.117 drochner 1421:
1.190 dyoung 1422: /* Unlink from device list. Link to garbage list. */
1.257 mlelstv 1423: TAILQ_REMOVE(&alldevs, dev, dv_list);
1.190 dyoung 1424: TAILQ_INSERT_TAIL(garbage, dev, dv_list);
1.117 drochner 1425:
1426: /* Remove from cfdriver's array. */
1427: cd->cd_devs[dev->dv_unit] = NULL;
1428:
1429: /*
1.190 dyoung 1430: * If the device now has no units in use, unlink its softc array.
1.117 drochner 1431: */
1.159 matt 1432: for (i = 0; i < cd->cd_ndevs; i++) {
1.117 drochner 1433: if (cd->cd_devs[i] != NULL)
1.187 dyoung 1434: break;
1435: }
1.190 dyoung 1436: /* Nothing found. Unlink, now. Deallocate, later. */
1.187 dyoung 1437: if (i == cd->cd_ndevs) {
1.190 dyoung 1438: dg->dg_ndevs = cd->cd_ndevs;
1439: dg->dg_devs = cd->cd_devs;
1.187 dyoung 1440: cd->cd_devs = NULL;
1441: cd->cd_ndevs = 0;
1442: }
1.190 dyoung 1443: }
1.187 dyoung 1444:
1.190 dyoung 1445: static void
1446: config_devdelete(device_t dev)
1447: {
1448: struct device_garbage *dg = &dev->dv_garbage;
1449: device_lock_t dvl = device_getlock(dev);
1.187 dyoung 1450:
1.286 riastrad 1451: KASSERTMSG(dev->dv_pending == 0, "%d", dev->dv_pending);
1452:
1.190 dyoung 1453: if (dg->dg_devs != NULL)
1.273 jdolecek 1454: kmem_free(dg->dg_devs, sizeof(device_t) * dg->dg_ndevs);
1.187 dyoung 1455:
1456: cv_destroy(&dvl->dvl_cv);
1457: mutex_destroy(&dvl->dvl_mtx);
1458:
1459: KASSERT(dev->dv_properties != NULL);
1460: prop_object_release(dev->dv_properties);
1461:
1.197 rmind 1462: if (dev->dv_activity_handlers)
1463: panic("%s with registered handlers", __func__);
1.187 dyoung 1464:
1465: if (dev->dv_locators) {
1466: size_t amount = *--dev->dv_locators;
1467: kmem_free(dev->dv_locators, amount);
1.117 drochner 1468: }
1.197 rmind 1469:
1.190 dyoung 1470: config_devfree(dev);
1471: }
1472:
1473: static int
1474: config_unit_nextfree(cfdriver_t cd, cfdata_t cf)
1475: {
1476: int unit;
1477:
1478: if (cf->cf_fstate == FSTATE_STAR) {
1479: for (unit = cf->cf_unit; unit < cd->cd_ndevs; unit++)
1480: if (cd->cd_devs[unit] == NULL)
1481: break;
1482: /*
1483: * unit is now the unit of the first NULL device pointer,
1484: * or max(cd->cd_ndevs,cf->cf_unit).
1485: */
1486: } else {
1487: unit = cf->cf_unit;
1488: if (unit < cd->cd_ndevs && cd->cd_devs[unit] != NULL)
1489: unit = -1;
1490: }
1491: return unit;
1492: }
1493:
1494: static int
1495: config_unit_alloc(device_t dev, cfdriver_t cd, cfdata_t cf)
1496: {
1.198 dyoung 1497: struct alldevs_foray af;
1498: int unit;
1.187 dyoung 1499:
1.198 dyoung 1500: config_alldevs_enter(&af);
1.190 dyoung 1501: for (;;) {
1502: unit = config_unit_nextfree(cd, cf);
1503: if (unit == -1)
1504: break;
1505: if (unit < cd->cd_ndevs) {
1506: cd->cd_devs[unit] = dev;
1507: dev->dv_unit = unit;
1508: break;
1509: }
1510: config_makeroom(unit, cd);
1511: }
1.198 dyoung 1512: config_alldevs_exit(&af);
1.187 dyoung 1513:
1.190 dyoung 1514: return unit;
1.117 drochner 1515: }
1.187 dyoung 1516:
1.117 drochner 1517: static device_t
1.289 thorpej 1518: config_devalloc(const device_t parent, const cfdata_t cf,
1519: const struct cfargs_internal * const args)
1.25 cgd 1520: {
1.190 dyoung 1521: cfdriver_t cd;
1522: cfattach_t ca;
1.50 augustss 1523: size_t lname, lunit;
1.52 cgd 1524: const char *xunit;
1.189 pooka 1525: int myunit;
1.25 cgd 1526: char num[10];
1.117 drochner 1527: device_t dev;
1.120 joerg 1528: void *dev_private;
1.96 drochner 1529: const struct cfiattrdata *ia;
1.174 dyoung 1530: device_lock_t dvl;
1.25 cgd 1531:
1.67 thorpej 1532: cd = config_cfdriver_lookup(cf->cf_name);
1.117 drochner 1533: if (cd == NULL)
1.175 cegger 1534: return NULL;
1.76 thorpej 1535:
1536: ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
1.117 drochner 1537: if (ca == NULL)
1.175 cegger 1538: return NULL;
1.76 thorpej 1539:
1.25 cgd 1540: /* get memory for all device vars */
1.271 thorpej 1541: KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
1.132 matt 1542: if (ca->ca_devsize > 0) {
1.166 ad 1543: dev_private = kmem_zalloc(ca->ca_devsize, KM_SLEEP);
1.132 matt 1544: } else {
1545: dev_private = NULL;
1546: }
1.271 thorpej 1547: dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
1.120 joerg 1548:
1.289 thorpej 1549: dev->dv_handle = args->devhandle;
1.278 thorpej 1550:
1.202 dyoung 1551: dev->dv_class = cd->cd_class;
1552: dev->dv_cfdata = cf;
1553: dev->dv_cfdriver = cd;
1554: dev->dv_cfattach = ca;
1555: dev->dv_activity_count = 0;
1556: dev->dv_activity_handlers = NULL;
1557: dev->dv_private = dev_private;
1558: dev->dv_flags = ca->ca_flags; /* inherit flags from class */
1559:
1.190 dyoung 1560: myunit = config_unit_alloc(dev, cd, cf);
1561: if (myunit == -1) {
1562: config_devfree(dev);
1563: return NULL;
1564: }
1565:
1566: /* compute length of name and decimal expansion of unit number */
1567: lname = strlen(cd->cd_name);
1568: xunit = number(&num[sizeof(num)], myunit);
1569: lunit = &num[sizeof(num)] - xunit;
1570: if (lname + lunit > sizeof(dev->dv_xname))
1.289 thorpej 1571: panic("config_devalloc: device name too long");
1.190 dyoung 1572:
1.174 dyoung 1573: dvl = device_getlock(dev);
1574:
1575: mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE);
1576: cv_init(&dvl->dvl_cv, "pmfsusp");
1577:
1.31 perry 1578: memcpy(dev->dv_xname, cd->cd_name, lname);
1579: memcpy(dev->dv_xname + lname, xunit, lunit);
1.25 cgd 1580: dev->dv_parent = parent;
1.124 jmcneill 1581: if (parent != NULL)
1582: dev->dv_depth = parent->dv_depth + 1;
1583: else
1584: dev->dv_depth = 0;
1.202 dyoung 1585: dev->dv_flags |= DVF_ACTIVE; /* always initially active */
1.289 thorpej 1586: if (args->locators) {
1.96 drochner 1587: KASSERT(parent); /* no locators at root */
1.201 dyoung 1588: ia = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
1.159 matt 1589: dev->dv_locators =
1.273 jdolecek 1590: kmem_alloc(sizeof(int) * (ia->ci_loclen + 1), KM_SLEEP);
1591: *dev->dv_locators++ = sizeof(int) * (ia->ci_loclen + 1);
1.289 thorpej 1592: memcpy(dev->dv_locators, args->locators,
1593: sizeof(int) * ia->ci_loclen);
1.90 drochner 1594: }
1.112 thorpej 1595: dev->dv_properties = prop_dictionary_create();
1596: KASSERT(dev->dv_properties != NULL);
1.29 thorpej 1597:
1.272 jmcneill 1598: prop_dictionary_set_string_nocopy(dev->dv_properties,
1.150 jmcneill 1599: "device-driver", dev->dv_cfdriver->cd_name);
1600: prop_dictionary_set_uint16(dev->dv_properties,
1601: "device-unit", dev->dv_unit);
1.236 joerg 1602: if (parent != NULL) {
1.272 jmcneill 1603: prop_dictionary_set_string(dev->dv_properties,
1.236 joerg 1604: "device-parent", device_xname(parent));
1605: }
1.150 jmcneill 1606:
1.221 pgoyette 1607: if (dev->dv_cfdriver->cd_attrs != NULL)
1608: config_add_attrib_dict(dev);
1609:
1.175 cegger 1610: return dev;
1.117 drochner 1611: }
1612:
1613: /*
1.221 pgoyette 1614: * Create an array of device attach attributes and add it
1615: * to the device's dv_properties dictionary.
1616: *
1617: * <key>interface-attributes</key>
1618: * <array>
1619: * <dict>
1620: * <key>attribute-name</key>
1621: * <string>foo</string>
1622: * <key>locators</key>
1623: * <array>
1624: * <dict>
1625: * <key>loc-name</key>
1626: * <string>foo-loc1</string>
1627: * </dict>
1628: * <dict>
1629: * <key>loc-name</key>
1630: * <string>foo-loc2</string>
1631: * <key>default</key>
1632: * <string>foo-loc2-default</string>
1633: * </dict>
1634: * ...
1635: * </array>
1636: * </dict>
1637: * ...
1638: * </array>
1639: */
1640:
1641: static void
1642: config_add_attrib_dict(device_t dev)
1643: {
1644: int i, j;
1645: const struct cfiattrdata *ci;
1646: prop_dictionary_t attr_dict, loc_dict;
1647: prop_array_t attr_array, loc_array;
1648:
1649: if ((attr_array = prop_array_create()) == NULL)
1650: return;
1651:
1652: for (i = 0; ; i++) {
1653: if ((ci = dev->dv_cfdriver->cd_attrs[i]) == NULL)
1654: break;
1655: if ((attr_dict = prop_dictionary_create()) == NULL)
1656: break;
1.272 jmcneill 1657: prop_dictionary_set_string_nocopy(attr_dict, "attribute-name",
1.221 pgoyette 1658: ci->ci_name);
1659:
1660: /* Create an array of the locator names and defaults */
1661:
1662: if (ci->ci_loclen != 0 &&
1663: (loc_array = prop_array_create()) != NULL) {
1664: for (j = 0; j < ci->ci_loclen; j++) {
1665: loc_dict = prop_dictionary_create();
1666: if (loc_dict == NULL)
1667: continue;
1.272 jmcneill 1668: prop_dictionary_set_string_nocopy(loc_dict,
1.221 pgoyette 1669: "loc-name", ci->ci_locdesc[j].cld_name);
1670: if (ci->ci_locdesc[j].cld_defaultstr != NULL)
1.272 jmcneill 1671: prop_dictionary_set_string_nocopy(
1.221 pgoyette 1672: loc_dict, "default",
1673: ci->ci_locdesc[j].cld_defaultstr);
1674: prop_array_set(loc_array, j, loc_dict);
1675: prop_object_release(loc_dict);
1676: }
1677: prop_dictionary_set_and_rel(attr_dict, "locators",
1678: loc_array);
1679: }
1680: prop_array_add(attr_array, attr_dict);
1681: prop_object_release(attr_dict);
1682: }
1683: if (i == 0)
1684: prop_object_release(attr_array);
1685: else
1686: prop_dictionary_set_and_rel(dev->dv_properties,
1687: "interface-attributes", attr_array);
1688:
1689: return;
1690: }
1691:
1692: /*
1.117 drochner 1693: * Attach a found device.
1694: */
1.289 thorpej 1695: static device_t
1696: config_attach_internal(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
1697: const struct cfargs_internal * const args)
1.117 drochner 1698: {
1699: device_t dev;
1700: struct cftable *ct;
1701: const char *drvname;
1.283 riastrad 1702: bool deferred;
1.117 drochner 1703:
1.282 riastrad 1704: KASSERT(KERNEL_LOCKED_P());
1705:
1.289 thorpej 1706: dev = config_devalloc(parent, cf, args);
1.117 drochner 1707: if (!dev)
1708: panic("config_attach: allocation of device softc failed");
1709:
1710: /* XXX redundant - see below? */
1711: if (cf->cf_fstate != FSTATE_STAR) {
1712: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1713: cf->cf_fstate = FSTATE_FOUND;
1714: }
1715:
1716: config_devlink(dev);
1717:
1.176 ad 1718: if (config_do_twiddle && cold)
1.80 thorpej 1719: twiddle();
1720: else
1721: aprint_naive("Found ");
1722: /*
1723: * We want the next two printfs for normal, verbose, and quiet,
1724: * but not silent (in which case, we're twiddling, instead).
1725: */
1726: if (parent == ROOT) {
1.143 cegger 1727: aprint_naive("%s (root)", device_xname(dev));
1728: aprint_normal("%s (root)", device_xname(dev));
1.80 thorpej 1729: } else {
1.243 msaitoh 1730: aprint_naive("%s at %s", device_xname(dev),
1731: device_xname(parent));
1732: aprint_normal("%s at %s", device_xname(dev),
1733: device_xname(parent));
1.25 cgd 1734: if (print)
1.52 cgd 1735: (void) (*print)(aux, NULL);
1.25 cgd 1736: }
1737:
1738: /*
1739: * Before attaching, clobber any unfound devices that are
1.45 cgd 1740: * otherwise identical.
1.117 drochner 1741: * XXX code above is redundant?
1.25 cgd 1742: */
1.117 drochner 1743: drvname = dev->dv_cfdriver->cd_name;
1.65 thorpej 1744: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1745: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.117 drochner 1746: if (STREQ(cf->cf_name, drvname) &&
1.65 thorpej 1747: cf->cf_unit == dev->dv_unit) {
1748: if (cf->cf_fstate == FSTATE_NOTFOUND)
1749: cf->cf_fstate = FSTATE_FOUND;
1750: }
1.25 cgd 1751: }
1.65 thorpej 1752: }
1.25 cgd 1753: device_register(dev, aux);
1.124 jmcneill 1754:
1.149 jmcneill 1755: /* Let userland know */
1756: devmon_report_device(dev, true);
1757:
1.283 riastrad 1758: config_pending_incr(dev);
1.117 drochner 1759: (*dev->dv_cfattach->ca_attach)(parent, dev, aux);
1.283 riastrad 1760: config_pending_decr(dev);
1.124 jmcneill 1761:
1.283 riastrad 1762: mutex_enter(&config_misc_lock);
1763: deferred = (dev->dv_pending != 0);
1764: mutex_exit(&config_misc_lock);
1765:
1766: if (!deferred && !device_pmf_is_registered(dev))
1.264 msaitoh 1767: aprint_debug_dev(dev,
1768: "WARNING: power management not supported\n");
1.124 jmcneill 1769:
1.42 thorpej 1770: config_process_deferred(&deferred_config_queue, dev);
1.196 martin 1771:
1772: device_register_post_config(dev, aux);
1.175 cegger 1773: return dev;
1.25 cgd 1774: }
1.29 thorpej 1775:
1.102 thorpej 1776: device_t
1.278 thorpej 1777: config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print,
1.289 thorpej 1778: const struct cfargs *cfargs)
1.102 thorpej 1779: {
1.289 thorpej 1780: struct cfargs_internal store;
1.102 thorpej 1781:
1.282 riastrad 1782: KASSERT(KERNEL_LOCKED_P());
1783:
1.289 thorpej 1784: return config_attach_internal(parent, cf, aux, print,
1785: cfargs_canonicalize(cfargs, &store));
1.102 thorpej 1786: }
1787:
1.29 thorpej 1788: /*
1.77 thorpej 1789: * As above, but for pseudo-devices. Pseudo-devices attached in this
1790: * way are silently inserted into the device tree, and their children
1791: * attached.
1792: *
1793: * Note that because pseudo-devices are attached silently, any information
1794: * the attach routine wishes to print should be prefixed with the device
1795: * name by the attach routine.
1796: */
1.102 thorpej 1797: device_t
1798: config_attach_pseudo(cfdata_t cf)
1.77 thorpej 1799: {
1.102 thorpej 1800: device_t dev;
1.77 thorpej 1801:
1.285 riastrad 1802: KERNEL_LOCK(1, NULL);
1.282 riastrad 1803:
1.289 thorpej 1804: struct cfargs_internal args = { };
1805: dev = config_devalloc(ROOT, cf, &args);
1.117 drochner 1806: if (!dev)
1.285 riastrad 1807: goto out;
1.77 thorpej 1808:
1.117 drochner 1809: /* XXX mark busy in cfdata */
1.77 thorpej 1810:
1.170 dyoung 1811: if (cf->cf_fstate != FSTATE_STAR) {
1812: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1813: cf->cf_fstate = FSTATE_FOUND;
1814: }
1815:
1.117 drochner 1816: config_devlink(dev);
1.77 thorpej 1817:
1818: #if 0 /* XXXJRT not yet */
1819: device_register(dev, NULL); /* like a root node */
1820: #endif
1.225 mlelstv 1821:
1822: /* Let userland know */
1823: devmon_report_device(dev, true);
1824:
1.283 riastrad 1825: config_pending_incr(dev);
1.117 drochner 1826: (*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
1.283 riastrad 1827: config_pending_decr(dev);
1.225 mlelstv 1828:
1.77 thorpej 1829: config_process_deferred(&deferred_config_queue, dev);
1.285 riastrad 1830:
1831: out: KERNEL_UNLOCK_ONE(NULL);
1.175 cegger 1832: return dev;
1.77 thorpej 1833: }
1834:
1835: /*
1.257 mlelstv 1836: * Caller must hold alldevs_lock.
1.197 rmind 1837: */
1838: static void
1839: config_collect_garbage(struct devicelist *garbage)
1840: {
1841: device_t dv;
1842:
1843: KASSERT(!cpu_intr_p());
1844: KASSERT(!cpu_softintr_p());
1.257 mlelstv 1845: KASSERT(mutex_owned(&alldevs_lock));
1.197 rmind 1846:
1.257 mlelstv 1847: while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) {
1848: TAILQ_FOREACH(dv, &alldevs, dv_list) {
1.197 rmind 1849: if (dv->dv_del_gen != 0)
1850: break;
1851: }
1852: if (dv == NULL) {
1.257 mlelstv 1853: alldevs_garbage = false;
1.197 rmind 1854: break;
1855: }
1856: config_devunlink(dv, garbage);
1857: }
1.257 mlelstv 1858: KASSERT(mutex_owned(&alldevs_lock));
1.197 rmind 1859: }
1860:
1861: static void
1862: config_dump_garbage(struct devicelist *garbage)
1863: {
1864: device_t dv;
1865:
1866: while ((dv = TAILQ_FIRST(garbage)) != NULL) {
1867: TAILQ_REMOVE(garbage, dv, dv_list);
1868: config_devdelete(dv);
1869: }
1870: }
1871:
1.283 riastrad 1872: static int
1873: config_detach_enter(device_t dev)
1874: {
1875: int error;
1876:
1877: mutex_enter(&config_misc_lock);
1878: for (;;) {
1879: if (dev->dv_pending == 0 && dev->dv_detaching == NULL) {
1880: dev->dv_detaching = curlwp;
1881: error = 0;
1882: break;
1883: }
1884: KASSERTMSG(dev->dv_detaching != curlwp,
1885: "recursively detaching %s", device_xname(dev));
1886: error = cv_wait_sig(&config_misc_cv, &config_misc_lock);
1887: if (error)
1888: break;
1889: }
1890: KASSERT(error || dev->dv_detaching == curlwp);
1891: mutex_exit(&config_misc_lock);
1892:
1893: return error;
1894: }
1895:
1896: static void
1897: config_detach_exit(device_t dev)
1898: {
1899:
1900: mutex_enter(&config_misc_lock);
1901: KASSERT(dev->dv_detaching == curlwp);
1902: dev->dv_detaching = NULL;
1903: cv_broadcast(&config_misc_cv);
1904: mutex_exit(&config_misc_lock);
1905: }
1906:
1.197 rmind 1907: /*
1.33 thorpej 1908: * Detach a device. Optionally forced (e.g. because of hardware
1909: * removal) and quiet. Returns zero if successful, non-zero
1910: * (an error code) otherwise.
1911: *
1912: * Note that this code wants to be run from a process context, so
1913: * that the detach can sleep to allow processes which have a device
1914: * open to run and unwind their stacks.
1915: */
1916: int
1.102 thorpej 1917: config_detach(device_t dev, int flags)
1.33 thorpej 1918: {
1.198 dyoung 1919: struct alldevs_foray af;
1.65 thorpej 1920: struct cftable *ct;
1.102 thorpej 1921: cfdata_t cf;
1.73 thorpej 1922: const struct cfattach *ca;
1.33 thorpej 1923: struct cfdriver *cd;
1.252 riastrad 1924: device_t d __diagused;
1.241 skrll 1925: int rv = 0;
1.33 thorpej 1926:
1.287 riastrad 1927: KERNEL_LOCK(1, NULL);
1.282 riastrad 1928:
1.161 christos 1929: cf = dev->dv_cfdata;
1.252 riastrad 1930: KASSERTMSG((cf == NULL || cf->cf_fstate == FSTATE_FOUND ||
1931: cf->cf_fstate == FSTATE_STAR),
1932: "config_detach: %s: bad device fstate: %d",
1933: device_xname(dev), cf ? cf->cf_fstate : -1);
1934:
1.77 thorpej 1935: cd = dev->dv_cfdriver;
1.67 thorpej 1936: KASSERT(cd != NULL);
1.76 thorpej 1937:
1.77 thorpej 1938: ca = dev->dv_cfattach;
1.76 thorpej 1939: KASSERT(ca != NULL);
1.33 thorpej 1940:
1.283 riastrad 1941: /*
1942: * Only one detach at a time, please -- and not until fully
1943: * attached.
1944: */
1945: rv = config_detach_enter(dev);
1.287 riastrad 1946: if (rv) {
1947: KERNEL_UNLOCK_ONE(NULL);
1.283 riastrad 1948: return rv;
1.287 riastrad 1949: }
1.283 riastrad 1950:
1.257 mlelstv 1951: mutex_enter(&alldevs_lock);
1.187 dyoung 1952: if (dev->dv_del_gen != 0) {
1.257 mlelstv 1953: mutex_exit(&alldevs_lock);
1.187 dyoung 1954: #ifdef DIAGNOSTIC
1955: printf("%s: %s is already detached\n", __func__,
1956: device_xname(dev));
1957: #endif /* DIAGNOSTIC */
1.283 riastrad 1958: config_detach_exit(dev);
1.287 riastrad 1959: KERNEL_UNLOCK_ONE(NULL);
1.187 dyoung 1960: return ENOENT;
1961: }
1.257 mlelstv 1962: alldevs_nwrite++;
1963: mutex_exit(&alldevs_lock);
1.136 dyoung 1964:
1.174 dyoung 1965: if (!detachall &&
1966: (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
1967: (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
1.183 dyoung 1968: rv = EOPNOTSUPP;
1.187 dyoung 1969: } else if (ca->ca_detach != NULL) {
1970: rv = (*ca->ca_detach)(dev, flags);
1971: } else
1972: rv = EOPNOTSUPP;
1.33 thorpej 1973:
1974: /*
1.187 dyoung 1975: * If it was not possible to detach the device, then we either
1976: * panic() (for the forced but failed case), or return an error.
1977: *
1978: * If it was possible to detach the device, ensure that the
1979: * device is deactivated.
1.33 thorpej 1980: */
1.187 dyoung 1981: if (rv == 0)
1982: dev->dv_flags &= ~DVF_ACTIVE;
1983: else if ((flags & DETACH_FORCE) == 0)
1984: goto out;
1985: else {
1986: panic("config_detach: forced detach of %s failed (%d)",
1987: device_xname(dev), rv);
1.33 thorpej 1988: }
1989:
1990: /*
1991: * The device has now been successfully detached.
1992: */
1993:
1.149 jmcneill 1994: /* Let userland know */
1995: devmon_report_device(dev, false);
1996:
1.33 thorpej 1997: #ifdef DIAGNOSTIC
1998: /*
1999: * Sanity: If you're successfully detached, you should have no
2000: * children. (Note that because children must be attached
2001: * after parents, we only need to search the latter part of
2002: * the list.)
2003: */
1.284 riastrad 2004: mutex_enter(&alldevs_lock);
1.33 thorpej 2005: for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1.48 enami 2006: d = TAILQ_NEXT(d, dv_list)) {
1.187 dyoung 2007: if (d->dv_parent == dev && d->dv_del_gen == 0) {
1.48 enami 2008: printf("config_detach: detached device %s"
1.243 msaitoh 2009: " has children %s\n", device_xname(dev),
2010: device_xname(d));
1.48 enami 2011: panic("config_detach");
2012: }
1.33 thorpej 2013: }
1.284 riastrad 2014: mutex_exit(&alldevs_lock);
1.33 thorpej 2015: #endif
2016:
1.90 drochner 2017: /* notify the parent that the child is gone */
2018: if (dev->dv_parent) {
1.102 thorpej 2019: device_t p = dev->dv_parent;
1.90 drochner 2020: if (p->dv_cfattach->ca_childdetached)
2021: (*p->dv_cfattach->ca_childdetached)(p, dev);
2022: }
2023:
1.33 thorpej 2024: /*
2025: * Mark cfdata to show that the unit can be reused, if possible.
2026: */
1.65 thorpej 2027: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 2028: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
2029: if (STREQ(cf->cf_name, cd->cd_name)) {
1.65 thorpej 2030: if (cf->cf_fstate == FSTATE_FOUND &&
2031: cf->cf_unit == dev->dv_unit)
2032: cf->cf_fstate = FSTATE_NOTFOUND;
2033: }
1.33 thorpej 2034: }
2035: }
2036:
1.77 thorpej 2037: if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1.136 dyoung 2038: aprint_normal_dev(dev, "detached\n");
1.33 thorpej 2039:
1.136 dyoung 2040: out:
1.283 riastrad 2041: config_detach_exit(dev);
2042:
1.198 dyoung 2043: config_alldevs_enter(&af);
1.257 mlelstv 2044: KASSERT(alldevs_nwrite != 0);
2045: --alldevs_nwrite;
1.211 dyoung 2046: if (rv == 0 && dev->dv_del_gen == 0) {
1.257 mlelstv 2047: if (alldevs_nwrite == 0 && alldevs_nread == 0)
1.211 dyoung 2048: config_devunlink(dev, &af.af_garbage);
2049: else {
1.257 mlelstv 2050: dev->dv_del_gen = alldevs_gen;
2051: alldevs_garbage = true;
1.211 dyoung 2052: }
2053: }
1.198 dyoung 2054: config_alldevs_exit(&af);
1.187 dyoung 2055:
1.287 riastrad 2056: KERNEL_UNLOCK_ONE(NULL);
2057:
1.136 dyoung 2058: return rv;
1.33 thorpej 2059: }
2060:
1.126 dyoung 2061: int
2062: config_detach_children(device_t parent, int flags)
2063: {
1.130 drochner 2064: device_t dv;
1.136 dyoung 2065: deviter_t di;
2066: int error = 0;
1.126 dyoung 2067:
1.282 riastrad 2068: KASSERT(KERNEL_LOCKED_P());
2069:
1.136 dyoung 2070: for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL;
2071: dv = deviter_next(&di)) {
2072: if (device_parent(dv) != parent)
2073: continue;
2074: if ((error = config_detach(dv, flags)) != 0)
1.130 drochner 2075: break;
1.136 dyoung 2076: }
2077: deviter_release(&di);
1.130 drochner 2078: return error;
1.126 dyoung 2079: }
2080:
1.178 dyoung 2081: device_t
2082: shutdown_first(struct shutdown_state *s)
2083: {
2084: if (!s->initialized) {
2085: deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
2086: s->initialized = true;
2087: }
2088: return shutdown_next(s);
2089: }
2090:
2091: device_t
2092: shutdown_next(struct shutdown_state *s)
2093: {
2094: device_t dv;
2095:
2096: while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
2097: ;
2098:
2099: if (dv == NULL)
2100: s->initialized = false;
2101:
2102: return dv;
2103: }
2104:
2105: bool
2106: config_detach_all(int how)
2107: {
2108: static struct shutdown_state s;
2109: device_t curdev;
2110: bool progress = false;
1.242 bouyer 2111: int flags;
1.178 dyoung 2112:
1.281 riastrad 2113: KERNEL_LOCK(1, NULL);
2114:
1.239 christos 2115: if ((how & (RB_NOSYNC|RB_DUMP)) != 0)
1.281 riastrad 2116: goto out;
1.178 dyoung 2117:
1.242 bouyer 2118: if ((how & RB_POWERDOWN) == RB_POWERDOWN)
2119: flags = DETACH_SHUTDOWN | DETACH_POWEROFF;
2120: else
2121: flags = DETACH_SHUTDOWN;
2122:
1.178 dyoung 2123: for (curdev = shutdown_first(&s); curdev != NULL;
2124: curdev = shutdown_next(&s)) {
2125: aprint_debug(" detaching %s, ", device_xname(curdev));
1.242 bouyer 2126: if (config_detach(curdev, flags) == 0) {
1.178 dyoung 2127: progress = true;
2128: aprint_debug("success.");
2129: } else
2130: aprint_debug("failed.");
2131: }
1.281 riastrad 2132:
2133: out: KERNEL_UNLOCK_ONE(NULL);
1.178 dyoung 2134: return progress;
2135: }
2136:
1.187 dyoung 2137: static bool
2138: device_is_ancestor_of(device_t ancestor, device_t descendant)
2139: {
2140: device_t dv;
2141:
2142: for (dv = descendant; dv != NULL; dv = device_parent(dv)) {
2143: if (device_parent(dv) == ancestor)
2144: return true;
2145: }
2146: return false;
2147: }
2148:
1.33 thorpej 2149: int
1.102 thorpej 2150: config_deactivate(device_t dev)
1.33 thorpej 2151: {
1.187 dyoung 2152: deviter_t di;
2153: const struct cfattach *ca;
2154: device_t descendant;
2155: int s, rv = 0, oflags;
1.33 thorpej 2156:
1.187 dyoung 2157: for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST);
2158: descendant != NULL;
2159: descendant = deviter_next(&di)) {
2160: if (dev != descendant &&
2161: !device_is_ancestor_of(dev, descendant))
2162: continue;
2163:
2164: if ((descendant->dv_flags & DVF_ACTIVE) == 0)
2165: continue;
1.33 thorpej 2166:
1.187 dyoung 2167: ca = descendant->dv_cfattach;
2168: oflags = descendant->dv_flags;
2169:
2170: descendant->dv_flags &= ~DVF_ACTIVE;
2171: if (ca->ca_activate == NULL)
2172: continue;
2173: s = splhigh();
2174: rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE);
2175: splx(s);
2176: if (rv != 0)
2177: descendant->dv_flags = oflags;
1.33 thorpej 2178: }
1.187 dyoung 2179: deviter_release(&di);
1.175 cegger 2180: return rv;
1.33 thorpej 2181: }
2182:
2183: /*
1.29 thorpej 2184: * Defer the configuration of the specified device until all
2185: * of its parent's devices have been attached.
2186: */
2187: void
1.102 thorpej 2188: config_defer(device_t dev, void (*func)(device_t))
1.29 thorpej 2189: {
2190: struct deferred_config *dc;
2191:
2192: if (dev->dv_parent == NULL)
2193: panic("config_defer: can't defer config of a root device");
2194:
1.266 jdolecek 2195: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
2196:
2197: config_pending_incr(dev);
2198:
2199: mutex_enter(&config_misc_lock);
1.29 thorpej 2200: #ifdef DIAGNOSTIC
1.266 jdolecek 2201: struct deferred_config *odc;
2202: TAILQ_FOREACH(odc, &deferred_config_queue, dc_queue) {
2203: if (odc->dc_dev == dev)
1.29 thorpej 2204: panic("config_defer: deferred twice");
2205: }
2206: #endif
2207: dc->dc_dev = dev;
2208: dc->dc_func = func;
2209: TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1.266 jdolecek 2210: mutex_exit(&config_misc_lock);
1.29 thorpej 2211: }
2212:
2213: /*
1.42 thorpej 2214: * Defer some autoconfiguration for a device until after interrupts
2215: * are enabled.
2216: */
2217: void
1.102 thorpej 2218: config_interrupts(device_t dev, void (*func)(device_t))
1.42 thorpej 2219: {
2220: struct deferred_config *dc;
2221:
2222: /*
2223: * If interrupts are enabled, callback now.
2224: */
1.43 thorpej 2225: if (cold == 0) {
1.42 thorpej 2226: (*func)(dev);
2227: return;
2228: }
2229:
1.266 jdolecek 2230: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
2231:
2232: config_pending_incr(dev);
2233:
2234: mutex_enter(&config_misc_lock);
1.42 thorpej 2235: #ifdef DIAGNOSTIC
1.266 jdolecek 2236: struct deferred_config *odc;
2237: TAILQ_FOREACH(odc, &interrupt_config_queue, dc_queue) {
2238: if (odc->dc_dev == dev)
1.42 thorpej 2239: panic("config_interrupts: deferred twice");
2240: }
2241: #endif
2242: dc->dc_dev = dev;
2243: dc->dc_func = func;
2244: TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1.266 jdolecek 2245: mutex_exit(&config_misc_lock);
1.42 thorpej 2246: }
2247:
2248: /*
1.207 tsutsui 2249: * Defer some autoconfiguration for a device until after root file system
2250: * is mounted (to load firmware etc).
2251: */
2252: void
2253: config_mountroot(device_t dev, void (*func)(device_t))
2254: {
2255: struct deferred_config *dc;
2256:
2257: /*
2258: * If root file system is mounted, callback now.
2259: */
1.208 tsutsui 2260: if (root_is_mounted) {
1.207 tsutsui 2261: (*func)(dev);
2262: return;
2263: }
2264:
1.266 jdolecek 2265: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
2266:
2267: mutex_enter(&config_misc_lock);
1.207 tsutsui 2268: #ifdef DIAGNOSTIC
1.266 jdolecek 2269: struct deferred_config *odc;
2270: TAILQ_FOREACH(odc, &mountroot_config_queue, dc_queue) {
2271: if (odc->dc_dev == dev)
1.207 tsutsui 2272: panic("%s: deferred twice", __func__);
2273: }
2274: #endif
2275:
2276: dc->dc_dev = dev;
2277: dc->dc_func = func;
2278: TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
1.266 jdolecek 2279: mutex_exit(&config_misc_lock);
1.207 tsutsui 2280: }
2281:
2282: /*
1.42 thorpej 2283: * Process a deferred configuration queue.
1.29 thorpej 2284: */
2285: static void
1.243 msaitoh 2286: config_process_deferred(struct deferred_config_head *queue, device_t parent)
1.29 thorpej 2287: {
1.266 jdolecek 2288: struct deferred_config *dc;
1.29 thorpej 2289:
1.282 riastrad 2290: KASSERT(KERNEL_LOCKED_P());
2291:
1.266 jdolecek 2292: mutex_enter(&config_misc_lock);
2293: dc = TAILQ_FIRST(queue);
2294: while (dc) {
1.42 thorpej 2295: if (parent == NULL || dc->dc_dev->dv_parent == parent) {
2296: TAILQ_REMOVE(queue, dc, dc_queue);
1.266 jdolecek 2297: mutex_exit(&config_misc_lock);
2298:
1.29 thorpej 2299: (*dc->dc_func)(dc->dc_dev);
1.228 christos 2300: config_pending_decr(dc->dc_dev);
1.159 matt 2301: kmem_free(dc, sizeof(*dc));
1.266 jdolecek 2302:
2303: mutex_enter(&config_misc_lock);
2304: /* Restart, queue might have changed */
2305: dc = TAILQ_FIRST(queue);
2306: } else {
2307: dc = TAILQ_NEXT(dc, dc_queue);
1.29 thorpej 2308: }
2309: }
1.266 jdolecek 2310: mutex_exit(&config_misc_lock);
1.47 thorpej 2311: }
2312:
2313: /*
2314: * Manipulate the config_pending semaphore.
2315: */
2316: void
1.228 christos 2317: config_pending_incr(device_t dev)
1.47 thorpej 2318: {
2319:
1.151 ad 2320: mutex_enter(&config_misc_lock);
1.274 riastrad 2321: KASSERTMSG(dev->dv_pending < INT_MAX,
2322: "%s: excess config_pending_incr", device_xname(dev));
2323: if (dev->dv_pending++ == 0)
2324: TAILQ_INSERT_TAIL(&config_pending, dev, dv_pending_list);
1.228 christos 2325: #ifdef DEBUG_AUTOCONF
1.274 riastrad 2326: printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending);
1.228 christos 2327: #endif
1.151 ad 2328: mutex_exit(&config_misc_lock);
1.47 thorpej 2329: }
2330:
2331: void
1.228 christos 2332: config_pending_decr(device_t dev)
1.47 thorpej 2333: {
2334:
1.151 ad 2335: mutex_enter(&config_misc_lock);
1.274 riastrad 2336: KASSERTMSG(dev->dv_pending > 0,
2337: "%s: excess config_pending_decr", device_xname(dev));
1.283 riastrad 2338: if (--dev->dv_pending == 0) {
1.274 riastrad 2339: TAILQ_REMOVE(&config_pending, dev, dv_pending_list);
1.283 riastrad 2340: cv_broadcast(&config_misc_cv);
2341: }
1.228 christos 2342: #ifdef DEBUG_AUTOCONF
1.274 riastrad 2343: printf("%s: %s %d\n", __func__, device_xname(dev), dev->dv_pending);
1.228 christos 2344: #endif
1.151 ad 2345: mutex_exit(&config_misc_lock);
1.75 thorpej 2346: }
2347:
2348: /*
2349: * Register a "finalization" routine. Finalization routines are
2350: * called iteratively once all real devices have been found during
2351: * autoconfiguration, for as long as any one finalizer has done
2352: * any work.
2353: */
2354: int
1.102 thorpej 2355: config_finalize_register(device_t dev, int (*fn)(device_t))
1.75 thorpej 2356: {
2357: struct finalize_hook *f;
1.281 riastrad 2358: int error = 0;
2359:
2360: KERNEL_LOCK(1, NULL);
1.75 thorpej 2361:
2362: /*
2363: * If finalization has already been done, invoke the
2364: * callback function now.
2365: */
2366: if (config_finalize_done) {
2367: while ((*fn)(dev) != 0)
2368: /* loop */ ;
1.281 riastrad 2369: goto out;
1.75 thorpej 2370: }
2371:
2372: /* Ensure this isn't already on the list. */
2373: TAILQ_FOREACH(f, &config_finalize_list, f_list) {
1.281 riastrad 2374: if (f->f_func == fn && f->f_dev == dev) {
2375: error = EEXIST;
2376: goto out;
2377: }
1.75 thorpej 2378: }
2379:
1.159 matt 2380: f = kmem_alloc(sizeof(*f), KM_SLEEP);
1.75 thorpej 2381: f->f_func = fn;
2382: f->f_dev = dev;
2383: TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
2384:
1.281 riastrad 2385: /* Success! */
2386: error = 0;
2387:
2388: out: KERNEL_UNLOCK_ONE(NULL);
2389: return error;
1.75 thorpej 2390: }
2391:
2392: void
2393: config_finalize(void)
2394: {
2395: struct finalize_hook *f;
1.142 ad 2396: struct pdevinit *pdev;
2397: extern struct pdevinit pdevinit[];
2398: int errcnt, rv;
2399:
2400: /*
2401: * Now that device driver threads have been created, wait for
2402: * them to finish any deferred autoconfiguration.
2403: */
1.151 ad 2404: mutex_enter(&config_misc_lock);
1.274 riastrad 2405: while (!TAILQ_EMPTY(&config_pending)) {
2406: device_t dev;
1.290 jmcneill 2407: int error;
2408:
2409: error = cv_timedwait(&config_misc_cv, &config_misc_lock,
2410: mstohz(1000));
2411: if (error == EWOULDBLOCK) {
2412: aprint_debug("waiting for devices:");
2413: TAILQ_FOREACH(dev, &config_pending, dv_pending_list)
2414: aprint_debug(" %s", device_xname(dev));
2415: aprint_debug("\n");
2416: }
1.274 riastrad 2417: }
1.151 ad 2418: mutex_exit(&config_misc_lock);
1.142 ad 2419:
1.167 ad 2420: KERNEL_LOCK(1, NULL);
2421:
1.142 ad 2422: /* Attach pseudo-devices. */
2423: for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
2424: (*pdev->pdev_attach)(pdev->pdev_count);
1.75 thorpej 2425:
2426: /* Run the hooks until none of them does any work. */
2427: do {
2428: rv = 0;
2429: TAILQ_FOREACH(f, &config_finalize_list, f_list)
2430: rv |= (*f->f_func)(f->f_dev);
2431: } while (rv != 0);
2432:
2433: config_finalize_done = 1;
2434:
2435: /* Now free all the hooks. */
2436: while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
2437: TAILQ_REMOVE(&config_finalize_list, f, f_list);
1.159 matt 2438: kmem_free(f, sizeof(*f));
1.79 thorpej 2439: }
1.142 ad 2440:
1.167 ad 2441: KERNEL_UNLOCK_ONE(NULL);
2442:
1.142 ad 2443: errcnt = aprint_get_error_count();
2444: if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
2445: (boothowto & AB_VERBOSE) == 0) {
1.176 ad 2446: mutex_enter(&config_misc_lock);
1.142 ad 2447: if (config_do_twiddle) {
2448: config_do_twiddle = 0;
1.169 ad 2449: printf_nolog(" done.\n");
1.142 ad 2450: }
1.176 ad 2451: mutex_exit(&config_misc_lock);
1.247 msaitoh 2452: }
2453: if (errcnt != 0) {
2454: printf("WARNING: %d error%s while detecting hardware; "
2455: "check system log.\n", errcnt,
2456: errcnt == 1 ? "" : "s");
1.142 ad 2457: }
1.79 thorpej 2458: }
2459:
1.176 ad 2460: void
1.222 matt 2461: config_twiddle_init(void)
1.180 pooka 2462: {
2463:
2464: if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
2465: config_do_twiddle = 1;
2466: }
2467: callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL);
2468: }
2469:
2470: void
1.176 ad 2471: config_twiddle_fn(void *cookie)
2472: {
2473:
2474: mutex_enter(&config_misc_lock);
2475: if (config_do_twiddle) {
2476: twiddle();
2477: callout_schedule(&config_twiddle_ch, mstohz(100));
2478: }
2479: mutex_exit(&config_misc_lock);
2480: }
2481:
1.187 dyoung 2482: static void
1.198 dyoung 2483: config_alldevs_enter(struct alldevs_foray *af)
2484: {
2485: TAILQ_INIT(&af->af_garbage);
1.257 mlelstv 2486: mutex_enter(&alldevs_lock);
1.198 dyoung 2487: config_collect_garbage(&af->af_garbage);
1.243 msaitoh 2488: }
1.198 dyoung 2489:
2490: static void
2491: config_alldevs_exit(struct alldevs_foray *af)
2492: {
1.257 mlelstv 2493: mutex_exit(&alldevs_lock);
1.198 dyoung 2494: config_dump_garbage(&af->af_garbage);
2495: }
2496:
1.104 thorpej 2497: /*
1.107 thorpej 2498: * device_lookup:
2499: *
2500: * Look up a device instance for a given driver.
2501: */
1.156 drochner 2502: device_t
1.107 thorpej 2503: device_lookup(cfdriver_t cd, int unit)
2504: {
1.187 dyoung 2505: device_t dv;
1.107 thorpej 2506:
1.257 mlelstv 2507: mutex_enter(&alldevs_lock);
1.107 thorpej 2508: if (unit < 0 || unit >= cd->cd_ndevs)
1.187 dyoung 2509: dv = NULL;
1.191 dyoung 2510: else if ((dv = cd->cd_devs[unit]) != NULL && dv->dv_del_gen != 0)
2511: dv = NULL;
1.257 mlelstv 2512: mutex_exit(&alldevs_lock);
1.187 dyoung 2513:
2514: return dv;
1.107 thorpej 2515: }
2516:
2517: /*
1.191 dyoung 2518: * device_lookup_private:
1.140 matt 2519: *
1.191 dyoung 2520: * Look up a softc instance for a given driver.
1.140 matt 2521: */
2522: void *
2523: device_lookup_private(cfdriver_t cd, int unit)
2524: {
2525:
1.198 dyoung 2526: return device_private(device_lookup(cd, unit));
1.140 matt 2527: }
2528:
2529: /*
1.131 joerg 2530: * device_find_by_xname:
2531: *
2532: * Returns the device of the given name or NULL if it doesn't exist.
2533: */
2534: device_t
2535: device_find_by_xname(const char *name)
2536: {
2537: device_t dv;
1.136 dyoung 2538: deviter_t di;
1.131 joerg 2539:
1.136 dyoung 2540: for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) {
1.131 joerg 2541: if (strcmp(device_xname(dv), name) == 0)
2542: break;
2543: }
1.136 dyoung 2544: deviter_release(&di);
1.131 joerg 2545:
2546: return dv;
2547: }
2548:
2549: /*
2550: * device_find_by_driver_unit:
2551: *
2552: * Returns the device of the given driver name and unit or
2553: * NULL if it doesn't exist.
2554: */
2555: device_t
2556: device_find_by_driver_unit(const char *name, int unit)
2557: {
2558: struct cfdriver *cd;
2559:
2560: if ((cd = config_cfdriver_lookup(name)) == NULL)
2561: return NULL;
2562: return device_lookup(cd, unit);
2563: }
2564:
1.276 thorpej 2565: static bool
2566: match_strcmp(const char * const s1, const char * const s2)
2567: {
2568: return strcmp(s1, s2) == 0;
2569: }
2570:
2571: static bool
2572: match_pmatch(const char * const s1, const char * const s2)
2573: {
2574: return pmatch(s1, s2, NULL) == 2;
2575: }
2576:
2577: static bool
2578: strarray_match_internal(const char ** const strings,
2579: unsigned int const nstrings, const char * const str,
2580: unsigned int * const indexp,
2581: bool (*match_fn)(const char *, const char *))
2582: {
2583: unsigned int i;
2584:
2585: if (strings == NULL || nstrings == 0) {
1.277 thorpej 2586: return false;
1.276 thorpej 2587: }
2588:
2589: for (i = 0; i < nstrings; i++) {
2590: if ((*match_fn)(strings[i], str)) {
2591: *indexp = i;
2592: return true;
2593: }
2594: }
2595:
2596: return false;
2597: }
2598:
2599: static int
2600: strarray_match(const char ** const strings, unsigned int const nstrings,
2601: const char * const str)
2602: {
2603: unsigned int idx;
2604:
2605: if (strarray_match_internal(strings, nstrings, str, &idx,
2606: match_strcmp)) {
2607: return (int)(nstrings - idx);
2608: }
2609: return 0;
2610: }
2611:
2612: static int
2613: strarray_pmatch(const char ** const strings, unsigned int const nstrings,
2614: const char * const pattern)
2615: {
2616: unsigned int idx;
2617:
2618: if (strarray_match_internal(strings, nstrings, pattern, &idx,
2619: match_pmatch)) {
2620: return (int)(nstrings - idx);
2621: }
2622: return 0;
2623: }
2624:
2625: static int
2626: device_compatible_match_strarray_internal(
2627: const char **device_compats, int ndevice_compats,
2628: const struct device_compatible_entry *driver_compats,
2629: const struct device_compatible_entry **matching_entryp,
2630: int (*match_fn)(const char **, unsigned int, const char *))
2631: {
2632: const struct device_compatible_entry *dce = NULL;
2633: int rv;
2634:
2635: if (ndevice_compats == 0 || device_compats == NULL ||
2636: driver_compats == NULL)
2637: return 0;
2638:
2639: for (dce = driver_compats; dce->compat != NULL; dce++) {
2640: rv = (*match_fn)(device_compats, ndevice_compats, dce->compat);
2641: if (rv != 0) {
2642: if (matching_entryp != NULL) {
2643: *matching_entryp = dce;
2644: }
2645: return rv;
2646: }
2647: }
2648: return 0;
2649: }
2650:
1.131 joerg 2651: /*
1.258 thorpej 2652: * device_compatible_match:
2653: *
2654: * Match a driver's "compatible" data against a device's
1.276 thorpej 2655: * "compatible" strings. Returns resulted weighted by
2656: * which device "compatible" string was matched.
2657: */
2658: int
2659: device_compatible_match(const char **device_compats, int ndevice_compats,
2660: const struct device_compatible_entry *driver_compats)
2661: {
2662: return device_compatible_match_strarray_internal(device_compats,
2663: ndevice_compats, driver_compats, NULL, strarray_match);
2664: }
2665:
2666: /*
2667: * device_compatible_pmatch:
2668: *
2669: * Like device_compatible_match(), but uses pmatch(9) to compare
2670: * the device "compatible" strings against patterns in the
2671: * driver's "compatible" data.
1.258 thorpej 2672: */
1.276 thorpej 2673: int
2674: device_compatible_pmatch(const char **device_compats, int ndevice_compats,
2675: const struct device_compatible_entry *driver_compats)
2676: {
2677: return device_compatible_match_strarray_internal(device_compats,
2678: ndevice_compats, driver_compats, NULL, strarray_pmatch);
2679: }
2680:
1.275 thorpej 2681: static int
1.276 thorpej 2682: device_compatible_match_strlist_internal(
2683: const char * const device_compats, size_t const device_compatsize,
1.275 thorpej 2684: const struct device_compatible_entry *driver_compats,
1.276 thorpej 2685: const struct device_compatible_entry **matching_entryp,
2686: int (*match_fn)(const char *, size_t, const char *))
1.258 thorpej 2687: {
2688: const struct device_compatible_entry *dce = NULL;
1.276 thorpej 2689: int rv;
1.258 thorpej 2690:
1.276 thorpej 2691: if (device_compats == NULL || device_compatsize == 0 ||
1.258 thorpej 2692: driver_compats == NULL)
1.261 thorpej 2693: return 0;
1.276 thorpej 2694:
2695: for (dce = driver_compats; dce->compat != NULL; dce++) {
2696: rv = (*match_fn)(device_compats, device_compatsize,
2697: dce->compat);
2698: if (rv != 0) {
2699: if (matching_entryp != NULL) {
2700: *matching_entryp = dce;
1.258 thorpej 2701: }
1.276 thorpej 2702: return rv;
1.258 thorpej 2703: }
2704: }
1.261 thorpej 2705: return 0;
1.258 thorpej 2706: }
2707:
1.276 thorpej 2708: /*
2709: * device_compatible_match_strlist:
2710: *
2711: * Like device_compatible_match(), but take the device
2712: * "compatible" strings as an OpenFirmware-style string
2713: * list.
2714: */
1.275 thorpej 2715: int
1.276 thorpej 2716: device_compatible_match_strlist(
2717: const char * const device_compats, size_t const device_compatsize,
2718: const struct device_compatible_entry *driver_compats)
2719: {
2720: return device_compatible_match_strlist_internal(device_compats,
2721: device_compatsize, driver_compats, NULL, strlist_match);
2722: }
2723:
2724: /*
2725: * device_compatible_pmatch_strlist:
2726: *
2727: * Like device_compatible_pmatch(), but take the device
2728: * "compatible" strings as an OpenFirmware-style string
2729: * list.
2730: */
2731: int
2732: device_compatible_pmatch_strlist(
2733: const char * const device_compats, size_t const device_compatsize,
2734: const struct device_compatible_entry *driver_compats)
1.275 thorpej 2735: {
1.276 thorpej 2736: return device_compatible_match_strlist_internal(device_compats,
2737: device_compatsize, driver_compats, NULL, strlist_pmatch);
1.275 thorpej 2738: }
2739:
1.277 thorpej 2740: static int
2741: device_compatible_match_id_internal(
2742: uintptr_t const id, uintptr_t const mask, uintptr_t const sentinel_id,
2743: const struct device_compatible_entry *driver_compats,
2744: const struct device_compatible_entry **matching_entryp)
2745: {
2746: const struct device_compatible_entry *dce = NULL;
2747:
2748: if (mask == 0)
2749: return 0;
2750:
2751: for (dce = driver_compats; dce->id != sentinel_id; dce++) {
2752: if ((id & mask) == dce->id) {
2753: if (matching_entryp != NULL) {
2754: *matching_entryp = dce;
2755: }
2756: return 1;
2757: }
2758: }
2759: return 0;
2760: }
2761:
2762: /*
2763: * device_compatible_match_id:
2764: *
2765: * Like device_compatible_match(), but takes a single
2766: * unsigned integer device ID.
2767: */
2768: int
2769: device_compatible_match_id(
2770: uintptr_t const id, uintptr_t const sentinel_id,
2771: const struct device_compatible_entry *driver_compats)
2772: {
2773: return device_compatible_match_id_internal(id, (uintptr_t)-1,
2774: sentinel_id, driver_compats, NULL);
2775: }
2776:
1.275 thorpej 2777: /*
2778: * device_compatible_lookup:
2779: *
2780: * Look up and return the device_compatible_entry, using the
2781: * same matching criteria used by device_compatible_match().
2782: */
2783: const struct device_compatible_entry *
2784: device_compatible_lookup(const char **device_compats, int ndevice_compats,
2785: const struct device_compatible_entry *driver_compats)
2786: {
2787: const struct device_compatible_entry *dce;
2788:
1.276 thorpej 2789: if (device_compatible_match_strarray_internal(device_compats,
2790: ndevice_compats, driver_compats, &dce, strarray_match)) {
2791: return dce;
2792: }
2793: return NULL;
2794: }
2795:
2796: /*
2797: * device_compatible_plookup:
2798: *
2799: * Look up and return the device_compatible_entry, using the
2800: * same matching criteria used by device_compatible_pmatch().
2801: */
2802: const struct device_compatible_entry *
2803: device_compatible_plookup(const char **device_compats, int ndevice_compats,
2804: const struct device_compatible_entry *driver_compats)
2805: {
2806: const struct device_compatible_entry *dce;
2807:
2808: if (device_compatible_match_strarray_internal(device_compats,
2809: ndevice_compats, driver_compats, &dce, strarray_pmatch)) {
2810: return dce;
2811: }
2812: return NULL;
2813: }
2814:
2815: /*
2816: * device_compatible_lookup_strlist:
2817: *
2818: * Like device_compatible_lookup(), but take the device
2819: * "compatible" strings as an OpenFirmware-style string
2820: * list.
2821: */
2822: const struct device_compatible_entry *
2823: device_compatible_lookup_strlist(
2824: const char * const device_compats, size_t const device_compatsize,
2825: const struct device_compatible_entry *driver_compats)
2826: {
2827: const struct device_compatible_entry *dce;
2828:
2829: if (device_compatible_match_strlist_internal(device_compats,
2830: device_compatsize, driver_compats, &dce, strlist_match)) {
2831: return dce;
2832: }
2833: return NULL;
2834: }
2835:
2836: /*
2837: * device_compatible_plookup_strlist:
2838: *
2839: * Like device_compatible_plookup(), but take the device
2840: * "compatible" strings as an OpenFirmware-style string
2841: * list.
2842: */
2843: const struct device_compatible_entry *
2844: device_compatible_plookup_strlist(
2845: const char * const device_compats, size_t const device_compatsize,
2846: const struct device_compatible_entry *driver_compats)
2847: {
2848: const struct device_compatible_entry *dce;
2849:
2850: if (device_compatible_match_strlist_internal(device_compats,
2851: device_compatsize, driver_compats, &dce, strlist_pmatch)) {
1.275 thorpej 2852: return dce;
2853: }
2854: return NULL;
2855: }
2856:
1.258 thorpej 2857: /*
1.277 thorpej 2858: * device_compatible_lookup_id:
2859: *
2860: * Like device_compatible_lookup(), but takes a single
2861: * unsigned integer device ID.
2862: */
2863: const struct device_compatible_entry *
2864: device_compatible_lookup_id(
2865: uintptr_t const id, uintptr_t const sentinel_id,
2866: const struct device_compatible_entry *driver_compats)
2867: {
2868: const struct device_compatible_entry *dce;
2869:
2870: if (device_compatible_match_id_internal(id, (uintptr_t)-1,
2871: sentinel_id, driver_compats, &dce)) {
2872: return dce;
2873: }
2874: return NULL;
2875: }
2876:
2877: /*
1.124 jmcneill 2878: * Power management related functions.
2879: */
2880:
2881: bool
2882: device_pmf_is_registered(device_t dev)
2883: {
2884: return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
2885: }
2886:
2887: bool
1.203 dyoung 2888: device_pmf_driver_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2889: {
2890: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
2891: return true;
2892: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
2893: return false;
1.195 dyoung 2894: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
1.183 dyoung 2895: dev->dv_driver_suspend != NULL &&
1.195 dyoung 2896: !(*dev->dv_driver_suspend)(dev, qual))
1.124 jmcneill 2897: return false;
2898:
2899: dev->dv_flags |= DVF_DRIVER_SUSPENDED;
2900: return true;
2901: }
2902:
2903: bool
1.203 dyoung 2904: device_pmf_driver_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2905: {
2906: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
2907: return true;
2908: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
2909: return false;
1.195 dyoung 2910: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
1.183 dyoung 2911: dev->dv_driver_resume != NULL &&
1.195 dyoung 2912: !(*dev->dv_driver_resume)(dev, qual))
1.124 jmcneill 2913: return false;
2914:
2915: dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
2916: return true;
2917: }
2918:
1.133 drochner 2919: bool
2920: device_pmf_driver_shutdown(device_t dev, int how)
2921: {
2922:
2923: if (*dev->dv_driver_shutdown != NULL &&
2924: !(*dev->dv_driver_shutdown)(dev, how))
2925: return false;
2926: return true;
2927: }
2928:
1.135 dyoung 2929: bool
1.124 jmcneill 2930: device_pmf_driver_register(device_t dev,
1.203 dyoung 2931: bool (*suspend)(device_t, const pmf_qual_t *),
2932: bool (*resume)(device_t, const pmf_qual_t *),
1.133 drochner 2933: bool (*shutdown)(device_t, int))
1.124 jmcneill 2934: {
2935: dev->dv_driver_suspend = suspend;
2936: dev->dv_driver_resume = resume;
1.133 drochner 2937: dev->dv_driver_shutdown = shutdown;
1.124 jmcneill 2938: dev->dv_flags |= DVF_POWER_HANDLERS;
1.135 dyoung 2939: return true;
1.124 jmcneill 2940: }
2941:
2942: void
2943: device_pmf_driver_deregister(device_t dev)
2944: {
1.174 dyoung 2945: device_lock_t dvl = device_getlock(dev);
1.157 drochner 2946:
1.124 jmcneill 2947: dev->dv_driver_suspend = NULL;
2948: dev->dv_driver_resume = NULL;
1.139 dyoung 2949:
1.174 dyoung 2950: mutex_enter(&dvl->dvl_mtx);
1.124 jmcneill 2951: dev->dv_flags &= ~DVF_POWER_HANDLERS;
1.174 dyoung 2952: while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) {
1.139 dyoung 2953: /* Wake a thread that waits for the lock. That
2954: * thread will fail to acquire the lock, and then
2955: * it will wake the next thread that waits for the
2956: * lock, or else it will wake us.
2957: */
1.174 dyoung 2958: cv_signal(&dvl->dvl_cv);
1.139 dyoung 2959: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2960: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.139 dyoung 2961: pmflock_debug(dev, __func__, __LINE__);
2962: }
1.174 dyoung 2963: mutex_exit(&dvl->dvl_mtx);
1.124 jmcneill 2964: }
2965:
2966: bool
2967: device_pmf_driver_child_register(device_t dev)
2968: {
2969: device_t parent = device_parent(dev);
2970:
2971: if (parent == NULL || parent->dv_driver_child_register == NULL)
2972: return true;
2973: return (*parent->dv_driver_child_register)(dev);
2974: }
2975:
2976: void
2977: device_pmf_driver_set_child_register(device_t dev,
2978: bool (*child_register)(device_t))
2979: {
2980: dev->dv_driver_child_register = child_register;
2981: }
2982:
1.139 dyoung 2983: static void
2984: pmflock_debug(device_t dev, const char *func, int line)
2985: {
1.292 ! riastrad 2986: #ifdef PMFLOCK_DEBUG
1.174 dyoung 2987: device_lock_t dvl = device_getlock(dev);
1.292 ! riastrad 2988: const char *curlwp_name;
! 2989:
! 2990: if (curlwp->l_name != NULL)
! 2991: curlwp_name = curlwp->l_name;
! 2992: else
! 2993: curlwp_name = curlwp->l_proc->p_comm;
1.139 dyoung 2994:
1.243 msaitoh 2995: aprint_debug_dev(dev,
2996: "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n", func, line,
1.292 ! riastrad 2997: curlwp_name, dvl->dvl_nlock, dvl->dvl_nwait, dev->dv_flags);
! 2998: #endif /* PMFLOCK_DEBUG */
1.139 dyoung 2999: }
3000:
3001: static bool
1.183 dyoung 3002: device_pmf_lock1(device_t dev)
1.139 dyoung 3003: {
1.174 dyoung 3004: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 3005:
1.155 dyoung 3006: while (device_pmf_is_registered(dev) &&
1.174 dyoung 3007: dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) {
3008: dvl->dvl_nwait++;
1.183 dyoung 3009: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 3010: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.183 dyoung 3011: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 3012: dvl->dvl_nwait--;
1.139 dyoung 3013: }
3014: if (!device_pmf_is_registered(dev)) {
1.183 dyoung 3015: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 3016: /* We could not acquire the lock, but some other thread may
3017: * wait for it, also. Wake that thread.
3018: */
1.174 dyoung 3019: cv_signal(&dvl->dvl_cv);
1.139 dyoung 3020: return false;
3021: }
1.174 dyoung 3022: dvl->dvl_nlock++;
3023: dvl->dvl_holder = curlwp;
1.183 dyoung 3024: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 3025: return true;
3026: }
3027:
3028: bool
1.183 dyoung 3029: device_pmf_lock(device_t dev)
1.139 dyoung 3030: {
3031: bool rc;
1.174 dyoung 3032: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 3033:
1.174 dyoung 3034: mutex_enter(&dvl->dvl_mtx);
1.183 dyoung 3035: rc = device_pmf_lock1(dev);
1.174 dyoung 3036: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 3037:
3038: return rc;
3039: }
3040:
3041: void
1.183 dyoung 3042: device_pmf_unlock(device_t dev)
1.139 dyoung 3043: {
1.174 dyoung 3044: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 3045:
1.174 dyoung 3046: KASSERT(dvl->dvl_nlock > 0);
3047: mutex_enter(&dvl->dvl_mtx);
3048: if (--dvl->dvl_nlock == 0)
3049: dvl->dvl_holder = NULL;
3050: cv_signal(&dvl->dvl_cv);
1.183 dyoung 3051: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 3052: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 3053: }
3054:
1.174 dyoung 3055: device_lock_t
3056: device_getlock(device_t dev)
1.139 dyoung 3057: {
1.174 dyoung 3058: return &dev->dv_lock;
1.139 dyoung 3059: }
3060:
1.124 jmcneill 3061: void *
3062: device_pmf_bus_private(device_t dev)
3063: {
3064: return dev->dv_bus_private;
3065: }
3066:
3067: bool
1.203 dyoung 3068: device_pmf_bus_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 3069: {
3070: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
3071: return true;
3072: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
3073: (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
3074: return false;
1.195 dyoung 3075: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
1.183 dyoung 3076: dev->dv_bus_suspend != NULL &&
1.195 dyoung 3077: !(*dev->dv_bus_suspend)(dev, qual))
1.124 jmcneill 3078: return false;
3079:
3080: dev->dv_flags |= DVF_BUS_SUSPENDED;
3081: return true;
3082: }
3083:
3084: bool
1.203 dyoung 3085: device_pmf_bus_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 3086: {
3087: if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
3088: return true;
1.195 dyoung 3089: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
1.183 dyoung 3090: dev->dv_bus_resume != NULL &&
1.195 dyoung 3091: !(*dev->dv_bus_resume)(dev, qual))
1.124 jmcneill 3092: return false;
3093:
3094: dev->dv_flags &= ~DVF_BUS_SUSPENDED;
3095: return true;
3096: }
3097:
1.133 drochner 3098: bool
3099: device_pmf_bus_shutdown(device_t dev, int how)
3100: {
3101:
3102: if (*dev->dv_bus_shutdown != NULL &&
3103: !(*dev->dv_bus_shutdown)(dev, how))
3104: return false;
3105: return true;
3106: }
3107:
1.124 jmcneill 3108: void
3109: device_pmf_bus_register(device_t dev, void *priv,
1.203 dyoung 3110: bool (*suspend)(device_t, const pmf_qual_t *),
3111: bool (*resume)(device_t, const pmf_qual_t *),
1.133 drochner 3112: bool (*shutdown)(device_t, int), void (*deregister)(device_t))
1.124 jmcneill 3113: {
3114: dev->dv_bus_private = priv;
3115: dev->dv_bus_resume = resume;
3116: dev->dv_bus_suspend = suspend;
1.133 drochner 3117: dev->dv_bus_shutdown = shutdown;
1.124 jmcneill 3118: dev->dv_bus_deregister = deregister;
3119: }
3120:
3121: void
3122: device_pmf_bus_deregister(device_t dev)
3123: {
3124: if (dev->dv_bus_deregister == NULL)
3125: return;
3126: (*dev->dv_bus_deregister)(dev);
3127: dev->dv_bus_private = NULL;
3128: dev->dv_bus_suspend = NULL;
3129: dev->dv_bus_resume = NULL;
3130: dev->dv_bus_deregister = NULL;
3131: }
3132:
3133: void *
3134: device_pmf_class_private(device_t dev)
3135: {
3136: return dev->dv_class_private;
3137: }
3138:
3139: bool
1.203 dyoung 3140: device_pmf_class_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 3141: {
3142: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
3143: return true;
1.195 dyoung 3144: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
1.183 dyoung 3145: dev->dv_class_suspend != NULL &&
1.195 dyoung 3146: !(*dev->dv_class_suspend)(dev, qual))
1.124 jmcneill 3147: return false;
3148:
3149: dev->dv_flags |= DVF_CLASS_SUSPENDED;
3150: return true;
3151: }
3152:
3153: bool
1.203 dyoung 3154: device_pmf_class_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 3155: {
3156: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
3157: return true;
3158: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
3159: (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
3160: return false;
1.195 dyoung 3161: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
1.183 dyoung 3162: dev->dv_class_resume != NULL &&
1.195 dyoung 3163: !(*dev->dv_class_resume)(dev, qual))
1.124 jmcneill 3164: return false;
3165:
3166: dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
3167: return true;
3168: }
3169:
3170: void
3171: device_pmf_class_register(device_t dev, void *priv,
1.203 dyoung 3172: bool (*suspend)(device_t, const pmf_qual_t *),
3173: bool (*resume)(device_t, const pmf_qual_t *),
1.124 jmcneill 3174: void (*deregister)(device_t))
3175: {
3176: dev->dv_class_private = priv;
3177: dev->dv_class_suspend = suspend;
3178: dev->dv_class_resume = resume;
3179: dev->dv_class_deregister = deregister;
3180: }
3181:
3182: void
3183: device_pmf_class_deregister(device_t dev)
3184: {
3185: if (dev->dv_class_deregister == NULL)
3186: return;
3187: (*dev->dv_class_deregister)(dev);
3188: dev->dv_class_private = NULL;
3189: dev->dv_class_suspend = NULL;
3190: dev->dv_class_resume = NULL;
3191: dev->dv_class_deregister = NULL;
3192: }
3193:
3194: bool
3195: device_active(device_t dev, devactive_t type)
3196: {
3197: size_t i;
3198:
3199: if (dev->dv_activity_count == 0)
3200: return false;
3201:
1.160 matt 3202: for (i = 0; i < dev->dv_activity_count; ++i) {
3203: if (dev->dv_activity_handlers[i] == NULL)
3204: break;
1.124 jmcneill 3205: (*dev->dv_activity_handlers[i])(dev, type);
1.160 matt 3206: }
1.124 jmcneill 3207:
3208: return true;
3209: }
3210:
3211: bool
3212: device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
3213: {
3214: void (**new_handlers)(device_t, devactive_t);
3215: void (**old_handlers)(device_t, devactive_t);
1.159 matt 3216: size_t i, old_size, new_size;
1.124 jmcneill 3217: int s;
3218:
3219: old_handlers = dev->dv_activity_handlers;
1.159 matt 3220: old_size = dev->dv_activity_count;
1.124 jmcneill 3221:
1.240 mlelstv 3222: KASSERT(old_size == 0 || old_handlers != NULL);
3223:
1.159 matt 3224: for (i = 0; i < old_size; ++i) {
3225: KASSERT(old_handlers[i] != handler);
3226: if (old_handlers[i] == NULL) {
3227: old_handlers[i] = handler;
3228: return true;
3229: }
1.124 jmcneill 3230: }
3231:
1.159 matt 3232: new_size = old_size + 4;
1.273 jdolecek 3233: new_handlers = kmem_alloc(sizeof(void *) * new_size, KM_SLEEP);
1.124 jmcneill 3234:
1.240 mlelstv 3235: for (i = 0; i < old_size; ++i)
3236: new_handlers[i] = old_handlers[i];
1.159 matt 3237: new_handlers[old_size] = handler;
1.240 mlelstv 3238: for (i = old_size+1; i < new_size; ++i)
3239: new_handlers[i] = NULL;
1.124 jmcneill 3240:
3241: s = splhigh();
3242: dev->dv_activity_count = new_size;
3243: dev->dv_activity_handlers = new_handlers;
3244: splx(s);
3245:
1.240 mlelstv 3246: if (old_size > 0)
1.273 jdolecek 3247: kmem_free(old_handlers, sizeof(void *) * old_size);
1.124 jmcneill 3248:
3249: return true;
3250: }
3251:
3252: void
3253: device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
3254: {
3255: void (**old_handlers)(device_t, devactive_t);
1.159 matt 3256: size_t i, old_size;
1.124 jmcneill 3257: int s;
3258:
3259: old_handlers = dev->dv_activity_handlers;
1.159 matt 3260: old_size = dev->dv_activity_count;
1.124 jmcneill 3261:
1.159 matt 3262: for (i = 0; i < old_size; ++i) {
1.124 jmcneill 3263: if (old_handlers[i] == handler)
3264: break;
1.159 matt 3265: if (old_handlers[i] == NULL)
3266: return; /* XXX panic? */
1.124 jmcneill 3267: }
3268:
1.159 matt 3269: if (i == old_size)
1.124 jmcneill 3270: return; /* XXX panic? */
3271:
1.159 matt 3272: for (; i < old_size - 1; ++i) {
3273: if ((old_handlers[i] = old_handlers[i + 1]) != NULL)
3274: continue;
1.124 jmcneill 3275:
1.159 matt 3276: if (i == 0) {
3277: s = splhigh();
3278: dev->dv_activity_count = 0;
3279: dev->dv_activity_handlers = NULL;
3280: splx(s);
1.273 jdolecek 3281: kmem_free(old_handlers, sizeof(void *) * old_size);
1.159 matt 3282: }
3283: return;
1.124 jmcneill 3284: }
1.159 matt 3285: old_handlers[i] = NULL;
1.124 jmcneill 3286: }
1.136 dyoung 3287:
1.187 dyoung 3288: /* Return true iff the device_t `dev' exists at generation `gen'. */
3289: static bool
3290: device_exists_at(device_t dv, devgen_t gen)
3291: {
3292: return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) &&
3293: dv->dv_add_gen <= gen;
3294: }
3295:
3296: static bool
3297: deviter_visits(const deviter_t *di, device_t dv)
3298: {
3299: return device_exists_at(dv, di->di_gen);
3300: }
3301:
1.136 dyoung 3302: /*
3303: * Device Iteration
3304: *
3305: * deviter_t: a device iterator. Holds state for a "walk" visiting
3306: * each device_t's in the device tree.
3307: *
3308: * deviter_init(di, flags): initialize the device iterator `di'
3309: * to "walk" the device tree. deviter_next(di) will return
3310: * the first device_t in the device tree, or NULL if there are
3311: * no devices.
3312: *
3313: * `flags' is one or more of DEVITER_F_RW, indicating that the
3314: * caller intends to modify the device tree by calling
3315: * config_detach(9) on devices in the order that the iterator
3316: * returns them; DEVITER_F_ROOT_FIRST, asking for the devices
3317: * nearest the "root" of the device tree to be returned, first;
3318: * DEVITER_F_LEAVES_FIRST, asking for the devices furthest from
3319: * the root of the device tree, first; and DEVITER_F_SHUTDOWN,
3320: * indicating both that deviter_init() should not respect any
3321: * locks on the device tree, and that deviter_next(di) may run
3322: * in more than one LWP before the walk has finished.
3323: *
3324: * Only one DEVITER_F_RW iterator may be in the device tree at
3325: * once.
3326: *
3327: * DEVITER_F_SHUTDOWN implies DEVITER_F_RW.
3328: *
3329: * Results are undefined if the flags DEVITER_F_ROOT_FIRST and
3330: * DEVITER_F_LEAVES_FIRST are used in combination.
3331: *
3332: * deviter_first(di, flags): initialize the device iterator `di'
3333: * and return the first device_t in the device tree, or NULL
3334: * if there are no devices. The statement
3335: *
3336: * dv = deviter_first(di);
3337: *
3338: * is shorthand for
3339: *
3340: * deviter_init(di);
3341: * dv = deviter_next(di);
3342: *
3343: * deviter_next(di): return the next device_t in the device tree,
3344: * or NULL if there are no more devices. deviter_next(di)
3345: * is undefined if `di' was not initialized with deviter_init() or
3346: * deviter_first().
3347: *
3348: * deviter_release(di): stops iteration (subsequent calls to
3349: * deviter_next() will return NULL), releases any locks and
3350: * resources held by the device iterator.
3351: *
3352: * Device iteration does not return device_t's in any particular
3353: * order. An iterator will never return the same device_t twice.
3354: * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
3355: * is called repeatedly on the same `di', it will eventually return
3356: * NULL. It is ok to attach/detach devices during device iteration.
3357: */
3358: void
3359: deviter_init(deviter_t *di, deviter_flags_t flags)
3360: {
3361: device_t dv;
3362:
1.187 dyoung 3363: memset(di, 0, sizeof(*di));
3364:
3365: if ((flags & DEVITER_F_SHUTDOWN) != 0)
1.136 dyoung 3366: flags |= DEVITER_F_RW;
1.187 dyoung 3367:
1.257 mlelstv 3368: mutex_enter(&alldevs_lock);
1.187 dyoung 3369: if ((flags & DEVITER_F_RW) != 0)
1.257 mlelstv 3370: alldevs_nwrite++;
1.187 dyoung 3371: else
1.257 mlelstv 3372: alldevs_nread++;
3373: di->di_gen = alldevs_gen++;
1.136 dyoung 3374: di->di_flags = flags;
3375:
3376: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
3377: case DEVITER_F_LEAVES_FIRST:
1.257 mlelstv 3378: TAILQ_FOREACH(dv, &alldevs, dv_list) {
1.187 dyoung 3379: if (!deviter_visits(di, dv))
3380: continue;
1.136 dyoung 3381: di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
1.187 dyoung 3382: }
1.136 dyoung 3383: break;
3384: case DEVITER_F_ROOT_FIRST:
1.257 mlelstv 3385: TAILQ_FOREACH(dv, &alldevs, dv_list) {
1.187 dyoung 3386: if (!deviter_visits(di, dv))
3387: continue;
1.136 dyoung 3388: di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
1.187 dyoung 3389: }
1.136 dyoung 3390: break;
3391: default:
3392: break;
3393: }
3394:
3395: deviter_reinit(di);
1.257 mlelstv 3396: mutex_exit(&alldevs_lock);
1.136 dyoung 3397: }
3398:
3399: static void
3400: deviter_reinit(deviter_t *di)
3401: {
1.248 riastrad 3402:
1.257 mlelstv 3403: KASSERT(mutex_owned(&alldevs_lock));
1.136 dyoung 3404: if ((di->di_flags & DEVITER_F_RW) != 0)
1.257 mlelstv 3405: di->di_prev = TAILQ_LAST(&alldevs, devicelist);
1.136 dyoung 3406: else
1.257 mlelstv 3407: di->di_prev = TAILQ_FIRST(&alldevs);
1.136 dyoung 3408: }
3409:
3410: device_t
3411: deviter_first(deviter_t *di, deviter_flags_t flags)
3412: {
1.248 riastrad 3413:
1.136 dyoung 3414: deviter_init(di, flags);
3415: return deviter_next(di);
3416: }
3417:
3418: static device_t
1.187 dyoung 3419: deviter_next2(deviter_t *di)
1.136 dyoung 3420: {
3421: device_t dv;
3422:
1.257 mlelstv 3423: KASSERT(mutex_owned(&alldevs_lock));
1.248 riastrad 3424:
1.136 dyoung 3425: dv = di->di_prev;
3426:
3427: if (dv == NULL)
1.191 dyoung 3428: return NULL;
3429:
3430: if ((di->di_flags & DEVITER_F_RW) != 0)
1.136 dyoung 3431: di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
3432: else
3433: di->di_prev = TAILQ_NEXT(dv, dv_list);
3434:
3435: return dv;
3436: }
3437:
1.187 dyoung 3438: static device_t
3439: deviter_next1(deviter_t *di)
3440: {
3441: device_t dv;
3442:
1.257 mlelstv 3443: KASSERT(mutex_owned(&alldevs_lock));
1.248 riastrad 3444:
1.187 dyoung 3445: do {
3446: dv = deviter_next2(di);
3447: } while (dv != NULL && !deviter_visits(di, dv));
3448:
3449: return dv;
3450: }
3451:
1.136 dyoung 3452: device_t
3453: deviter_next(deviter_t *di)
3454: {
3455: device_t dv = NULL;
3456:
1.257 mlelstv 3457: mutex_enter(&alldevs_lock);
1.136 dyoung 3458: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
3459: case 0:
1.248 riastrad 3460: dv = deviter_next1(di);
3461: break;
1.136 dyoung 3462: case DEVITER_F_LEAVES_FIRST:
3463: while (di->di_curdepth >= 0) {
3464: if ((dv = deviter_next1(di)) == NULL) {
3465: di->di_curdepth--;
3466: deviter_reinit(di);
3467: } else if (dv->dv_depth == di->di_curdepth)
3468: break;
3469: }
1.248 riastrad 3470: break;
1.136 dyoung 3471: case DEVITER_F_ROOT_FIRST:
3472: while (di->di_curdepth <= di->di_maxdepth) {
3473: if ((dv = deviter_next1(di)) == NULL) {
3474: di->di_curdepth++;
3475: deviter_reinit(di);
3476: } else if (dv->dv_depth == di->di_curdepth)
3477: break;
3478: }
1.248 riastrad 3479: break;
1.136 dyoung 3480: default:
1.248 riastrad 3481: break;
1.136 dyoung 3482: }
1.257 mlelstv 3483: mutex_exit(&alldevs_lock);
1.248 riastrad 3484:
3485: return dv;
1.136 dyoung 3486: }
3487:
3488: void
3489: deviter_release(deviter_t *di)
3490: {
3491: bool rw = (di->di_flags & DEVITER_F_RW) != 0;
3492:
1.257 mlelstv 3493: mutex_enter(&alldevs_lock);
1.187 dyoung 3494: if (rw)
1.257 mlelstv 3495: --alldevs_nwrite;
1.187 dyoung 3496: else
1.257 mlelstv 3497: --alldevs_nread;
1.187 dyoung 3498: /* XXX wake a garbage-collection thread */
1.257 mlelstv 3499: mutex_exit(&alldevs_lock);
1.136 dyoung 3500: }
1.174 dyoung 3501:
1.201 dyoung 3502: const char *
3503: cfdata_ifattr(const struct cfdata *cf)
3504: {
3505: return cf->cf_pspec->cfp_iattr;
3506: }
3507:
1.193 dyoung 3508: bool
3509: ifattr_match(const char *snull, const char *t)
3510: {
3511: return (snull == NULL) || strcmp(snull, t) == 0;
3512: }
3513:
1.192 dyoung 3514: void
3515: null_childdetached(device_t self, device_t child)
3516: {
3517: /* do nothing */
3518: }
3519:
1.182 pooka 3520: static void
3521: sysctl_detach_setup(struct sysctllog **clog)
1.174 dyoung 3522: {
3523:
1.230 pooka 3524: sysctl_createv(clog, 0, NULL, NULL,
1.174 dyoung 3525: CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.205 jruoho 3526: CTLTYPE_BOOL, "detachall",
1.174 dyoung 3527: SYSCTL_DESCR("Detach all devices at shutdown"),
3528: NULL, 0, &detachall, 0,
1.230 pooka 3529: CTL_KERN, CTL_CREATE, CTL_EOL);
1.174 dyoung 3530: }
CVSweb <webmaster@jp.NetBSD.org>