Annotation of src/sys/kern/subr_autoconf.c, Revision 1.233
1.233 ! uebayasi 1: /* $NetBSD$ */
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.233 ! uebayasi 80: __KERNEL_RCSID(0, "$NetBSD$");
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.118 dyoung 110:
111: #include <sys/disk.h>
112:
1.231 tls 113: #include <sys/rnd.h>
114:
1.16 mycroft 115: #include <machine/limits.h>
1.1 glass 116:
117: /*
118: * Autoconfiguration subroutines.
119: */
120:
121: /*
1.231 tls 122: * Device autoconfiguration timings are mixed into the entropy pool.
123: */
124: extern krndsource_t rnd_autoconf_source;
125:
126: /*
1.1 glass 127: * ioconf.c exports exactly two names: cfdata and cfroots. All system
128: * devices and drivers are found via these tables.
129: */
130: extern struct cfdata cfdata[];
1.84 matt 131: extern const short cfroots[];
1.1 glass 132:
1.65 thorpej 133: /*
1.67 thorpej 134: * List of all cfdriver structures. We use this to detect duplicates
135: * when other cfdrivers are loaded.
136: */
1.69 thorpej 137: struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
138: extern struct cfdriver * const cfdriver_list_initial[];
1.67 thorpej 139:
140: /*
1.76 thorpej 141: * Initial list of cfattach's.
142: */
143: extern const struct cfattachinit cfattachinit[];
144:
145: /*
1.65 thorpej 146: * List of cfdata tables. We always have one such list -- the one
147: * built statically when the kernel was configured.
148: */
1.121 matt 149: struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
1.65 thorpej 150: static struct cftable initcftable;
151:
1.102 thorpej 152: #define ROOT ((device_t)NULL)
1.1 glass 153:
1.16 mycroft 154: struct matchinfo {
1.99 drochner 155: cfsubmatch_t fn;
1.224 chs 156: device_t parent;
1.99 drochner 157: const int *locs;
1.25 cgd 158: void *aux;
159: struct cfdata *match;
160: int pri;
1.16 mycroft 161: };
1.17 christos 162:
1.198 dyoung 163: struct alldevs_foray {
164: int af_s;
165: struct devicelist af_garbage;
166: };
167:
1.51 cgd 168: static char *number(char *, int);
1.102 thorpej 169: static void mapply(struct matchinfo *, cfdata_t);
1.117 drochner 170: static device_t config_devalloc(const device_t, const cfdata_t, const int *);
1.187 dyoung 171: static void config_devdelete(device_t);
1.190 dyoung 172: static void config_devunlink(device_t, struct devicelist *);
1.117 drochner 173: static void config_makeroom(int, struct cfdriver *);
174: static void config_devlink(device_t);
1.187 dyoung 175: static void config_alldevs_unlock(int);
176: static int config_alldevs_lock(void);
1.198 dyoung 177: static void config_alldevs_enter(struct alldevs_foray *);
178: static void config_alldevs_exit(struct alldevs_foray *);
1.221 pgoyette 179: static void config_add_attrib_dict(device_t);
1.197 rmind 180:
181: static void config_collect_garbage(struct devicelist *);
182: static void config_dump_garbage(struct devicelist *);
183:
1.139 dyoung 184: static void pmflock_debug(device_t, const char *, int);
185:
1.136 dyoung 186: static device_t deviter_next1(deviter_t *);
187: static void deviter_reinit(deviter_t *);
188:
1.29 thorpej 189: struct deferred_config {
190: TAILQ_ENTRY(deferred_config) dc_queue;
1.102 thorpej 191: device_t dc_dev;
192: void (*dc_func)(device_t);
1.29 thorpej 193: };
194:
1.42 thorpej 195: TAILQ_HEAD(deferred_config_head, deferred_config);
1.29 thorpej 196:
1.121 matt 197: struct deferred_config_head deferred_config_queue =
198: TAILQ_HEAD_INITIALIZER(deferred_config_queue);
199: struct deferred_config_head interrupt_config_queue =
200: TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
1.142 ad 201: int interrupt_config_threads = 8;
1.207 tsutsui 202: struct deferred_config_head mountroot_config_queue =
203: TAILQ_HEAD_INITIALIZER(mountroot_config_queue);
204: int mountroot_config_threads = 2;
1.208 tsutsui 205: static bool root_is_mounted = false;
1.42 thorpej 206:
1.102 thorpej 207: static void config_process_deferred(struct deferred_config_head *, device_t);
1.29 thorpej 208:
1.75 thorpej 209: /* Hooks to finalize configuration once all real devices have been found. */
210: struct finalize_hook {
211: TAILQ_ENTRY(finalize_hook) f_list;
1.102 thorpej 212: int (*f_func)(device_t);
213: device_t f_dev;
1.75 thorpej 214: };
1.121 matt 215: static TAILQ_HEAD(, finalize_hook) config_finalize_list =
216: TAILQ_HEAD_INITIALIZER(config_finalize_list);
1.75 thorpej 217: static int config_finalize_done;
218:
1.56 thorpej 219: /* list of all devices */
1.187 dyoung 220: static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
221: static kmutex_t alldevs_mtx;
222: static volatile bool alldevs_garbage = false;
223: static volatile devgen_t alldevs_gen = 1;
224: static volatile int alldevs_nread = 0;
225: static volatile int alldevs_nwrite = 0;
1.56 thorpej 226:
1.151 ad 227: static int config_pending; /* semaphore for mountroot */
228: static kmutex_t config_misc_lock;
229: static kcondvar_t config_misc_cv;
1.47 thorpej 230:
1.210 martin 231: static bool detachall = false;
1.174 dyoung 232:
1.67 thorpej 233: #define STREQ(s1, s2) \
1.70 thorpej 234: (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
1.67 thorpej 235:
1.185 pooka 236: static bool config_initialized = false; /* config_init() has been called. */
1.74 thorpej 237:
1.80 thorpej 238: static int config_do_twiddle;
1.176 ad 239: static callout_t config_twiddle_ch;
1.80 thorpej 240:
1.182 pooka 241: static void sysctl_detach_setup(struct sysctllog **);
242:
1.204 pooka 243: typedef int (*cfdriver_fn)(struct cfdriver *);
244: static int
245: frob_cfdrivervec(struct cfdriver * const *cfdriverv,
246: cfdriver_fn drv_do, cfdriver_fn drv_undo,
247: const char *style, bool dopanic)
248: {
1.226 christos 249: void (*pr)(const char *, ...) __printflike(1, 2) =
250: dopanic ? panic : printf;
1.229 martin 251: int i, error = 0, e2 __diagused;
1.204 pooka 252:
253: for (i = 0; cfdriverv[i] != NULL; i++) {
254: if ((error = drv_do(cfdriverv[i])) != 0) {
255: pr("configure: `%s' driver %s failed: %d",
256: cfdriverv[i]->cd_name, style, error);
257: goto bad;
258: }
259: }
260:
261: KASSERT(error == 0);
262: return 0;
263:
264: bad:
265: printf("\n");
266: for (i--; i >= 0; i--) {
267: e2 = drv_undo(cfdriverv[i]);
268: KASSERT(e2 == 0);
269: }
270:
271: return error;
272: }
273:
274: typedef int (*cfattach_fn)(const char *, struct cfattach *);
275: static int
276: frob_cfattachvec(const struct cfattachinit *cfattachv,
277: cfattach_fn att_do, cfattach_fn att_undo,
278: const char *style, bool dopanic)
279: {
280: const struct cfattachinit *cfai = NULL;
1.226 christos 281: void (*pr)(const char *, ...) __printflike(1, 2) =
282: dopanic ? panic : printf;
1.229 martin 283: int j = 0, error = 0, e2 __diagused;
1.204 pooka 284:
285: for (cfai = &cfattachv[0]; cfai->cfai_name != NULL; cfai++) {
286: for (j = 0; cfai->cfai_list[j] != NULL; j++) {
287: if ((error = att_do(cfai->cfai_name,
1.214 mbalmer 288: cfai->cfai_list[j])) != 0) {
1.204 pooka 289: pr("configure: attachment `%s' "
290: "of `%s' driver %s failed: %d",
291: cfai->cfai_list[j]->ca_name,
292: cfai->cfai_name, style, error);
293: goto bad;
294: }
295: }
296: }
297:
298: KASSERT(error == 0);
299: return 0;
300:
301: bad:
302: /*
303: * Rollback in reverse order. dunno if super-important, but
304: * do that anyway. Although the code looks a little like
305: * someone did a little integration (in the math sense).
306: */
307: printf("\n");
308: if (cfai) {
309: bool last;
310:
311: for (last = false; last == false; ) {
312: if (cfai == &cfattachv[0])
313: last = true;
314: for (j--; j >= 0; j--) {
315: e2 = att_undo(cfai->cfai_name,
316: cfai->cfai_list[j]);
317: KASSERT(e2 == 0);
318: }
319: if (!last) {
320: cfai--;
321: for (j = 0; cfai->cfai_list[j] != NULL; j++)
322: ;
323: }
324: }
325: }
326:
327: return error;
328: }
329:
1.20 cgd 330: /*
1.74 thorpej 331: * Initialize the autoconfiguration data structures. Normally this
332: * is done by configure(), but some platforms need to do this very
333: * early (to e.g. initialize the console).
1.20 cgd 334: */
335: void
1.74 thorpej 336: config_init(void)
1.20 cgd 337: {
1.67 thorpej 338:
1.185 pooka 339: KASSERT(config_initialized == false);
1.74 thorpej 340:
1.199 dyoung 341: mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_VM);
1.136 dyoung 342:
1.151 ad 343: mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
344: cv_init(&config_misc_cv, "cfgmisc");
345:
1.176 ad 346: callout_init(&config_twiddle_ch, CALLOUT_MPSAFE);
347:
1.204 pooka 348: frob_cfdrivervec(cfdriver_list_initial,
349: config_cfdriver_attach, NULL, "bootstrap", true);
350: frob_cfattachvec(cfattachinit,
351: config_cfattach_attach, NULL, "bootstrap", true);
1.20 cgd 352:
1.65 thorpej 353: initcftable.ct_cfdata = cfdata;
354: TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
1.185 pooka 355:
356: config_initialized = true;
357: }
358:
1.204 pooka 359: /*
360: * Init or fini drivers and attachments. Either all or none
361: * are processed (via rollback). It would be nice if this were
362: * atomic to outside consumers, but with the current state of
363: * locking ...
364: */
365: int
366: config_init_component(struct cfdriver * const *cfdriverv,
367: const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
368: {
369: int error;
370:
371: if ((error = frob_cfdrivervec(cfdriverv,
372: config_cfdriver_attach, config_cfdriver_detach, "init", false))!= 0)
373: return error;
374: if ((error = frob_cfattachvec(cfattachv,
375: config_cfattach_attach, config_cfattach_detach,
376: "init", false)) != 0) {
377: frob_cfdrivervec(cfdriverv,
378: config_cfdriver_detach, NULL, "init rollback", true);
379: return error;
380: }
381: if ((error = config_cfdata_attach(cfdatav, 1)) != 0) {
382: frob_cfattachvec(cfattachv,
383: config_cfattach_detach, NULL, "init rollback", true);
384: frob_cfdrivervec(cfdriverv,
385: config_cfdriver_detach, NULL, "init rollback", true);
386: return error;
387: }
388:
389: return 0;
390: }
391:
392: int
393: config_fini_component(struct cfdriver * const *cfdriverv,
394: const struct cfattachinit *cfattachv, struct cfdata *cfdatav)
395: {
396: int error;
397:
398: if ((error = config_cfdata_detach(cfdatav)) != 0)
399: return error;
400: if ((error = frob_cfattachvec(cfattachv,
401: config_cfattach_detach, config_cfattach_attach,
402: "fini", false)) != 0) {
403: if (config_cfdata_attach(cfdatav, 0) != 0)
404: panic("config_cfdata fini rollback failed");
405: return error;
406: }
407: if ((error = frob_cfdrivervec(cfdriverv,
408: config_cfdriver_detach, config_cfdriver_attach,
409: "fini", false)) != 0) {
410: frob_cfattachvec(cfattachv,
411: config_cfattach_attach, NULL, "fini rollback", true);
412: if (config_cfdata_attach(cfdatav, 0) != 0)
413: panic("config_cfdata fini rollback failed");
414: return error;
415: }
416:
417: return 0;
418: }
419:
1.185 pooka 420: void
421: config_init_mi(void)
422: {
423:
424: if (!config_initialized)
425: config_init();
426:
1.182 pooka 427: sysctl_detach_setup(NULL);
1.74 thorpej 428: }
429:
1.126 dyoung 430: void
431: config_deferred(device_t dev)
432: {
433: config_process_deferred(&deferred_config_queue, dev);
434: config_process_deferred(&interrupt_config_queue, dev);
1.207 tsutsui 435: config_process_deferred(&mountroot_config_queue, dev);
1.126 dyoung 436: }
437:
1.142 ad 438: static void
439: config_interrupts_thread(void *cookie)
440: {
441: struct deferred_config *dc;
442:
443: while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
444: TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
445: (*dc->dc_func)(dc->dc_dev);
1.228 christos 446: config_pending_decr(dc->dc_dev);
1.159 matt 447: kmem_free(dc, sizeof(*dc));
1.142 ad 448: }
449: kthread_exit(0);
450: }
451:
1.74 thorpej 452: void
1.222 matt 453: config_create_interruptthreads(void)
1.74 thorpej 454: {
1.180 pooka 455: int i;
1.144 ad 456:
1.142 ad 457: for (i = 0; i < interrupt_config_threads; i++) {
458: (void)kthread_create(PRI_NONE, 0, NULL,
1.223 matt 459: config_interrupts_thread, NULL, NULL, "configintr");
1.142 ad 460: }
1.20 cgd 461: }
462:
1.207 tsutsui 463: static void
464: config_mountroot_thread(void *cookie)
465: {
466: struct deferred_config *dc;
467:
468: while ((dc = TAILQ_FIRST(&mountroot_config_queue)) != NULL) {
469: TAILQ_REMOVE(&mountroot_config_queue, dc, dc_queue);
470: (*dc->dc_func)(dc->dc_dev);
471: kmem_free(dc, sizeof(*dc));
472: }
473: kthread_exit(0);
474: }
475:
476: void
1.222 matt 477: config_create_mountrootthreads(void)
1.207 tsutsui 478: {
479: int i;
480:
1.208 tsutsui 481: if (!root_is_mounted)
482: root_is_mounted = true;
483:
1.207 tsutsui 484: for (i = 0; i < mountroot_config_threads; i++) {
485: (void)kthread_create(PRI_NONE, 0, NULL,
1.223 matt 486: config_mountroot_thread, NULL, NULL, "configroot");
1.207 tsutsui 487: }
488: }
489:
1.1 glass 490: /*
1.149 jmcneill 491: * Announce device attach/detach to userland listeners.
492: */
493: static void
494: devmon_report_device(device_t dev, bool isattach)
495: {
496: #if NDRVCTL > 0
497: prop_dictionary_t ev;
498: const char *parent;
499: const char *what;
500: device_t pdev = device_parent(dev);
501:
502: ev = prop_dictionary_create();
503: if (ev == NULL)
504: return;
505:
506: what = (isattach ? "device-attach" : "device-detach");
507: parent = (pdev == NULL ? "root" : device_xname(pdev));
508: if (!prop_dictionary_set_cstring(ev, "device", device_xname(dev)) ||
509: !prop_dictionary_set_cstring(ev, "parent", parent)) {
510: prop_object_release(ev);
511: return;
512: }
513:
514: devmon_insert(what, ev);
515: #endif
516: }
517:
518: /*
1.67 thorpej 519: * Add a cfdriver to the system.
520: */
521: int
522: config_cfdriver_attach(struct cfdriver *cd)
523: {
524: struct cfdriver *lcd;
525:
526: /* Make sure this driver isn't already in the system. */
527: LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
528: if (STREQ(lcd->cd_name, cd->cd_name))
1.175 cegger 529: return EEXIST;
1.67 thorpej 530: }
531:
1.76 thorpej 532: LIST_INIT(&cd->cd_attach);
1.67 thorpej 533: LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
534:
1.175 cegger 535: return 0;
1.67 thorpej 536: }
537:
538: /*
539: * Remove a cfdriver from the system.
540: */
541: int
542: config_cfdriver_detach(struct cfdriver *cd)
543: {
1.198 dyoung 544: struct alldevs_foray af;
545: int i, rc = 0;
1.67 thorpej 546:
1.198 dyoung 547: config_alldevs_enter(&af);
1.67 thorpej 548: /* Make sure there are no active instances. */
549: for (i = 0; i < cd->cd_ndevs; i++) {
1.187 dyoung 550: if (cd->cd_devs[i] != NULL) {
551: rc = EBUSY;
552: break;
553: }
1.67 thorpej 554: }
1.198 dyoung 555: config_alldevs_exit(&af);
1.187 dyoung 556:
557: if (rc != 0)
558: return rc;
1.67 thorpej 559:
1.76 thorpej 560: /* ...and no attachments loaded. */
561: if (LIST_EMPTY(&cd->cd_attach) == 0)
1.175 cegger 562: return EBUSY;
1.76 thorpej 563:
1.67 thorpej 564: LIST_REMOVE(cd, cd_list);
565:
566: KASSERT(cd->cd_devs == NULL);
567:
1.175 cegger 568: return 0;
1.67 thorpej 569: }
570:
571: /*
572: * Look up a cfdriver by name.
573: */
1.78 isaki 574: struct cfdriver *
1.67 thorpej 575: config_cfdriver_lookup(const char *name)
576: {
577: struct cfdriver *cd;
1.69 thorpej 578:
1.67 thorpej 579: LIST_FOREACH(cd, &allcfdrivers, cd_list) {
580: if (STREQ(cd->cd_name, name))
1.175 cegger 581: return cd;
1.67 thorpej 582: }
583:
1.175 cegger 584: return NULL;
1.67 thorpej 585: }
586:
587: /*
1.76 thorpej 588: * Add a cfattach to the specified driver.
589: */
590: int
591: config_cfattach_attach(const char *driver, struct cfattach *ca)
592: {
593: struct cfattach *lca;
594: struct cfdriver *cd;
595:
596: cd = config_cfdriver_lookup(driver);
597: if (cd == NULL)
1.175 cegger 598: return ESRCH;
1.76 thorpej 599:
600: /* Make sure this attachment isn't already on this driver. */
601: LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
602: if (STREQ(lca->ca_name, ca->ca_name))
1.175 cegger 603: return EEXIST;
1.76 thorpej 604: }
605:
606: LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
607:
1.175 cegger 608: return 0;
1.76 thorpej 609: }
610:
611: /*
612: * Remove a cfattach from the specified driver.
613: */
614: int
615: config_cfattach_detach(const char *driver, struct cfattach *ca)
616: {
1.198 dyoung 617: struct alldevs_foray af;
1.76 thorpej 618: struct cfdriver *cd;
1.102 thorpej 619: device_t dev;
1.198 dyoung 620: int i, rc = 0;
1.76 thorpej 621:
622: cd = config_cfdriver_lookup(driver);
623: if (cd == NULL)
1.175 cegger 624: return ESRCH;
1.76 thorpej 625:
1.198 dyoung 626: config_alldevs_enter(&af);
1.76 thorpej 627: /* Make sure there are no active instances. */
628: for (i = 0; i < cd->cd_ndevs; i++) {
629: if ((dev = cd->cd_devs[i]) == NULL)
630: continue;
1.187 dyoung 631: if (dev->dv_cfattach == ca) {
632: rc = EBUSY;
633: break;
634: }
1.76 thorpej 635: }
1.198 dyoung 636: config_alldevs_exit(&af);
1.187 dyoung 637:
638: if (rc != 0)
639: return rc;
1.76 thorpej 640:
641: LIST_REMOVE(ca, ca_list);
642:
1.175 cegger 643: return 0;
1.76 thorpej 644: }
645:
646: /*
647: * Look up a cfattach by name.
648: */
649: static struct cfattach *
650: config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
651: {
652: struct cfattach *ca;
653:
654: LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
655: if (STREQ(ca->ca_name, atname))
1.175 cegger 656: return ca;
1.76 thorpej 657: }
658:
1.175 cegger 659: return NULL;
1.76 thorpej 660: }
661:
662: /*
663: * Look up a cfattach by driver/attachment name.
664: */
665: struct cfattach *
666: config_cfattach_lookup(const char *name, const char *atname)
667: {
668: struct cfdriver *cd;
669:
670: cd = config_cfdriver_lookup(name);
671: if (cd == NULL)
1.175 cegger 672: return NULL;
1.76 thorpej 673:
1.175 cegger 674: return config_cfattach_lookup_cd(cd, atname);
1.76 thorpej 675: }
676:
677: /*
1.1 glass 678: * Apply the matching function and choose the best. This is used
679: * a few times and we want to keep the code small.
680: */
1.16 mycroft 681: static void
1.102 thorpej 682: mapply(struct matchinfo *m, cfdata_t cf)
1.1 glass 683: {
1.50 augustss 684: int pri;
1.1 glass 685:
1.99 drochner 686: if (m->fn != NULL) {
687: pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
1.90 drochner 688: } else {
1.100 drochner 689: pri = config_match(m->parent, cf, m->aux);
1.3 glass 690: }
1.1 glass 691: if (pri > m->pri) {
1.25 cgd 692: m->match = cf;
1.1 glass 693: m->pri = pri;
694: }
695: }
696:
1.98 drochner 697: int
1.102 thorpej 698: config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
1.98 drochner 699: {
700: const struct cfiattrdata *ci;
701: const struct cflocdesc *cl;
702: int nlocs, i;
703:
1.201 dyoung 704: ci = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
1.98 drochner 705: KASSERT(ci);
706: nlocs = ci->ci_loclen;
1.154 drochner 707: KASSERT(!nlocs || locs);
1.98 drochner 708: for (i = 0; i < nlocs; i++) {
709: cl = &ci->ci_locdesc[i];
1.233 ! uebayasi 710: if (cl->cld_defaultstr != NULL &&
! 711: cf->cf_loc[i] == cl->cld_default)
! 712: continue;
! 713: if (cf->cf_loc[i] == locs[i])
! 714: continue;
! 715: return 0;
1.98 drochner 716: }
717:
1.175 cegger 718: return config_match(parent, cf, aux);
1.98 drochner 719: }
720:
1.1 glass 721: /*
1.96 drochner 722: * Helper function: check whether the driver supports the interface attribute
723: * and return its descriptor structure.
1.91 drochner 724: */
1.96 drochner 725: static const struct cfiattrdata *
726: cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
1.91 drochner 727: {
1.96 drochner 728: const struct cfiattrdata * const *cpp;
1.91 drochner 729:
730: if (cd->cd_attrs == NULL)
1.175 cegger 731: return 0;
1.91 drochner 732:
733: for (cpp = cd->cd_attrs; *cpp; cpp++) {
1.96 drochner 734: if (STREQ((*cpp)->ci_name, ia)) {
1.91 drochner 735: /* Match. */
1.175 cegger 736: return *cpp;
1.91 drochner 737: }
738: }
1.175 cegger 739: return 0;
1.91 drochner 740: }
741:
742: /*
1.96 drochner 743: * Lookup an interface attribute description by name.
744: * If the driver is given, consider only its supported attributes.
745: */
746: const struct cfiattrdata *
747: cfiattr_lookup(const char *name, const struct cfdriver *cd)
748: {
749: const struct cfdriver *d;
750: const struct cfiattrdata *ia;
751:
752: if (cd)
1.175 cegger 753: return cfdriver_get_iattr(cd, name);
1.96 drochner 754:
755: LIST_FOREACH(d, &allcfdrivers, cd_list) {
756: ia = cfdriver_get_iattr(d, name);
757: if (ia)
1.175 cegger 758: return ia;
1.96 drochner 759: }
1.175 cegger 760: return 0;
1.96 drochner 761: }
762:
763: /*
1.66 thorpej 764: * Determine if `parent' is a potential parent for a device spec based
765: * on `cfp'.
766: */
767: static int
1.102 thorpej 768: cfparent_match(const device_t parent, const struct cfparent *cfp)
1.66 thorpej 769: {
1.67 thorpej 770: struct cfdriver *pcd;
1.70 thorpej 771:
772: /* We don't match root nodes here. */
773: if (cfp == NULL)
1.175 cegger 774: return 0;
1.66 thorpej 775:
1.77 thorpej 776: pcd = parent->dv_cfdriver;
1.67 thorpej 777: KASSERT(pcd != NULL);
778:
1.66 thorpej 779: /*
780: * First, ensure this parent has the correct interface
781: * attribute.
782: */
1.96 drochner 783: if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
1.175 cegger 784: return 0;
1.66 thorpej 785:
786: /*
787: * If no specific parent device instance was specified (i.e.
788: * we're attaching to the attribute only), we're done!
789: */
790: if (cfp->cfp_parent == NULL)
1.175 cegger 791: return 1;
1.66 thorpej 792:
793: /*
794: * Check the parent device's name.
795: */
1.71 thorpej 796: if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
1.175 cegger 797: return 0; /* not the same parent */
1.66 thorpej 798:
799: /*
800: * Make sure the unit number matches.
801: */
1.77 thorpej 802: if (cfp->cfp_unit == DVUNIT_ANY || /* wildcard */
1.66 thorpej 803: cfp->cfp_unit == parent->dv_unit)
1.175 cegger 804: return 1;
1.66 thorpej 805:
806: /* Unit numbers don't match. */
1.175 cegger 807: return 0;
1.68 thorpej 808: }
809:
810: /*
1.90 drochner 811: * Helper for config_cfdata_attach(): check all devices whether it could be
812: * parent any attachment in the config data table passed, and rescan.
813: */
814: static void
815: rescan_with_cfdata(const struct cfdata *cf)
816: {
1.102 thorpej 817: device_t d;
1.90 drochner 818: const struct cfdata *cf1;
1.136 dyoung 819: deviter_t di;
820:
1.90 drochner 821:
822: /*
1.164 ad 823: * "alldevs" is likely longer than a modules's cfdata, so make it
1.90 drochner 824: * the outer loop.
825: */
1.136 dyoung 826: for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) {
1.90 drochner 827:
828: if (!(d->dv_cfattach->ca_rescan))
829: continue;
830:
831: for (cf1 = cf; cf1->cf_name; cf1++) {
832:
833: if (!cfparent_match(d, cf1->cf_pspec))
834: continue;
835:
836: (*d->dv_cfattach->ca_rescan)(d,
1.201 dyoung 837: cfdata_ifattr(cf1), cf1->cf_loc);
1.209 jruoho 838:
839: config_deferred(d);
1.90 drochner 840: }
841: }
1.136 dyoung 842: deviter_release(&di);
1.90 drochner 843: }
844:
845: /*
846: * Attach a supplemental config data table and rescan potential
847: * parent devices if required.
848: */
849: int
1.102 thorpej 850: config_cfdata_attach(cfdata_t cf, int scannow)
1.90 drochner 851: {
852: struct cftable *ct;
853:
1.159 matt 854: ct = kmem_alloc(sizeof(*ct), KM_SLEEP);
1.90 drochner 855: ct->ct_cfdata = cf;
856: TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
857:
858: if (scannow)
859: rescan_with_cfdata(cf);
860:
1.175 cegger 861: return 0;
1.90 drochner 862: }
863:
864: /*
865: * Helper for config_cfdata_detach: check whether a device is
866: * found through any attachment in the config data table.
867: */
868: static int
1.224 chs 869: dev_in_cfdata(device_t d, cfdata_t cf)
1.90 drochner 870: {
871: const struct cfdata *cf1;
872:
873: for (cf1 = cf; cf1->cf_name; cf1++)
874: if (d->dv_cfdata == cf1)
1.175 cegger 875: return 1;
1.90 drochner 876:
1.175 cegger 877: return 0;
1.90 drochner 878: }
879:
880: /*
881: * Detach a supplemental config data table. Detach all devices found
882: * through that table (and thus keeping references to it) before.
883: */
884: int
1.102 thorpej 885: config_cfdata_detach(cfdata_t cf)
1.90 drochner 886: {
1.102 thorpej 887: device_t d;
1.136 dyoung 888: int error = 0;
1.90 drochner 889: struct cftable *ct;
1.136 dyoung 890: deviter_t di;
1.90 drochner 891:
1.136 dyoung 892: for (d = deviter_first(&di, DEVITER_F_RW); d != NULL;
893: d = deviter_next(&di)) {
894: if (!dev_in_cfdata(d, cf))
895: continue;
896: if ((error = config_detach(d, 0)) != 0)
897: break;
898: }
899: deviter_release(&di);
900: if (error) {
901: aprint_error_dev(d, "unable to detach instance\n");
902: return error;
1.90 drochner 903: }
904:
905: TAILQ_FOREACH(ct, &allcftables, ct_list) {
906: if (ct->ct_cfdata == cf) {
907: TAILQ_REMOVE(&allcftables, ct, ct_list);
1.159 matt 908: kmem_free(ct, sizeof(*ct));
1.175 cegger 909: return 0;
1.90 drochner 910: }
911: }
912:
913: /* not found -- shouldn't happen */
1.175 cegger 914: return EINVAL;
1.90 drochner 915: }
916:
917: /*
1.68 thorpej 918: * Invoke the "match" routine for a cfdata entry on behalf of
919: * an external caller, usually a "submatch" routine.
920: */
921: int
1.102 thorpej 922: config_match(device_t parent, cfdata_t cf, void *aux)
1.68 thorpej 923: {
1.76 thorpej 924: struct cfattach *ca;
925:
926: ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
927: if (ca == NULL) {
928: /* No attachment for this entry, oh well. */
1.175 cegger 929: return 0;
1.76 thorpej 930: }
1.68 thorpej 931:
1.175 cegger 932: return (*ca->ca_match)(parent, cf, aux);
1.66 thorpej 933: }
934:
935: /*
1.1 glass 936: * Iterate over all potential children of some device, calling the given
937: * function (default being the child's match function) for each one.
938: * Nonzero returns are matches; the highest value returned is considered
939: * the best match. Return the `found child' if we got a match, or NULL
940: * otherwise. The `aux' pointer is simply passed on through.
941: *
942: * Note that this function is designed so that it can be used to apply
943: * an arbitrary function to all potential children (its return value
944: * can be ignored).
945: */
1.102 thorpej 946: cfdata_t
947: config_search_loc(cfsubmatch_t fn, device_t parent,
1.99 drochner 948: const char *ifattr, const int *locs, void *aux)
1.90 drochner 949: {
950: struct cftable *ct;
1.102 thorpej 951: cfdata_t cf;
1.90 drochner 952: struct matchinfo m;
953:
954: KASSERT(config_initialized);
1.96 drochner 955: KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
1.90 drochner 956:
1.99 drochner 957: m.fn = fn;
1.1 glass 958: m.parent = parent;
1.99 drochner 959: m.locs = locs;
1.25 cgd 960: m.aux = aux;
1.14 mycroft 961: m.match = NULL;
1.1 glass 962: m.pri = 0;
1.65 thorpej 963:
964: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 965: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.90 drochner 966:
967: /* We don't match root nodes here. */
968: if (!cf->cf_pspec)
969: continue;
970:
1.65 thorpej 971: /*
972: * Skip cf if no longer eligible, otherwise scan
973: * through parents for one matching `parent', and
974: * try match function.
975: */
976: if (cf->cf_fstate == FSTATE_FOUND)
977: continue;
978: if (cf->cf_fstate == FSTATE_DNOTFOUND ||
979: cf->cf_fstate == FSTATE_DSTAR)
980: continue;
1.90 drochner 981:
982: /*
983: * If an interface attribute was specified,
984: * consider only children which attach to
985: * that attribute.
986: */
1.201 dyoung 987: if (ifattr && !STREQ(ifattr, cfdata_ifattr(cf)))
1.90 drochner 988: continue;
989:
1.66 thorpej 990: if (cfparent_match(parent, cf->cf_pspec))
991: mapply(&m, cf);
1.65 thorpej 992: }
1.1 glass 993: }
1.175 cegger 994: return m.match;
1.1 glass 995: }
996:
1.102 thorpej 997: cfdata_t
998: config_search_ia(cfsubmatch_t fn, device_t parent, const char *ifattr,
999: void *aux)
1000: {
1001:
1.175 cegger 1002: return config_search_loc(fn, parent, ifattr, NULL, aux);
1.102 thorpej 1003: }
1004:
1.16 mycroft 1005: /*
1.1 glass 1006: * Find the given root device.
1007: * This is much like config_search, but there is no parent.
1.65 thorpej 1008: * Don't bother with multiple cfdata tables; the root node
1009: * must always be in the initial table.
1.1 glass 1010: */
1.102 thorpej 1011: cfdata_t
1.95 drochner 1012: config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
1.1 glass 1013: {
1.102 thorpej 1014: cfdata_t cf;
1.84 matt 1015: const short *p;
1.1 glass 1016: struct matchinfo m;
1017:
1.99 drochner 1018: m.fn = fn;
1.1 glass 1019: m.parent = ROOT;
1.25 cgd 1020: m.aux = aux;
1.14 mycroft 1021: m.match = NULL;
1.1 glass 1022: m.pri = 0;
1.114 christos 1023: m.locs = 0;
1.1 glass 1024: /*
1025: * Look at root entries for matching name. We do not bother
1026: * with found-state here since only one root should ever be
1027: * searched (and it must be done first).
1028: */
1029: for (p = cfroots; *p >= 0; p++) {
1030: cf = &cfdata[*p];
1.67 thorpej 1031: if (strcmp(cf->cf_name, rootname) == 0)
1.16 mycroft 1032: mapply(&m, cf);
1.1 glass 1033: }
1.175 cegger 1034: return m.match;
1.1 glass 1035: }
1036:
1.83 jdolecek 1037: static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
1.1 glass 1038:
1039: /*
1040: * The given `aux' argument describes a device that has been found
1041: * on the given parent, but not necessarily configured. Locate the
1.18 cgd 1042: * configuration data for that device (using the submatch function
1043: * provided, or using candidates' cd_match configuration driver
1.218 dyoung 1044: * functions) and attach it, and return its device_t. If the device was
1045: * not configured, call the given `print' function and return NULL.
1.1 glass 1046: */
1.102 thorpej 1047: device_t
1048: config_found_sm_loc(device_t parent,
1.99 drochner 1049: const char *ifattr, const int *locs, void *aux,
1.95 drochner 1050: cfprint_t print, cfsubmatch_t submatch)
1.90 drochner 1051: {
1.102 thorpej 1052: cfdata_t cf;
1.90 drochner 1053:
1.99 drochner 1054: if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux)))
1055: return(config_attach_loc(parent, cf, locs, aux, print));
1.90 drochner 1056: if (print) {
1.176 ad 1057: if (config_do_twiddle && cold)
1.90 drochner 1058: twiddle();
1.143 cegger 1059: aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]);
1.90 drochner 1060: }
1.105 jmcneill 1061:
1.231 tls 1062: /*
1063: * This has the effect of mixing in a single timestamp to the
1064: * entropy pool. Experiments indicate the estimator will almost
1065: * always attribute one bit of entropy to this sample; analysis
1066: * of device attach/detach timestamps on FreeBSD indicates 4
1067: * bits of entropy/sample so this seems appropriately conservative.
1068: */
1069: rnd_add_uint32(&rnd_autoconf_source, 0);
1.175 cegger 1070: return NULL;
1.90 drochner 1071: }
1072:
1.102 thorpej 1073: device_t
1074: config_found_ia(device_t parent, const char *ifattr, void *aux,
1075: cfprint_t print)
1076: {
1077:
1.175 cegger 1078: return config_found_sm_loc(parent, ifattr, NULL, aux, print, NULL);
1.102 thorpej 1079: }
1080:
1081: device_t
1082: config_found(device_t parent, void *aux, cfprint_t print)
1083: {
1084:
1.175 cegger 1085: return config_found_sm_loc(parent, NULL, NULL, aux, print, NULL);
1.102 thorpej 1086: }
1087:
1.1 glass 1088: /*
1089: * As above, but for root devices.
1090: */
1.102 thorpej 1091: device_t
1.52 cgd 1092: config_rootfound(const char *rootname, void *aux)
1.1 glass 1093: {
1.102 thorpej 1094: cfdata_t cf;
1.25 cgd 1095:
1.220 plunky 1096: if ((cf = config_rootsearch(NULL, rootname, aux)) != NULL)
1097: return config_attach(ROOT, cf, aux, NULL);
1.80 thorpej 1098: aprint_error("root device %s not configured\n", rootname);
1.175 cegger 1099: return NULL;
1.1 glass 1100: }
1101:
1102: /* just like sprintf(buf, "%d") except that it works from the end */
1103: static char *
1.51 cgd 1104: number(char *ep, int n)
1.1 glass 1105: {
1106:
1107: *--ep = 0;
1108: while (n >= 10) {
1109: *--ep = (n % 10) + '0';
1110: n /= 10;
1111: }
1112: *--ep = n + '0';
1.175 cegger 1113: return ep;
1.1 glass 1114: }
1115:
1116: /*
1.59 augustss 1117: * Expand the size of the cd_devs array if necessary.
1.187 dyoung 1118: *
1119: * The caller must hold alldevs_mtx. config_makeroom() may release and
1120: * re-acquire alldevs_mtx, so callers should re-check conditions such
1121: * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom()
1122: * returns.
1.59 augustss 1123: */
1.117 drochner 1124: static void
1.59 augustss 1125: config_makeroom(int n, struct cfdriver *cd)
1126: {
1.232 matt 1127: int ondevs, nndevs;
1.190 dyoung 1128: device_t *osp, *nsp;
1.59 augustss 1129:
1.187 dyoung 1130: alldevs_nwrite++;
1131:
1.232 matt 1132: for (nndevs = MAX(4, cd->cd_ndevs); nndevs <= n; nndevs += nndevs)
1.190 dyoung 1133: ;
1134:
1135: while (n >= cd->cd_ndevs) {
1136: /*
1137: * Need to expand the array.
1138: */
1.232 matt 1139: ondevs = cd->cd_ndevs;
1.190 dyoung 1140: osp = cd->cd_devs;
1141:
1142: /* Release alldevs_mtx around allocation, which may
1143: * sleep.
1144: */
1145: mutex_exit(&alldevs_mtx);
1.232 matt 1146: nsp = kmem_alloc(sizeof(device_t[nndevs]), KM_SLEEP);
1.190 dyoung 1147: if (nsp == NULL)
1148: panic("%s: could not expand cd_devs", __func__);
1149: mutex_enter(&alldevs_mtx);
1150:
1151: /* If another thread moved the array while we did
1152: * not hold alldevs_mtx, try again.
1153: */
1154: if (cd->cd_devs != osp) {
1.206 dyoung 1155: mutex_exit(&alldevs_mtx);
1.232 matt 1156: kmem_free(nsp, sizeof(device_t[nndevs]));
1.206 dyoung 1157: mutex_enter(&alldevs_mtx);
1.190 dyoung 1158: continue;
1159: }
1.59 augustss 1160:
1.232 matt 1161: memset(nsp + ondevs, 0, sizeof(device_t[nndevs - ondevs]));
1162: if (ondevs != 0)
1163: memcpy(nsp, cd->cd_devs, sizeof(device_t[ondevs]));
1.190 dyoung 1164:
1.232 matt 1165: cd->cd_ndevs = nndevs;
1.190 dyoung 1166: cd->cd_devs = nsp;
1.232 matt 1167: if (ondevs != 0) {
1.206 dyoung 1168: mutex_exit(&alldevs_mtx);
1.232 matt 1169: kmem_free(osp, sizeof(device_t[ondevs]));
1.206 dyoung 1170: mutex_enter(&alldevs_mtx);
1171: }
1.59 augustss 1172: }
1.187 dyoung 1173: alldevs_nwrite--;
1.59 augustss 1174: }
1175:
1.190 dyoung 1176: /*
1177: * Put dev into the devices list.
1178: */
1.117 drochner 1179: static void
1180: config_devlink(device_t dev)
1181: {
1.187 dyoung 1182: int s;
1.117 drochner 1183:
1.187 dyoung 1184: s = config_alldevs_lock();
1.117 drochner 1185:
1.190 dyoung 1186: KASSERT(device_cfdriver(dev)->cd_devs[dev->dv_unit] == dev);
1187:
1188: dev->dv_add_gen = alldevs_gen;
1.136 dyoung 1189: /* It is safe to add a device to the tail of the list while
1.187 dyoung 1190: * readers and writers are in the list.
1.136 dyoung 1191: */
1.190 dyoung 1192: TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
1.187 dyoung 1193: config_alldevs_unlock(s);
1.117 drochner 1194: }
1195:
1.190 dyoung 1196: static void
1197: config_devfree(device_t dev)
1198: {
1199: int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
1200:
1201: if (dev->dv_cfattach->ca_devsize > 0)
1202: kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
1203: if (priv)
1204: kmem_free(dev, sizeof(*dev));
1205: }
1206:
1.187 dyoung 1207: /*
1.197 rmind 1208: * Caller must hold alldevs_mtx.
1.187 dyoung 1209: */
1.117 drochner 1210: static void
1.190 dyoung 1211: config_devunlink(device_t dev, struct devicelist *garbage)
1.117 drochner 1212: {
1.190 dyoung 1213: struct device_garbage *dg = &dev->dv_garbage;
1214: cfdriver_t cd = device_cfdriver(dev);
1215: int i;
1.187 dyoung 1216:
1217: KASSERT(mutex_owned(&alldevs_mtx));
1.117 drochner 1218:
1.190 dyoung 1219: /* Unlink from device list. Link to garbage list. */
1.117 drochner 1220: TAILQ_REMOVE(&alldevs, dev, dv_list);
1.190 dyoung 1221: TAILQ_INSERT_TAIL(garbage, dev, dv_list);
1.117 drochner 1222:
1223: /* Remove from cfdriver's array. */
1224: cd->cd_devs[dev->dv_unit] = NULL;
1225:
1226: /*
1.190 dyoung 1227: * If the device now has no units in use, unlink its softc array.
1.117 drochner 1228: */
1.159 matt 1229: for (i = 0; i < cd->cd_ndevs; i++) {
1.117 drochner 1230: if (cd->cd_devs[i] != NULL)
1.187 dyoung 1231: break;
1232: }
1.190 dyoung 1233: /* Nothing found. Unlink, now. Deallocate, later. */
1.187 dyoung 1234: if (i == cd->cd_ndevs) {
1.190 dyoung 1235: dg->dg_ndevs = cd->cd_ndevs;
1236: dg->dg_devs = cd->cd_devs;
1.187 dyoung 1237: cd->cd_devs = NULL;
1238: cd->cd_ndevs = 0;
1239: }
1.190 dyoung 1240: }
1.187 dyoung 1241:
1.190 dyoung 1242: static void
1243: config_devdelete(device_t dev)
1244: {
1245: struct device_garbage *dg = &dev->dv_garbage;
1246: device_lock_t dvl = device_getlock(dev);
1.187 dyoung 1247:
1.190 dyoung 1248: if (dg->dg_devs != NULL)
1249: kmem_free(dg->dg_devs, sizeof(device_t[dg->dg_ndevs]));
1.187 dyoung 1250:
1251: cv_destroy(&dvl->dvl_cv);
1252: mutex_destroy(&dvl->dvl_mtx);
1253:
1254: KASSERT(dev->dv_properties != NULL);
1255: prop_object_release(dev->dv_properties);
1256:
1.197 rmind 1257: if (dev->dv_activity_handlers)
1258: panic("%s with registered handlers", __func__);
1.187 dyoung 1259:
1260: if (dev->dv_locators) {
1261: size_t amount = *--dev->dv_locators;
1262: kmem_free(dev->dv_locators, amount);
1.117 drochner 1263: }
1.197 rmind 1264:
1.190 dyoung 1265: config_devfree(dev);
1266: }
1267:
1268: static int
1269: config_unit_nextfree(cfdriver_t cd, cfdata_t cf)
1270: {
1271: int unit;
1272:
1273: if (cf->cf_fstate == FSTATE_STAR) {
1274: for (unit = cf->cf_unit; unit < cd->cd_ndevs; unit++)
1275: if (cd->cd_devs[unit] == NULL)
1276: break;
1277: /*
1278: * unit is now the unit of the first NULL device pointer,
1279: * or max(cd->cd_ndevs,cf->cf_unit).
1280: */
1281: } else {
1282: unit = cf->cf_unit;
1283: if (unit < cd->cd_ndevs && cd->cd_devs[unit] != NULL)
1284: unit = -1;
1285: }
1286: return unit;
1287: }
1288:
1289: static int
1290: config_unit_alloc(device_t dev, cfdriver_t cd, cfdata_t cf)
1291: {
1.198 dyoung 1292: struct alldevs_foray af;
1293: int unit;
1.187 dyoung 1294:
1.198 dyoung 1295: config_alldevs_enter(&af);
1.190 dyoung 1296: for (;;) {
1297: unit = config_unit_nextfree(cd, cf);
1298: if (unit == -1)
1299: break;
1300: if (unit < cd->cd_ndevs) {
1301: cd->cd_devs[unit] = dev;
1302: dev->dv_unit = unit;
1303: break;
1304: }
1305: config_makeroom(unit, cd);
1306: }
1.198 dyoung 1307: config_alldevs_exit(&af);
1.187 dyoung 1308:
1.190 dyoung 1309: return unit;
1.117 drochner 1310: }
1.187 dyoung 1311:
1.117 drochner 1312: static device_t
1313: config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
1.25 cgd 1314: {
1.190 dyoung 1315: cfdriver_t cd;
1316: cfattach_t ca;
1.50 augustss 1317: size_t lname, lunit;
1.52 cgd 1318: const char *xunit;
1.189 pooka 1319: int myunit;
1.25 cgd 1320: char num[10];
1.117 drochner 1321: device_t dev;
1.120 joerg 1322: void *dev_private;
1.96 drochner 1323: const struct cfiattrdata *ia;
1.174 dyoung 1324: device_lock_t dvl;
1.25 cgd 1325:
1.67 thorpej 1326: cd = config_cfdriver_lookup(cf->cf_name);
1.117 drochner 1327: if (cd == NULL)
1.175 cegger 1328: return NULL;
1.76 thorpej 1329:
1330: ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
1.117 drochner 1331: if (ca == NULL)
1.175 cegger 1332: return NULL;
1.76 thorpej 1333:
1.120 joerg 1334: if ((ca->ca_flags & DVF_PRIV_ALLOC) == 0 &&
1335: ca->ca_devsize < sizeof(struct device))
1.219 martin 1336: panic("config_devalloc: %s (%zu < %zu)", cf->cf_atname,
1337: ca->ca_devsize, sizeof(struct device));
1.66 thorpej 1338:
1.25 cgd 1339: /* get memory for all device vars */
1.132 matt 1340: KASSERT((ca->ca_flags & DVF_PRIV_ALLOC) || ca->ca_devsize >= sizeof(struct device));
1341: if (ca->ca_devsize > 0) {
1.166 ad 1342: dev_private = kmem_zalloc(ca->ca_devsize, KM_SLEEP);
1.132 matt 1343: if (dev_private == NULL)
1344: panic("config_devalloc: memory allocation for device softc failed");
1345: } else {
1346: KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
1347: dev_private = NULL;
1348: }
1.120 joerg 1349:
1350: if ((ca->ca_flags & DVF_PRIV_ALLOC) != 0) {
1.166 ad 1351: dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
1.120 joerg 1352: } else {
1353: dev = dev_private;
1.216 christos 1354: #ifdef DIAGNOSTIC
1355: printf("%s has not been converted to device_t\n", cd->cd_name);
1356: #endif
1.120 joerg 1357: }
1358: if (dev == NULL)
1359: panic("config_devalloc: memory allocation for device_t failed");
1.124 jmcneill 1360:
1.202 dyoung 1361: dev->dv_class = cd->cd_class;
1362: dev->dv_cfdata = cf;
1363: dev->dv_cfdriver = cd;
1364: dev->dv_cfattach = ca;
1365: dev->dv_activity_count = 0;
1366: dev->dv_activity_handlers = NULL;
1367: dev->dv_private = dev_private;
1368: dev->dv_flags = ca->ca_flags; /* inherit flags from class */
1369:
1.190 dyoung 1370: myunit = config_unit_alloc(dev, cd, cf);
1371: if (myunit == -1) {
1372: config_devfree(dev);
1373: return NULL;
1374: }
1375:
1376: /* compute length of name and decimal expansion of unit number */
1377: lname = strlen(cd->cd_name);
1378: xunit = number(&num[sizeof(num)], myunit);
1379: lunit = &num[sizeof(num)] - xunit;
1380: if (lname + lunit > sizeof(dev->dv_xname))
1381: panic("config_devalloc: device name too long");
1382:
1.174 dyoung 1383: dvl = device_getlock(dev);
1384:
1385: mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE);
1386: cv_init(&dvl->dvl_cv, "pmfsusp");
1387:
1.31 perry 1388: memcpy(dev->dv_xname, cd->cd_name, lname);
1389: memcpy(dev->dv_xname + lname, xunit, lunit);
1.25 cgd 1390: dev->dv_parent = parent;
1.124 jmcneill 1391: if (parent != NULL)
1392: dev->dv_depth = parent->dv_depth + 1;
1393: else
1394: dev->dv_depth = 0;
1.202 dyoung 1395: dev->dv_flags |= DVF_ACTIVE; /* always initially active */
1.97 drochner 1396: if (locs) {
1.96 drochner 1397: KASSERT(parent); /* no locators at root */
1.201 dyoung 1398: ia = cfiattr_lookup(cfdata_ifattr(cf), parent->dv_cfdriver);
1.159 matt 1399: dev->dv_locators =
1.166 ad 1400: kmem_alloc(sizeof(int [ia->ci_loclen + 1]), KM_SLEEP);
1.159 matt 1401: *dev->dv_locators++ = sizeof(int [ia->ci_loclen + 1]);
1402: memcpy(dev->dv_locators, locs, sizeof(int [ia->ci_loclen]));
1.90 drochner 1403: }
1.112 thorpej 1404: dev->dv_properties = prop_dictionary_create();
1405: KASSERT(dev->dv_properties != NULL);
1.29 thorpej 1406:
1.150 jmcneill 1407: prop_dictionary_set_cstring_nocopy(dev->dv_properties,
1408: "device-driver", dev->dv_cfdriver->cd_name);
1409: prop_dictionary_set_uint16(dev->dv_properties,
1410: "device-unit", dev->dv_unit);
1411:
1.221 pgoyette 1412: if (dev->dv_cfdriver->cd_attrs != NULL)
1413: config_add_attrib_dict(dev);
1414:
1.175 cegger 1415: return dev;
1.117 drochner 1416: }
1417:
1418: /*
1.221 pgoyette 1419: * Create an array of device attach attributes and add it
1420: * to the device's dv_properties dictionary.
1421: *
1422: * <key>interface-attributes</key>
1423: * <array>
1424: * <dict>
1425: * <key>attribute-name</key>
1426: * <string>foo</string>
1427: * <key>locators</key>
1428: * <array>
1429: * <dict>
1430: * <key>loc-name</key>
1431: * <string>foo-loc1</string>
1432: * </dict>
1433: * <dict>
1434: * <key>loc-name</key>
1435: * <string>foo-loc2</string>
1436: * <key>default</key>
1437: * <string>foo-loc2-default</string>
1438: * </dict>
1439: * ...
1440: * </array>
1441: * </dict>
1442: * ...
1443: * </array>
1444: */
1445:
1446: static void
1447: config_add_attrib_dict(device_t dev)
1448: {
1449: int i, j;
1450: const struct cfiattrdata *ci;
1451: prop_dictionary_t attr_dict, loc_dict;
1452: prop_array_t attr_array, loc_array;
1453:
1454: if ((attr_array = prop_array_create()) == NULL)
1455: return;
1456:
1457: for (i = 0; ; i++) {
1458: if ((ci = dev->dv_cfdriver->cd_attrs[i]) == NULL)
1459: break;
1460: if ((attr_dict = prop_dictionary_create()) == NULL)
1461: break;
1462: prop_dictionary_set_cstring_nocopy(attr_dict, "attribute-name",
1463: ci->ci_name);
1464:
1465: /* Create an array of the locator names and defaults */
1466:
1467: if (ci->ci_loclen != 0 &&
1468: (loc_array = prop_array_create()) != NULL) {
1469: for (j = 0; j < ci->ci_loclen; j++) {
1470: loc_dict = prop_dictionary_create();
1471: if (loc_dict == NULL)
1472: continue;
1473: prop_dictionary_set_cstring_nocopy(loc_dict,
1474: "loc-name", ci->ci_locdesc[j].cld_name);
1475: if (ci->ci_locdesc[j].cld_defaultstr != NULL)
1476: prop_dictionary_set_cstring_nocopy(
1477: loc_dict, "default",
1478: ci->ci_locdesc[j].cld_defaultstr);
1479: prop_array_set(loc_array, j, loc_dict);
1480: prop_object_release(loc_dict);
1481: }
1482: prop_dictionary_set_and_rel(attr_dict, "locators",
1483: loc_array);
1484: }
1485: prop_array_add(attr_array, attr_dict);
1486: prop_object_release(attr_dict);
1487: }
1488: if (i == 0)
1489: prop_object_release(attr_array);
1490: else
1491: prop_dictionary_set_and_rel(dev->dv_properties,
1492: "interface-attributes", attr_array);
1493:
1494: return;
1495: }
1496:
1497: /*
1.117 drochner 1498: * Attach a found device.
1499: */
1500: device_t
1501: config_attach_loc(device_t parent, cfdata_t cf,
1502: const int *locs, void *aux, cfprint_t print)
1503: {
1504: device_t dev;
1505: struct cftable *ct;
1506: const char *drvname;
1507:
1508: dev = config_devalloc(parent, cf, locs);
1509: if (!dev)
1510: panic("config_attach: allocation of device softc failed");
1511:
1512: /* XXX redundant - see below? */
1513: if (cf->cf_fstate != FSTATE_STAR) {
1514: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1515: cf->cf_fstate = FSTATE_FOUND;
1516: }
1517:
1518: config_devlink(dev);
1519:
1.176 ad 1520: if (config_do_twiddle && cold)
1.80 thorpej 1521: twiddle();
1522: else
1523: aprint_naive("Found ");
1524: /*
1525: * We want the next two printfs for normal, verbose, and quiet,
1526: * but not silent (in which case, we're twiddling, instead).
1527: */
1528: if (parent == ROOT) {
1.143 cegger 1529: aprint_naive("%s (root)", device_xname(dev));
1530: aprint_normal("%s (root)", device_xname(dev));
1.80 thorpej 1531: } else {
1.143 cegger 1532: aprint_naive("%s at %s", device_xname(dev), device_xname(parent));
1533: aprint_normal("%s at %s", device_xname(dev), device_xname(parent));
1.25 cgd 1534: if (print)
1.52 cgd 1535: (void) (*print)(aux, NULL);
1.25 cgd 1536: }
1537:
1538: /*
1539: * Before attaching, clobber any unfound devices that are
1.45 cgd 1540: * otherwise identical.
1.117 drochner 1541: * XXX code above is redundant?
1.25 cgd 1542: */
1.117 drochner 1543: drvname = dev->dv_cfdriver->cd_name;
1.65 thorpej 1544: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1545: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.117 drochner 1546: if (STREQ(cf->cf_name, drvname) &&
1.65 thorpej 1547: cf->cf_unit == dev->dv_unit) {
1548: if (cf->cf_fstate == FSTATE_NOTFOUND)
1549: cf->cf_fstate = FSTATE_FOUND;
1550: }
1.25 cgd 1551: }
1.65 thorpej 1552: }
1.25 cgd 1553: device_register(dev, aux);
1.124 jmcneill 1554:
1.149 jmcneill 1555: /* Let userland know */
1556: devmon_report_device(dev, true);
1557:
1.117 drochner 1558: (*dev->dv_cfattach->ca_attach)(parent, dev, aux);
1.124 jmcneill 1559:
1560: if (!device_pmf_is_registered(dev))
1.125 jmcneill 1561: aprint_debug_dev(dev, "WARNING: power management not supported\n");
1.124 jmcneill 1562:
1.42 thorpej 1563: config_process_deferred(&deferred_config_queue, dev);
1.196 martin 1564:
1565: device_register_post_config(dev, aux);
1.175 cegger 1566: return dev;
1.25 cgd 1567: }
1.29 thorpej 1568:
1.102 thorpej 1569: device_t
1570: config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print)
1571: {
1572:
1.175 cegger 1573: return config_attach_loc(parent, cf, NULL, aux, print);
1.102 thorpej 1574: }
1575:
1.29 thorpej 1576: /*
1.77 thorpej 1577: * As above, but for pseudo-devices. Pseudo-devices attached in this
1578: * way are silently inserted into the device tree, and their children
1579: * attached.
1580: *
1581: * Note that because pseudo-devices are attached silently, any information
1582: * the attach routine wishes to print should be prefixed with the device
1583: * name by the attach routine.
1584: */
1.102 thorpej 1585: device_t
1586: config_attach_pseudo(cfdata_t cf)
1.77 thorpej 1587: {
1.102 thorpej 1588: device_t dev;
1.77 thorpej 1589:
1.117 drochner 1590: dev = config_devalloc(ROOT, cf, NULL);
1591: if (!dev)
1.175 cegger 1592: return NULL;
1.77 thorpej 1593:
1.117 drochner 1594: /* XXX mark busy in cfdata */
1.77 thorpej 1595:
1.170 dyoung 1596: if (cf->cf_fstate != FSTATE_STAR) {
1597: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1598: cf->cf_fstate = FSTATE_FOUND;
1599: }
1600:
1.117 drochner 1601: config_devlink(dev);
1.77 thorpej 1602:
1603: #if 0 /* XXXJRT not yet */
1604: device_register(dev, NULL); /* like a root node */
1605: #endif
1.225 mlelstv 1606:
1607: /* Let userland know */
1608: devmon_report_device(dev, true);
1609:
1.117 drochner 1610: (*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
1.225 mlelstv 1611:
1.77 thorpej 1612: config_process_deferred(&deferred_config_queue, dev);
1.175 cegger 1613: return dev;
1.77 thorpej 1614: }
1615:
1616: /*
1.197 rmind 1617: * Caller must hold alldevs_mtx.
1618: */
1619: static void
1620: config_collect_garbage(struct devicelist *garbage)
1621: {
1622: device_t dv;
1623:
1624: KASSERT(!cpu_intr_p());
1625: KASSERT(!cpu_softintr_p());
1626: KASSERT(mutex_owned(&alldevs_mtx));
1627:
1628: while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) {
1629: TAILQ_FOREACH(dv, &alldevs, dv_list) {
1630: if (dv->dv_del_gen != 0)
1631: break;
1632: }
1633: if (dv == NULL) {
1634: alldevs_garbage = false;
1635: break;
1636: }
1637: config_devunlink(dv, garbage);
1638: }
1639: KASSERT(mutex_owned(&alldevs_mtx));
1640: }
1641:
1642: static void
1643: config_dump_garbage(struct devicelist *garbage)
1644: {
1645: device_t dv;
1646:
1647: while ((dv = TAILQ_FIRST(garbage)) != NULL) {
1648: TAILQ_REMOVE(garbage, dv, dv_list);
1649: config_devdelete(dv);
1650: }
1651: }
1652:
1653: /*
1.33 thorpej 1654: * Detach a device. Optionally forced (e.g. because of hardware
1655: * removal) and quiet. Returns zero if successful, non-zero
1656: * (an error code) otherwise.
1657: *
1658: * Note that this code wants to be run from a process context, so
1659: * that the detach can sleep to allow processes which have a device
1660: * open to run and unwind their stacks.
1661: */
1662: int
1.102 thorpej 1663: config_detach(device_t dev, int flags)
1.33 thorpej 1664: {
1.198 dyoung 1665: struct alldevs_foray af;
1.65 thorpej 1666: struct cftable *ct;
1.102 thorpej 1667: cfdata_t cf;
1.73 thorpej 1668: const struct cfattach *ca;
1.33 thorpej 1669: struct cfdriver *cd;
1670: #ifdef DIAGNOSTIC
1.102 thorpej 1671: device_t d;
1.33 thorpej 1672: #endif
1.187 dyoung 1673: int rv = 0, s;
1.33 thorpej 1674:
1675: #ifdef DIAGNOSTIC
1.161 christos 1676: cf = dev->dv_cfdata;
1677: if (cf != NULL && cf->cf_fstate != FSTATE_FOUND &&
1678: cf->cf_fstate != FSTATE_STAR)
1679: panic("config_detach: %s: bad device fstate %d",
1680: device_xname(dev), cf ? cf->cf_fstate : -1);
1.33 thorpej 1681: #endif
1.77 thorpej 1682: cd = dev->dv_cfdriver;
1.67 thorpej 1683: KASSERT(cd != NULL);
1.76 thorpej 1684:
1.77 thorpej 1685: ca = dev->dv_cfattach;
1.76 thorpej 1686: KASSERT(ca != NULL);
1.33 thorpej 1687:
1.187 dyoung 1688: s = config_alldevs_lock();
1689: if (dev->dv_del_gen != 0) {
1690: config_alldevs_unlock(s);
1691: #ifdef DIAGNOSTIC
1692: printf("%s: %s is already detached\n", __func__,
1693: device_xname(dev));
1694: #endif /* DIAGNOSTIC */
1695: return ENOENT;
1696: }
1697: alldevs_nwrite++;
1698: config_alldevs_unlock(s);
1.136 dyoung 1699:
1.174 dyoung 1700: if (!detachall &&
1701: (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
1702: (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
1.183 dyoung 1703: rv = EOPNOTSUPP;
1.187 dyoung 1704: } else if (ca->ca_detach != NULL) {
1705: rv = (*ca->ca_detach)(dev, flags);
1706: } else
1707: rv = EOPNOTSUPP;
1.33 thorpej 1708:
1709: /*
1.187 dyoung 1710: * If it was not possible to detach the device, then we either
1711: * panic() (for the forced but failed case), or return an error.
1712: *
1713: * If it was possible to detach the device, ensure that the
1714: * device is deactivated.
1.33 thorpej 1715: */
1.187 dyoung 1716: if (rv == 0)
1717: dev->dv_flags &= ~DVF_ACTIVE;
1718: else if ((flags & DETACH_FORCE) == 0)
1719: goto out;
1720: else {
1721: panic("config_detach: forced detach of %s failed (%d)",
1722: device_xname(dev), rv);
1.33 thorpej 1723: }
1724:
1725: /*
1726: * The device has now been successfully detached.
1727: */
1728:
1.149 jmcneill 1729: /* Let userland know */
1730: devmon_report_device(dev, false);
1731:
1.33 thorpej 1732: #ifdef DIAGNOSTIC
1733: /*
1734: * Sanity: If you're successfully detached, you should have no
1735: * children. (Note that because children must be attached
1736: * after parents, we only need to search the latter part of
1737: * the list.)
1738: */
1739: for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1.48 enami 1740: d = TAILQ_NEXT(d, dv_list)) {
1.187 dyoung 1741: if (d->dv_parent == dev && d->dv_del_gen == 0) {
1.48 enami 1742: printf("config_detach: detached device %s"
1.143 cegger 1743: " has children %s\n", device_xname(dev), device_xname(d));
1.48 enami 1744: panic("config_detach");
1745: }
1.33 thorpej 1746: }
1747: #endif
1748:
1.90 drochner 1749: /* notify the parent that the child is gone */
1750: if (dev->dv_parent) {
1.102 thorpej 1751: device_t p = dev->dv_parent;
1.90 drochner 1752: if (p->dv_cfattach->ca_childdetached)
1753: (*p->dv_cfattach->ca_childdetached)(p, dev);
1754: }
1755:
1.33 thorpej 1756: /*
1757: * Mark cfdata to show that the unit can be reused, if possible.
1758: */
1.65 thorpej 1759: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1760: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1761: if (STREQ(cf->cf_name, cd->cd_name)) {
1.65 thorpej 1762: if (cf->cf_fstate == FSTATE_FOUND &&
1763: cf->cf_unit == dev->dv_unit)
1764: cf->cf_fstate = FSTATE_NOTFOUND;
1765: }
1.33 thorpej 1766: }
1767: }
1768:
1.77 thorpej 1769: if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1.136 dyoung 1770: aprint_normal_dev(dev, "detached\n");
1.33 thorpej 1771:
1.136 dyoung 1772: out:
1.198 dyoung 1773: config_alldevs_enter(&af);
1.178 dyoung 1774: KASSERT(alldevs_nwrite != 0);
1.187 dyoung 1775: --alldevs_nwrite;
1.211 dyoung 1776: if (rv == 0 && dev->dv_del_gen == 0) {
1777: if (alldevs_nwrite == 0 && alldevs_nread == 0)
1778: config_devunlink(dev, &af.af_garbage);
1779: else {
1780: dev->dv_del_gen = alldevs_gen;
1781: alldevs_garbage = true;
1782: }
1783: }
1.198 dyoung 1784: config_alldevs_exit(&af);
1.187 dyoung 1785:
1.136 dyoung 1786: return rv;
1.33 thorpej 1787: }
1788:
1.126 dyoung 1789: int
1790: config_detach_children(device_t parent, int flags)
1791: {
1.130 drochner 1792: device_t dv;
1.136 dyoung 1793: deviter_t di;
1794: int error = 0;
1.126 dyoung 1795:
1.136 dyoung 1796: for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL;
1797: dv = deviter_next(&di)) {
1798: if (device_parent(dv) != parent)
1799: continue;
1800: if ((error = config_detach(dv, flags)) != 0)
1.130 drochner 1801: break;
1.136 dyoung 1802: }
1803: deviter_release(&di);
1.130 drochner 1804: return error;
1.126 dyoung 1805: }
1806:
1.178 dyoung 1807: device_t
1808: shutdown_first(struct shutdown_state *s)
1809: {
1810: if (!s->initialized) {
1811: deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
1812: s->initialized = true;
1813: }
1814: return shutdown_next(s);
1815: }
1816:
1817: device_t
1818: shutdown_next(struct shutdown_state *s)
1819: {
1820: device_t dv;
1821:
1822: while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
1823: ;
1824:
1825: if (dv == NULL)
1826: s->initialized = false;
1827:
1828: return dv;
1829: }
1830:
1831: bool
1832: config_detach_all(int how)
1833: {
1834: static struct shutdown_state s;
1835: device_t curdev;
1836: bool progress = false;
1837:
1838: if ((how & RB_NOSYNC) != 0)
1839: return false;
1840:
1841: for (curdev = shutdown_first(&s); curdev != NULL;
1842: curdev = shutdown_next(&s)) {
1843: aprint_debug(" detaching %s, ", device_xname(curdev));
1844: if (config_detach(curdev, DETACH_SHUTDOWN) == 0) {
1845: progress = true;
1846: aprint_debug("success.");
1847: } else
1848: aprint_debug("failed.");
1849: }
1850: return progress;
1851: }
1852:
1.187 dyoung 1853: static bool
1854: device_is_ancestor_of(device_t ancestor, device_t descendant)
1855: {
1856: device_t dv;
1857:
1858: for (dv = descendant; dv != NULL; dv = device_parent(dv)) {
1859: if (device_parent(dv) == ancestor)
1860: return true;
1861: }
1862: return false;
1863: }
1864:
1.33 thorpej 1865: int
1.102 thorpej 1866: config_deactivate(device_t dev)
1.33 thorpej 1867: {
1.187 dyoung 1868: deviter_t di;
1869: const struct cfattach *ca;
1870: device_t descendant;
1871: int s, rv = 0, oflags;
1.33 thorpej 1872:
1.187 dyoung 1873: for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST);
1874: descendant != NULL;
1875: descendant = deviter_next(&di)) {
1876: if (dev != descendant &&
1877: !device_is_ancestor_of(dev, descendant))
1878: continue;
1879:
1880: if ((descendant->dv_flags & DVF_ACTIVE) == 0)
1881: continue;
1.33 thorpej 1882:
1.187 dyoung 1883: ca = descendant->dv_cfattach;
1884: oflags = descendant->dv_flags;
1885:
1886: descendant->dv_flags &= ~DVF_ACTIVE;
1887: if (ca->ca_activate == NULL)
1888: continue;
1889: s = splhigh();
1890: rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE);
1891: splx(s);
1892: if (rv != 0)
1893: descendant->dv_flags = oflags;
1.33 thorpej 1894: }
1.187 dyoung 1895: deviter_release(&di);
1.175 cegger 1896: return rv;
1.33 thorpej 1897: }
1898:
1899: /*
1.29 thorpej 1900: * Defer the configuration of the specified device until all
1901: * of its parent's devices have been attached.
1902: */
1903: void
1.102 thorpej 1904: config_defer(device_t dev, void (*func)(device_t))
1.29 thorpej 1905: {
1906: struct deferred_config *dc;
1907:
1908: if (dev->dv_parent == NULL)
1909: panic("config_defer: can't defer config of a root device");
1910:
1911: #ifdef DIAGNOSTIC
1.188 dyoung 1912: TAILQ_FOREACH(dc, &deferred_config_queue, dc_queue) {
1.29 thorpej 1913: if (dc->dc_dev == dev)
1914: panic("config_defer: deferred twice");
1915: }
1916: #endif
1917:
1.166 ad 1918: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
1.43 thorpej 1919: if (dc == NULL)
1920: panic("config_defer: unable to allocate callback");
1.29 thorpej 1921:
1922: dc->dc_dev = dev;
1923: dc->dc_func = func;
1924: TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1.228 christos 1925: config_pending_incr(dev);
1.29 thorpej 1926: }
1927:
1928: /*
1.42 thorpej 1929: * Defer some autoconfiguration for a device until after interrupts
1930: * are enabled.
1931: */
1932: void
1.102 thorpej 1933: config_interrupts(device_t dev, void (*func)(device_t))
1.42 thorpej 1934: {
1935: struct deferred_config *dc;
1936:
1937: /*
1938: * If interrupts are enabled, callback now.
1939: */
1.43 thorpej 1940: if (cold == 0) {
1.42 thorpej 1941: (*func)(dev);
1942: return;
1943: }
1944:
1945: #ifdef DIAGNOSTIC
1.188 dyoung 1946: TAILQ_FOREACH(dc, &interrupt_config_queue, dc_queue) {
1.42 thorpej 1947: if (dc->dc_dev == dev)
1948: panic("config_interrupts: deferred twice");
1949: }
1950: #endif
1951:
1.166 ad 1952: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
1.43 thorpej 1953: if (dc == NULL)
1954: panic("config_interrupts: unable to allocate callback");
1.42 thorpej 1955:
1956: dc->dc_dev = dev;
1957: dc->dc_func = func;
1958: TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1.228 christos 1959: config_pending_incr(dev);
1.42 thorpej 1960: }
1961:
1962: /*
1.207 tsutsui 1963: * Defer some autoconfiguration for a device until after root file system
1964: * is mounted (to load firmware etc).
1965: */
1966: void
1967: config_mountroot(device_t dev, void (*func)(device_t))
1968: {
1969: struct deferred_config *dc;
1970:
1971: /*
1972: * If root file system is mounted, callback now.
1973: */
1.208 tsutsui 1974: if (root_is_mounted) {
1.207 tsutsui 1975: (*func)(dev);
1976: return;
1977: }
1978:
1979: #ifdef DIAGNOSTIC
1980: TAILQ_FOREACH(dc, &mountroot_config_queue, dc_queue) {
1981: if (dc->dc_dev == dev)
1982: panic("%s: deferred twice", __func__);
1983: }
1984: #endif
1985:
1986: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
1987: if (dc == NULL)
1988: panic("%s: unable to allocate callback", __func__);
1989:
1990: dc->dc_dev = dev;
1991: dc->dc_func = func;
1992: TAILQ_INSERT_TAIL(&mountroot_config_queue, dc, dc_queue);
1993: }
1994:
1995: /*
1.42 thorpej 1996: * Process a deferred configuration queue.
1.29 thorpej 1997: */
1998: static void
1.51 cgd 1999: config_process_deferred(struct deferred_config_head *queue,
1.102 thorpej 2000: device_t parent)
1.29 thorpej 2001: {
2002: struct deferred_config *dc, *ndc;
2003:
1.42 thorpej 2004: for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
1.29 thorpej 2005: ndc = TAILQ_NEXT(dc, dc_queue);
1.42 thorpej 2006: if (parent == NULL || dc->dc_dev->dv_parent == parent) {
2007: TAILQ_REMOVE(queue, dc, dc_queue);
1.29 thorpej 2008: (*dc->dc_func)(dc->dc_dev);
1.228 christos 2009: config_pending_decr(dc->dc_dev);
1.159 matt 2010: kmem_free(dc, sizeof(*dc));
1.29 thorpej 2011: }
2012: }
1.47 thorpej 2013: }
2014:
2015: /*
2016: * Manipulate the config_pending semaphore.
2017: */
2018: void
1.228 christos 2019: config_pending_incr(device_t dev)
1.47 thorpej 2020: {
2021:
1.151 ad 2022: mutex_enter(&config_misc_lock);
1.47 thorpej 2023: config_pending++;
1.228 christos 2024: #ifdef DEBUG_AUTOCONF
2025: printf("%s: %s %d\n", __func__, device_xname(dev), config_pending);
2026: #endif
1.151 ad 2027: mutex_exit(&config_misc_lock);
1.47 thorpej 2028: }
2029:
2030: void
1.228 christos 2031: config_pending_decr(device_t dev)
1.47 thorpej 2032: {
2033:
2034: #ifdef DIAGNOSTIC
2035: if (config_pending == 0)
2036: panic("config_pending_decr: config_pending == 0");
2037: #endif
1.151 ad 2038: mutex_enter(&config_misc_lock);
1.47 thorpej 2039: config_pending--;
1.228 christos 2040: #ifdef DEBUG_AUTOCONF
2041: printf("%s: %s %d\n", __func__, device_xname(dev), config_pending);
2042: #endif
1.47 thorpej 2043: if (config_pending == 0)
1.151 ad 2044: cv_broadcast(&config_misc_cv);
2045: mutex_exit(&config_misc_lock);
1.75 thorpej 2046: }
2047:
2048: /*
2049: * Register a "finalization" routine. Finalization routines are
2050: * called iteratively once all real devices have been found during
2051: * autoconfiguration, for as long as any one finalizer has done
2052: * any work.
2053: */
2054: int
1.102 thorpej 2055: config_finalize_register(device_t dev, int (*fn)(device_t))
1.75 thorpej 2056: {
2057: struct finalize_hook *f;
2058:
2059: /*
2060: * If finalization has already been done, invoke the
2061: * callback function now.
2062: */
2063: if (config_finalize_done) {
2064: while ((*fn)(dev) != 0)
2065: /* loop */ ;
2066: }
2067:
2068: /* Ensure this isn't already on the list. */
2069: TAILQ_FOREACH(f, &config_finalize_list, f_list) {
2070: if (f->f_func == fn && f->f_dev == dev)
1.175 cegger 2071: return EEXIST;
1.75 thorpej 2072: }
2073:
1.159 matt 2074: f = kmem_alloc(sizeof(*f), KM_SLEEP);
1.75 thorpej 2075: f->f_func = fn;
2076: f->f_dev = dev;
2077: TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
2078:
1.175 cegger 2079: return 0;
1.75 thorpej 2080: }
2081:
2082: void
2083: config_finalize(void)
2084: {
2085: struct finalize_hook *f;
1.142 ad 2086: struct pdevinit *pdev;
2087: extern struct pdevinit pdevinit[];
2088: int errcnt, rv;
2089:
2090: /*
2091: * Now that device driver threads have been created, wait for
2092: * them to finish any deferred autoconfiguration.
2093: */
1.151 ad 2094: mutex_enter(&config_misc_lock);
2095: while (config_pending != 0)
2096: cv_wait(&config_misc_cv, &config_misc_lock);
2097: mutex_exit(&config_misc_lock);
1.142 ad 2098:
1.167 ad 2099: KERNEL_LOCK(1, NULL);
2100:
1.142 ad 2101: /* Attach pseudo-devices. */
2102: for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
2103: (*pdev->pdev_attach)(pdev->pdev_count);
1.75 thorpej 2104:
2105: /* Run the hooks until none of them does any work. */
2106: do {
2107: rv = 0;
2108: TAILQ_FOREACH(f, &config_finalize_list, f_list)
2109: rv |= (*f->f_func)(f->f_dev);
2110: } while (rv != 0);
2111:
2112: config_finalize_done = 1;
2113:
2114: /* Now free all the hooks. */
2115: while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
2116: TAILQ_REMOVE(&config_finalize_list, f, f_list);
1.159 matt 2117: kmem_free(f, sizeof(*f));
1.79 thorpej 2118: }
1.142 ad 2119:
1.167 ad 2120: KERNEL_UNLOCK_ONE(NULL);
2121:
1.142 ad 2122: errcnt = aprint_get_error_count();
2123: if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
2124: (boothowto & AB_VERBOSE) == 0) {
1.176 ad 2125: mutex_enter(&config_misc_lock);
1.142 ad 2126: if (config_do_twiddle) {
2127: config_do_twiddle = 0;
1.169 ad 2128: printf_nolog(" done.\n");
1.142 ad 2129: }
1.176 ad 2130: mutex_exit(&config_misc_lock);
1.142 ad 2131: if (errcnt != 0) {
2132: printf("WARNING: %d error%s while detecting hardware; "
2133: "check system log.\n", errcnt,
2134: errcnt == 1 ? "" : "s");
2135: }
2136: }
1.79 thorpej 2137: }
2138:
1.176 ad 2139: void
1.222 matt 2140: config_twiddle_init(void)
1.180 pooka 2141: {
2142:
2143: if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
2144: config_do_twiddle = 1;
2145: }
2146: callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL);
2147: }
2148:
2149: void
1.176 ad 2150: config_twiddle_fn(void *cookie)
2151: {
2152:
2153: mutex_enter(&config_misc_lock);
2154: if (config_do_twiddle) {
2155: twiddle();
2156: callout_schedule(&config_twiddle_ch, mstohz(100));
2157: }
2158: mutex_exit(&config_misc_lock);
2159: }
2160:
1.187 dyoung 2161: static int
2162: config_alldevs_lock(void)
2163: {
2164: mutex_enter(&alldevs_mtx);
1.206 dyoung 2165: return 0;
1.187 dyoung 2166: }
2167:
2168: static void
1.198 dyoung 2169: config_alldevs_enter(struct alldevs_foray *af)
2170: {
2171: TAILQ_INIT(&af->af_garbage);
2172: af->af_s = config_alldevs_lock();
2173: config_collect_garbage(&af->af_garbage);
2174: }
2175:
2176: static void
2177: config_alldevs_exit(struct alldevs_foray *af)
2178: {
2179: config_alldevs_unlock(af->af_s);
2180: config_dump_garbage(&af->af_garbage);
2181: }
2182:
1.206 dyoung 2183: /*ARGSUSED*/
1.198 dyoung 2184: static void
1.187 dyoung 2185: config_alldevs_unlock(int s)
2186: {
2187: mutex_exit(&alldevs_mtx);
2188: }
2189:
1.104 thorpej 2190: /*
1.107 thorpej 2191: * device_lookup:
2192: *
2193: * Look up a device instance for a given driver.
2194: */
1.156 drochner 2195: device_t
1.107 thorpej 2196: device_lookup(cfdriver_t cd, int unit)
2197: {
1.187 dyoung 2198: device_t dv;
2199: int s;
1.107 thorpej 2200:
1.187 dyoung 2201: s = config_alldevs_lock();
2202: KASSERT(mutex_owned(&alldevs_mtx));
1.107 thorpej 2203: if (unit < 0 || unit >= cd->cd_ndevs)
1.187 dyoung 2204: dv = NULL;
1.191 dyoung 2205: else if ((dv = cd->cd_devs[unit]) != NULL && dv->dv_del_gen != 0)
2206: dv = NULL;
1.187 dyoung 2207: config_alldevs_unlock(s);
2208:
2209: return dv;
1.107 thorpej 2210: }
2211:
2212: /*
1.191 dyoung 2213: * device_lookup_private:
1.140 matt 2214: *
1.191 dyoung 2215: * Look up a softc instance for a given driver.
1.140 matt 2216: */
2217: void *
2218: device_lookup_private(cfdriver_t cd, int unit)
2219: {
2220:
1.198 dyoung 2221: return device_private(device_lookup(cd, unit));
1.140 matt 2222: }
2223:
2224: /*
1.131 joerg 2225: * device_find_by_xname:
2226: *
2227: * Returns the device of the given name or NULL if it doesn't exist.
2228: */
2229: device_t
2230: device_find_by_xname(const char *name)
2231: {
2232: device_t dv;
1.136 dyoung 2233: deviter_t di;
1.131 joerg 2234:
1.136 dyoung 2235: for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) {
1.131 joerg 2236: if (strcmp(device_xname(dv), name) == 0)
2237: break;
2238: }
1.136 dyoung 2239: deviter_release(&di);
1.131 joerg 2240:
2241: return dv;
2242: }
2243:
2244: /*
2245: * device_find_by_driver_unit:
2246: *
2247: * Returns the device of the given driver name and unit or
2248: * NULL if it doesn't exist.
2249: */
2250: device_t
2251: device_find_by_driver_unit(const char *name, int unit)
2252: {
2253: struct cfdriver *cd;
2254:
2255: if ((cd = config_cfdriver_lookup(name)) == NULL)
2256: return NULL;
2257: return device_lookup(cd, unit);
2258: }
2259:
2260: /*
1.124 jmcneill 2261: * Power management related functions.
2262: */
2263:
2264: bool
2265: device_pmf_is_registered(device_t dev)
2266: {
2267: return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
2268: }
2269:
2270: bool
1.203 dyoung 2271: device_pmf_driver_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2272: {
2273: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
2274: return true;
2275: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
2276: return false;
1.195 dyoung 2277: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
1.183 dyoung 2278: dev->dv_driver_suspend != NULL &&
1.195 dyoung 2279: !(*dev->dv_driver_suspend)(dev, qual))
1.124 jmcneill 2280: return false;
2281:
2282: dev->dv_flags |= DVF_DRIVER_SUSPENDED;
2283: return true;
2284: }
2285:
2286: bool
1.203 dyoung 2287: device_pmf_driver_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2288: {
2289: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
2290: return true;
2291: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
2292: return false;
1.195 dyoung 2293: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_DRIVER &&
1.183 dyoung 2294: dev->dv_driver_resume != NULL &&
1.195 dyoung 2295: !(*dev->dv_driver_resume)(dev, qual))
1.124 jmcneill 2296: return false;
2297:
2298: dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
2299: return true;
2300: }
2301:
1.133 drochner 2302: bool
2303: device_pmf_driver_shutdown(device_t dev, int how)
2304: {
2305:
2306: if (*dev->dv_driver_shutdown != NULL &&
2307: !(*dev->dv_driver_shutdown)(dev, how))
2308: return false;
2309: return true;
2310: }
2311:
1.135 dyoung 2312: bool
1.124 jmcneill 2313: device_pmf_driver_register(device_t dev,
1.203 dyoung 2314: bool (*suspend)(device_t, const pmf_qual_t *),
2315: bool (*resume)(device_t, const pmf_qual_t *),
1.133 drochner 2316: bool (*shutdown)(device_t, int))
1.124 jmcneill 2317: {
2318: dev->dv_driver_suspend = suspend;
2319: dev->dv_driver_resume = resume;
1.133 drochner 2320: dev->dv_driver_shutdown = shutdown;
1.124 jmcneill 2321: dev->dv_flags |= DVF_POWER_HANDLERS;
1.135 dyoung 2322: return true;
1.124 jmcneill 2323: }
2324:
1.139 dyoung 2325: static const char *
2326: curlwp_name(void)
2327: {
2328: if (curlwp->l_name != NULL)
2329: return curlwp->l_name;
2330: else
2331: return curlwp->l_proc->p_comm;
2332: }
2333:
1.124 jmcneill 2334: void
2335: device_pmf_driver_deregister(device_t dev)
2336: {
1.174 dyoung 2337: device_lock_t dvl = device_getlock(dev);
1.157 drochner 2338:
1.124 jmcneill 2339: dev->dv_driver_suspend = NULL;
2340: dev->dv_driver_resume = NULL;
1.139 dyoung 2341:
1.174 dyoung 2342: mutex_enter(&dvl->dvl_mtx);
1.124 jmcneill 2343: dev->dv_flags &= ~DVF_POWER_HANDLERS;
1.174 dyoung 2344: while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) {
1.139 dyoung 2345: /* Wake a thread that waits for the lock. That
2346: * thread will fail to acquire the lock, and then
2347: * it will wake the next thread that waits for the
2348: * lock, or else it will wake us.
2349: */
1.174 dyoung 2350: cv_signal(&dvl->dvl_cv);
1.139 dyoung 2351: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2352: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.139 dyoung 2353: pmflock_debug(dev, __func__, __LINE__);
2354: }
1.174 dyoung 2355: mutex_exit(&dvl->dvl_mtx);
1.124 jmcneill 2356: }
2357:
2358: bool
2359: device_pmf_driver_child_register(device_t dev)
2360: {
2361: device_t parent = device_parent(dev);
2362:
2363: if (parent == NULL || parent->dv_driver_child_register == NULL)
2364: return true;
2365: return (*parent->dv_driver_child_register)(dev);
2366: }
2367:
2368: void
2369: device_pmf_driver_set_child_register(device_t dev,
2370: bool (*child_register)(device_t))
2371: {
2372: dev->dv_driver_child_register = child_register;
2373: }
2374:
1.139 dyoung 2375: static void
2376: pmflock_debug(device_t dev, const char *func, int line)
2377: {
1.174 dyoung 2378: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2379:
1.174 dyoung 2380: aprint_debug_dev(dev, "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n",
2381: func, line, curlwp_name(), dvl->dvl_nlock, dvl->dvl_nwait,
1.139 dyoung 2382: dev->dv_flags);
2383: }
2384:
2385: static bool
1.183 dyoung 2386: device_pmf_lock1(device_t dev)
1.139 dyoung 2387: {
1.174 dyoung 2388: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2389:
1.155 dyoung 2390: while (device_pmf_is_registered(dev) &&
1.174 dyoung 2391: dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) {
2392: dvl->dvl_nwait++;
1.183 dyoung 2393: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2394: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.183 dyoung 2395: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2396: dvl->dvl_nwait--;
1.139 dyoung 2397: }
2398: if (!device_pmf_is_registered(dev)) {
1.183 dyoung 2399: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 2400: /* We could not acquire the lock, but some other thread may
2401: * wait for it, also. Wake that thread.
2402: */
1.174 dyoung 2403: cv_signal(&dvl->dvl_cv);
1.139 dyoung 2404: return false;
2405: }
1.174 dyoung 2406: dvl->dvl_nlock++;
2407: dvl->dvl_holder = curlwp;
1.183 dyoung 2408: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 2409: return true;
2410: }
2411:
2412: bool
1.183 dyoung 2413: device_pmf_lock(device_t dev)
1.139 dyoung 2414: {
2415: bool rc;
1.174 dyoung 2416: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2417:
1.174 dyoung 2418: mutex_enter(&dvl->dvl_mtx);
1.183 dyoung 2419: rc = device_pmf_lock1(dev);
1.174 dyoung 2420: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 2421:
2422: return rc;
2423: }
2424:
2425: void
1.183 dyoung 2426: device_pmf_unlock(device_t dev)
1.139 dyoung 2427: {
1.174 dyoung 2428: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2429:
1.174 dyoung 2430: KASSERT(dvl->dvl_nlock > 0);
2431: mutex_enter(&dvl->dvl_mtx);
2432: if (--dvl->dvl_nlock == 0)
2433: dvl->dvl_holder = NULL;
2434: cv_signal(&dvl->dvl_cv);
1.183 dyoung 2435: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2436: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 2437: }
2438:
1.174 dyoung 2439: device_lock_t
2440: device_getlock(device_t dev)
1.139 dyoung 2441: {
1.174 dyoung 2442: return &dev->dv_lock;
1.139 dyoung 2443: }
2444:
1.124 jmcneill 2445: void *
2446: device_pmf_bus_private(device_t dev)
2447: {
2448: return dev->dv_bus_private;
2449: }
2450:
2451: bool
1.203 dyoung 2452: device_pmf_bus_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2453: {
2454: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
2455: return true;
2456: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
2457: (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
2458: return false;
1.195 dyoung 2459: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
1.183 dyoung 2460: dev->dv_bus_suspend != NULL &&
1.195 dyoung 2461: !(*dev->dv_bus_suspend)(dev, qual))
1.124 jmcneill 2462: return false;
2463:
2464: dev->dv_flags |= DVF_BUS_SUSPENDED;
2465: return true;
2466: }
2467:
2468: bool
1.203 dyoung 2469: device_pmf_bus_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2470: {
2471: if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
2472: return true;
1.195 dyoung 2473: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_BUS &&
1.183 dyoung 2474: dev->dv_bus_resume != NULL &&
1.195 dyoung 2475: !(*dev->dv_bus_resume)(dev, qual))
1.124 jmcneill 2476: return false;
2477:
2478: dev->dv_flags &= ~DVF_BUS_SUSPENDED;
2479: return true;
2480: }
2481:
1.133 drochner 2482: bool
2483: device_pmf_bus_shutdown(device_t dev, int how)
2484: {
2485:
2486: if (*dev->dv_bus_shutdown != NULL &&
2487: !(*dev->dv_bus_shutdown)(dev, how))
2488: return false;
2489: return true;
2490: }
2491:
1.124 jmcneill 2492: void
2493: device_pmf_bus_register(device_t dev, void *priv,
1.203 dyoung 2494: bool (*suspend)(device_t, const pmf_qual_t *),
2495: bool (*resume)(device_t, const pmf_qual_t *),
1.133 drochner 2496: bool (*shutdown)(device_t, int), void (*deregister)(device_t))
1.124 jmcneill 2497: {
2498: dev->dv_bus_private = priv;
2499: dev->dv_bus_resume = resume;
2500: dev->dv_bus_suspend = suspend;
1.133 drochner 2501: dev->dv_bus_shutdown = shutdown;
1.124 jmcneill 2502: dev->dv_bus_deregister = deregister;
2503: }
2504:
2505: void
2506: device_pmf_bus_deregister(device_t dev)
2507: {
2508: if (dev->dv_bus_deregister == NULL)
2509: return;
2510: (*dev->dv_bus_deregister)(dev);
2511: dev->dv_bus_private = NULL;
2512: dev->dv_bus_suspend = NULL;
2513: dev->dv_bus_resume = NULL;
2514: dev->dv_bus_deregister = NULL;
2515: }
2516:
2517: void *
2518: device_pmf_class_private(device_t dev)
2519: {
2520: return dev->dv_class_private;
2521: }
2522:
2523: bool
1.203 dyoung 2524: device_pmf_class_suspend(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2525: {
2526: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
2527: return true;
1.195 dyoung 2528: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
1.183 dyoung 2529: dev->dv_class_suspend != NULL &&
1.195 dyoung 2530: !(*dev->dv_class_suspend)(dev, qual))
1.124 jmcneill 2531: return false;
2532:
2533: dev->dv_flags |= DVF_CLASS_SUSPENDED;
2534: return true;
2535: }
2536:
2537: bool
1.203 dyoung 2538: device_pmf_class_resume(device_t dev, const pmf_qual_t *qual)
1.124 jmcneill 2539: {
2540: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
2541: return true;
2542: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
2543: (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
2544: return false;
1.195 dyoung 2545: if (pmf_qual_depth(qual) <= DEVACT_LEVEL_CLASS &&
1.183 dyoung 2546: dev->dv_class_resume != NULL &&
1.195 dyoung 2547: !(*dev->dv_class_resume)(dev, qual))
1.124 jmcneill 2548: return false;
2549:
2550: dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
2551: return true;
2552: }
2553:
2554: void
2555: device_pmf_class_register(device_t dev, void *priv,
1.203 dyoung 2556: bool (*suspend)(device_t, const pmf_qual_t *),
2557: bool (*resume)(device_t, const pmf_qual_t *),
1.124 jmcneill 2558: void (*deregister)(device_t))
2559: {
2560: dev->dv_class_private = priv;
2561: dev->dv_class_suspend = suspend;
2562: dev->dv_class_resume = resume;
2563: dev->dv_class_deregister = deregister;
2564: }
2565:
2566: void
2567: device_pmf_class_deregister(device_t dev)
2568: {
2569: if (dev->dv_class_deregister == NULL)
2570: return;
2571: (*dev->dv_class_deregister)(dev);
2572: dev->dv_class_private = NULL;
2573: dev->dv_class_suspend = NULL;
2574: dev->dv_class_resume = NULL;
2575: dev->dv_class_deregister = NULL;
2576: }
2577:
2578: bool
2579: device_active(device_t dev, devactive_t type)
2580: {
2581: size_t i;
2582:
2583: if (dev->dv_activity_count == 0)
2584: return false;
2585:
1.160 matt 2586: for (i = 0; i < dev->dv_activity_count; ++i) {
2587: if (dev->dv_activity_handlers[i] == NULL)
2588: break;
1.124 jmcneill 2589: (*dev->dv_activity_handlers[i])(dev, type);
1.160 matt 2590: }
1.124 jmcneill 2591:
2592: return true;
2593: }
2594:
2595: bool
2596: device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
2597: {
2598: void (**new_handlers)(device_t, devactive_t);
2599: void (**old_handlers)(device_t, devactive_t);
1.159 matt 2600: size_t i, old_size, new_size;
1.124 jmcneill 2601: int s;
2602:
2603: old_handlers = dev->dv_activity_handlers;
1.159 matt 2604: old_size = dev->dv_activity_count;
1.124 jmcneill 2605:
1.159 matt 2606: for (i = 0; i < old_size; ++i) {
2607: KASSERT(old_handlers[i] != handler);
2608: if (old_handlers[i] == NULL) {
2609: old_handlers[i] = handler;
2610: return true;
2611: }
1.124 jmcneill 2612: }
2613:
1.159 matt 2614: new_size = old_size + 4;
2615: new_handlers = kmem_alloc(sizeof(void *[new_size]), KM_SLEEP);
1.124 jmcneill 2616:
1.159 matt 2617: memcpy(new_handlers, old_handlers, sizeof(void *[old_size]));
2618: new_handlers[old_size] = handler;
2619: memset(new_handlers + old_size + 1, 0,
2620: sizeof(int [new_size - (old_size+1)]));
1.124 jmcneill 2621:
2622: s = splhigh();
2623: dev->dv_activity_count = new_size;
2624: dev->dv_activity_handlers = new_handlers;
2625: splx(s);
2626:
2627: if (old_handlers != NULL)
1.165 macallan 2628: kmem_free(old_handlers, sizeof(void * [old_size]));
1.124 jmcneill 2629:
2630: return true;
2631: }
2632:
2633: void
2634: device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
2635: {
2636: void (**old_handlers)(device_t, devactive_t);
1.159 matt 2637: size_t i, old_size;
1.124 jmcneill 2638: int s;
2639:
2640: old_handlers = dev->dv_activity_handlers;
1.159 matt 2641: old_size = dev->dv_activity_count;
1.124 jmcneill 2642:
1.159 matt 2643: for (i = 0; i < old_size; ++i) {
1.124 jmcneill 2644: if (old_handlers[i] == handler)
2645: break;
1.159 matt 2646: if (old_handlers[i] == NULL)
2647: return; /* XXX panic? */
1.124 jmcneill 2648: }
2649:
1.159 matt 2650: if (i == old_size)
1.124 jmcneill 2651: return; /* XXX panic? */
2652:
1.159 matt 2653: for (; i < old_size - 1; ++i) {
2654: if ((old_handlers[i] = old_handlers[i + 1]) != NULL)
2655: continue;
1.124 jmcneill 2656:
1.159 matt 2657: if (i == 0) {
2658: s = splhigh();
2659: dev->dv_activity_count = 0;
2660: dev->dv_activity_handlers = NULL;
2661: splx(s);
2662: kmem_free(old_handlers, sizeof(void *[old_size]));
2663: }
2664: return;
1.124 jmcneill 2665: }
1.159 matt 2666: old_handlers[i] = NULL;
1.124 jmcneill 2667: }
1.136 dyoung 2668:
1.187 dyoung 2669: /* Return true iff the device_t `dev' exists at generation `gen'. */
2670: static bool
2671: device_exists_at(device_t dv, devgen_t gen)
2672: {
2673: return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) &&
2674: dv->dv_add_gen <= gen;
2675: }
2676:
2677: static bool
2678: deviter_visits(const deviter_t *di, device_t dv)
2679: {
2680: return device_exists_at(dv, di->di_gen);
2681: }
2682:
1.136 dyoung 2683: /*
2684: * Device Iteration
2685: *
2686: * deviter_t: a device iterator. Holds state for a "walk" visiting
2687: * each device_t's in the device tree.
2688: *
2689: * deviter_init(di, flags): initialize the device iterator `di'
2690: * to "walk" the device tree. deviter_next(di) will return
2691: * the first device_t in the device tree, or NULL if there are
2692: * no devices.
2693: *
2694: * `flags' is one or more of DEVITER_F_RW, indicating that the
2695: * caller intends to modify the device tree by calling
2696: * config_detach(9) on devices in the order that the iterator
2697: * returns them; DEVITER_F_ROOT_FIRST, asking for the devices
2698: * nearest the "root" of the device tree to be returned, first;
2699: * DEVITER_F_LEAVES_FIRST, asking for the devices furthest from
2700: * the root of the device tree, first; and DEVITER_F_SHUTDOWN,
2701: * indicating both that deviter_init() should not respect any
2702: * locks on the device tree, and that deviter_next(di) may run
2703: * in more than one LWP before the walk has finished.
2704: *
2705: * Only one DEVITER_F_RW iterator may be in the device tree at
2706: * once.
2707: *
2708: * DEVITER_F_SHUTDOWN implies DEVITER_F_RW.
2709: *
2710: * Results are undefined if the flags DEVITER_F_ROOT_FIRST and
2711: * DEVITER_F_LEAVES_FIRST are used in combination.
2712: *
2713: * deviter_first(di, flags): initialize the device iterator `di'
2714: * and return the first device_t in the device tree, or NULL
2715: * if there are no devices. The statement
2716: *
2717: * dv = deviter_first(di);
2718: *
2719: * is shorthand for
2720: *
2721: * deviter_init(di);
2722: * dv = deviter_next(di);
2723: *
2724: * deviter_next(di): return the next device_t in the device tree,
2725: * or NULL if there are no more devices. deviter_next(di)
2726: * is undefined if `di' was not initialized with deviter_init() or
2727: * deviter_first().
2728: *
2729: * deviter_release(di): stops iteration (subsequent calls to
2730: * deviter_next() will return NULL), releases any locks and
2731: * resources held by the device iterator.
2732: *
2733: * Device iteration does not return device_t's in any particular
2734: * order. An iterator will never return the same device_t twice.
2735: * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
2736: * is called repeatedly on the same `di', it will eventually return
2737: * NULL. It is ok to attach/detach devices during device iteration.
2738: */
2739: void
2740: deviter_init(deviter_t *di, deviter_flags_t flags)
2741: {
2742: device_t dv;
1.187 dyoung 2743: int s;
1.136 dyoung 2744:
1.187 dyoung 2745: memset(di, 0, sizeof(*di));
2746:
2747: s = config_alldevs_lock();
2748: if ((flags & DEVITER_F_SHUTDOWN) != 0)
1.136 dyoung 2749: flags |= DEVITER_F_RW;
1.187 dyoung 2750:
2751: if ((flags & DEVITER_F_RW) != 0)
1.136 dyoung 2752: alldevs_nwrite++;
1.187 dyoung 2753: else
2754: alldevs_nread++;
2755: di->di_gen = alldevs_gen++;
2756: config_alldevs_unlock(s);
1.136 dyoung 2757:
2758: di->di_flags = flags;
2759:
2760: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2761: case DEVITER_F_LEAVES_FIRST:
1.187 dyoung 2762: TAILQ_FOREACH(dv, &alldevs, dv_list) {
2763: if (!deviter_visits(di, dv))
2764: continue;
1.136 dyoung 2765: di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
1.187 dyoung 2766: }
1.136 dyoung 2767: break;
2768: case DEVITER_F_ROOT_FIRST:
1.187 dyoung 2769: TAILQ_FOREACH(dv, &alldevs, dv_list) {
2770: if (!deviter_visits(di, dv))
2771: continue;
1.136 dyoung 2772: di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
1.187 dyoung 2773: }
1.136 dyoung 2774: break;
2775: default:
2776: break;
2777: }
2778:
2779: deviter_reinit(di);
2780: }
2781:
2782: static void
2783: deviter_reinit(deviter_t *di)
2784: {
2785: if ((di->di_flags & DEVITER_F_RW) != 0)
2786: di->di_prev = TAILQ_LAST(&alldevs, devicelist);
2787: else
2788: di->di_prev = TAILQ_FIRST(&alldevs);
2789: }
2790:
2791: device_t
2792: deviter_first(deviter_t *di, deviter_flags_t flags)
2793: {
2794: deviter_init(di, flags);
2795: return deviter_next(di);
2796: }
2797:
2798: static device_t
1.187 dyoung 2799: deviter_next2(deviter_t *di)
1.136 dyoung 2800: {
2801: device_t dv;
2802:
2803: dv = di->di_prev;
2804:
2805: if (dv == NULL)
1.191 dyoung 2806: return NULL;
2807:
2808: if ((di->di_flags & DEVITER_F_RW) != 0)
1.136 dyoung 2809: di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
2810: else
2811: di->di_prev = TAILQ_NEXT(dv, dv_list);
2812:
2813: return dv;
2814: }
2815:
1.187 dyoung 2816: static device_t
2817: deviter_next1(deviter_t *di)
2818: {
2819: device_t dv;
2820:
2821: do {
2822: dv = deviter_next2(di);
2823: } while (dv != NULL && !deviter_visits(di, dv));
2824:
2825: return dv;
2826: }
2827:
1.136 dyoung 2828: device_t
2829: deviter_next(deviter_t *di)
2830: {
2831: device_t dv = NULL;
2832:
2833: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2834: case 0:
2835: return deviter_next1(di);
2836: case DEVITER_F_LEAVES_FIRST:
2837: while (di->di_curdepth >= 0) {
2838: if ((dv = deviter_next1(di)) == NULL) {
2839: di->di_curdepth--;
2840: deviter_reinit(di);
2841: } else if (dv->dv_depth == di->di_curdepth)
2842: break;
2843: }
2844: return dv;
2845: case DEVITER_F_ROOT_FIRST:
2846: while (di->di_curdepth <= di->di_maxdepth) {
2847: if ((dv = deviter_next1(di)) == NULL) {
2848: di->di_curdepth++;
2849: deviter_reinit(di);
2850: } else if (dv->dv_depth == di->di_curdepth)
2851: break;
2852: }
2853: return dv;
2854: default:
2855: return NULL;
2856: }
2857: }
2858:
2859: void
2860: deviter_release(deviter_t *di)
2861: {
2862: bool rw = (di->di_flags & DEVITER_F_RW) != 0;
1.187 dyoung 2863: int s;
1.136 dyoung 2864:
1.187 dyoung 2865: s = config_alldevs_lock();
2866: if (rw)
2867: --alldevs_nwrite;
2868: else
1.178 dyoung 2869: --alldevs_nread;
1.187 dyoung 2870: /* XXX wake a garbage-collection thread */
2871: config_alldevs_unlock(s);
1.136 dyoung 2872: }
1.174 dyoung 2873:
1.201 dyoung 2874: const char *
2875: cfdata_ifattr(const struct cfdata *cf)
2876: {
2877: return cf->cf_pspec->cfp_iattr;
2878: }
2879:
1.193 dyoung 2880: bool
2881: ifattr_match(const char *snull, const char *t)
2882: {
2883: return (snull == NULL) || strcmp(snull, t) == 0;
2884: }
2885:
1.192 dyoung 2886: void
2887: null_childdetached(device_t self, device_t child)
2888: {
2889: /* do nothing */
2890: }
2891:
1.182 pooka 2892: static void
2893: sysctl_detach_setup(struct sysctllog **clog)
1.174 dyoung 2894: {
2895:
1.230 pooka 2896: sysctl_createv(clog, 0, NULL, NULL,
1.174 dyoung 2897: CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.205 jruoho 2898: CTLTYPE_BOOL, "detachall",
1.174 dyoung 2899: SYSCTL_DESCR("Detach all devices at shutdown"),
2900: NULL, 0, &detachall, 0,
1.230 pooka 2901: CTL_KERN, CTL_CREATE, CTL_EOL);
1.174 dyoung 2902: }
CVSweb <webmaster@jp.NetBSD.org>