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

1.55.2.11! thorpej     1: /* $NetBSD: subr_autoconf.c,v 1.55.2.10 2002/12/11 06:43:07 thorpej Exp $ */
1.53      cgd         2:
                      3: /*
                      4:  * Copyright (c) 1996, 2000 Christopher G. Demetriou
                      5:  * All rights reserved.
1.54      cgd         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
                     18:  *          NetBSD Project.  See http://www.netbsd.org/ for
                     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.
                     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.54      cgd        33:  *
                     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.
                     58:  * 3. All advertising materials mentioning features or use of this software
                     59:  *    must display the following acknowledgement:
                     60:  *     This product includes software developed by the University of
                     61:  *     California, Berkeley and its contributors.
                     62:  * 4. Neither the name of the University nor the names of its contributors
                     63:  *    may be used to endorse or promote products derived from this software
                     64:  *    without specific prior written permission.
1.1       glass      65:  *
1.7       glass      66:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     67:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     68:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     69:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     70:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     71:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     72:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     73:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     74:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     75:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     76:  * SUCH DAMAGE.
1.1       glass      77:  *
1.8       cgd        78:  * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp  (LBL)
1.9       cgd        79:  *
1.28      fvdl       80:  *     @(#)subr_autoconf.c     8.3 (Berkeley) 5/17/94
1.1       glass      81:  */
                     82:
1.51      cgd        83: #include <sys/cdefs.h>
1.55.2.11! thorpej    84: __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.55.2.10 2002/12/11 06:43:07 thorpej Exp $");
1.55.2.5  nathanw    85:
                     86: #include "opt_ddb.h"
1.51      cgd        87:
1.4       mycroft    88: #include <sys/param.h>
                     89: #include <sys/device.h>
                     90: #include <sys/malloc.h>
1.17      christos   91: #include <sys/systm.h>
1.43      thorpej    92: #include <sys/kernel.h>
1.33      thorpej    93: #include <sys/errno.h>
1.47      thorpej    94: #include <sys/proc.h>
1.55.2.11! thorpej    95: #include <sys/reboot.h>
1.16      mycroft    96: #include <machine/limits.h>
1.1       glass      97:
1.55.2.2  nathanw    98: #include "opt_userconf.h"
                     99: #ifdef USERCONF
                    100: #include <sys/userconf.h>
                    101: #endif
                    102:
1.1       glass     103: /*
                    104:  * Autoconfiguration subroutines.
                    105:  */
                    106:
                    107: /*
                    108:  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
                    109:  * devices and drivers are found via these tables.
                    110:  */
                    111: extern struct cfdata cfdata[];
                    112: extern short cfroots[];
                    113:
1.55.2.8  nathanw   114: /*
                    115:  * List of all cfdriver structures.  We use this to detect duplicates
                    116:  * when other cfdrivers are loaded.
                    117:  */
                    118: struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
                    119: extern struct cfdriver * const cfdriver_list_initial[];
                    120:
                    121: /*
                    122:  * Initial list of cfattach's.
                    123:  */
                    124: extern const struct cfattachinit cfattachinit[];
                    125:
                    126: /*
                    127:  * List of cfdata tables.  We always have one such list -- the one
                    128:  * built statically when the kernel was configured.
                    129:  */
                    130: struct cftablelist allcftables;
                    131: static struct cftable initcftable;
                    132:
1.1       glass     133: #define        ROOT ((struct device *)NULL)
                    134:
1.16      mycroft   135: struct matchinfo {
                    136:        cfmatch_t fn;
                    137:        struct  device *parent;
1.25      cgd       138:        void    *aux;
                    139:        struct  cfdata *match;
                    140:        int     pri;
1.16      mycroft   141: };
1.17      christos  142:
1.51      cgd       143: static char *number(char *, int);
                    144: static void mapply(struct matchinfo *, struct cfdata *);
1.16      mycroft   145:
1.29      thorpej   146: struct deferred_config {
                    147:        TAILQ_ENTRY(deferred_config) dc_queue;
                    148:        struct device *dc_dev;
1.51      cgd       149:        void (*dc_func)(struct device *);
1.29      thorpej   150: };
                    151:
1.42      thorpej   152: TAILQ_HEAD(deferred_config_head, deferred_config);
1.29      thorpej   153:
1.42      thorpej   154: struct deferred_config_head deferred_config_queue;
                    155: struct deferred_config_head interrupt_config_queue;
                    156:
1.51      cgd       157: static void config_process_deferred(struct deferred_config_head *,
                    158:        struct device *);
1.29      thorpej   159:
1.55.2.8  nathanw   160: /* Hooks to finalize configuration once all real devices have been found. */
                    161: struct finalize_hook {
                    162:        TAILQ_ENTRY(finalize_hook) f_list;
                    163:        int (*f_func)(struct device *);
                    164:        struct device *f_dev;
                    165: };
                    166: static TAILQ_HEAD(, finalize_hook) config_finalize_list;
                    167: static int config_finalize_done;
                    168:
1.55.2.1  nathanw   169: /* list of all devices */
                    170: struct devicelist alldevs;
                    171:
                    172: /* list of all events */
                    173: struct evcntlist allevents = TAILQ_HEAD_INITIALIZER(allevents);
1.20      cgd       174:
1.47      thorpej   175: __volatile int config_pending;         /* semaphore for mountroot */
                    176:
1.55.2.8  nathanw   177: #define        STREQ(s1, s2)                   \
                    178:        (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
                    179:
                    180: static int config_initialized;         /* config_init() has been called. */
                    181:
1.55.2.11! thorpej   182: static int config_do_twiddle;
        !           183:
1.20      cgd       184: /*
1.55.2.8  nathanw   185:  * Initialize the autoconfiguration data structures.  Normally this
                    186:  * is done by configure(), but some platforms need to do this very
                    187:  * early (to e.g. initialize the console).
1.20      cgd       188:  */
                    189: void
1.55.2.8  nathanw   190: config_init(void)
1.20      cgd       191: {
1.55.2.8  nathanw   192:        const struct cfattachinit *cfai;
                    193:        int i, j;
                    194:
                    195:        if (config_initialized)
                    196:                return;
                    197:
                    198:        /* allcfdrivers is statically initialized. */
                    199:        for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
                    200:                if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
                    201:                        panic("configure: duplicate `%s' drivers",
                    202:                            cfdriver_list_initial[i]->cd_name);
                    203:        }
                    204:
                    205:        for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
                    206:                for (j = 0; cfai->cfai_list[j] != NULL; j++) {
                    207:                        if (config_cfattach_attach(cfai->cfai_name,
                    208:                                                   cfai->cfai_list[j]) != 0)
                    209:                                panic("configure: duplicate `%s' attachment "
                    210:                                    "of `%s' driver",
                    211:                                    cfai->cfai_list[j]->ca_name,
                    212:                                    cfai->cfai_name);
                    213:                }
                    214:        }
                    215:
                    216:        TAILQ_INIT(&allcftables);
                    217:        initcftable.ct_cfdata = cfdata;
                    218:        TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
