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

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

CVSweb <webmaster@jp.NetBSD.org>