[BACK]Return to subr_autoconf.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/subr_autoconf.c, Revision 1.292

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

CVSweb <webmaster@jp.NetBSD.org>