1.20      cgd       219:
1.29      thorpej   220:        TAILQ_INIT(&deferred_config_queue);
1.42      thorpej   221:        TAILQ_INIT(&interrupt_config_queue);
1.55.2.8  nathanw   222:        TAILQ_INIT(&config_finalize_list);
1.41      thorpej   223:        TAILQ_INIT(&alldevs);
1.55.2.2  nathanw   224:
1.55.2.8  nathanw   225:        config_initialized = 1;
                    226: }
                    227:
                    228: /*
                    229:  * Configure the system's hardware.
                    230:  */
                    231: void
                    232: configure(void)
                    233: {
1.55.2.11! thorpej   234:        int errcnt;
1.55.2.8  nathanw   235:
                    236:        /* Initialize data structures. */
                    237:        config_init();
                    238:
1.55.2.2  nathanw   239: #ifdef USERCONF
                    240:        if (boothowto & RB_USERCONF)
                    241:                user_config();
                    242: #endif
1.41      thorpej   243:
1.55.2.11! thorpej   244:        if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
        !           245:                config_do_twiddle = 1;
        !           246:                printf_nolog("Detecting hardware...");
        !           247:        }
        !           248:
1.41      thorpej   249:        /*
                    250:         * Do the machine-dependent portion of autoconfiguration.  This
                    251:         * sets the configuration machinery here in motion by "finding"
                    252:         * the root bus.  When this function returns, we expect interrupts
                    253:         * to be enabled.
                    254:         */
                    255:        cpu_configure();
1.43      thorpej   256:
                    257:        /*
                    258:         * Now that we've found all the hardware, start the real time
                    259:         * and statistics clocks.
                    260:         */
                    261:        initclocks();
                    262:
                    263:        cold = 0;       /* clocks are running, we're warm now! */
1.42      thorpej   264:
                    265:        /*
                    266:         * Now callback to finish configuration for devices which want
                    267:         * to do this once interrupts are enabled.
                    268:         */
                    269:        config_process_deferred(&interrupt_config_queue, NULL);
1.55.2.11! thorpej   270:
        !           271:        errcnt = aprint_get_error_count();
        !           272:        if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
        !           273:            (boothowto & AB_VERBOSE) == 0) {
        !           274:                if (config_do_twiddle) {
        !           275:                        config_do_twiddle = 0;
        !           276:                        printf_nolog("done.\n");
        !           277:                }
        !           278:                if (errcnt != 0) {
        !           279:                        printf("WARNING: %d error%s while detecting hardware; "
        !           280:                            "check system log.\n", errcnt,
        !           281:                            errcnt == 1 ? "" : "s");
        !           282:                }
        !           283:        }
1.20      cgd       284: }
                    285:
1.1       glass     286: /*
1.55.2.8  nathanw   287:  * Add a cfdriver to the system.
                    288:  */
                    289: int
                    290: config_cfdriver_attach(struct cfdriver *cd)
                    291: {
                    292:        struct cfdriver *lcd;
                    293:
                    294:        /* Make sure this driver isn't already in the system. */
                    295:        LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
                    296:                if (STREQ(lcd->cd_name, cd->cd_name))
                    297:                        return (EEXIST);
                    298:        }
                    299:
                    300:        LIST_INIT(&cd->cd_attach);
                    301:        LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
                    302:
                    303:        return (0);
                    304: }
                    305:
                    306: /*
                    307:  * Remove a cfdriver from the system.
                    308:  */
                    309: int
                    310: config_cfdriver_detach(struct cfdriver *cd)
                    311: {
                    312:        int i;
                    313:
                    314:        /* Make sure there are no active instances. */
                    315:        for (i = 0; i < cd->cd_ndevs; i++) {
                    316:                if (cd->cd_devs[i] != NULL)
                    317:                        return (EBUSY);
                    318:        }
                    319:
                    320:        /* ...and no attachments loaded. */
                    321:        if (LIST_EMPTY(&cd->cd_attach) == 0)
                    322:                return (EBUSY);
                    323:
                    324:        LIST_REMOVE(cd, cd_list);
                    325:
                    326:        KASSERT(cd->cd_devs == NULL);
                    327:
                    328:        return (0);
                    329: }
                    330:
                    331: /*
                    332:  * Look up a cfdriver by name.
                    333:  */
1.55.2.9  nathanw   334: struct cfdriver *
1.55.2.8  nathanw   335: config_cfdriver_lookup(const char *name)
                    336: {
                    337:        struct cfdriver *cd;
                    338:
                    339:        LIST_FOREACH(cd, &allcfdrivers, cd_list) {
                    340:                if (STREQ(cd->cd_name, name))
                    341:                        return (cd);
                    342:        }
                    343:
                    344:        return (NULL);
                    345: }
                    346:
                    347: /*
                    348:  * Add a cfattach to the specified driver.
                    349:  */
                    350: int
                    351: config_cfattach_attach(const char *driver, struct cfattach *ca)
                    352: {
                    353:        struct cfattach *lca;
                    354:        struct cfdriver *cd;
                    355:
                    356:        cd = config_cfdriver_lookup(driver);
                    357:        if (cd == NULL)
                    358:                return (ESRCH);
                    359:
                    360:        /* Make sure this attachment isn't already on this driver. */
                    361:        LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
                    362:                if (STREQ(lca->ca_name, ca->ca_name))
                    363:                        return (EEXIST);
                    364:        }
                    365:
                    366:        LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
                    367:
                    368:        return (0);
                    369: }
                    370:
                    371: /*
                    372:  * Remove a cfattach from the specified driver.
                    373:  */
                    374: int
                    375: config_cfattach_detach(const char *driver, struct cfattach *ca)
                    376: {
                    377:        struct cfdriver *cd;
                    378:        struct device *dev;
                    379:        int i;
                    380:
                    381:        cd = config_cfdriver_lookup(driver);
                    382:        if (cd == NULL)
                    383:                return (ESRCH);
                    384:
                    385:        /* Make sure there are no active instances. */
                    386:        for (i = 0; i < cd->cd_ndevs; i++) {
                    387:                if ((dev = cd->cd_devs[i]) == NULL)
                    388:                        continue;
                    389:                if (dev->dv_cfattach == ca)
                    390:                        return (EBUSY);
                    391:        }
                    392:
                    393:        LIST_REMOVE(ca, ca_list);
                    394:
                    395:        return (0);
                    396: }
                    397:
                    398: /*
                    399:  * Look up a cfattach by name.
                    400:  */
                    401: static struct cfattach *
                    402: config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
                    403: {
                    404:        struct cfattach *ca;
                    405:
                    406:        LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
                    407:                if (STREQ(ca->ca_name, atname))
                    408:                        return (ca);
                    409:        }
                    410:
                    411:        return (NULL);
                    412: }
                    413:
                    414: /*
                    415:  * Look up a cfattach by driver/attachment name.
                    416:  */
                    417: struct cfattach *
                    418: config_cfattach_lookup(const char *name, const char *atname)
                    419: {
                    420:        struct cfdriver *cd;
                    421:
                    422:        cd = config_cfdriver_lookup(name);
                    423:        if (cd == NULL)
                    424:                return (NULL);
                    425:
                    426:        return (config_cfattach_lookup_cd(cd, atname));
                    427: }
                    428:
                    429: /*
1.1       glass     430:  * Apply the matching function and choose the best.  This is used
                    431:  * a few times and we want to keep the code small.
                    432:  */
