[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.233

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

CVSweb <webmaster@jp.NetBSD.org>