Annotation of src/sys/kern/subr_autoconf.c, Revision 1.183
1.183 ! dyoung 1: /* $NetBSD: subr_autoconf.c,v 1.182 2009/09/16 15:23:04 pooka Exp $ */
1.53 cgd 2:
3: /*
4: * Copyright (c) 1996, 2000 Christopher G. Demetriou
5: * All rights reserved.
1.93 perry 6: *
1.53 cgd 7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
1.54 cgd 17: * This product includes software developed for the
1.88 keihan 18: * NetBSD Project. See http://www.NetBSD.org/ for
1.54 cgd 19: * information about NetBSD.
1.53 cgd 20: * 4. The name of the author may not be used to endorse or promote products
1.54 cgd 21: * derived from this software without specific prior written permission.
1.93 perry 22: *
1.53 cgd 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.93 perry 33: *
1.54 cgd 34: * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
1.53 cgd 35: */
1.9 cgd 36:
1.1 glass 37: /*
1.7 glass 38: * Copyright (c) 1992, 1993
39: * The Regents of the University of California. All rights reserved.
1.1 glass 40: *
41: * This software was developed by the Computer Systems Engineering group
42: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43: * contributed to Berkeley.
44: *
45: * All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the University of
48: * California, Lawrence Berkeley Laboratories.
49: *
1.7 glass 50: * Redistribution and use in source and binary forms, with or without
51: * modification, are permitted provided that the following conditions
52: * are met:
53: * 1. Redistributions of source code must retain the above copyright
54: * notice, this list of conditions and the following disclaimer.
55: * 2. Redistributions in binary form must reproduce the above copyright
56: * notice, this list of conditions and the following disclaimer in the
57: * documentation and/or other materials provided with the distribution.
1.87 agc 58: * 3. Neither the name of the University nor the names of its contributors
1.7 glass 59: * may be used to endorse or promote products derived from this software
60: * without specific prior written permission.
1.1 glass 61: *
1.7 glass 62: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
1.1 glass 73: *
1.8 cgd 74: * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
1.9 cgd 75: *
1.28 fvdl 76: * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
1.1 glass 77: */
78:
1.51 cgd 79: #include <sys/cdefs.h>
1.183 ! dyoung 80: __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.182 2009/09/16 15:23:04 pooka Exp $");
1.62 simonb 81:
1.180 pooka 82: #ifdef _KERNEL_OPT
1.62 simonb 83: #include "opt_ddb.h"
1.149 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.4 mycroft 92: #include <sys/malloc.h>
1.159 matt 93: #include <sys/kmem.h>
1.17 christos 94: #include <sys/systm.h>
1.43 thorpej 95: #include <sys/kernel.h>
1.33 thorpej 96: #include <sys/errno.h>
1.47 thorpej 97: #include <sys/proc.h>
1.82 mrg 98: #include <sys/reboot.h>
1.142 ad 99: #include <sys/kthread.h>
1.118 dyoung 100: #include <sys/buf.h>
101: #include <sys/dirent.h>
102: #include <sys/vnode.h>
103: #include <sys/mount.h>
104: #include <sys/namei.h>
105: #include <sys/unistd.h>
106: #include <sys/fcntl.h>
107: #include <sys/lockf.h>
1.124 jmcneill 108: #include <sys/callout.h>
1.149 jmcneill 109: #include <sys/devmon.h>
1.153 cegger 110: #include <sys/cpu.h>
1.174 dyoung 111: #include <sys/sysctl.h>
1.118 dyoung 112:
113: #include <sys/disk.h>
114:
1.16 mycroft 115: #include <machine/limits.h>
1.1 glass 116:
1.180 pooka 117: #if defined(__i386__) && defined(_KERNEL_OPT)
1.105 jmcneill 118: #include "opt_splash.h"
119: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
120: #include <dev/splash/splash.h>
121: extern struct splash_progress *splash_progress_state;
122: #endif
1.106 martin 123: #endif
1.105 jmcneill 124:
1.1 glass 125: /*
126: * Autoconfiguration subroutines.
127: */
128:
129: /*
130: * ioconf.c exports exactly two names: cfdata and cfroots. All system
131: * devices and drivers are found via these tables.
132: */
133: extern struct cfdata cfdata[];
1.84 matt 134: extern const short cfroots[];
1.1 glass 135:
1.65 thorpej 136: /*
1.67 thorpej 137: * List of all cfdriver structures. We use this to detect duplicates
138: * when other cfdrivers are loaded.
139: */
1.69 thorpej 140: struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
141: extern struct cfdriver * const cfdriver_list_initial[];
1.67 thorpej 142:
143: /*
1.76 thorpej 144: * Initial list of cfattach's.
145: */
146: extern const struct cfattachinit cfattachinit[];
147:
148: /*
1.65 thorpej 149: * List of cfdata tables. We always have one such list -- the one
150: * built statically when the kernel was configured.
151: */
1.121 matt 152: struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
1.65 thorpej 153: static struct cftable initcftable;
154:
1.102 thorpej 155: #define ROOT ((device_t)NULL)
1.1 glass 156:
1.16 mycroft 157: struct matchinfo {
1.99 drochner 158: cfsubmatch_t fn;
1.16 mycroft 159: struct device *parent;
1.99 drochner 160: const int *locs;
1.25 cgd 161: void *aux;
162: struct cfdata *match;
163: int pri;
1.16 mycroft 164: };
1.17 christos 165:
1.51 cgd 166: static char *number(char *, int);
1.102 thorpej 167: static void mapply(struct matchinfo *, cfdata_t);
1.117 drochner 168: static device_t config_devalloc(const device_t, const cfdata_t, const int *);
169: static void config_devdealloc(device_t);
170: static void config_makeroom(int, struct cfdriver *);
171: static void config_devlink(device_t);
172: static void config_devunlink(device_t);
1.16 mycroft 173:
1.139 dyoung 174: static void pmflock_debug(device_t, const char *, int);
175:
1.136 dyoung 176: static device_t deviter_next1(deviter_t *);
177: static void deviter_reinit(deviter_t *);
178:
1.29 thorpej 179: struct deferred_config {
180: TAILQ_ENTRY(deferred_config) dc_queue;
1.102 thorpej 181: device_t dc_dev;
182: void (*dc_func)(device_t);
1.29 thorpej 183: };
184:
1.42 thorpej 185: TAILQ_HEAD(deferred_config_head, deferred_config);
1.29 thorpej 186:
1.121 matt 187: struct deferred_config_head deferred_config_queue =
188: TAILQ_HEAD_INITIALIZER(deferred_config_queue);
189: struct deferred_config_head interrupt_config_queue =
190: TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
1.142 ad 191: int interrupt_config_threads = 8;
1.42 thorpej 192:
1.102 thorpej 193: static void config_process_deferred(struct deferred_config_head *, device_t);
1.29 thorpej 194:
1.75 thorpej 195: /* Hooks to finalize configuration once all real devices have been found. */
196: struct finalize_hook {
197: TAILQ_ENTRY(finalize_hook) f_list;
1.102 thorpej 198: int (*f_func)(device_t);
199: device_t f_dev;
1.75 thorpej 200: };
1.121 matt 201: static TAILQ_HEAD(, finalize_hook) config_finalize_list =
202: TAILQ_HEAD_INITIALIZER(config_finalize_list);
1.75 thorpej 203: static int config_finalize_done;
204:
1.56 thorpej 205: /* list of all devices */
1.121 matt 206: struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
1.136 dyoung 207: kcondvar_t alldevs_cv;
208: kmutex_t alldevs_mtx;
209: static int alldevs_nread = 0;
210: static int alldevs_nwrite = 0;
211: static lwp_t *alldevs_writer = NULL;
1.56 thorpej 212:
1.151 ad 213: static int config_pending; /* semaphore for mountroot */
214: static kmutex_t config_misc_lock;
215: static kcondvar_t config_misc_cv;
1.47 thorpej 216:
1.174 dyoung 217: static int detachall = 0;
218:
1.67 thorpej 219: #define STREQ(s1, s2) \
1.70 thorpej 220: (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
1.67 thorpej 221:
1.74 thorpej 222: static int config_initialized; /* config_init() has been called. */
223:
1.80 thorpej 224: static int config_do_twiddle;
1.176 ad 225: static callout_t config_twiddle_ch;
1.80 thorpej 226:
1.182 pooka 227: static void sysctl_detach_setup(struct sysctllog **);
228:
1.20 cgd 229: /*
1.74 thorpej 230: * Initialize the autoconfiguration data structures. Normally this
231: * is done by configure(), but some platforms need to do this very
232: * early (to e.g. initialize the console).
1.20 cgd 233: */
234: void
1.74 thorpej 235: config_init(void)
1.20 cgd 236: {
1.76 thorpej 237: const struct cfattachinit *cfai;
238: int i, j;
1.67 thorpej 239:
1.74 thorpej 240: if (config_initialized)
241: return;
242:
1.136 dyoung 243: mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE);
244: cv_init(&alldevs_cv, "alldevs");
245:
1.151 ad 246: mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE);
247: cv_init(&config_misc_cv, "cfgmisc");
248:
1.176 ad 249: callout_init(&config_twiddle_ch, CALLOUT_MPSAFE);
250:
1.69 thorpej 251: /* allcfdrivers is statically initialized. */
1.76 thorpej 252: for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
1.67 thorpej 253: if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
254: panic("configure: duplicate `%s' drivers",
255: cfdriver_list_initial[i]->cd_name);
1.76 thorpej 256: }
257:
258: for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
259: for (j = 0; cfai->cfai_list[j] != NULL; j++) {
260: if (config_cfattach_attach(cfai->cfai_name,
261: cfai->cfai_list[j]) != 0)
262: panic("configure: duplicate `%s' attachment "
263: "of `%s' driver",
264: cfai->cfai_list[j]->ca_name,
265: cfai->cfai_name);
266: }
267: }
1.20 cgd 268:
1.65 thorpej 269: initcftable.ct_cfdata = cfdata;
270: TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
1.182 pooka 271: sysctl_detach_setup(NULL);
1.65 thorpej 272:
1.74 thorpej 273: config_initialized = 1;
274: }
275:
1.126 dyoung 276: void
277: config_deferred(device_t dev)
278: {
279: config_process_deferred(&deferred_config_queue, dev);
280: config_process_deferred(&interrupt_config_queue, dev);
281: }
282:
1.142 ad 283: static void
284: config_interrupts_thread(void *cookie)
285: {
286: struct deferred_config *dc;
287:
288: while ((dc = TAILQ_FIRST(&interrupt_config_queue)) != NULL) {
289: TAILQ_REMOVE(&interrupt_config_queue, dc, dc_queue);
290: (*dc->dc_func)(dc->dc_dev);
1.159 matt 291: kmem_free(dc, sizeof(*dc));
1.142 ad 292: config_pending_decr();
293: }
294: kthread_exit(0);
295: }
296:
1.74 thorpej 297: void
1.180 pooka 298: config_create_interruptthreads()
1.74 thorpej 299: {
1.180 pooka 300: int i;
1.144 ad 301:
1.142 ad 302: for (i = 0; i < interrupt_config_threads; i++) {
303: (void)kthread_create(PRI_NONE, 0, NULL,
304: config_interrupts_thread, NULL, NULL, "config");
305: }
1.20 cgd 306: }
307:
1.1 glass 308: /*
1.149 jmcneill 309: * Announce device attach/detach to userland listeners.
310: */
311: static void
312: devmon_report_device(device_t dev, bool isattach)
313: {
314: #if NDRVCTL > 0
315: prop_dictionary_t ev;
316: const char *parent;
317: const char *what;
318: device_t pdev = device_parent(dev);
319:
320: ev = prop_dictionary_create();
321: if (ev == NULL)
322: return;
323:
324: what = (isattach ? "device-attach" : "device-detach");
325: parent = (pdev == NULL ? "root" : device_xname(pdev));
326: if (!prop_dictionary_set_cstring(ev, "device", device_xname(dev)) ||
327: !prop_dictionary_set_cstring(ev, "parent", parent)) {
328: prop_object_release(ev);
329: return;
330: }
331:
332: devmon_insert(what, ev);
333: #endif
334: }
335:
336: /*
1.67 thorpej 337: * Add a cfdriver to the system.
338: */
339: int
340: config_cfdriver_attach(struct cfdriver *cd)
341: {
342: struct cfdriver *lcd;
343:
344: /* Make sure this driver isn't already in the system. */
345: LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
346: if (STREQ(lcd->cd_name, cd->cd_name))
1.175 cegger 347: return EEXIST;
1.67 thorpej 348: }
349:
1.76 thorpej 350: LIST_INIT(&cd->cd_attach);
1.67 thorpej 351: LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
352:
1.175 cegger 353: return 0;
1.67 thorpej 354: }
355:
356: /*
357: * Remove a cfdriver from the system.
358: */
359: int
360: config_cfdriver_detach(struct cfdriver *cd)
361: {
362: int i;
363:
364: /* Make sure there are no active instances. */
365: for (i = 0; i < cd->cd_ndevs; i++) {
366: if (cd->cd_devs[i] != NULL)
1.175 cegger 367: return EBUSY;
1.67 thorpej 368: }
369:
1.76 thorpej 370: /* ...and no attachments loaded. */
371: if (LIST_EMPTY(&cd->cd_attach) == 0)
1.175 cegger 372: return EBUSY;
1.76 thorpej 373:
1.67 thorpej 374: LIST_REMOVE(cd, cd_list);
375:
376: KASSERT(cd->cd_devs == NULL);
377:
1.175 cegger 378: return 0;
1.67 thorpej 379: }
380:
381: /*
382: * Look up a cfdriver by name.
383: */
1.78 isaki 384: struct cfdriver *
1.67 thorpej 385: config_cfdriver_lookup(const char *name)
386: {
387: struct cfdriver *cd;
1.69 thorpej 388:
1.67 thorpej 389: LIST_FOREACH(cd, &allcfdrivers, cd_list) {
390: if (STREQ(cd->cd_name, name))
1.175 cegger 391: return cd;
1.67 thorpej 392: }
393:
1.175 cegger 394: return NULL;
1.67 thorpej 395: }
396:
397: /*
1.76 thorpej 398: * Add a cfattach to the specified driver.
399: */
400: int
401: config_cfattach_attach(const char *driver, struct cfattach *ca)
402: {
403: struct cfattach *lca;
404: struct cfdriver *cd;
405:
406: cd = config_cfdriver_lookup(driver);
407: if (cd == NULL)
1.175 cegger 408: return ESRCH;
1.76 thorpej 409:
410: /* Make sure this attachment isn't already on this driver. */
411: LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
412: if (STREQ(lca->ca_name, ca->ca_name))
1.175 cegger 413: return EEXIST;
1.76 thorpej 414: }
415:
416: LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
417:
1.175 cegger 418: return 0;
1.76 thorpej 419: }
420:
421: /*
422: * Remove a cfattach from the specified driver.
423: */
424: int
425: config_cfattach_detach(const char *driver, struct cfattach *ca)
426: {
427: struct cfdriver *cd;
1.102 thorpej 428: device_t dev;
1.76 thorpej 429: int i;
430:
431: cd = config_cfdriver_lookup(driver);
432: if (cd == NULL)
1.175 cegger 433: return ESRCH;
1.76 thorpej 434:
435: /* Make sure there are no active instances. */
436: for (i = 0; i < cd->cd_ndevs; i++) {
437: if ((dev = cd->cd_devs[i]) == NULL)
438: continue;
1.77 thorpej 439: if (dev->dv_cfattach == ca)
1.175 cegger 440: return EBUSY;
1.76 thorpej 441: }
442:
443: LIST_REMOVE(ca, ca_list);
444:
1.175 cegger 445: return 0;
1.76 thorpej 446: }
447:
448: /*
449: * Look up a cfattach by name.
450: */
451: static struct cfattach *
452: config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
453: {
454: struct cfattach *ca;
455:
456: LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
457: if (STREQ(ca->ca_name, atname))
1.175 cegger 458: return ca;
1.76 thorpej 459: }
460:
1.175 cegger 461: return NULL;
1.76 thorpej 462: }
463:
464: /*
465: * Look up a cfattach by driver/attachment name.
466: */
467: struct cfattach *
468: config_cfattach_lookup(const char *name, const char *atname)
469: {
470: struct cfdriver *cd;
471:
472: cd = config_cfdriver_lookup(name);
473: if (cd == NULL)
1.175 cegger 474: return NULL;
1.76 thorpej 475:
1.175 cegger 476: return config_cfattach_lookup_cd(cd, atname);
1.76 thorpej 477: }
478:
479: /*
1.1 glass 480: * Apply the matching function and choose the best. This is used
481: * a few times and we want to keep the code small.
482: */
1.16 mycroft 483: static void
1.102 thorpej 484: mapply(struct matchinfo *m, cfdata_t cf)
1.1 glass 485: {
1.50 augustss 486: int pri;
1.1 glass 487:
1.99 drochner 488: if (m->fn != NULL) {
489: pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
1.90 drochner 490: } else {
1.100 drochner 491: pri = config_match(m->parent, cf, m->aux);
1.3 glass 492: }
1.1 glass 493: if (pri > m->pri) {
1.25 cgd 494: m->match = cf;
1.1 glass 495: m->pri = pri;
496: }
497: }
498:
1.98 drochner 499: int
1.102 thorpej 500: config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
1.98 drochner 501: {
502: const struct cfiattrdata *ci;
503: const struct cflocdesc *cl;
504: int nlocs, i;
505:
506: ci = cfiattr_lookup(cf->cf_pspec->cfp_iattr, parent->dv_cfdriver);
507: KASSERT(ci);
508: nlocs = ci->ci_loclen;
1.154 drochner 509: KASSERT(!nlocs || locs);
1.98 drochner 510: for (i = 0; i < nlocs; i++) {
511: cl = &ci->ci_locdesc[i];
512: /* !cld_defaultstr means no default value */
513: if ((!(cl->cld_defaultstr)
514: || (cf->cf_loc[i] != cl->cld_default))
515: && cf->cf_loc[i] != locs[i])
1.175 cegger 516: return 0;
1.98 drochner 517: }
518:
1.175 cegger 519: return config_match(parent, cf, aux);
1.98 drochner 520: }
521:
1.1 glass 522: /*
1.96 drochner 523: * Helper function: check whether the driver supports the interface attribute
524: * and return its descriptor structure.
1.91 drochner 525: */
1.96 drochner 526: static const struct cfiattrdata *
527: cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
1.91 drochner 528: {
1.96 drochner 529: const struct cfiattrdata * const *cpp;
1.91 drochner 530:
531: if (cd->cd_attrs == NULL)
1.175 cegger 532: return 0;
1.91 drochner 533:
534: for (cpp = cd->cd_attrs; *cpp; cpp++) {
1.96 drochner 535: if (STREQ((*cpp)->ci_name, ia)) {
1.91 drochner 536: /* Match. */
1.175 cegger 537: return *cpp;
1.91 drochner 538: }
539: }
1.175 cegger 540: return 0;
1.91 drochner 541: }
542:
543: /*
1.96 drochner 544: * Lookup an interface attribute description by name.
545: * If the driver is given, consider only its supported attributes.
546: */
547: const struct cfiattrdata *
548: cfiattr_lookup(const char *name, const struct cfdriver *cd)
549: {
550: const struct cfdriver *d;
551: const struct cfiattrdata *ia;
552:
553: if (cd)
1.175 cegger 554: return cfdriver_get_iattr(cd, name);
1.96 drochner 555:
556: LIST_FOREACH(d, &allcfdrivers, cd_list) {
557: ia = cfdriver_get_iattr(d, name);
558: if (ia)
1.175 cegger 559: return ia;
1.96 drochner 560: }
1.175 cegger 561: return 0;
1.96 drochner 562: }
563:
564: /*
1.66 thorpej 565: * Determine if `parent' is a potential parent for a device spec based
566: * on `cfp'.
567: */
568: static int
1.102 thorpej 569: cfparent_match(const device_t parent, const struct cfparent *cfp)
1.66 thorpej 570: {
1.67 thorpej 571: struct cfdriver *pcd;
1.70 thorpej 572:
573: /* We don't match root nodes here. */
574: if (cfp == NULL)
1.175 cegger 575: return 0;
1.66 thorpej 576:
1.77 thorpej 577: pcd = parent->dv_cfdriver;
1.67 thorpej 578: KASSERT(pcd != NULL);
579:
1.66 thorpej 580: /*
581: * First, ensure this parent has the correct interface
582: * attribute.
583: */
1.96 drochner 584: if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
1.175 cegger 585: return 0;
1.66 thorpej 586:
587: /*
588: * If no specific parent device instance was specified (i.e.
589: * we're attaching to the attribute only), we're done!
590: */
591: if (cfp->cfp_parent == NULL)
1.175 cegger 592: return 1;
1.66 thorpej 593:
594: /*
595: * Check the parent device's name.
596: */
1.71 thorpej 597: if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
1.175 cegger 598: return 0; /* not the same parent */
1.66 thorpej 599:
600: /*
601: * Make sure the unit number matches.
602: */
1.77 thorpej 603: if (cfp->cfp_unit == DVUNIT_ANY || /* wildcard */
1.66 thorpej 604: cfp->cfp_unit == parent->dv_unit)
1.175 cegger 605: return 1;
1.66 thorpej 606:
607: /* Unit numbers don't match. */
1.175 cegger 608: return 0;
1.68 thorpej 609: }
610:
611: /*
1.90 drochner 612: * Helper for config_cfdata_attach(): check all devices whether it could be
613: * parent any attachment in the config data table passed, and rescan.
614: */
615: static void
616: rescan_with_cfdata(const struct cfdata *cf)
617: {
1.102 thorpej 618: device_t d;
1.90 drochner 619: const struct cfdata *cf1;
1.136 dyoung 620: deviter_t di;
621:
1.90 drochner 622:
623: /*
1.164 ad 624: * "alldevs" is likely longer than a modules's cfdata, so make it
1.90 drochner 625: * the outer loop.
626: */
1.136 dyoung 627: for (d = deviter_first(&di, 0); d != NULL; d = deviter_next(&di)) {
1.90 drochner 628:
629: if (!(d->dv_cfattach->ca_rescan))
630: continue;
631:
632: for (cf1 = cf; cf1->cf_name; cf1++) {
633:
634: if (!cfparent_match(d, cf1->cf_pspec))
635: continue;
636:
637: (*d->dv_cfattach->ca_rescan)(d,
638: cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
639: }
640: }
1.136 dyoung 641: deviter_release(&di);
1.90 drochner 642: }
643:
644: /*
645: * Attach a supplemental config data table and rescan potential
646: * parent devices if required.
647: */
648: int
1.102 thorpej 649: config_cfdata_attach(cfdata_t cf, int scannow)
1.90 drochner 650: {
651: struct cftable *ct;
652:
1.159 matt 653: ct = kmem_alloc(sizeof(*ct), KM_SLEEP);
1.90 drochner 654: ct->ct_cfdata = cf;
655: TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
656:
657: if (scannow)
658: rescan_with_cfdata(cf);
659:
1.175 cegger 660: return 0;
1.90 drochner 661: }
662:
663: /*
664: * Helper for config_cfdata_detach: check whether a device is
665: * found through any attachment in the config data table.
666: */
667: static int
668: dev_in_cfdata(const struct device *d, const struct cfdata *cf)
669: {
670: const struct cfdata *cf1;
671:
672: for (cf1 = cf; cf1->cf_name; cf1++)
673: if (d->dv_cfdata == cf1)
1.175 cegger 674: return 1;
1.90 drochner 675:
1.175 cegger 676: return 0;
1.90 drochner 677: }
678:
679: /*
680: * Detach a supplemental config data table. Detach all devices found
681: * through that table (and thus keeping references to it) before.
682: */
683: int
1.102 thorpej 684: config_cfdata_detach(cfdata_t cf)
1.90 drochner 685: {
1.102 thorpej 686: device_t d;
1.136 dyoung 687: int error = 0;
1.90 drochner 688: struct cftable *ct;
1.136 dyoung 689: deviter_t di;
1.90 drochner 690:
1.136 dyoung 691: for (d = deviter_first(&di, DEVITER_F_RW); d != NULL;
692: d = deviter_next(&di)) {
693: if (!dev_in_cfdata(d, cf))
694: continue;
695: if ((error = config_detach(d, 0)) != 0)
696: break;
697: }
698: deviter_release(&di);
699: if (error) {
700: aprint_error_dev(d, "unable to detach instance\n");
701: return error;
1.90 drochner 702: }
703:
704: TAILQ_FOREACH(ct, &allcftables, ct_list) {
705: if (ct->ct_cfdata == cf) {
706: TAILQ_REMOVE(&allcftables, ct, ct_list);
1.159 matt 707: kmem_free(ct, sizeof(*ct));
1.175 cegger 708: return 0;
1.90 drochner 709: }
710: }
711:
712: /* not found -- shouldn't happen */
1.175 cegger 713: return EINVAL;
1.90 drochner 714: }
715:
716: /*
1.68 thorpej 717: * Invoke the "match" routine for a cfdata entry on behalf of
718: * an external caller, usually a "submatch" routine.
719: */
720: int
1.102 thorpej 721: config_match(device_t parent, cfdata_t cf, void *aux)
1.68 thorpej 722: {
1.76 thorpej 723: struct cfattach *ca;
724:
725: ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
726: if (ca == NULL) {
727: /* No attachment for this entry, oh well. */
1.175 cegger 728: return 0;
1.76 thorpej 729: }
1.68 thorpej 730:
1.175 cegger 731: return (*ca->ca_match)(parent, cf, aux);
1.66 thorpej 732: }
733:
734: /*
1.1 glass 735: * Iterate over all potential children of some device, calling the given
736: * function (default being the child's match function) for each one.
737: * Nonzero returns are matches; the highest value returned is considered
738: * the best match. Return the `found child' if we got a match, or NULL
739: * otherwise. The `aux' pointer is simply passed on through.
740: *
741: * Note that this function is designed so that it can be used to apply
742: * an arbitrary function to all potential children (its return value
743: * can be ignored).
744: */
1.102 thorpej 745: cfdata_t
746: config_search_loc(cfsubmatch_t fn, device_t parent,
1.99 drochner 747: const char *ifattr, const int *locs, void *aux)
1.90 drochner 748: {
749: struct cftable *ct;
1.102 thorpej 750: cfdata_t cf;
1.90 drochner 751: struct matchinfo m;
752:
753: KASSERT(config_initialized);
1.96 drochner 754: KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
1.90 drochner 755:
1.99 drochner 756: m.fn = fn;
1.1 glass 757: m.parent = parent;
1.99 drochner 758: m.locs = locs;
1.25 cgd 759: m.aux = aux;
1.14 mycroft 760: m.match = NULL;
1.1 glass 761: m.pri = 0;
1.65 thorpej 762:
763: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 764: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.90 drochner 765:
766: /* We don't match root nodes here. */
767: if (!cf->cf_pspec)
768: continue;
769:
1.65 thorpej 770: /*
771: * Skip cf if no longer eligible, otherwise scan
772: * through parents for one matching `parent', and
773: * try match function.
774: */
775: if (cf->cf_fstate == FSTATE_FOUND)
776: continue;
777: if (cf->cf_fstate == FSTATE_DNOTFOUND ||
778: cf->cf_fstate == FSTATE_DSTAR)
779: continue;
1.90 drochner 780:
781: /*
782: * If an interface attribute was specified,
783: * consider only children which attach to
784: * that attribute.
785: */
786: if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
787: continue;
788:
1.66 thorpej 789: if (cfparent_match(parent, cf->cf_pspec))
790: mapply(&m, cf);
1.65 thorpej 791: }
1.1 glass 792: }
1.175 cegger 793: return m.match;
1.1 glass 794: }
795:
1.102 thorpej 796: cfdata_t
797: config_search_ia(cfsubmatch_t fn, device_t parent, const char *ifattr,
798: void *aux)
799: {
800:
1.175 cegger 801: return config_search_loc(fn, parent, ifattr, NULL, aux);
1.102 thorpej 802: }
803:
1.16 mycroft 804: /*
1.1 glass 805: * Find the given root device.
806: * This is much like config_search, but there is no parent.
1.65 thorpej 807: * Don't bother with multiple cfdata tables; the root node
808: * must always be in the initial table.
1.1 glass 809: */
1.102 thorpej 810: cfdata_t
1.95 drochner 811: config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
1.1 glass 812: {
1.102 thorpej 813: cfdata_t cf;
1.84 matt 814: const short *p;
1.1 glass 815: struct matchinfo m;
816:
1.99 drochner 817: m.fn = fn;
1.1 glass 818: m.parent = ROOT;
1.25 cgd 819: m.aux = aux;
1.14 mycroft 820: m.match = NULL;
1.1 glass 821: m.pri = 0;
1.114 christos 822: m.locs = 0;
1.1 glass 823: /*
824: * Look at root entries for matching name. We do not bother
825: * with found-state here since only one root should ever be
826: * searched (and it must be done first).
827: */
828: for (p = cfroots; *p >= 0; p++) {
829: cf = &cfdata[*p];
1.67 thorpej 830: if (strcmp(cf->cf_name, rootname) == 0)
1.16 mycroft 831: mapply(&m, cf);
1.1 glass 832: }
1.175 cegger 833: return m.match;
1.1 glass 834: }
835:
1.83 jdolecek 836: static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
1.1 glass 837:
838: /*
839: * The given `aux' argument describes a device that has been found
840: * on the given parent, but not necessarily configured. Locate the
1.18 cgd 841: * configuration data for that device (using the submatch function
842: * provided, or using candidates' cd_match configuration driver
843: * functions) and attach it, and return true. If the device was
1.1 glass 844: * not configured, call the given `print' function and return 0.
845: */
1.102 thorpej 846: device_t
847: config_found_sm_loc(device_t parent,
1.99 drochner 848: const char *ifattr, const int *locs, void *aux,
1.95 drochner 849: cfprint_t print, cfsubmatch_t submatch)
1.90 drochner 850: {
1.102 thorpej 851: cfdata_t cf;
1.90 drochner 852:
1.105 jmcneill 853: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
854: if (splash_progress_state)
855: splash_progress_update(splash_progress_state);
856: #endif
857:
1.99 drochner 858: if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux)))
859: return(config_attach_loc(parent, cf, locs, aux, print));
1.90 drochner 860: if (print) {
1.176 ad 861: if (config_do_twiddle && cold)
1.90 drochner 862: twiddle();
1.143 cegger 863: aprint_normal("%s", msgs[(*print)(aux, device_xname(parent))]);
1.90 drochner 864: }
1.105 jmcneill 865:
866: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
867: if (splash_progress_state)
868: splash_progress_update(splash_progress_state);
869: #endif
870:
1.175 cegger 871: return NULL;
1.90 drochner 872: }
873:
1.102 thorpej 874: device_t
875: config_found_ia(device_t parent, const char *ifattr, void *aux,
876: cfprint_t print)
877: {
878:
1.175 cegger 879: return config_found_sm_loc(parent, ifattr, NULL, aux, print, NULL);
1.102 thorpej 880: }
881:
882: device_t
883: config_found(device_t parent, void *aux, cfprint_t print)
884: {
885:
1.175 cegger 886: return config_found_sm_loc(parent, NULL, NULL, aux, print, NULL);
1.102 thorpej 887: }
888:
1.1 glass 889: /*
890: * As above, but for root devices.
891: */
1.102 thorpej 892: device_t
1.52 cgd 893: config_rootfound(const char *rootname, void *aux)
1.1 glass 894: {
1.102 thorpej 895: cfdata_t cf;
1.25 cgd 896:
1.95 drochner 897: if ((cf = config_rootsearch((cfsubmatch_t)NULL, rootname, aux)) != NULL)
1.175 cegger 898: return config_attach(ROOT, cf, aux, (cfprint_t)NULL);
1.80 thorpej 899: aprint_error("root device %s not configured\n", rootname);
1.175 cegger 900: return NULL;
1.1 glass 901: }
902:
903: /* just like sprintf(buf, "%d") except that it works from the end */
904: static char *
1.51 cgd 905: number(char *ep, int n)
1.1 glass 906: {
907:
908: *--ep = 0;
909: while (n >= 10) {
910: *--ep = (n % 10) + '0';
911: n /= 10;
912: }
913: *--ep = n + '0';
1.175 cegger 914: return ep;
1.1 glass 915: }
916:
917: /*
1.59 augustss 918: * Expand the size of the cd_devs array if necessary.
919: */
1.117 drochner 920: static void
1.59 augustss 921: config_makeroom(int n, struct cfdriver *cd)
922: {
923: int old, new;
1.156 drochner 924: device_t *nsp;
1.59 augustss 925:
926: if (n < cd->cd_ndevs)
927: return;
928:
929: /*
930: * Need to expand the array.
931: */
932: old = cd->cd_ndevs;
1.61 thorpej 933: if (old == 0)
1.115 chs 934: new = 4;
1.59 augustss 935: else
936: new = old * 2;
937: while (new <= n)
938: new *= 2;
939: cd->cd_ndevs = new;
1.166 ad 940: nsp = kmem_alloc(sizeof(device_t [new]), KM_SLEEP);
1.60 augustss 941: if (nsp == NULL)
1.59 augustss 942: panic("config_attach: %sing dev array",
943: old != 0 ? "expand" : "creat");
1.159 matt 944: memset(nsp + old, 0, sizeof(device_t [new - old]));
1.61 thorpej 945: if (old != 0) {
1.159 matt 946: memcpy(nsp, cd->cd_devs, sizeof(device_t [old]));
947: kmem_free(cd->cd_devs, sizeof(device_t [old]));
1.59 augustss 948: }
949: cd->cd_devs = nsp;
950: }
951:
1.117 drochner 952: static void
953: config_devlink(device_t dev)
954: {
955: struct cfdriver *cd = dev->dv_cfdriver;
956:
957: /* put this device in the devices array */
958: config_makeroom(dev->dv_unit, cd);
959: if (cd->cd_devs[dev->dv_unit])
1.143 cegger 960: panic("config_attach: duplicate %s", device_xname(dev));
1.117 drochner 961: cd->cd_devs[dev->dv_unit] = dev;
962:
1.136 dyoung 963: /* It is safe to add a device to the tail of the list while
964: * readers are in the list, but not while a writer is in
965: * the list. Wait for any writer to complete.
966: */
967: mutex_enter(&alldevs_mtx);
968: while (alldevs_nwrite != 0 && alldevs_writer != curlwp)
969: cv_wait(&alldevs_cv, &alldevs_mtx);
1.117 drochner 970: TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */
1.136 dyoung 971: cv_signal(&alldevs_cv);
972: mutex_exit(&alldevs_mtx);
1.117 drochner 973: }
974:
975: static void
976: config_devunlink(device_t dev)
977: {
978: struct cfdriver *cd = dev->dv_cfdriver;
979: int i;
980:
981: /* Unlink from device list. */
982: TAILQ_REMOVE(&alldevs, dev, dv_list);
983:
984: /* Remove from cfdriver's array. */
985: cd->cd_devs[dev->dv_unit] = NULL;
986:
987: /*
988: * If the device now has no units in use, deallocate its softc array.
989: */
1.159 matt 990: for (i = 0; i < cd->cd_ndevs; i++) {
1.117 drochner 991: if (cd->cd_devs[i] != NULL)
1.159 matt 992: return;
1.117 drochner 993: }
1.159 matt 994: /* nothing found; deallocate */
995: kmem_free(cd->cd_devs, sizeof(device_t [cd->cd_ndevs]));
996: cd->cd_devs = NULL;
997: cd->cd_ndevs = 0;
1.117 drochner 998: }
999:
1000: static device_t
1001: config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
1.25 cgd 1002: {
1.50 augustss 1003: struct cfdriver *cd;
1.76 thorpej 1004: struct cfattach *ca;
1.50 augustss 1005: size_t lname, lunit;
1.52 cgd 1006: const char *xunit;
1.25 cgd 1007: int myunit;
1008: char num[10];
1.117 drochner 1009: device_t dev;
1.120 joerg 1010: void *dev_private;
1.96 drochner 1011: const struct cfiattrdata *ia;
1.174 dyoung 1012: device_lock_t dvl;
1.25 cgd 1013:
1.67 thorpej 1014: cd = config_cfdriver_lookup(cf->cf_name);
1.117 drochner 1015: if (cd == NULL)
1.175 cegger 1016: return NULL;
1.76 thorpej 1017:
1018: ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
1.117 drochner 1019: if (ca == NULL)
1.175 cegger 1020: return NULL;
1.76 thorpej 1021:
1.120 joerg 1022: if ((ca->ca_flags & DVF_PRIV_ALLOC) == 0 &&
1023: ca->ca_devsize < sizeof(struct device))
1.140 matt 1024: panic("config_devalloc: %s", cf->cf_atname);
1.66 thorpej 1025:
1.46 cgd 1026: #ifndef __BROKEN_CONFIG_UNIT_USAGE
1.45 cgd 1027: if (cf->cf_fstate == FSTATE_STAR) {
1028: for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
1029: if (cd->cd_devs[myunit] == NULL)
1030: break;
1031: /*
1032: * myunit is now the unit of the first NULL device pointer,
1033: * or max(cd->cd_ndevs,cf->cf_unit).
1034: */
1035: } else {
1036: myunit = cf->cf_unit;
1.117 drochner 1037: if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
1.175 cegger 1038: return NULL;
1.117 drochner 1039: }
1.66 thorpej 1040: #else
1.46 cgd 1041: myunit = cf->cf_unit;
1.66 thorpej 1042: #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
1.25 cgd 1043:
1044: /* compute length of name and decimal expansion of unit number */
1045: lname = strlen(cd->cd_name);
1.30 perry 1046: xunit = number(&num[sizeof(num)], myunit);
1047: lunit = &num[sizeof(num)] - xunit;
1.64 drochner 1048: if (lname + lunit > sizeof(dev->dv_xname))
1.117 drochner 1049: panic("config_devalloc: device name too long");
1.25 cgd 1050:
1051: /* get memory for all device vars */
1.132 matt 1052: KASSERT((ca->ca_flags & DVF_PRIV_ALLOC) || ca->ca_devsize >= sizeof(struct device));
1053: if (ca->ca_devsize > 0) {
1.166 ad 1054: dev_private = kmem_zalloc(ca->ca_devsize, KM_SLEEP);
1.132 matt 1055: if (dev_private == NULL)
1056: panic("config_devalloc: memory allocation for device softc failed");
1057: } else {
1058: KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
1059: dev_private = NULL;
1060: }
1.120 joerg 1061:
1062: if ((ca->ca_flags & DVF_PRIV_ALLOC) != 0) {
1.166 ad 1063: dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
1.120 joerg 1064: } else {
1065: dev = dev_private;
1066: }
1067: if (dev == NULL)
1068: panic("config_devalloc: memory allocation for device_t failed");
1.124 jmcneill 1069:
1.174 dyoung 1070: dvl = device_getlock(dev);
1071:
1072: mutex_init(&dvl->dvl_mtx, MUTEX_DEFAULT, IPL_NONE);
1073: cv_init(&dvl->dvl_cv, "pmfsusp");
1074:
1.25 cgd 1075: dev->dv_class = cd->cd_class;
1076: dev->dv_cfdata = cf;
1.76 thorpej 1077: dev->dv_cfdriver = cd;
1078: dev->dv_cfattach = ca;
1.25 cgd 1079: dev->dv_unit = myunit;
1.124 jmcneill 1080: dev->dv_activity_count = 0;
1081: dev->dv_activity_handlers = NULL;
1.120 joerg 1082: dev->dv_private = dev_private;
1.31 perry 1083: memcpy(dev->dv_xname, cd->cd_name, lname);
1084: memcpy(dev->dv_xname + lname, xunit, lunit);
1.25 cgd 1085: dev->dv_parent = parent;
1.124 jmcneill 1086: if (parent != NULL)
1087: dev->dv_depth = parent->dv_depth + 1;
1088: else
1089: dev->dv_depth = 0;
1.33 thorpej 1090: dev->dv_flags = DVF_ACTIVE; /* always initially active */
1.120 joerg 1091: dev->dv_flags |= ca->ca_flags; /* inherit flags from class */
1.97 drochner 1092: if (locs) {
1.96 drochner 1093: KASSERT(parent); /* no locators at root */
1094: ia = cfiattr_lookup(cf->cf_pspec->cfp_iattr,
1095: parent->dv_cfdriver);
1.159 matt 1096: dev->dv_locators =
1.166 ad 1097: kmem_alloc(sizeof(int [ia->ci_loclen + 1]), KM_SLEEP);
1.159 matt 1098: *dev->dv_locators++ = sizeof(int [ia->ci_loclen + 1]);
1099: memcpy(dev->dv_locators, locs, sizeof(int [ia->ci_loclen]));
1.90 drochner 1100: }
1.112 thorpej 1101: dev->dv_properties = prop_dictionary_create();
1102: KASSERT(dev->dv_properties != NULL);
1.29 thorpej 1103:
1.150 jmcneill 1104: prop_dictionary_set_cstring_nocopy(dev->dv_properties,
1105: "device-driver", dev->dv_cfdriver->cd_name);
1106: prop_dictionary_set_uint16(dev->dv_properties,
1107: "device-unit", dev->dv_unit);
1108:
1.175 cegger 1109: return dev;
1.117 drochner 1110: }
1111:
1112: static void
1113: config_devdealloc(device_t dev)
1114: {
1.174 dyoung 1115: device_lock_t dvl = device_getlock(dev);
1.162 drochner 1116: int priv = (dev->dv_flags & DVF_PRIV_ALLOC);
1.117 drochner 1117:
1.174 dyoung 1118: cv_destroy(&dvl->dvl_cv);
1119: mutex_destroy(&dvl->dvl_mtx);
1120:
1.117 drochner 1121: KASSERT(dev->dv_properties != NULL);
1122: prop_object_release(dev->dv_properties);
1123:
1.124 jmcneill 1124: if (dev->dv_activity_handlers)
1125: panic("config_devdealloc with registered handlers");
1126:
1.159 matt 1127: if (dev->dv_locators) {
1128: size_t amount = *--dev->dv_locators;
1129: kmem_free(dev->dv_locators, amount);
1130: }
1.117 drochner 1131:
1.162 drochner 1132: if (dev->dv_cfattach->ca_devsize > 0)
1.159 matt 1133: kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize);
1.162 drochner 1134: if (priv)
1135: kmem_free(dev, sizeof(*dev));
1.117 drochner 1136: }
1137:
1138: /*
1139: * Attach a found device.
1140: */
1141: device_t
1142: config_attach_loc(device_t parent, cfdata_t cf,
1143: const int *locs, void *aux, cfprint_t print)
1144: {
1145: device_t dev;
1146: struct cftable *ct;
1147: const char *drvname;
1148:
1149: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1150: if (splash_progress_state)
1151: splash_progress_update(splash_progress_state);
1152: #endif
1153:
1154: dev = config_devalloc(parent, cf, locs);
1155: if (!dev)
1156: panic("config_attach: allocation of device softc failed");
1157:
1158: /* XXX redundant - see below? */
1159: if (cf->cf_fstate != FSTATE_STAR) {
1160: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1161: cf->cf_fstate = FSTATE_FOUND;
1162: }
1163: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1164: else
1165: cf->cf_unit++;
1166: #endif
1167:
1168: config_devlink(dev);
1169:
1.176 ad 1170: if (config_do_twiddle && cold)
1.80 thorpej 1171: twiddle();
1172: else
1173: aprint_naive("Found ");
1174: /*
1175: * We want the next two printfs for normal, verbose, and quiet,
1176: * but not silent (in which case, we're twiddling, instead).
1177: */
1178: if (parent == ROOT) {
1.143 cegger 1179: aprint_naive("%s (root)", device_xname(dev));
1180: aprint_normal("%s (root)", device_xname(dev));
1.80 thorpej 1181: } else {
1.143 cegger 1182: aprint_naive("%s at %s", device_xname(dev), device_xname(parent));
1183: aprint_normal("%s at %s", device_xname(dev), device_xname(parent));
1.25 cgd 1184: if (print)
1.52 cgd 1185: (void) (*print)(aux, NULL);
1.25 cgd 1186: }
1187:
1188: /*
1189: * Before attaching, clobber any unfound devices that are
1.45 cgd 1190: * otherwise identical.
1.117 drochner 1191: * XXX code above is redundant?
1.25 cgd 1192: */
1.117 drochner 1193: drvname = dev->dv_cfdriver->cd_name;
1.65 thorpej 1194: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1195: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.117 drochner 1196: if (STREQ(cf->cf_name, drvname) &&
1.65 thorpej 1197: cf->cf_unit == dev->dv_unit) {
1198: if (cf->cf_fstate == FSTATE_NOTFOUND)
1199: cf->cf_fstate = FSTATE_FOUND;
1.46 cgd 1200: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.66 thorpej 1201: /*
1202: * Bump the unit number on all starred cfdata
1203: * entries for this device.
1204: */
1.65 thorpej 1205: if (cf->cf_fstate == FSTATE_STAR)
1206: cf->cf_unit++;
1.46 cgd 1207: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.65 thorpej 1208: }
1.25 cgd 1209: }
1.65 thorpej 1210: }
1.49 danw 1211: #ifdef __HAVE_DEVICE_REGISTER
1.25 cgd 1212: device_register(dev, aux);
1213: #endif
1.124 jmcneill 1214:
1.149 jmcneill 1215: /* Let userland know */
1216: devmon_report_device(dev, true);
1217:
1.105 jmcneill 1218: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1219: if (splash_progress_state)
1220: splash_progress_update(splash_progress_state);
1221: #endif
1.117 drochner 1222: (*dev->dv_cfattach->ca_attach)(parent, dev, aux);
1.105 jmcneill 1223: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
1224: if (splash_progress_state)
1225: splash_progress_update(splash_progress_state);
1226: #endif
1.124 jmcneill 1227:
1228: if (!device_pmf_is_registered(dev))
1.125 jmcneill 1229: aprint_debug_dev(dev, "WARNING: power management not supported\n");
1.124 jmcneill 1230:
1.42 thorpej 1231: config_process_deferred(&deferred_config_queue, dev);
1.175 cegger 1232: return dev;
1.25 cgd 1233: }
1.29 thorpej 1234:
1.102 thorpej 1235: device_t
1236: config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print)
1237: {
1238:
1.175 cegger 1239: return config_attach_loc(parent, cf, NULL, aux, print);
1.102 thorpej 1240: }
1241:
1.29 thorpej 1242: /*
1.77 thorpej 1243: * As above, but for pseudo-devices. Pseudo-devices attached in this
1244: * way are silently inserted into the device tree, and their children
1245: * attached.
1246: *
1247: * Note that because pseudo-devices are attached silently, any information
1248: * the attach routine wishes to print should be prefixed with the device
1249: * name by the attach routine.
1250: */
1.102 thorpej 1251: device_t
1252: config_attach_pseudo(cfdata_t cf)
1.77 thorpej 1253: {
1.102 thorpej 1254: device_t dev;
1.77 thorpej 1255:
1.117 drochner 1256: dev = config_devalloc(ROOT, cf, NULL);
1257: if (!dev)
1.175 cegger 1258: return NULL;
1.77 thorpej 1259:
1.117 drochner 1260: /* XXX mark busy in cfdata */
1.77 thorpej 1261:
1.170 dyoung 1262: if (cf->cf_fstate != FSTATE_STAR) {
1263: KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
1264: cf->cf_fstate = FSTATE_FOUND;
1265: }
1266:
1.117 drochner 1267: config_devlink(dev);
1.77 thorpej 1268:
1269: #if 0 /* XXXJRT not yet */
1270: #ifdef __HAVE_DEVICE_REGISTER
1271: device_register(dev, NULL); /* like a root node */
1272: #endif
1273: #endif
1.117 drochner 1274: (*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
1.77 thorpej 1275: config_process_deferred(&deferred_config_queue, dev);
1.175 cegger 1276: return dev;
1.77 thorpej 1277: }
1278:
1279: /*
1.33 thorpej 1280: * Detach a device. Optionally forced (e.g. because of hardware
1281: * removal) and quiet. Returns zero if successful, non-zero
1282: * (an error code) otherwise.
1283: *
1284: * Note that this code wants to be run from a process context, so
1285: * that the detach can sleep to allow processes which have a device
1286: * open to run and unwind their stacks.
1287: */
1288: int
1.102 thorpej 1289: config_detach(device_t dev, int flags)
1.33 thorpej 1290: {
1.65 thorpej 1291: struct cftable *ct;
1.102 thorpej 1292: cfdata_t cf;
1.73 thorpej 1293: const struct cfattach *ca;
1.33 thorpej 1294: struct cfdriver *cd;
1295: #ifdef DIAGNOSTIC
1.102 thorpej 1296: device_t d;
1.33 thorpej 1297: #endif
1.117 drochner 1298: int rv = 0;
1.33 thorpej 1299:
1300: #ifdef DIAGNOSTIC
1.161 christos 1301: cf = dev->dv_cfdata;
1302: if (cf != NULL && cf->cf_fstate != FSTATE_FOUND &&
1303: cf->cf_fstate != FSTATE_STAR)
1304: panic("config_detach: %s: bad device fstate %d",
1305: device_xname(dev), cf ? cf->cf_fstate : -1);
1.33 thorpej 1306: #endif
1.77 thorpej 1307: cd = dev->dv_cfdriver;
1.67 thorpej 1308: KASSERT(cd != NULL);
1.76 thorpej 1309:
1.77 thorpej 1310: ca = dev->dv_cfattach;
1.76 thorpej 1311: KASSERT(ca != NULL);
1.33 thorpej 1312:
1.136 dyoung 1313: KASSERT(curlwp != NULL);
1314: mutex_enter(&alldevs_mtx);
1315: if (alldevs_nwrite > 0 && alldevs_writer == NULL)
1316: ;
1317: else while (alldevs_nread != 0 ||
1318: (alldevs_nwrite != 0 && alldevs_writer != curlwp))
1319: cv_wait(&alldevs_cv, &alldevs_mtx);
1320: if (alldevs_nwrite++ == 0)
1321: alldevs_writer = curlwp;
1322: mutex_exit(&alldevs_mtx);
1323:
1.33 thorpej 1324: /*
1325: * Ensure the device is deactivated. If the device doesn't
1326: * have an activation entry point, we allow DVF_ACTIVE to
1327: * remain set. Otherwise, if DVF_ACTIVE is still set, the
1328: * device is busy, and the detach fails.
1329: */
1.174 dyoung 1330: if (!detachall &&
1331: (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN &&
1332: (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) {
1.183 ! dyoung 1333: rv = EOPNOTSUPP;
1.177 dyoung 1334: } else if ((rv = config_deactivate(dev)) == EOPNOTSUPP)
1335: rv = 0; /* Do not treat EOPNOTSUPP as an error */
1.33 thorpej 1336:
1337: /*
1338: * Try to detach the device. If that's not possible, then
1339: * we either panic() (for the forced but failed case), or
1340: * return an error.
1341: */
1342: if (rv == 0) {
1343: if (ca->ca_detach != NULL)
1344: rv = (*ca->ca_detach)(dev, flags);
1345: else
1346: rv = EOPNOTSUPP;
1347: }
1348: if (rv != 0) {
1349: if ((flags & DETACH_FORCE) == 0)
1.136 dyoung 1350: goto out;
1.33 thorpej 1351: else
1352: panic("config_detach: forced detach of %s failed (%d)",
1.143 cegger 1353: device_xname(dev), rv);
1.33 thorpej 1354: }
1355:
1.171 dyoung 1356: dev->dv_flags &= ~DVF_ACTIVE;
1357:
1.33 thorpej 1358: /*
1359: * The device has now been successfully detached.
1360: */
1361:
1.149 jmcneill 1362: /* Let userland know */
1363: devmon_report_device(dev, false);
1364:
1.33 thorpej 1365: #ifdef DIAGNOSTIC
1366: /*
1367: * Sanity: If you're successfully detached, you should have no
1368: * children. (Note that because children must be attached
1369: * after parents, we only need to search the latter part of
1370: * the list.)
1371: */
1372: for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1.48 enami 1373: d = TAILQ_NEXT(d, dv_list)) {
1374: if (d->dv_parent == dev) {
1375: printf("config_detach: detached device %s"
1.143 cegger 1376: " has children %s\n", device_xname(dev), device_xname(d));
1.48 enami 1377: panic("config_detach");
1378: }
1.33 thorpej 1379: }
1380: #endif
1381:
1.90 drochner 1382: /* notify the parent that the child is gone */
1383: if (dev->dv_parent) {
1.102 thorpej 1384: device_t p = dev->dv_parent;
1.90 drochner 1385: if (p->dv_cfattach->ca_childdetached)
1386: (*p->dv_cfattach->ca_childdetached)(p, dev);
1387: }
1388:
1.33 thorpej 1389: /*
1390: * Mark cfdata to show that the unit can be reused, if possible.
1391: */
1.65 thorpej 1392: TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67 thorpej 1393: for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1394: if (STREQ(cf->cf_name, cd->cd_name)) {
1.65 thorpej 1395: if (cf->cf_fstate == FSTATE_FOUND &&
1396: cf->cf_unit == dev->dv_unit)
1397: cf->cf_fstate = FSTATE_NOTFOUND;
1.46 cgd 1398: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.66 thorpej 1399: /*
1400: * Note that we can only re-use a starred
1401: * unit number if the unit being detached
1402: * had the last assigned unit number.
1403: */
1.65 thorpej 1404: if (cf->cf_fstate == FSTATE_STAR &&
1405: cf->cf_unit == dev->dv_unit + 1)
1406: cf->cf_unit--;
1.46 cgd 1407: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.65 thorpej 1408: }
1.33 thorpej 1409: }
1410: }
1411:
1.117 drochner 1412: config_devunlink(dev);
1.33 thorpej 1413:
1.77 thorpej 1414: if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1.136 dyoung 1415: aprint_normal_dev(dev, "detached\n");
1.33 thorpej 1416:
1.117 drochner 1417: config_devdealloc(dev);
1.33 thorpej 1418:
1.136 dyoung 1419: out:
1420: mutex_enter(&alldevs_mtx);
1.178 dyoung 1421: KASSERT(alldevs_nwrite != 0);
1.136 dyoung 1422: if (--alldevs_nwrite == 0)
1423: alldevs_writer = NULL;
1424: cv_signal(&alldevs_cv);
1425: mutex_exit(&alldevs_mtx);
1426: return rv;
1.33 thorpej 1427: }
1428:
1.126 dyoung 1429: int
1430: config_detach_children(device_t parent, int flags)
1431: {
1.130 drochner 1432: device_t dv;
1.136 dyoung 1433: deviter_t di;
1434: int error = 0;
1.126 dyoung 1435:
1.136 dyoung 1436: for (dv = deviter_first(&di, DEVITER_F_RW); dv != NULL;
1437: dv = deviter_next(&di)) {
1438: if (device_parent(dv) != parent)
1439: continue;
1440: if ((error = config_detach(dv, flags)) != 0)
1.130 drochner 1441: break;
1.136 dyoung 1442: }
1443: deviter_release(&di);
1.130 drochner 1444: return error;
1.126 dyoung 1445: }
1446:
1.178 dyoung 1447: device_t
1448: shutdown_first(struct shutdown_state *s)
1449: {
1450: if (!s->initialized) {
1451: deviter_init(&s->di, DEVITER_F_SHUTDOWN|DEVITER_F_LEAVES_FIRST);
1452: s->initialized = true;
1453: }
1454: return shutdown_next(s);
1455: }
1456:
1457: device_t
1458: shutdown_next(struct shutdown_state *s)
1459: {
1460: device_t dv;
1461:
1462: while ((dv = deviter_next(&s->di)) != NULL && !device_is_active(dv))
1463: ;
1464:
1465: if (dv == NULL)
1466: s->initialized = false;
1467:
1468: return dv;
1469: }
1470:
1471: bool
1472: config_detach_all(int how)
1473: {
1474: static struct shutdown_state s;
1475: device_t curdev;
1476: bool progress = false;
1477:
1478: if ((how & RB_NOSYNC) != 0)
1479: return false;
1480:
1481: for (curdev = shutdown_first(&s); curdev != NULL;
1482: curdev = shutdown_next(&s)) {
1483: aprint_debug(" detaching %s, ", device_xname(curdev));
1484: if (config_detach(curdev, DETACH_SHUTDOWN) == 0) {
1485: progress = true;
1486: aprint_debug("success.");
1487: } else
1488: aprint_debug("failed.");
1489: }
1490: return progress;
1491: }
1492:
1.33 thorpej 1493: int
1.102 thorpej 1494: config_activate(device_t dev)
1.33 thorpej 1495: {
1.76 thorpej 1496: const struct cfattach *ca = dev->dv_cfattach;
1.34 thorpej 1497: int rv = 0, oflags = dev->dv_flags;
1.33 thorpej 1498:
1499: if (ca->ca_activate == NULL)
1.175 cegger 1500: return EOPNOTSUPP;
1.33 thorpej 1501:
1502: if ((dev->dv_flags & DVF_ACTIVE) == 0) {
1503: dev->dv_flags |= DVF_ACTIVE;
1504: rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
1.34 thorpej 1505: if (rv)
1506: dev->dv_flags = oflags;
1.33 thorpej 1507: }
1.175 cegger 1508: return rv;
1.33 thorpej 1509: }
1510:
1511: int
1.102 thorpej 1512: config_deactivate(device_t dev)
1.33 thorpej 1513: {
1.76 thorpej 1514: const struct cfattach *ca = dev->dv_cfattach;
1.34 thorpej 1515: int rv = 0, oflags = dev->dv_flags;
1.33 thorpej 1516:
1517: if (ca->ca_activate == NULL)
1.175 cegger 1518: return EOPNOTSUPP;
1.33 thorpej 1519:
1520: if (dev->dv_flags & DVF_ACTIVE) {
1521: dev->dv_flags &= ~DVF_ACTIVE;
1522: rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
1.34 thorpej 1523: if (rv)
1524: dev->dv_flags = oflags;
1.33 thorpej 1525: }
1.175 cegger 1526: return rv;
1.33 thorpej 1527: }
1528:
1529: /*
1.29 thorpej 1530: * Defer the configuration of the specified device until all
1531: * of its parent's devices have been attached.
1532: */
1533: void
1.102 thorpej 1534: config_defer(device_t dev, void (*func)(device_t))
1.29 thorpej 1535: {
1536: struct deferred_config *dc;
1537:
1538: if (dev->dv_parent == NULL)
1539: panic("config_defer: can't defer config of a root device");
1540:
1541: #ifdef DIAGNOSTIC
1542: for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
1543: dc = TAILQ_NEXT(dc, dc_queue)) {
1544: if (dc->dc_dev == dev)
1545: panic("config_defer: deferred twice");
1546: }
1547: #endif
1548:
1.166 ad 1549: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
1.43 thorpej 1550: if (dc == NULL)
1551: panic("config_defer: unable to allocate callback");
1.29 thorpej 1552:
1553: dc->dc_dev = dev;
1554: dc->dc_func = func;
1555: TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1.47 thorpej 1556: config_pending_incr();
1.29 thorpej 1557: }
1558:
1559: /*
1.42 thorpej 1560: * Defer some autoconfiguration for a device until after interrupts
1561: * are enabled.
1562: */
1563: void
1.102 thorpej 1564: config_interrupts(device_t dev, void (*func)(device_t))
1.42 thorpej 1565: {
1566: struct deferred_config *dc;
1567:
1568: /*
1569: * If interrupts are enabled, callback now.
1570: */
1.43 thorpej 1571: if (cold == 0) {
1.42 thorpej 1572: (*func)(dev);
1573: return;
1574: }
1575:
1576: #ifdef DIAGNOSTIC
1577: for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
1578: dc = TAILQ_NEXT(dc, dc_queue)) {
1579: if (dc->dc_dev == dev)
1580: panic("config_interrupts: deferred twice");
1581: }
1582: #endif
1583:
1.166 ad 1584: dc = kmem_alloc(sizeof(*dc), KM_SLEEP);
1.43 thorpej 1585: if (dc == NULL)
1586: panic("config_interrupts: unable to allocate callback");
1.42 thorpej 1587:
1588: dc->dc_dev = dev;
1589: dc->dc_func = func;
1590: TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1.47 thorpej 1591: config_pending_incr();
1.42 thorpej 1592: }
1593:
1594: /*
1595: * Process a deferred configuration queue.
1.29 thorpej 1596: */
1597: static void
1.51 cgd 1598: config_process_deferred(struct deferred_config_head *queue,
1.102 thorpej 1599: device_t parent)
1.29 thorpej 1600: {
1601: struct deferred_config *dc, *ndc;
1602:
1.42 thorpej 1603: for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
1.29 thorpej 1604: ndc = TAILQ_NEXT(dc, dc_queue);
1.42 thorpej 1605: if (parent == NULL || dc->dc_dev->dv_parent == parent) {
1606: TAILQ_REMOVE(queue, dc, dc_queue);
1.29 thorpej 1607: (*dc->dc_func)(dc->dc_dev);
1.159 matt 1608: kmem_free(dc, sizeof(*dc));
1.47 thorpej 1609: config_pending_decr();
1.29 thorpej 1610: }
1611: }
1.47 thorpej 1612: }
1613:
1614: /*
1615: * Manipulate the config_pending semaphore.
1616: */
1617: void
1.51 cgd 1618: config_pending_incr(void)
1.47 thorpej 1619: {
1620:
1.151 ad 1621: mutex_enter(&config_misc_lock);
1.47 thorpej 1622: config_pending++;
1.151 ad 1623: mutex_exit(&config_misc_lock);
1.47 thorpej 1624: }
1625:
1626: void
1.51 cgd 1627: config_pending_decr(void)
1.47 thorpej 1628: {
1629:
1630: #ifdef DIAGNOSTIC
1631: if (config_pending == 0)
1632: panic("config_pending_decr: config_pending == 0");
1633: #endif
1.151 ad 1634: mutex_enter(&config_misc_lock);
1.47 thorpej 1635: config_pending--;
1636: if (config_pending == 0)
1.151 ad 1637: cv_broadcast(&config_misc_cv);
1638: mutex_exit(&config_misc_lock);
1.75 thorpej 1639: }
1640:
1641: /*
1642: * Register a "finalization" routine. Finalization routines are
1643: * called iteratively once all real devices have been found during
1644: * autoconfiguration, for as long as any one finalizer has done
1645: * any work.
1646: */
1647: int
1.102 thorpej 1648: config_finalize_register(device_t dev, int (*fn)(device_t))
1.75 thorpej 1649: {
1650: struct finalize_hook *f;
1651:
1652: /*
1653: * If finalization has already been done, invoke the
1654: * callback function now.
1655: */
1656: if (config_finalize_done) {
1657: while ((*fn)(dev) != 0)
1658: /* loop */ ;
1659: }
1660:
1661: /* Ensure this isn't already on the list. */
1662: TAILQ_FOREACH(f, &config_finalize_list, f_list) {
1663: if (f->f_func == fn && f->f_dev == dev)
1.175 cegger 1664: return EEXIST;
1.75 thorpej 1665: }
1666:
1.159 matt 1667: f = kmem_alloc(sizeof(*f), KM_SLEEP);
1.75 thorpej 1668: f->f_func = fn;
1669: f->f_dev = dev;
1670: TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
1671:
1.175 cegger 1672: return 0;
1.75 thorpej 1673: }
1674:
1675: void
1676: config_finalize(void)
1677: {
1678: struct finalize_hook *f;
1.142 ad 1679: struct pdevinit *pdev;
1680: extern struct pdevinit pdevinit[];
1681: int errcnt, rv;
1682:
1683: /*
1684: * Now that device driver threads have been created, wait for
1685: * them to finish any deferred autoconfiguration.
1686: */
1.151 ad 1687: mutex_enter(&config_misc_lock);
1688: while (config_pending != 0)
1689: cv_wait(&config_misc_cv, &config_misc_lock);
1690: mutex_exit(&config_misc_lock);
1.142 ad 1691:
1.167 ad 1692: KERNEL_LOCK(1, NULL);
1693:
1.142 ad 1694: /* Attach pseudo-devices. */
1695: for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
1696: (*pdev->pdev_attach)(pdev->pdev_count);
1.75 thorpej 1697:
1698: /* Run the hooks until none of them does any work. */
1699: do {
1700: rv = 0;
1701: TAILQ_FOREACH(f, &config_finalize_list, f_list)
1702: rv |= (*f->f_func)(f->f_dev);
1703: } while (rv != 0);
1704:
1705: config_finalize_done = 1;
1706:
1707: /* Now free all the hooks. */
1708: while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
1709: TAILQ_REMOVE(&config_finalize_list, f, f_list);
1.159 matt 1710: kmem_free(f, sizeof(*f));
1.79 thorpej 1711: }
1.142 ad 1712:
1.167 ad 1713: KERNEL_UNLOCK_ONE(NULL);
1714:
1.142 ad 1715: errcnt = aprint_get_error_count();
1716: if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
1717: (boothowto & AB_VERBOSE) == 0) {
1.176 ad 1718: mutex_enter(&config_misc_lock);
1.142 ad 1719: if (config_do_twiddle) {
1720: config_do_twiddle = 0;
1.169 ad 1721: printf_nolog(" done.\n");
1.142 ad 1722: }
1.176 ad 1723: mutex_exit(&config_misc_lock);
1.142 ad 1724: if (errcnt != 0) {
1725: printf("WARNING: %d error%s while detecting hardware; "
1726: "check system log.\n", errcnt,
1727: errcnt == 1 ? "" : "s");
1728: }
1729: }
1.79 thorpej 1730: }
1731:
1.176 ad 1732: void
1.180 pooka 1733: config_twiddle_init()
1734: {
1735:
1736: if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
1737: config_do_twiddle = 1;
1738: }
1739: callout_setfunc(&config_twiddle_ch, config_twiddle_fn, NULL);
1740: }
1741:
1742: void
1.176 ad 1743: config_twiddle_fn(void *cookie)
1744: {
1745:
1746: mutex_enter(&config_misc_lock);
1747: if (config_do_twiddle) {
1748: twiddle();
1749: callout_schedule(&config_twiddle_ch, mstohz(100));
1750: }
1751: mutex_exit(&config_misc_lock);
1752: }
1753:
1.104 thorpej 1754: /*
1.107 thorpej 1755: * device_lookup:
1756: *
1757: * Look up a device instance for a given driver.
1758: */
1.156 drochner 1759: device_t
1.107 thorpej 1760: device_lookup(cfdriver_t cd, int unit)
1761: {
1762:
1763: if (unit < 0 || unit >= cd->cd_ndevs)
1.175 cegger 1764: return NULL;
1.107 thorpej 1765:
1.175 cegger 1766: return cd->cd_devs[unit];
1.107 thorpej 1767: }
1768:
1769: /*
1.140 matt 1770: * device_lookup:
1771: *
1772: * Look up a device instance for a given driver.
1773: */
1774: void *
1775: device_lookup_private(cfdriver_t cd, int unit)
1776: {
1777: device_t dv;
1778:
1779: if (unit < 0 || unit >= cd->cd_ndevs)
1780: return NULL;
1781:
1782: if ((dv = cd->cd_devs[unit]) == NULL)
1783: return NULL;
1784:
1785: return dv->dv_private;
1786: }
1787:
1788: /*
1.107 thorpej 1789: * Accessor functions for the device_t type.
1790: */
1791: devclass_t
1792: device_class(device_t dev)
1793: {
1794:
1.175 cegger 1795: return dev->dv_class;
1.107 thorpej 1796: }
1797:
1798: cfdata_t
1799: device_cfdata(device_t dev)
1800: {
1801:
1.175 cegger 1802: return dev->dv_cfdata;
1.107 thorpej 1803: }
1804:
1805: cfdriver_t
1806: device_cfdriver(device_t dev)
1807: {
1808:
1.175 cegger 1809: return dev->dv_cfdriver;
1.107 thorpej 1810: }
1811:
1812: cfattach_t
1813: device_cfattach(device_t dev)
1814: {
1815:
1.175 cegger 1816: return dev->dv_cfattach;
1.107 thorpej 1817: }
1818:
1819: int
1820: device_unit(device_t dev)
1821: {
1822:
1.175 cegger 1823: return dev->dv_unit;
1.107 thorpej 1824: }
1825:
1826: const char *
1827: device_xname(device_t dev)
1828: {
1829:
1.175 cegger 1830: return dev->dv_xname;
1.107 thorpej 1831: }
1832:
1833: device_t
1834: device_parent(device_t dev)
1835: {
1836:
1.175 cegger 1837: return dev->dv_parent;
1.107 thorpej 1838: }
1839:
1.116 thorpej 1840: bool
1.183 ! dyoung 1841: device_activation(device_t dev, devact_level_t level)
! 1842: {
! 1843: int active_flags;
! 1844:
! 1845: active_flags = DVF_ACTIVE;
! 1846: switch (level) {
! 1847: case DEVACT_LEVEL_FULL:
! 1848: active_flags |= DVF_CLASS_SUSPENDED;
! 1849: /*FALLTHROUGH*/
! 1850: case DEVACT_LEVEL_DRIVER:
! 1851: active_flags |= DVF_DRIVER_SUSPENDED;
! 1852: /*FALLTHROUGH*/
! 1853: case DEVACT_LEVEL_BUS:
! 1854: active_flags |= DVF_BUS_SUSPENDED;
! 1855: break;
! 1856: }
! 1857:
! 1858: return (dev->dv_flags & active_flags) == DVF_ACTIVE;
! 1859: }
! 1860:
! 1861: bool
1.107 thorpej 1862: device_is_active(device_t dev)
1863: {
1.124 jmcneill 1864: int active_flags;
1865:
1866: active_flags = DVF_ACTIVE;
1867: active_flags |= DVF_CLASS_SUSPENDED;
1868: active_flags |= DVF_DRIVER_SUSPENDED;
1869: active_flags |= DVF_BUS_SUSPENDED;
1870:
1.175 cegger 1871: return (dev->dv_flags & active_flags) == DVF_ACTIVE;
1.124 jmcneill 1872: }
1873:
1874: bool
1875: device_is_enabled(device_t dev)
1876: {
1877: return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
1878: }
1879:
1880: bool
1881: device_has_power(device_t dev)
1882: {
1883: int active_flags;
1884:
1885: active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
1.107 thorpej 1886:
1.175 cegger 1887: return (dev->dv_flags & active_flags) == DVF_ACTIVE;
1.107 thorpej 1888: }
1889:
1.109 thorpej 1890: int
1.111 thorpej 1891: device_locator(device_t dev, u_int locnum)
1.107 thorpej 1892: {
1893:
1.109 thorpej 1894: KASSERT(dev->dv_locators != NULL);
1.175 cegger 1895: return dev->dv_locators[locnum];
1.107 thorpej 1896: }
1.108 thorpej 1897:
1.110 thorpej 1898: void *
1899: device_private(device_t dev)
1900: {
1901:
1.134 cube 1902: /*
1903: * The reason why device_private(NULL) is allowed is to simplify the
1904: * work of a lot of userspace request handlers (i.e., c/bdev
1905: * handlers) which grab cfdriver_t->cd_units[n].
1906: * It avoids having them test for it to be NULL and only then calling
1907: * device_private.
1908: */
1909: return dev == NULL ? NULL : dev->dv_private;
1.110 thorpej 1910: }
1911:
1.112 thorpej 1912: prop_dictionary_t
1913: device_properties(device_t dev)
1914: {
1915:
1.175 cegger 1916: return dev->dv_properties;
1.112 thorpej 1917: }
1918:
1.108 thorpej 1919: /*
1920: * device_is_a:
1921: *
1922: * Returns true if the device is an instance of the specified
1923: * driver.
1924: */
1.116 thorpej 1925: bool
1.108 thorpej 1926: device_is_a(device_t dev, const char *dname)
1927: {
1928:
1.175 cegger 1929: return strcmp(dev->dv_cfdriver->cd_name, dname) == 0;
1.108 thorpej 1930: }
1.124 jmcneill 1931:
1932: /*
1.131 joerg 1933: * device_find_by_xname:
1934: *
1935: * Returns the device of the given name or NULL if it doesn't exist.
1936: */
1937: device_t
1938: device_find_by_xname(const char *name)
1939: {
1940: device_t dv;
1.136 dyoung 1941: deviter_t di;
1.131 joerg 1942:
1.136 dyoung 1943: for (dv = deviter_first(&di, 0); dv != NULL; dv = deviter_next(&di)) {
1.131 joerg 1944: if (strcmp(device_xname(dv), name) == 0)
1945: break;
1946: }
1.136 dyoung 1947: deviter_release(&di);
1.131 joerg 1948:
1949: return dv;
1950: }
1951:
1952: /*
1953: * device_find_by_driver_unit:
1954: *
1955: * Returns the device of the given driver name and unit or
1956: * NULL if it doesn't exist.
1957: */
1958: device_t
1959: device_find_by_driver_unit(const char *name, int unit)
1960: {
1961: struct cfdriver *cd;
1962:
1963: if ((cd = config_cfdriver_lookup(name)) == NULL)
1964: return NULL;
1965: return device_lookup(cd, unit);
1966: }
1967:
1968: /*
1.124 jmcneill 1969: * Power management related functions.
1970: */
1971:
1972: bool
1973: device_pmf_is_registered(device_t dev)
1974: {
1975: return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
1976: }
1977:
1978: bool
1.135 dyoung 1979: device_pmf_driver_suspend(device_t dev PMF_FN_ARGS)
1.124 jmcneill 1980: {
1981: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
1982: return true;
1983: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
1984: return false;
1.183 ! dyoung 1985: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_DRIVER &&
! 1986: dev->dv_driver_suspend != NULL &&
1.135 dyoung 1987: !(*dev->dv_driver_suspend)(dev PMF_FN_CALL))
1.124 jmcneill 1988: return false;
1989:
1990: dev->dv_flags |= DVF_DRIVER_SUSPENDED;
1991: return true;
1992: }
1993:
1994: bool
1.135 dyoung 1995: device_pmf_driver_resume(device_t dev PMF_FN_ARGS)
1.124 jmcneill 1996: {
1997: if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
1998: return true;
1999: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
2000: return false;
1.183 ! dyoung 2001: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_DRIVER &&
! 2002: dev->dv_driver_resume != NULL &&
1.135 dyoung 2003: !(*dev->dv_driver_resume)(dev PMF_FN_CALL))
1.124 jmcneill 2004: return false;
2005:
2006: dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
2007: return true;
2008: }
2009:
1.133 drochner 2010: bool
2011: device_pmf_driver_shutdown(device_t dev, int how)
2012: {
2013:
2014: if (*dev->dv_driver_shutdown != NULL &&
2015: !(*dev->dv_driver_shutdown)(dev, how))
2016: return false;
2017: return true;
2018: }
2019:
1.135 dyoung 2020: bool
1.124 jmcneill 2021: device_pmf_driver_register(device_t dev,
1.135 dyoung 2022: bool (*suspend)(device_t PMF_FN_PROTO),
2023: bool (*resume)(device_t PMF_FN_PROTO),
1.133 drochner 2024: bool (*shutdown)(device_t, int))
1.124 jmcneill 2025: {
2026: dev->dv_driver_suspend = suspend;
2027: dev->dv_driver_resume = resume;
1.133 drochner 2028: dev->dv_driver_shutdown = shutdown;
1.124 jmcneill 2029: dev->dv_flags |= DVF_POWER_HANDLERS;
1.135 dyoung 2030: return true;
1.124 jmcneill 2031: }
2032:
1.139 dyoung 2033: static const char *
2034: curlwp_name(void)
2035: {
2036: if (curlwp->l_name != NULL)
2037: return curlwp->l_name;
2038: else
2039: return curlwp->l_proc->p_comm;
2040: }
2041:
1.124 jmcneill 2042: void
2043: device_pmf_driver_deregister(device_t dev)
2044: {
1.174 dyoung 2045: device_lock_t dvl = device_getlock(dev);
1.157 drochner 2046:
1.124 jmcneill 2047: dev->dv_driver_suspend = NULL;
2048: dev->dv_driver_resume = NULL;
1.139 dyoung 2049:
1.174 dyoung 2050: mutex_enter(&dvl->dvl_mtx);
1.124 jmcneill 2051: dev->dv_flags &= ~DVF_POWER_HANDLERS;
1.174 dyoung 2052: while (dvl->dvl_nlock > 0 || dvl->dvl_nwait > 0) {
1.139 dyoung 2053: /* Wake a thread that waits for the lock. That
2054: * thread will fail to acquire the lock, and then
2055: * it will wake the next thread that waits for the
2056: * lock, or else it will wake us.
2057: */
1.174 dyoung 2058: cv_signal(&dvl->dvl_cv);
1.139 dyoung 2059: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2060: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.139 dyoung 2061: pmflock_debug(dev, __func__, __LINE__);
2062: }
1.174 dyoung 2063: mutex_exit(&dvl->dvl_mtx);
1.124 jmcneill 2064: }
2065:
2066: bool
2067: device_pmf_driver_child_register(device_t dev)
2068: {
2069: device_t parent = device_parent(dev);
2070:
2071: if (parent == NULL || parent->dv_driver_child_register == NULL)
2072: return true;
2073: return (*parent->dv_driver_child_register)(dev);
2074: }
2075:
2076: void
2077: device_pmf_driver_set_child_register(device_t dev,
2078: bool (*child_register)(device_t))
2079: {
2080: dev->dv_driver_child_register = child_register;
2081: }
2082:
1.139 dyoung 2083: static void
2084: pmflock_debug(device_t dev, const char *func, int line)
2085: {
1.174 dyoung 2086: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2087:
1.174 dyoung 2088: aprint_debug_dev(dev, "%s.%d, %s dvl_nlock %d dvl_nwait %d dv_flags %x\n",
2089: func, line, curlwp_name(), dvl->dvl_nlock, dvl->dvl_nwait,
1.139 dyoung 2090: dev->dv_flags);
2091: }
2092:
2093: static bool
1.183 ! dyoung 2094: device_pmf_lock1(device_t dev)
1.139 dyoung 2095: {
1.174 dyoung 2096: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2097:
1.155 dyoung 2098: while (device_pmf_is_registered(dev) &&
1.174 dyoung 2099: dvl->dvl_nlock > 0 && dvl->dvl_holder != curlwp) {
2100: dvl->dvl_nwait++;
1.183 ! dyoung 2101: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2102: cv_wait(&dvl->dvl_cv, &dvl->dvl_mtx);
1.183 ! dyoung 2103: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2104: dvl->dvl_nwait--;
1.139 dyoung 2105: }
2106: if (!device_pmf_is_registered(dev)) {
1.183 ! dyoung 2107: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 2108: /* We could not acquire the lock, but some other thread may
2109: * wait for it, also. Wake that thread.
2110: */
1.174 dyoung 2111: cv_signal(&dvl->dvl_cv);
1.139 dyoung 2112: return false;
2113: }
1.174 dyoung 2114: dvl->dvl_nlock++;
2115: dvl->dvl_holder = curlwp;
1.183 ! dyoung 2116: pmflock_debug(dev, __func__, __LINE__);
1.139 dyoung 2117: return true;
2118: }
2119:
2120: bool
1.183 ! dyoung 2121: device_pmf_lock(device_t dev)
1.139 dyoung 2122: {
2123: bool rc;
1.174 dyoung 2124: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2125:
1.174 dyoung 2126: mutex_enter(&dvl->dvl_mtx);
1.183 ! dyoung 2127: rc = device_pmf_lock1(dev);
1.174 dyoung 2128: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 2129:
2130: return rc;
2131: }
2132:
2133: void
1.183 ! dyoung 2134: device_pmf_unlock(device_t dev)
1.139 dyoung 2135: {
1.174 dyoung 2136: device_lock_t dvl = device_getlock(dev);
1.139 dyoung 2137:
1.174 dyoung 2138: KASSERT(dvl->dvl_nlock > 0);
2139: mutex_enter(&dvl->dvl_mtx);
2140: if (--dvl->dvl_nlock == 0)
2141: dvl->dvl_holder = NULL;
2142: cv_signal(&dvl->dvl_cv);
1.183 ! dyoung 2143: pmflock_debug(dev, __func__, __LINE__);
1.174 dyoung 2144: mutex_exit(&dvl->dvl_mtx);
1.139 dyoung 2145: }
2146:
1.174 dyoung 2147: device_lock_t
2148: device_getlock(device_t dev)
1.139 dyoung 2149: {
1.174 dyoung 2150: return &dev->dv_lock;
1.139 dyoung 2151: }
2152:
1.124 jmcneill 2153: void *
2154: device_pmf_bus_private(device_t dev)
2155: {
2156: return dev->dv_bus_private;
2157: }
2158:
2159: bool
1.135 dyoung 2160: device_pmf_bus_suspend(device_t dev PMF_FN_ARGS)
1.124 jmcneill 2161: {
2162: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
2163: return true;
2164: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
2165: (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
2166: return false;
1.183 ! dyoung 2167: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_BUS &&
! 2168: dev->dv_bus_suspend != NULL &&
1.135 dyoung 2169: !(*dev->dv_bus_suspend)(dev PMF_FN_CALL))
1.124 jmcneill 2170: return false;
2171:
2172: dev->dv_flags |= DVF_BUS_SUSPENDED;
2173: return true;
2174: }
2175:
2176: bool
1.135 dyoung 2177: device_pmf_bus_resume(device_t dev PMF_FN_ARGS)
1.124 jmcneill 2178: {
2179: if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
2180: return true;
1.183 ! dyoung 2181: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_BUS &&
! 2182: dev->dv_bus_resume != NULL &&
1.135 dyoung 2183: !(*dev->dv_bus_resume)(dev PMF_FN_CALL))
1.124 jmcneill 2184: return false;
2185:
2186: dev->dv_flags &= ~DVF_BUS_SUSPENDED;
2187: return true;
2188: }
2189:
1.133 drochner 2190: bool
2191: device_pmf_bus_shutdown(device_t dev, int how)
2192: {
2193:
2194: if (*dev->dv_bus_shutdown != NULL &&
2195: !(*dev->dv_bus_shutdown)(dev, how))
2196: return false;
2197: return true;
2198: }
2199:
1.124 jmcneill 2200: void
2201: device_pmf_bus_register(device_t dev, void *priv,
1.135 dyoung 2202: bool (*suspend)(device_t PMF_FN_PROTO),
2203: bool (*resume)(device_t PMF_FN_PROTO),
1.133 drochner 2204: bool (*shutdown)(device_t, int), void (*deregister)(device_t))
1.124 jmcneill 2205: {
2206: dev->dv_bus_private = priv;
2207: dev->dv_bus_resume = resume;
2208: dev->dv_bus_suspend = suspend;
1.133 drochner 2209: dev->dv_bus_shutdown = shutdown;
1.124 jmcneill 2210: dev->dv_bus_deregister = deregister;
2211: }
2212:
2213: void
2214: device_pmf_bus_deregister(device_t dev)
2215: {
2216: if (dev->dv_bus_deregister == NULL)
2217: return;
2218: (*dev->dv_bus_deregister)(dev);
2219: dev->dv_bus_private = NULL;
2220: dev->dv_bus_suspend = NULL;
2221: dev->dv_bus_resume = NULL;
2222: dev->dv_bus_deregister = NULL;
2223: }
2224:
2225: void *
2226: device_pmf_class_private(device_t dev)
2227: {
2228: return dev->dv_class_private;
2229: }
2230:
2231: bool
1.135 dyoung 2232: device_pmf_class_suspend(device_t dev PMF_FN_ARGS)
1.124 jmcneill 2233: {
2234: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
2235: return true;
1.183 ! dyoung 2236: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_CLASS &&
! 2237: dev->dv_class_suspend != NULL &&
1.135 dyoung 2238: !(*dev->dv_class_suspend)(dev PMF_FN_CALL))
1.124 jmcneill 2239: return false;
2240:
2241: dev->dv_flags |= DVF_CLASS_SUSPENDED;
2242: return true;
2243: }
2244:
2245: bool
1.135 dyoung 2246: device_pmf_class_resume(device_t dev PMF_FN_ARGS)
1.124 jmcneill 2247: {
2248: if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
2249: return true;
2250: if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
2251: (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
2252: return false;
1.183 ! dyoung 2253: if (pmf_qual_depth(PMF_FN_CALL1) <= DEVACT_LEVEL_CLASS &&
! 2254: dev->dv_class_resume != NULL &&
1.135 dyoung 2255: !(*dev->dv_class_resume)(dev PMF_FN_CALL))
1.124 jmcneill 2256: return false;
2257:
2258: dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
2259: return true;
2260: }
2261:
2262: void
2263: device_pmf_class_register(device_t dev, void *priv,
1.135 dyoung 2264: bool (*suspend)(device_t PMF_FN_PROTO),
2265: bool (*resume)(device_t PMF_FN_PROTO),
1.124 jmcneill 2266: void (*deregister)(device_t))
2267: {
2268: dev->dv_class_private = priv;
2269: dev->dv_class_suspend = suspend;
2270: dev->dv_class_resume = resume;
2271: dev->dv_class_deregister = deregister;
2272: }
2273:
2274: void
2275: device_pmf_class_deregister(device_t dev)
2276: {
2277: if (dev->dv_class_deregister == NULL)
2278: return;
2279: (*dev->dv_class_deregister)(dev);
2280: dev->dv_class_private = NULL;
2281: dev->dv_class_suspend = NULL;
2282: dev->dv_class_resume = NULL;
2283: dev->dv_class_deregister = NULL;
2284: }
2285:
2286: bool
2287: device_active(device_t dev, devactive_t type)
2288: {
2289: size_t i;
2290:
2291: if (dev->dv_activity_count == 0)
2292: return false;
2293:
1.160 matt 2294: for (i = 0; i < dev->dv_activity_count; ++i) {
2295: if (dev->dv_activity_handlers[i] == NULL)
2296: break;
1.124 jmcneill 2297: (*dev->dv_activity_handlers[i])(dev, type);
1.160 matt 2298: }
1.124 jmcneill 2299:
2300: return true;
2301: }
2302:
2303: bool
2304: device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
2305: {
2306: void (**new_handlers)(device_t, devactive_t);
2307: void (**old_handlers)(device_t, devactive_t);
1.159 matt 2308: size_t i, old_size, new_size;
1.124 jmcneill 2309: int s;
2310:
2311: old_handlers = dev->dv_activity_handlers;
1.159 matt 2312: old_size = dev->dv_activity_count;
1.124 jmcneill 2313:
1.159 matt 2314: for (i = 0; i < old_size; ++i) {
2315: KASSERT(old_handlers[i] != handler);
2316: if (old_handlers[i] == NULL) {
2317: old_handlers[i] = handler;
2318: return true;
2319: }
1.124 jmcneill 2320: }
2321:
1.159 matt 2322: new_size = old_size + 4;
2323: new_handlers = kmem_alloc(sizeof(void *[new_size]), KM_SLEEP);
1.124 jmcneill 2324:
1.159 matt 2325: memcpy(new_handlers, old_handlers, sizeof(void *[old_size]));
2326: new_handlers[old_size] = handler;
2327: memset(new_handlers + old_size + 1, 0,
2328: sizeof(int [new_size - (old_size+1)]));
1.124 jmcneill 2329:
2330: s = splhigh();
2331: dev->dv_activity_count = new_size;
2332: dev->dv_activity_handlers = new_handlers;
2333: splx(s);
2334:
2335: if (old_handlers != NULL)
1.165 macallan 2336: kmem_free(old_handlers, sizeof(void * [old_size]));
1.124 jmcneill 2337:
2338: return true;
2339: }
2340:
2341: void
2342: device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
2343: {
2344: void (**old_handlers)(device_t, devactive_t);
1.159 matt 2345: size_t i, old_size;
1.124 jmcneill 2346: int s;
2347:
2348: old_handlers = dev->dv_activity_handlers;
1.159 matt 2349: old_size = dev->dv_activity_count;
1.124 jmcneill 2350:
1.159 matt 2351: for (i = 0; i < old_size; ++i) {
1.124 jmcneill 2352: if (old_handlers[i] == handler)
2353: break;
1.159 matt 2354: if (old_handlers[i] == NULL)
2355: return; /* XXX panic? */
1.124 jmcneill 2356: }
2357:
1.159 matt 2358: if (i == old_size)
1.124 jmcneill 2359: return; /* XXX panic? */
2360:
1.159 matt 2361: for (; i < old_size - 1; ++i) {
2362: if ((old_handlers[i] = old_handlers[i + 1]) != NULL)
2363: continue;
1.124 jmcneill 2364:
1.159 matt 2365: if (i == 0) {
2366: s = splhigh();
2367: dev->dv_activity_count = 0;
2368: dev->dv_activity_handlers = NULL;
2369: splx(s);
2370: kmem_free(old_handlers, sizeof(void *[old_size]));
2371: }
2372: return;
1.124 jmcneill 2373: }
1.159 matt 2374: old_handlers[i] = NULL;
1.124 jmcneill 2375: }
1.136 dyoung 2376:
2377: /*
2378: * Device Iteration
2379: *
2380: * deviter_t: a device iterator. Holds state for a "walk" visiting
2381: * each device_t's in the device tree.
2382: *
2383: * deviter_init(di, flags): initialize the device iterator `di'
2384: * to "walk" the device tree. deviter_next(di) will return
2385: * the first device_t in the device tree, or NULL if there are
2386: * no devices.
2387: *
2388: * `flags' is one or more of DEVITER_F_RW, indicating that the
2389: * caller intends to modify the device tree by calling
2390: * config_detach(9) on devices in the order that the iterator
2391: * returns them; DEVITER_F_ROOT_FIRST, asking for the devices
2392: * nearest the "root" of the device tree to be returned, first;
2393: * DEVITER_F_LEAVES_FIRST, asking for the devices furthest from
2394: * the root of the device tree, first; and DEVITER_F_SHUTDOWN,
2395: * indicating both that deviter_init() should not respect any
2396: * locks on the device tree, and that deviter_next(di) may run
2397: * in more than one LWP before the walk has finished.
2398: *
2399: * Only one DEVITER_F_RW iterator may be in the device tree at
2400: * once.
2401: *
2402: * DEVITER_F_SHUTDOWN implies DEVITER_F_RW.
2403: *
2404: * Results are undefined if the flags DEVITER_F_ROOT_FIRST and
2405: * DEVITER_F_LEAVES_FIRST are used in combination.
2406: *
2407: * deviter_first(di, flags): initialize the device iterator `di'
2408: * and return the first device_t in the device tree, or NULL
2409: * if there are no devices. The statement
2410: *
2411: * dv = deviter_first(di);
2412: *
2413: * is shorthand for
2414: *
2415: * deviter_init(di);
2416: * dv = deviter_next(di);
2417: *
2418: * deviter_next(di): return the next device_t in the device tree,
2419: * or NULL if there are no more devices. deviter_next(di)
2420: * is undefined if `di' was not initialized with deviter_init() or
2421: * deviter_first().
2422: *
2423: * deviter_release(di): stops iteration (subsequent calls to
2424: * deviter_next() will return NULL), releases any locks and
2425: * resources held by the device iterator.
2426: *
2427: * Device iteration does not return device_t's in any particular
2428: * order. An iterator will never return the same device_t twice.
2429: * Device iteration is guaranteed to complete---i.e., if deviter_next(di)
2430: * is called repeatedly on the same `di', it will eventually return
2431: * NULL. It is ok to attach/detach devices during device iteration.
2432: */
2433: void
2434: deviter_init(deviter_t *di, deviter_flags_t flags)
2435: {
2436: device_t dv;
2437: bool rw;
2438:
2439: mutex_enter(&alldevs_mtx);
2440: if ((flags & DEVITER_F_SHUTDOWN) != 0) {
2441: flags |= DEVITER_F_RW;
2442: alldevs_nwrite++;
2443: alldevs_writer = NULL;
2444: alldevs_nread = 0;
2445: } else {
2446: rw = (flags & DEVITER_F_RW) != 0;
2447:
2448: if (alldevs_nwrite > 0 && alldevs_writer == NULL)
2449: ;
2450: else while ((alldevs_nwrite != 0 && alldevs_writer != curlwp) ||
2451: (rw && alldevs_nread != 0))
2452: cv_wait(&alldevs_cv, &alldevs_mtx);
2453:
2454: if (rw) {
2455: if (alldevs_nwrite++ == 0)
2456: alldevs_writer = curlwp;
2457: } else
2458: alldevs_nread++;
2459: }
2460: mutex_exit(&alldevs_mtx);
2461:
2462: memset(di, 0, sizeof(*di));
2463:
2464: di->di_flags = flags;
2465:
2466: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2467: case DEVITER_F_LEAVES_FIRST:
2468: TAILQ_FOREACH(dv, &alldevs, dv_list)
2469: di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth);
2470: break;
2471: case DEVITER_F_ROOT_FIRST:
2472: TAILQ_FOREACH(dv, &alldevs, dv_list)
2473: di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth);
2474: break;
2475: default:
2476: break;
2477: }
2478:
2479: deviter_reinit(di);
2480: }
2481:
2482: static void
2483: deviter_reinit(deviter_t *di)
2484: {
2485: if ((di->di_flags & DEVITER_F_RW) != 0)
2486: di->di_prev = TAILQ_LAST(&alldevs, devicelist);
2487: else
2488: di->di_prev = TAILQ_FIRST(&alldevs);
2489: }
2490:
2491: device_t
2492: deviter_first(deviter_t *di, deviter_flags_t flags)
2493: {
2494: deviter_init(di, flags);
2495: return deviter_next(di);
2496: }
2497:
2498: static device_t
2499: deviter_next1(deviter_t *di)
2500: {
2501: device_t dv;
2502:
2503: dv = di->di_prev;
2504:
2505: if (dv == NULL)
2506: ;
2507: else if ((di->di_flags & DEVITER_F_RW) != 0)
2508: di->di_prev = TAILQ_PREV(dv, devicelist, dv_list);
2509: else
2510: di->di_prev = TAILQ_NEXT(dv, dv_list);
2511:
2512: return dv;
2513: }
2514:
2515: device_t
2516: deviter_next(deviter_t *di)
2517: {
2518: device_t dv = NULL;
2519:
2520: switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) {
2521: case 0:
2522: return deviter_next1(di);
2523: case DEVITER_F_LEAVES_FIRST:
2524: while (di->di_curdepth >= 0) {
2525: if ((dv = deviter_next1(di)) == NULL) {
2526: di->di_curdepth--;
2527: deviter_reinit(di);
2528: } else if (dv->dv_depth == di->di_curdepth)
2529: break;
2530: }
2531: return dv;
2532: case DEVITER_F_ROOT_FIRST:
2533: while (di->di_curdepth <= di->di_maxdepth) {
2534: if ((dv = deviter_next1(di)) == NULL) {
2535: di->di_curdepth++;
2536: deviter_reinit(di);
2537: } else if (dv->dv_depth == di->di_curdepth)
2538: break;
2539: }
2540: return dv;
2541: default:
2542: return NULL;
2543: }
2544: }
2545:
2546: void
2547: deviter_release(deviter_t *di)
2548: {
2549: bool rw = (di->di_flags & DEVITER_F_RW) != 0;
2550:
2551: mutex_enter(&alldevs_mtx);
1.178 dyoung 2552: if (!rw) {
2553: --alldevs_nread;
2554: cv_signal(&alldevs_cv);
2555: } else if (alldevs_nwrite > 0 && alldevs_writer == NULL) {
2556: --alldevs_nwrite; /* shutting down: do not signal */
2557: } else {
2558: KASSERT(alldevs_nwrite != 0);
2559: if (--alldevs_nwrite == 0)
2560: alldevs_writer = NULL;
1.136 dyoung 2561: cv_signal(&alldevs_cv);
2562: }
2563: mutex_exit(&alldevs_mtx);
2564: }
1.174 dyoung 2565:
1.182 pooka 2566: static void
2567: sysctl_detach_setup(struct sysctllog **clog)
1.174 dyoung 2568: {
2569: const struct sysctlnode *node = NULL;
2570:
2571: sysctl_createv(clog, 0, NULL, &node,
2572: CTLFLAG_PERMANENT,
2573: CTLTYPE_NODE, "kern", NULL,
2574: NULL, 0, NULL, 0,
2575: CTL_KERN, CTL_EOL);
2576:
2577: if (node == NULL)
2578: return;
2579:
2580: sysctl_createv(clog, 0, &node, NULL,
2581: CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
2582: CTLTYPE_INT, "detachall",
2583: SYSCTL_DESCR("Detach all devices at shutdown"),
2584: NULL, 0, &detachall, 0,
2585: CTL_CREATE, CTL_EOL);
2586: }
CVSweb <webmaster@jp.NetBSD.org>