1.16      mycroft   433: static void
1.51      cgd       434: mapply(struct matchinfo *m, struct cfdata *cf)
1.1       glass     435: {
1.50      augustss  436:        int pri;
1.1       glass     437:
                    438:        if (m->fn != NULL)
1.25      cgd       439:                pri = (*m->fn)(m->parent, cf, m->aux);
1.3       glass     440:        else {
1.55.2.8  nathanw   441:                struct cfattach *ca;
                    442:
                    443:                ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
                    444:                if (ca == NULL) {
                    445:                        /* No attachment for this entry, oh well. */
                    446:                        return;
                    447:                }
                    448:                if (ca->ca_match == NULL) {
                    449:                        panic("mapply: no match function for '%s' attachment "
                    450:                            "of '%s'", cf->cf_atname, cf->cf_name);
1.3       glass     451:                }
1.55.2.8  nathanw   452:                pri = (*ca->ca_match)(m->parent, cf, m->aux);
1.3       glass     453:        }
1.1       glass     454:        if (pri > m->pri) {
1.25      cgd       455:                m->match = cf;
1.1       glass     456:                m->pri = pri;
                    457:        }
                    458: }
                    459:
                    460: /*
1.55.2.8  nathanw   461:  * Determine if `parent' is a potential parent for a device spec based
                    462:  * on `cfp'.
                    463:  */
                    464: static int
                    465: cfparent_match(struct device *parent, const struct cfparent *cfp)
                    466: {
                    467:        struct cfdriver *pcd;
                    468:        const char * const *cpp;
                    469:        const char *cp;
                    470:
                    471:        /* We don't match root nodes here. */
                    472:        if (cfp == NULL)
                    473:                return (0);
                    474:
                    475:        pcd = parent->dv_cfdriver;
                    476:        KASSERT(pcd != NULL);
                    477:
                    478:        /*
                    479:         * First, ensure this parent has the correct interface
                    480:         * attribute.
                    481:         */
                    482:        if (pcd->cd_attrs == NULL)
                    483:                return (0);     /* no interface attributes -> no children */
                    484:        for (cpp = pcd->cd_attrs; (cp = *cpp) != NULL; cpp++) {
                    485:                if (STREQ(cp, cfp->cfp_iattr)) {
                    486:                        /* Match. */
                    487:                        break;
                    488:                }
                    489:        }
                    490:        if (cp == NULL)
                    491:                return (0);     /* doesn't carry the req'd attribute */
                    492:
                    493:        /*
                    494:         * If no specific parent device instance was specified (i.e.
                    495:         * we're attaching to the attribute only), we're done!
                    496:         */
                    497:        if (cfp->cfp_parent == NULL)
                    498:                return (1);
                    499:
                    500:        /*
                    501:         * Check the parent device's name.
                    502:         */
                    503:        if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
                    504:                return (0);     /* not the same parent */
                    505:
                    506:        /*
                    507:         * Make sure the unit number matches.
                    508:         */
                    509:        if (cfp->cfp_unit == DVUNIT_ANY ||      /* wildcard */
                    510:            cfp->cfp_unit == parent->dv_unit)
                    511:                return (1);
                    512:
                    513:        /* Unit numbers don't match. */
                    514:        return (0);
                    515: }
                    516:
                    517: /*
                    518:  * Invoke the "match" routine for a cfdata entry on behalf of
                    519:  * an external caller, usually a "submatch" routine.
                    520:  */
                    521: int
                    522: config_match(struct device *parent, struct cfdata *cf, void *aux)
                    523: {
                    524:        struct cfattach *ca;
                    525:
                    526:        ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
                    527:        if (ca == NULL) {
                    528:                /* No attachment for this entry, oh well. */
                    529:                return (0);
                    530:        }
                    531:
                    532:        return ((*ca->ca_match)(parent, cf, aux));
                    533: }
                    534:
                    535: /*
1.1       glass     536:  * Iterate over all potential children of some device, calling the given
                    537:  * function (default being the child's match function) for each one.
                    538:  * Nonzero returns are matches; the highest value returned is considered
                    539:  * the best match.  Return the `found child' if we got a match, or NULL
                    540:  * otherwise.  The `aux' pointer is simply passed on through.
                    541:  *
                    542:  * Note that this function is designed so that it can be used to apply
                    543:  * an arbitrary function to all potential children (its return value
                    544:  * can be ignored).
                    545:  */
1.25      cgd       546: struct cfdata *
1.51      cgd       547: config_search(cfmatch_t fn, struct device *parent, void *aux)
1.1       glass     548: {
1.55.2.8  nathanw   549:        struct cftable *ct;
1.50      augustss  550:        struct cfdata *cf;
1.1       glass     551:        struct matchinfo m;
                    552:
1.55.2.8  nathanw   553:        KASSERT(config_initialized);
                    554:
1.1       glass     555:        m.fn = fn;
                    556:        m.parent = parent;
1.25      cgd       557:        m.aux = aux;
1.14      mycroft   558:        m.match = NULL;
1.1       glass     559:        m.pri = 0;
1.55.2.8  nathanw   560:
                    561:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
                    562:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
                    563:                        /*
                    564:                         * Skip cf if no longer eligible, otherwise scan
                    565:                         * through parents for one matching `parent', and
                    566:                         * try match function.
                    567:                         */
                    568:                        if (cf->cf_fstate == FSTATE_FOUND)
                    569:                                continue;
                    570:                        if (cf->cf_fstate == FSTATE_DNOTFOUND ||
                    571:                            cf->cf_fstate == FSTATE_DSTAR)
                    572:                                continue;
                    573:                        if (cfparent_match(parent, cf->cf_pspec))
1.16      mycroft   574:                                mapply(&m, cf);
1.55.2.8  nathanw   575:                }
1.1       glass     576:        }
                    577:        return (m.match);
                    578: }
                    579:
1.16      mycroft   580: /*
1.1       glass     581:  * Find the given root device.
                    582:  * This is much like config_search, but there is no parent.
1.55.2.8  nathanw   583:  * Don't bother with multiple cfdata tables; the root node
                    584:  * must always be in the initial table.
1.1       glass     585:  */
1.25      cgd       586: struct cfdata *
1.52      cgd       587: config_rootsearch(cfmatch_t fn, const char *rootname, void *aux)
1.1       glass     588: {
1.50      augustss  589:        struct cfdata *cf;
                    590:        short *p;
1.1       glass     591:        struct matchinfo m;
                    592:
                    593:        m.fn = fn;
                    594:        m.parent = ROOT;
1.25      cgd       595:        m.aux = aux;
1.14      mycroft   596:        m.match = NULL;
1.1       glass     597:        m.pri = 0;
                    598:        /*
                    599:         * Look at root entries for matching name.  We do not bother
                    600:         * with found-state here since only one root should ever be
                    601:         * searched (and it must be done first).
                    602:         */
                    603:        for (p = cfroots; *p >= 0; p++) {
                    604:                cf = &cfdata[*p];
1.55.2.8  nathanw   605:                if (strcmp(cf->cf_name, rootname) == 0)
1.16      mycroft   606:                        mapply(&m, cf);
1.1       glass     607:        }
                    608:        return (m.match);
                    609: }
                    610:
1.52      cgd       611: static const char *msgs[3] = { "", " not configured\n", " unsupported\n" };
1.1       glass     612:
                    613: /*
                    614:  * The given `aux' argument describes a device that has been found
                    615:  * on the given parent, but not necessarily configured.  Locate the
1.18      cgd       616:  * configuration data for that device (using the submatch function
                    617:  * provided, or using candidates' cd_match configuration driver
                    618:  * functions) and attach it, and return true.  If the device was
1.1       glass     619:  * not configured, call the given `print' function and return 0.
                    620:  */
1.21      cgd       621: struct device *
1.51      cgd       622: config_found_sm(struct device *parent, void *aux, cfprint_t print,
                    623:     cfmatch_t submatch)
1.1       glass     624: {
1.25      cgd       625:        struct cfdata *cf;
                    626:
                    627:        if ((cf = config_search(submatch, parent, aux)) != NULL)
                    628:                return (config_attach(parent, cf, aux, print));
1.55.2.11! thorpej   629:        if (print) {
        !           630:                if (config_do_twiddle)
        !           631:                        twiddle();
        !           632:                aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
        !           633:        }
1.21      cgd       634:        return (NULL);
1.1       glass     635: }
                    636:
                    637: /*
                    638:  * As above, but for root devices.
                    639:  */
1.21      cgd       640: struct device *
1.52      cgd       641: config_rootfound(const char *rootname, void *aux)
1.1       glass     642: {
1.25      cgd       643:        struct cfdata *cf;
                    644:
                    645:        if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
                    646:                return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
1.55.2.11! thorpej   647:        aprint_error("root device %s not configured\n", rootname);
1.21      cgd       648:        return (NULL);
1.1       glass     649: }
                    650:
                    651: /* just like sprintf(buf, "%d") except that it works from the end */
                    652: static char *
1.51      cgd       653: number(char *ep, int n)
1.1       glass     654: {
                    655:
                    656:        *--ep = 0;
                    657:        while (n >= 10) {
                    658:                *--ep = (n % 10) + '0';
                    659:                n /= 10;
                    660:        }
                    661:        *--ep = n + '0';
                    662:        return (ep);
                    663: }
                    664:
                    665: /*
1.55.2.4  nathanw   666:  * Expand the size of the cd_devs array if necessary.
                    667:  */
                    668: void
                    669: config_makeroom(int n, struct cfdriver *cd)
                    670: {
                    671:        int old, new;
                    672:        void **nsp;
                    673:
                    674:        if (n < cd->cd_ndevs)
                    675:                return;
                    676:
                    677:        /*
                    678:         * Need to expand the array.
                    679:         */
                    680:        old = cd->cd_ndevs;
                    681:        if (old == 0)
                    682:                new = MINALLOCSIZE / sizeof(void *);
                    683:        else
                    684:                new = old * 2;
                    685:        while (new <= n)
                    686:                new *= 2;
                    687:        cd->cd_ndevs = new;
                    688:        nsp = malloc(new * sizeof(void *), M_DEVBUF,
                    689:            cold ? M_NOWAIT : M_WAITOK);
                    690:        if (nsp == NULL)
                    691:                panic("config_attach: %sing dev array",
                    692:                    old != 0 ? "expand" : "creat");
                    693:        memset(nsp + old, 0, (new - old) * sizeof(void *));
                    694:        if (old != 0) {
                    695:                memcpy(nsp, cd->cd_devs, old * sizeof(void *));
                    696:                free(cd->cd_devs, M_DEVBUF);
                    697:        }
                    698:        cd->cd_devs = nsp;
                    699: }
                    700:
                    701: /*
1.1       glass     702:  * Attach a found device.  Allocates memory for device variables.
                    703:  */
1.25      cgd       704: struct device *
1.51      cgd       705: config_attach(struct device *parent, struct cfdata *cf, void *aux,
                    706:        cfprint_t print)
1.25      cgd       707: {
1.50      augustss  708:        struct device *dev;
1.55.2.8  nathanw   709:        struct cftable *ct;
1.50      augustss  710:        struct cfdriver *cd;
                    711:        struct cfattach *ca;
                    712:        size_t lname, lunit;
1.52      cgd       713:        const char *xunit;
1.25      cgd       714:        int myunit;
                    715:        char num[10];
                    716:
1.55.2.8  nathanw   717:        cd = config_cfdriver_lookup(cf->cf_name);
                    718:        KASSERT(cd != NULL);
                    719:
                    720:        ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
                    721:        KASSERT(ca != NULL);
                    722:
1.25      cgd       723:        if (ca->ca_devsize < sizeof(struct device))
                    724:                panic("config_attach");
1.55.2.8  nathanw   725:
1.46      cgd       726: #ifndef __BROKEN_CONFIG_UNIT_USAGE
1.45      cgd       727:        if (cf->cf_fstate == FSTATE_STAR) {
                    728:                for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
                    729:                        if (cd->cd_devs[myunit] == NULL)
                    730:                                break;
                    731:                /*
                    732:                 * myunit is now the unit of the first NULL device pointer,
                    733:                 * or max(cd->cd_ndevs,cf->cf_unit).
                    734:                 */
                    735:        } else {
                    736:                myunit = cf->cf_unit;
1.55.2.8  nathanw   737:                KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
                    738:                cf->cf_fstate = FSTATE_FOUND;
                    739:        }
                    740: #else
1.46      cgd       741:        myunit = cf->cf_unit;
                    742:        if (cf->cf_fstate == FSTATE_STAR)
                    743:                cf->cf_unit++;
                    744:        else {
1.25      cgd       745:                KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
                    746:                cf->cf_fstate = FSTATE_FOUND;
                    747:        }
1.55.2.8  nathanw   748: #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
1.25      cgd       749:
                    750:        /* compute length of name and decimal expansion of unit number */
                    751:        lname = strlen(cd->cd_name);
1.30      perry     752:        xunit = number(&num[sizeof(num)], myunit);
                    753:        lunit = &num[sizeof(num)] - xunit;
1.55.2.7  nathanw   754:        if (lname + lunit > sizeof(dev->dv_xname))
1.25      cgd       755:                panic("config_attach: device name too long");
                    756:
                    757:        /* get memory for all device vars */
1.43      thorpej   758:        dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF,
                    759:            cold ? M_NOWAIT : M_WAITOK);
1.25      cgd       760:        if (!dev)
                    761:            panic("config_attach: memory allocation for device softc failed");
1.31      perry     762:        memset(dev, 0, ca->ca_devsize);
1.25      cgd       763:        TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);      /* link up */
                    764:        dev->dv_class = cd->cd_class;
                    765:        dev->dv_cfdata = cf;
1.55.2.8  nathanw   766:        dev->dv_cfdriver = cd;
                    767:        dev->dv_cfattach = ca;
1.25      cgd       768:        dev->dv_unit = myunit;
1.31      perry     769:        memcpy(dev->dv_xname, cd->cd_name, lname);
                    770:        memcpy(dev->dv_xname + lname, xunit, lunit);
1.25      cgd       771:        dev->dv_parent = parent;
1.33      thorpej   772:        dev->dv_flags = DVF_ACTIVE;     /* always initially active */
1.29      thorpej   773:
1.55.2.11! thorpej   774:        if (config_do_twiddle)
        !           775:                twiddle();
        !           776:        else
        !           777:                aprint_naive("Found ");
        !           778:        /*
        !           779:         * We want the next two printfs for normal, verbose, and quiet,
        !           780:         * but not silent (in which case, we're twiddling, instead).
        !           781:         */
        !           782:        if (parent == ROOT) {
        !           783:                if (config_do_twiddle)
        !           784:                        aprint_normal("%s (root)", dev->dv_xname);
        !           785:                else
        !           786:                        printf("%s (root)", dev->dv_xname);
        !           787:        } else {
        !           788:                if (config_do_twiddle)
        !           789:                        aprint_normal("%s at %s", dev->dv_xname,
        !           790:                            parent->dv_xname);
        !           791:                else
        !           792:                        printf("%s at %s", dev->dv_xname, parent->dv_xname);
1.25      cgd       793:                if (print)
1.52      cgd       794:                        (void) (*print)(aux, NULL);
1.25      cgd       795:        }
                    796:
                    797:        /* put this device in the devices array */
1.55.2.4  nathanw   798:        config_makeroom(dev->dv_unit, cd);
1.25      cgd       799:        if (cd->cd_devs[dev->dv_unit])
                    800:                panic("config_attach: duplicate %s", dev->dv_xname);
                    801:        cd->cd_devs[dev->dv_unit] = dev;
                    802:
                    803:        /*
                    804:         * Before attaching, clobber any unfound devices that are
1.45      cgd       805:         * otherwise identical.
1.25      cgd       806:         */
1.55.2.8  nathanw   807:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
                    808:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
                    809:                        if (STREQ(cf->cf_name, cd->cd_name) &&
                    810:                            cf->cf_unit == dev->dv_unit) {
                    811:                                if (cf->cf_fstate == FSTATE_NOTFOUND)
                    812:                                        cf->cf_fstate = FSTATE_FOUND;
1.46      cgd       813: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.55.2.8  nathanw   814:                                /*
                    815:                                 * Bump the unit number on all starred cfdata
                    816:                                 * entries for this device.
                    817:                                 */
                    818:                                if (cf->cf_fstate == FSTATE_STAR)
                    819:                                        cf->cf_unit++;
1.46      cgd       820: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.55.2.8  nathanw   821:                        }
1.25      cgd       822:                }
1.55.2.8  nathanw   823:        }
1.49      danw      824: #ifdef __HAVE_DEVICE_REGISTER
1.25      cgd       825:        device_register(dev, aux);
                    826: #endif
                    827:        (*ca->ca_attach)(parent, dev, aux);
1.42      thorpej   828:        config_process_deferred(&deferred_config_queue, dev);
1.25      cgd       829:        return (dev);
                    830: }
1.29      thorpej   831:
                    832: /*
1.55.2.8  nathanw   833:  * As above, but for pseudo-devices.  Pseudo-devices attached in this
                    834:  * way are silently inserted into the device tree, and their children
                    835:  * attached.
                    836:  *
                    837:  * Note that because pseudo-devices are attached silently, any information
                    838:  * the attach routine wishes to print should be prefixed with the device
                    839:  * name by the attach routine.
                    840:  */
                    841: struct device *
                    842: config_attach_pseudo(const char *name, int unit)
                    843: {
                    844:        struct device *dev;
                    845:        struct cfdriver *cd;
                    846:        struct cfattach *ca;
                    847:        size_t lname, lunit;
                    848:        const char *xunit;
                    849:        int myunit;
                    850:        char num[10];
                    851:
                    852:        cd = config_cfdriver_lookup(name);
                    853:        if (cd == NULL)
                    854:                return (NULL);
                    855:
                    856:        ca = config_cfattach_lookup_cd(cd, name);
                    857:        if (ca == NULL)
                    858:                return (NULL);
                    859:
                    860:        if (ca->ca_devsize < sizeof(struct device))
                    861:                panic("config_attach_pseudo");
                    862:
                    863:        if (unit == DVUNIT_ANY) {
                    864:                for (myunit = 0; myunit < cd->cd_ndevs; myunit++)
                    865:                        if (cd->cd_devs[myunit] == NULL)
                    866:                                break;
                    867:                /*
                    868:                 * myunit is now the unit of the first NULL device pointer.
                    869:                 */
                    870:        } else {
                    871:                myunit = unit;
                    872:                if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
                    873:                        return (NULL);
                    874:        }
                    875:
                    876:        /* compute length of name and decimal expansion of unit number */
                    877:        lname = strlen(cd->cd_name);
                    878:        xunit = number(&num[sizeof(num)], myunit);
                    879:        lunit = &num[sizeof(num)] - xunit;
                    880:        if (lname + lunit > sizeof(dev->dv_xname))
                    881:                panic("config_attach_pseudo: device name too long");
                    882:
                    883:        /* get memory for all device vars */
                    884:        dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF,
                    885:            cold ? M_NOWAIT : M_WAITOK);
                    886:        if (!dev)
                    887:                panic("config_attach_pseudo: memory allocation for device "
                    888:                    "softc failed");
                    889:        memset(dev, 0, ca->ca_devsize);
                    890:        TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);      /* link up */
                    891:        dev->dv_class = cd->cd_class;
                    892:        dev->dv_cfdata = NULL;
                    893:        dev->dv_cfdriver = cd;
                    894:        dev->dv_cfattach = ca;
                    895:        dev->dv_unit = myunit;
                    896:        memcpy(dev->dv_xname, cd->cd_name, lname);
                    897:        memcpy(dev->dv_xname + lname, xunit, lunit);
                    898:        dev->dv_parent = ROOT;
                    899:        dev->dv_flags = DVF_ACTIVE;     /* always initially active */
                    900:
                    901:        /* put this device in the devices array */
                    902:        config_makeroom(dev->dv_unit, cd);
                    903:        if (cd->cd_devs[dev->dv_unit])
                    904:                panic("config_attach_pseudo: duplicate %s", dev->dv_xname);
                    905:        cd->cd_devs[dev->dv_unit] = dev;
                    906:
                    907: #if 0  /* XXXJRT not yet */
                    908: #ifdef __HAVE_DEVICE_REGISTER
                    909:        device_register(dev, NULL);     /* like a root node */
                    910: #endif
                    911: #endif
                    912:        (*ca->ca_attach)(ROOT, dev, NULL);
                    913:        config_process_deferred(&deferred_config_queue, dev);
                    914:        return (dev);
                    915: }
                    916:
                    917: /*
1.33      thorpej   918:  * Detach a device.  Optionally forced (e.g. because of hardware
                    919:  * removal) and quiet.  Returns zero if successful, non-zero
                    920:  * (an error code) otherwise.
                    921:  *
                    922:  * Note that this code wants to be run from a process context, so
                    923:  * that the detach can sleep to allow processes which have a device
                    924:  * open to run and unwind their stacks.
                    925:  */
                    926: int
1.51      cgd       927: config_detach(struct device *dev, int flags)
1.33      thorpej   928: {
1.55.2.8  nathanw   929:        struct cftable *ct;
1.33      thorpej   930:        struct cfdata *cf;
1.55.2.8  nathanw   931:        const struct cfattach *ca;
1.33      thorpej   932:        struct cfdriver *cd;
                    933: #ifdef DIAGNOSTIC
                    934:        struct device *d;
                    935: #endif
1.36      thorpej   936:        int rv = 0, i;
1.33      thorpej   937:
                    938: #ifdef DIAGNOSTIC
1.55.2.8  nathanw   939:        if (dev->dv_cfdata != NULL &&
                    940:            dev->dv_cfdata->cf_fstate != FSTATE_FOUND &&
                    941:            dev->dv_cfdata->cf_fstate != FSTATE_STAR)
1.33      thorpej   942:                panic("config_detach: bad device fstate");
                    943: #endif
1.55.2.8  nathanw   944:        cd = dev->dv_cfdriver;
                    945:        KASSERT(cd != NULL);
                    946:
                    947:        ca = dev->dv_cfattach;
                    948:        KASSERT(ca != NULL);
1.33      thorpej   949:
                    950:        /*
                    951:         * Ensure the device is deactivated.  If the device doesn't
                    952:         * have an activation entry point, we allow DVF_ACTIVE to
                    953:         * remain set.  Otherwise, if DVF_ACTIVE is still set, the
                    954:         * device is busy, and the detach fails.
                    955:         */
1.35      thorpej   956:        if (ca->ca_activate != NULL)
                    957:                rv = config_deactivate(dev);
1.33      thorpej   958:
                    959:        /*
                    960:         * Try to detach the device.  If that's not possible, then
                    961:         * we either panic() (for the forced but failed case), or
                    962:         * return an error.
                    963:         */
                    964:        if (rv == 0) {
                    965:                if (ca->ca_detach != NULL)
                    966:                        rv = (*ca->ca_detach)(dev, flags);
                    967:                else
                    968:                        rv = EOPNOTSUPP;
                    969:        }
                    970:        if (rv != 0) {
                    971:                if ((flags & DETACH_FORCE) == 0)
                    972:                        return (rv);
                    973:                else
                    974:                        panic("config_detach: forced detach of %s failed (%d)",
                    975:                            dev->dv_xname, rv);
                    976:        }
                    977:
                    978:        /*
                    979:         * The device has now been successfully detached.
                    980:         */
                    981:
                    982: #ifdef DIAGNOSTIC
                    983:        /*
                    984:         * Sanity: If you're successfully detached, you should have no
                    985:         * children.  (Note that because children must be attached
                    986:         * after parents, we only need to search the latter part of
                    987:         * the list.)
                    988:         */
                    989:        for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1.48      enami     990:            d = TAILQ_NEXT(d, dv_list)) {
                    991:                if (d->dv_parent == dev) {
                    992:                        printf("config_detach: detached device %s"
                    993:                            " has children %s\n", dev->dv_xname, d->dv_xname);
                    994:                        panic("config_detach");
                    995:                }
1.33      thorpej   996:        }
                    997: #endif
                    998:
                    999:        /*
                   1000:         * Mark cfdata to show that the unit can be reused, if possible.
                   1001:         */
1.55.2.8  nathanw  1002:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
                   1003:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
                   1004:                        if (STREQ(cf->cf_name, cd->cd_name)) {
                   1005:                                if (cf->cf_fstate == FSTATE_FOUND &&
                   1006:                                    cf->cf_unit == dev->dv_unit)
                   1007:                                        cf->cf_fstate = FSTATE_NOTFOUND;
1.46      cgd      1008: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.55.2.8  nathanw  1009:                                /*
                   1010:                                 * Note that we can only re-use a starred
                   1011:                                 * unit number if the unit being detached
                   1012:                                 * had the last assigned unit number.
                   1013:                                 */
                   1014:                                if (cf->cf_fstate == FSTATE_STAR &&
                   1015:                                    cf->cf_unit == dev->dv_unit + 1)
                   1016:                                        cf->cf_unit--;
1.46      cgd      1017: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.55.2.8  nathanw  1018:                        }
1.33      thorpej  1019:                }
                   1020:        }
                   1021:
                   1022:        /*
                   1023:         * Unlink from device list.
                   1024:         */
                   1025:        TAILQ_REMOVE(&alldevs, dev, dv_list);
                   1026:
                   1027:        /*
1.55.2.8  nathanw  1028:         * Remove from cfdriver's array, tell the world (unless it was
                   1029:         * a pseudo-device), and free softc.
1.33      thorpej  1030:         */
                   1031:        cd->cd_devs[dev->dv_unit] = NULL;
1.55.2.8  nathanw  1032:        if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1.55.2.11! thorpej  1033:                aprint_normal("%s detached\n", dev->dv_xname);
1.33      thorpej  1034:        free(dev, M_DEVBUF);
                   1035:
                   1036:        /*
                   1037:         * If the device now has no units in use, deallocate its softc array.
                   1038:         */
                   1039:        for (i = 0; i < cd->cd_ndevs; i++)
                   1040:                if (cd->cd_devs[i] != NULL)
                   1041:                        break;
                   1042:        if (i == cd->cd_ndevs) {                /* nothing found; deallocate */
                   1043:                free(cd->cd_devs, M_DEVBUF);
                   1044:                cd->cd_devs = NULL;
                   1045:                cd->cd_ndevs = 0;
                   1046:        }
                   1047:
                   1048:        /*
                   1049:         * Return success.
                   1050:         */
                   1051:        return (0);
                   1052: }
                   1053:
                   1054: int
1.51      cgd      1055: config_activate(struct device *dev)
1.33      thorpej  1056: {
1.55.2.8  nathanw  1057:        const struct cfattach *ca = dev->dv_cfattach;
1.34      thorpej  1058:        int rv = 0, oflags = dev->dv_flags;
1.33      thorpej  1059:
                   1060:        if (ca->ca_activate == NULL)
                   1061:                return (EOPNOTSUPP);
                   1062:
                   1063:        if ((dev->dv_flags & DVF_ACTIVE) == 0) {
                   1064:                dev->dv_flags |= DVF_ACTIVE;
                   1065:                rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
1.34      thorpej  1066:                if (rv)
                   1067:                        dev->dv_flags = oflags;
1.33      thorpej  1068:        }
                   1069:        return (rv);
                   1070: }
                   1071:
                   1072: int
1.51      cgd      1073: config_deactivate(struct device *dev)
1.33      thorpej  1074: {
1.55.2.8  nathanw  1075:        const struct cfattach *ca = dev->dv_cfattach;
1.34      thorpej  1076:        int rv = 0, oflags = dev->dv_flags;
1.33      thorpej  1077:
                   1078:        if (ca->ca_activate == NULL)
                   1079:                return (EOPNOTSUPP);
                   1080:
                   1081:        if (dev->dv_flags & DVF_ACTIVE) {
                   1082:                dev->dv_flags &= ~DVF_ACTIVE;
                   1083:                rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
1.34      thorpej  1084:                if (rv)
                   1085:                        dev->dv_flags = oflags;
1.33      thorpej  1086:        }
                   1087:        return (rv);
                   1088: }
                   1089:
                   1090: /*
1.29      thorpej  1091:  * Defer the configuration of the specified device until all
                   1092:  * of its parent's devices have been attached.
                   1093:  */
                   1094: void
1.51      cgd      1095: config_defer(struct device *dev, void (*func)(struct device *))
1.29      thorpej  1096: {
                   1097:        struct deferred_config *dc;
                   1098:
                   1099:        if (dev->dv_parent == NULL)
                   1100:                panic("config_defer: can't defer config of a root device");
                   1101:
                   1102: #ifdef DIAGNOSTIC
                   1103:        for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
                   1104:             dc = TAILQ_NEXT(dc, dc_queue)) {
                   1105:                if (dc->dc_dev == dev)
                   1106:                        panic("config_defer: deferred twice");
                   1107:        }
                   1108: #endif
                   1109:
1.43      thorpej  1110:        dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
                   1111:        if (dc == NULL)
                   1112:                panic("config_defer: unable to allocate callback");
1.29      thorpej  1113:
                   1114:        dc->dc_dev = dev;
                   1115:        dc->dc_func = func;
                   1116:        TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1.47      thorpej  1117:        config_pending_incr();
1.29      thorpej  1118: }
                   1119:
                   1120: /*
1.42      thorpej  1121:  * Defer some autoconfiguration for a device until after interrupts
                   1122:  * are enabled.
                   1123:  */
                   1124: void
1.51      cgd      1125: config_interrupts(struct device *dev, void (*func)(struct device *))
1.42      thorpej  1126: {
                   1127:        struct deferred_config *dc;
                   1128:
                   1129:        /*
                   1130:         * If interrupts are enabled, callback now.
                   1131:         */
1.43      thorpej  1132:        if (cold == 0) {
1.42      thorpej  1133:                (*func)(dev);
                   1134:                return;
                   1135:        }
                   1136:
                   1137: #ifdef DIAGNOSTIC
                   1138:        for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
                   1139:             dc = TAILQ_NEXT(dc, dc_queue)) {
                   1140:                if (dc->dc_dev == dev)
                   1141:                        panic("config_interrupts: deferred twice");
                   1142:        }
                   1143: #endif
                   1144:
1.43      thorpej  1145:        dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
                   1146:        if (dc == NULL)
                   1147:                panic("config_interrupts: unable to allocate callback");
1.42      thorpej  1148:
                   1149:        dc->dc_dev = dev;
                   1150:        dc->dc_func = func;
                   1151:        TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1.47      thorpej  1152:        config_pending_incr();
1.42      thorpej  1153: }
                   1154:
                   1155: /*
                   1156:  * Process a deferred configuration queue.
1.29      thorpej  1157:  */
                   1158: static void
1.51      cgd      1159: config_process_deferred(struct deferred_config_head *queue,
                   1160:     struct device *parent)
1.29      thorpej  1161: {
                   1162:        struct deferred_config *dc, *ndc;
                   1163:
1.42      thorpej  1164:        for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
1.29      thorpej  1165:                ndc = TAILQ_NEXT(dc, dc_queue);
1.42      thorpej  1166:                if (parent == NULL || dc->dc_dev->dv_parent == parent) {
                   1167:                        TAILQ_REMOVE(queue, dc, dc_queue);
1.29      thorpej  1168:                        (*dc->dc_func)(dc->dc_dev);
                   1169:                        free(dc, M_DEVBUF);
1.47      thorpej  1170:                        config_pending_decr();
1.29      thorpej  1171:                }
                   1172:        }
1.47      thorpej  1173: }
                   1174:
                   1175: /*
                   1176:  * Manipulate the config_pending semaphore.
                   1177:  */
                   1178: void
1.51      cgd      1179: config_pending_incr(void)
1.47      thorpej  1180: {
                   1181:
                   1182:        config_pending++;
                   1183: }
                   1184:
                   1185: void
1.51      cgd      1186: config_pending_decr(void)
1.47      thorpej  1187: {
                   1188:
                   1189: #ifdef DIAGNOSTIC
                   1190:        if (config_pending == 0)
                   1191:                panic("config_pending_decr: config_pending == 0");
                   1192: #endif
                   1193:        config_pending--;
                   1194:        if (config_pending == 0)
                   1195:                wakeup((void *)&config_pending);
1.55.2.8  nathanw  1196: }
                   1197:
                   1198: /*
                   1199:  * Register a "finalization" routine.  Finalization routines are
                   1200:  * called iteratively once all real devices have been found during
                   1201:  * autoconfiguration, for as long as any one finalizer has done
                   1202:  * any work.
                   1203:  */
                   1204: int
                   1205: config_finalize_register(struct device *dev, int (*fn)(struct device *))
                   1206: {
                   1207:        struct finalize_hook *f;
                   1208:
                   1209:        /*
                   1210:         * If finalization has already been done, invoke the
                   1211:         * callback function now.
                   1212:         */
                   1213:        if (config_finalize_done) {
                   1214:                while ((*fn)(dev) != 0)
                   1215:                        /* loop */ ;
                   1216:        }
                   1217:
                   1218:        /* Ensure this isn't already on the list. */
                   1219:        TAILQ_FOREACH(f, &config_finalize_list, f_list) {
                   1220:                if (f->f_func == fn && f->f_dev == dev)
                   1221:                        return (EEXIST);
                   1222:        }
                   1223:
                   1224:        f = malloc(sizeof(*f), M_TEMP, M_WAITOK);
                   1225:        f->f_func = fn;
                   1226:        f->f_dev = dev;
                   1227:        TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
                   1228:
                   1229:        return (0);
                   1230: }
                   1231:
                   1232: void
                   1233: config_finalize(void)
                   1234: {
                   1235:        struct finalize_hook *f;
                   1236:        int rv;
                   1237:
                   1238:        /* Run the hooks until none of them does any work. */
                   1239:        do {
                   1240:                rv = 0;
                   1241:                TAILQ_FOREACH(f, &config_finalize_list, f_list)
                   1242:                        rv |= (*f->f_func)(f->f_dev);
                   1243:        } while (rv != 0);
                   1244:
                   1245:        config_finalize_done = 1;
                   1246:
                   1247:        /* Now free all the hooks. */
                   1248:        while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
                   1249:                TAILQ_REMOVE(&config_finalize_list, f, f_list);
                   1250:                free(f, M_TEMP);
                   1251:        }
1.29      thorpej  1252: }
1.1       glass    1253:
                   1254: /*
1.55.2.10  thorpej  1255:  * We need a dummy object to stuff into the evcnt link set to
                   1256:  * ensure that there always is at least one object in the set.
                   1257:  */
                   1258: static struct evcnt dummy_static_evcnt;
                   1259: __link_set_add_bss(evcnts, dummy_static_evcnt);
                   1260:
                   1261: /*
                   1262:  * Initialize event counters.  This does the attach procedure for
                   1263:  * each of the static event counters in the "evcnts" link set.
                   1264:  */
                   1265: void
                   1266: evcnt_init(void)
                   1267: {
                   1268:        __link_set_decl(evcnts, struct evcnt);
                   1269:        struct evcnt * const *evp;
                   1270:
                   1271:        __link_set_foreach(evp, evcnts) {
                   1272:                if (*evp == &dummy_static_evcnt)
                   1273:                        continue;
                   1274:                evcnt_attach_static(*evp);
                   1275:        }
                   1276: }
                   1277:
                   1278: /*
1.53      cgd      1279:  * Attach a statically-initialized event.  The type and string pointers
                   1280:  * are already set up.
1.1       glass    1281:  */
                   1282: void
1.53      cgd      1283: evcnt_attach_static(struct evcnt *ev)
1.1       glass    1284: {
1.53      cgd      1285:        int len;
1.1       glass    1286:
1.53      cgd      1287:        len = strlen(ev->ev_group);
1.1       glass    1288: #ifdef DIAGNOSTIC
1.53      cgd      1289:        if (len >= EVCNT_STRING_MAX)            /* ..._MAX includes NUL */
                   1290:                panic("evcnt_attach_static: group length (%s)", ev->ev_group);
1.1       glass    1291: #endif
1.53      cgd      1292:        ev->ev_grouplen = len;
                   1293:
                   1294:        len = strlen(ev->ev_name);
                   1295: #ifdef DIAGNOSTIC
                   1296:        if (len >= EVCNT_STRING_MAX)            /* ..._MAX includes NUL */
                   1297:                panic("evcnt_attach_static: name length (%s)", ev->ev_name);
                   1298: #endif
                   1299:        ev->ev_namelen = len;
                   1300:
1.20      cgd      1301:        TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
1.53      cgd      1302: }
                   1303:
                   1304: /*
                   1305:  * Attach a dynamically-initialized event.  Zero it, set up the type
                   1306:  * and string pointers and then act like it was statically initialized.
                   1307:  */
                   1308: void
                   1309: evcnt_attach_dynamic(struct evcnt *ev, int type, const struct evcnt *parent,
                   1310:     const char *group, const char *name)
                   1311: {
                   1312:
                   1313:        memset(ev, 0, sizeof *ev);
                   1314:        ev->ev_type = type;
                   1315:        ev->ev_parent = parent;
                   1316:        ev->ev_group = group;
                   1317:        ev->ev_name = name;
                   1318:        evcnt_attach_static(ev);
1.33      thorpej  1319: }
                   1320:
                   1321: /*
                   1322:  * Detach an event.
                   1323:  */
                   1324: void
1.51      cgd      1325: evcnt_detach(struct evcnt *ev)
1.33      thorpej  1326: {
                   1327:
                   1328:        TAILQ_REMOVE(&allevents, ev, ev_list);
1.1       glass    1329: }
1.55.2.5  nathanw  1330:
                   1331: #ifdef DDB
                   1332: void
                   1333: event_print(int full, void (*pr)(const char *, ...))
                   1334: {
                   1335:        struct evcnt *evp;
                   1336:
                   1337:        TAILQ_FOREACH(evp, &allevents, ev_list) {
                   1338:                if (evp->ev_count == 0 && !full)
                   1339:                        continue;
                   1340:
                   1341:                (*pr)("evcnt type %d: %s %s = %lld\n", evp->ev_type,
                   1342:                    evp->ev_group, evp->ev_name, evp->ev_count);
                   1343:        }
                   1344: }
                   1345: #endif /* DDB */

CVSweb <webmaster@jp.NetBSD.org>