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

1.133   ! drochner    1: /* $NetBSD: subr_autoconf.c,v 1.132 2008/02/27 19:59:05 matt 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.133   ! drochner   80: __KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.132 2008/02/27 19:59:05 matt Exp $");
1.62      simonb     81:
1.122     ad         82: #include "opt_multiprocessor.h"
1.62      simonb     83: #include "opt_ddb.h"
1.51      cgd        84:
1.4       mycroft    85: #include <sys/param.h>
                     86: #include <sys/device.h>
1.118     dyoung     87: #include <sys/disklabel.h>
                     88: #include <sys/conf.h>
                     89: #include <sys/kauth.h>
1.4       mycroft    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.82      mrg        95: #include <sys/reboot.h>
1.118     dyoung     96:
                     97: #include <sys/buf.h>
                     98: #include <sys/dirent.h>
                     99: #include <sys/vnode.h>
                    100: #include <sys/mount.h>
                    101: #include <sys/namei.h>
                    102: #include <sys/unistd.h>
                    103: #include <sys/fcntl.h>
                    104: #include <sys/lockf.h>
1.124     jmcneill  105: #include <sys/callout.h>
1.118     dyoung    106:
                    107: #include <sys/disk.h>
                    108:
1.16      mycroft   109: #include <machine/limits.h>
1.1       glass     110:
1.57      gmcgarry  111: #include "opt_userconf.h"
                    112: #ifdef USERCONF
                    113: #include <sys/userconf.h>
                    114: #endif
                    115:
1.106     martin    116: #ifdef __i386__
1.105     jmcneill  117: #include "opt_splash.h"
                    118: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                    119: #include <dev/splash/splash.h>
                    120: extern struct splash_progress *splash_progress_state;
                    121: #endif
1.106     martin    122: #endif
1.105     jmcneill  123:
1.1       glass     124: /*
                    125:  * Autoconfiguration subroutines.
                    126:  */
                    127:
                    128: /*
                    129:  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
                    130:  * devices and drivers are found via these tables.
                    131:  */
                    132: extern struct cfdata cfdata[];
1.84      matt      133: extern const short cfroots[];
1.1       glass     134:
1.65      thorpej   135: /*
1.67      thorpej   136:  * List of all cfdriver structures.  We use this to detect duplicates
                    137:  * when other cfdrivers are loaded.
                    138:  */
1.69      thorpej   139: struct cfdriverlist allcfdrivers = LIST_HEAD_INITIALIZER(&allcfdrivers);
                    140: extern struct cfdriver * const cfdriver_list_initial[];
1.67      thorpej   141:
                    142: /*
1.76      thorpej   143:  * Initial list of cfattach's.
                    144:  */
                    145: extern const struct cfattachinit cfattachinit[];
                    146:
                    147: /*
1.65      thorpej   148:  * List of cfdata tables.  We always have one such list -- the one
                    149:  * built statically when the kernel was configured.
                    150:  */
1.121     matt      151: struct cftablelist allcftables = TAILQ_HEAD_INITIALIZER(allcftables);
1.65      thorpej   152: static struct cftable initcftable;
                    153:
1.102     thorpej   154: #define        ROOT ((device_t)NULL)
1.1       glass     155:
1.16      mycroft   156: struct matchinfo {
1.99      drochner  157:        cfsubmatch_t fn;
1.16      mycroft   158:        struct  device *parent;
1.99      drochner  159:        const int *locs;
1.25      cgd       160:        void    *aux;
                    161:        struct  cfdata *match;
                    162:        int     pri;
1.16      mycroft   163: };
1.17      christos  164:
1.51      cgd       165: static char *number(char *, int);
1.102     thorpej   166: static void mapply(struct matchinfo *, cfdata_t);
1.117     drochner  167: static device_t config_devalloc(const device_t, const cfdata_t, const int *);
                    168: static void config_devdealloc(device_t);
                    169: static void config_makeroom(int, struct cfdriver *);
                    170: static void config_devlink(device_t);
                    171: static void config_devunlink(device_t);
1.16      mycroft   172:
1.29      thorpej   173: struct deferred_config {
                    174:        TAILQ_ENTRY(deferred_config) dc_queue;
1.102     thorpej   175:        device_t dc_dev;
                    176:        void (*dc_func)(device_t);
1.29      thorpej   177: };
                    178:
1.42      thorpej   179: TAILQ_HEAD(deferred_config_head, deferred_config);
1.29      thorpej   180:
1.121     matt      181: struct deferred_config_head deferred_config_queue =
                    182:        TAILQ_HEAD_INITIALIZER(deferred_config_queue);
                    183: struct deferred_config_head interrupt_config_queue =
                    184:        TAILQ_HEAD_INITIALIZER(interrupt_config_queue);
1.42      thorpej   185:
1.102     thorpej   186: static void config_process_deferred(struct deferred_config_head *, device_t);
1.29      thorpej   187:
1.75      thorpej   188: /* Hooks to finalize configuration once all real devices have been found. */
                    189: struct finalize_hook {
                    190:        TAILQ_ENTRY(finalize_hook) f_list;
1.102     thorpej   191:        int (*f_func)(device_t);
                    192:        device_t f_dev;
1.75      thorpej   193: };
1.121     matt      194: static TAILQ_HEAD(, finalize_hook) config_finalize_list =
                    195:        TAILQ_HEAD_INITIALIZER(config_finalize_list);
1.75      thorpej   196: static int config_finalize_done;
                    197:
1.56      thorpej   198: /* list of all devices */
1.121     matt      199: struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
1.56      thorpej   200:
1.103     perry     201: volatile int config_pending;           /* semaphore for mountroot */
1.47      thorpej   202:
1.67      thorpej   203: #define        STREQ(s1, s2)                   \
1.70      thorpej   204:        (*(s1) == *(s2) && strcmp((s1), (s2)) == 0)
1.67      thorpej   205:
1.74      thorpej   206: static int config_initialized;         /* config_init() has been called. */
                    207:
1.80      thorpej   208: static int config_do_twiddle;
                    209:
1.118     dyoung    210: struct vnode *
                    211: opendisk(struct device *dv)
                    212: {
                    213:        int bmajor, bminor;
                    214:        struct vnode *tmpvn;
                    215:        int error;
                    216:        dev_t dev;
                    217:
                    218:        /*
                    219:         * Lookup major number for disk block device.
                    220:         */
                    221:        bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
                    222:        if (bmajor == -1)
                    223:                return NULL;
                    224:
                    225:        bminor = minor(device_unit(dv));
                    226:        /*
                    227:         * Fake a temporary vnode for the disk, open it, and read
                    228:         * and hash the sectors.
                    229:         */
                    230:        dev = device_is_a(dv, "dk") ? makedev(bmajor, bminor) :
                    231:            MAKEDISKDEV(bmajor, bminor, RAW_PART);
                    232:        if (bdevvp(dev, &tmpvn))
                    233:                panic("%s: can't alloc vnode for %s", __func__,
                    234:                    device_xname(dv));
1.123     pooka     235:        error = VOP_OPEN(tmpvn, FREAD, NOCRED);
1.118     dyoung    236:        if (error) {
                    237: #ifndef DEBUG
                    238:                /*
                    239:                 * Ignore errors caused by missing device, partition,
                    240:                 * or medium.
                    241:                 */
                    242:                if (error != ENXIO && error != ENODEV)
                    243: #endif
                    244:                        printf("%s: can't open dev %s (%d)\n",
                    245:                            __func__, device_xname(dv), error);
                    246:                vput(tmpvn);
                    247:                return NULL;
                    248:        }
                    249:
                    250:        return tmpvn;
                    251: }
                    252:
                    253: int
                    254: config_handle_wedges(struct device *dv, int par)
                    255: {
                    256:        struct dkwedge_list wl;
                    257:        struct dkwedge_info *wi;
                    258:        struct vnode *vn;
                    259:        char diskname[16];
                    260:        int i, error;
                    261:
                    262:        if ((vn = opendisk(dv)) == NULL)
                    263:                return -1;
                    264:
                    265:        wl.dkwl_bufsize = sizeof(*wi) * 16;
                    266:        wl.dkwl_buf = wi = malloc(wl.dkwl_bufsize, M_TEMP, M_WAITOK);
                    267:
1.123     pooka     268:        error = VOP_IOCTL(vn, DIOCLWEDGES, &wl, FREAD, NOCRED);
                    269:        VOP_CLOSE(vn, FREAD, NOCRED);
1.118     dyoung    270:        vput(vn);
                    271:        if (error) {
                    272: #ifdef DEBUG_WEDGE
                    273:                printf("%s: List wedges returned %d\n",
                    274:                    device_xname(dv), error);
                    275: #endif
                    276:                free(wi, M_TEMP);
                    277:                return -1;
                    278:        }
                    279:
                    280: #ifdef DEBUG_WEDGE
                    281:        printf("%s: Returned %u(%u) wedges\n", device_xname(dv),
                    282:            wl.dkwl_nwedges, wl.dkwl_ncopied);
                    283: #endif
                    284:        snprintf(diskname, sizeof(diskname), "%s%c", device_xname(dv),
                    285:            par + 'a');
                    286:
                    287:        for (i = 0; i < wl.dkwl_ncopied; i++) {
                    288: #ifdef DEBUG_WEDGE
                    289:                printf("%s: Looking for %s in %s\n",
                    290:                    device_xname(dv), diskname, wi[i].dkw_wname);
                    291: #endif
                    292:                if (strcmp(wi[i].dkw_wname, diskname) == 0)
                    293:                        break;
                    294:        }
                    295:
                    296:        if (i == wl.dkwl_ncopied) {
                    297: #ifdef DEBUG_WEDGE
                    298:                printf("%s: Cannot find wedge with parent %s\n",
                    299:                    device_xname(dv), diskname);
                    300: #endif
                    301:                free(wi, M_TEMP);
                    302:                return -1;
                    303:        }
                    304:
                    305: #ifdef DEBUG_WEDGE
                    306:        printf("%s: Setting boot wedge %s (%s) at %llu %llu\n",
                    307:                device_xname(dv), wi[i].dkw_devname, wi[i].dkw_wname,
                    308:                (unsigned long long)wi[i].dkw_offset,
                    309:                (unsigned long long)wi[i].dkw_size);
                    310: #endif
                    311:        dkwedge_set_bootwedge(dv, wi[i].dkw_offset, wi[i].dkw_size);
                    312:        free(wi, M_TEMP);
                    313:        return 0;
                    314: }
                    315:
1.20      cgd       316: /*
1.74      thorpej   317:  * Initialize the autoconfiguration data structures.  Normally this
                    318:  * is done by configure(), but some platforms need to do this very
                    319:  * early (to e.g. initialize the console).
1.20      cgd       320:  */
                    321: void
1.74      thorpej   322: config_init(void)
1.20      cgd       323: {
1.76      thorpej   324:        const struct cfattachinit *cfai;
                    325:        int i, j;
1.67      thorpej   326:
1.74      thorpej   327:        if (config_initialized)
                    328:                return;
                    329:
1.69      thorpej   330:        /* allcfdrivers is statically initialized. */
1.76      thorpej   331:        for (i = 0; cfdriver_list_initial[i] != NULL; i++) {
1.67      thorpej   332:                if (config_cfdriver_attach(cfdriver_list_initial[i]) != 0)
                    333:                        panic("configure: duplicate `%s' drivers",
                    334:                            cfdriver_list_initial[i]->cd_name);
1.76      thorpej   335:        }
                    336:
                    337:        for (cfai = &cfattachinit[0]; cfai->cfai_name != NULL; cfai++) {
                    338:                for (j = 0; cfai->cfai_list[j] != NULL; j++) {
                    339:                        if (config_cfattach_attach(cfai->cfai_name,
                    340:                                                   cfai->cfai_list[j]) != 0)
                    341:                                panic("configure: duplicate `%s' attachment "
                    342:                                    "of `%s' driver",
                    343:                                    cfai->cfai_list[j]->ca_name,
                    344:                                    cfai->cfai_name);
                    345:                }
                    346:        }
1.20      cgd       347:
1.65      thorpej   348:        initcftable.ct_cfdata = cfdata;
                    349:        TAILQ_INSERT_TAIL(&allcftables, &initcftable, ct_list);
                    350:
1.74      thorpej   351:        config_initialized = 1;
                    352: }
                    353:
1.126     dyoung    354: void
                    355: config_deferred(device_t dev)
                    356: {
                    357:        config_process_deferred(&deferred_config_queue, dev);
                    358:        config_process_deferred(&interrupt_config_queue, dev);
                    359: }
                    360:
1.74      thorpej   361: /*
                    362:  * Configure the system's hardware.
                    363:  */
                    364: void
                    365: configure(void)
                    366: {
1.80      thorpej   367:        int errcnt;
1.74      thorpej   368:
                    369:        /* Initialize data structures. */
                    370:        config_init();
1.124     jmcneill  371:        pmf_init();
1.86      thorpej   372:
1.57      gmcgarry  373: #ifdef USERCONF
                    374:        if (boothowto & RB_USERCONF)
                    375:                user_config();
                    376: #endif
1.41      thorpej   377:
1.80      thorpej   378:        if ((boothowto & (AB_SILENT|AB_VERBOSE)) == AB_SILENT) {
                    379:                config_do_twiddle = 1;
                    380:                printf_nolog("Detecting hardware...");
                    381:        }
                    382:
1.41      thorpej   383:        /*
                    384:         * Do the machine-dependent portion of autoconfiguration.  This
                    385:         * sets the configuration machinery here in motion by "finding"
                    386:         * the root bus.  When this function returns, we expect interrupts
                    387:         * to be enabled.
                    388:         */
                    389:        cpu_configure();
1.43      thorpej   390:
1.119     tsutsui   391:        /* Initialize callouts, part 2. */
                    392:        callout_startup2();
                    393:
1.43      thorpej   394:        /*
                    395:         * Now that we've found all the hardware, start the real time
                    396:         * and statistics clocks.
                    397:         */
                    398:        initclocks();
                    399:
                    400:        cold = 0;       /* clocks are running, we're warm now! */
1.42      thorpej   401:
1.129     yamt      402:        /* Boot the secondary processors. */
                    403:        mp_online = true;
1.122     ad        404: #if defined(MULTIPROCESSOR)
                    405:        cpu_boot_secondary_processors();
                    406: #endif
                    407:
1.42      thorpej   408:        /*
                    409:         * Now callback to finish configuration for devices which want
                    410:         * to do this once interrupts are enabled.
                    411:         */
                    412:        config_process_deferred(&interrupt_config_queue, NULL);
1.80      thorpej   413:
                    414:        errcnt = aprint_get_error_count();
                    415:        if ((boothowto & (AB_QUIET|AB_SILENT)) != 0 &&
                    416:            (boothowto & AB_VERBOSE) == 0) {
                    417:                if (config_do_twiddle) {
                    418:                        config_do_twiddle = 0;
                    419:                        printf_nolog("done.\n");
                    420:                }
                    421:                if (errcnt != 0) {
                    422:                        printf("WARNING: %d error%s while detecting hardware; "
                    423:                            "check system log.\n", errcnt,
                    424:                            errcnt == 1 ? "" : "s");
                    425:                }
                    426:        }
1.20      cgd       427: }
                    428:
1.1       glass     429: /*
1.67      thorpej   430:  * Add a cfdriver to the system.
                    431:  */
                    432: int
                    433: config_cfdriver_attach(struct cfdriver *cd)
                    434: {
                    435:        struct cfdriver *lcd;
                    436:
                    437:        /* Make sure this driver isn't already in the system. */
                    438:        LIST_FOREACH(lcd, &allcfdrivers, cd_list) {
                    439:                if (STREQ(lcd->cd_name, cd->cd_name))
                    440:                        return (EEXIST);
                    441:        }
                    442:
1.76      thorpej   443:        LIST_INIT(&cd->cd_attach);
1.67      thorpej   444:        LIST_INSERT_HEAD(&allcfdrivers, cd, cd_list);
                    445:
                    446:        return (0);
                    447: }
                    448:
                    449: /*
                    450:  * Remove a cfdriver from the system.
                    451:  */
                    452: int
                    453: config_cfdriver_detach(struct cfdriver *cd)
                    454: {
                    455:        int i;
                    456:
                    457:        /* Make sure there are no active instances. */
                    458:        for (i = 0; i < cd->cd_ndevs; i++) {
                    459:                if (cd->cd_devs[i] != NULL)
                    460:                        return (EBUSY);
                    461:        }
                    462:
1.76      thorpej   463:        /* ...and no attachments loaded. */
                    464:        if (LIST_EMPTY(&cd->cd_attach) == 0)
                    465:                return (EBUSY);
                    466:
1.67      thorpej   467:        LIST_REMOVE(cd, cd_list);
                    468:
                    469:        KASSERT(cd->cd_devs == NULL);
                    470:
                    471:        return (0);
                    472: }
                    473:
                    474: /*
                    475:  * Look up a cfdriver by name.
                    476:  */
1.78      isaki     477: struct cfdriver *
1.67      thorpej   478: config_cfdriver_lookup(const char *name)
                    479: {
                    480:        struct cfdriver *cd;
1.69      thorpej   481:
1.67      thorpej   482:        LIST_FOREACH(cd, &allcfdrivers, cd_list) {
                    483:                if (STREQ(cd->cd_name, name))
                    484:                        return (cd);
                    485:        }
                    486:
                    487:        return (NULL);
                    488: }
                    489:
                    490: /*
1.76      thorpej   491:  * Add a cfattach to the specified driver.
                    492:  */
                    493: int
                    494: config_cfattach_attach(const char *driver, struct cfattach *ca)
                    495: {
                    496:        struct cfattach *lca;
                    497:        struct cfdriver *cd;
                    498:
                    499:        cd = config_cfdriver_lookup(driver);
                    500:        if (cd == NULL)
                    501:                return (ESRCH);
                    502:
                    503:        /* Make sure this attachment isn't already on this driver. */
                    504:        LIST_FOREACH(lca, &cd->cd_attach, ca_list) {
                    505:                if (STREQ(lca->ca_name, ca->ca_name))
                    506:                        return (EEXIST);
                    507:        }
                    508:
                    509:        LIST_INSERT_HEAD(&cd->cd_attach, ca, ca_list);
                    510:
                    511:        return (0);
                    512: }
                    513:
                    514: /*
                    515:  * Remove a cfattach from the specified driver.
                    516:  */
                    517: int
                    518: config_cfattach_detach(const char *driver, struct cfattach *ca)
                    519: {
                    520:        struct cfdriver *cd;
1.102     thorpej   521:        device_t dev;
1.76      thorpej   522:        int i;
                    523:
                    524:        cd = config_cfdriver_lookup(driver);
                    525:        if (cd == NULL)
                    526:                return (ESRCH);
                    527:
                    528:        /* Make sure there are no active instances. */
                    529:        for (i = 0; i < cd->cd_ndevs; i++) {
                    530:                if ((dev = cd->cd_devs[i]) == NULL)
                    531:                        continue;
1.77      thorpej   532:                if (dev->dv_cfattach == ca)
1.76      thorpej   533:                        return (EBUSY);
                    534:        }
                    535:
                    536:        LIST_REMOVE(ca, ca_list);
                    537:
                    538:        return (0);
                    539: }
                    540:
                    541: /*
                    542:  * Look up a cfattach by name.
                    543:  */
                    544: static struct cfattach *
                    545: config_cfattach_lookup_cd(struct cfdriver *cd, const char *atname)
                    546: {
                    547:        struct cfattach *ca;
                    548:
                    549:        LIST_FOREACH(ca, &cd->cd_attach, ca_list) {
                    550:                if (STREQ(ca->ca_name, atname))
                    551:                        return (ca);
                    552:        }
                    553:
                    554:        return (NULL);
                    555: }
                    556:
                    557: /*
                    558:  * Look up a cfattach by driver/attachment name.
                    559:  */
                    560: struct cfattach *
                    561: config_cfattach_lookup(const char *name, const char *atname)
                    562: {
                    563:        struct cfdriver *cd;
                    564:
                    565:        cd = config_cfdriver_lookup(name);
                    566:        if (cd == NULL)
                    567:                return (NULL);
                    568:
                    569:        return (config_cfattach_lookup_cd(cd, atname));
                    570: }
                    571:
                    572: /*
1.1       glass     573:  * Apply the matching function and choose the best.  This is used
                    574:  * a few times and we want to keep the code small.
                    575:  */
1.16      mycroft   576: static void
1.102     thorpej   577: mapply(struct matchinfo *m, cfdata_t cf)
1.1       glass     578: {
1.50      augustss  579:        int pri;
1.1       glass     580:
1.99      drochner  581:        if (m->fn != NULL) {
                    582:                pri = (*m->fn)(m->parent, cf, m->locs, m->aux);
1.90      drochner  583:        } else {
1.100     drochner  584:                pri = config_match(m->parent, cf, m->aux);
1.3       glass     585:        }
1.1       glass     586:        if (pri > m->pri) {
1.25      cgd       587:                m->match = cf;
1.1       glass     588:                m->pri = pri;
                    589:        }
                    590: }
                    591:
1.98      drochner  592: int
1.102     thorpej   593: config_stdsubmatch(device_t parent, cfdata_t cf, const int *locs, void *aux)
1.98      drochner  594: {
                    595:        const struct cfiattrdata *ci;
                    596:        const struct cflocdesc *cl;
                    597:        int nlocs, i;
                    598:
                    599:        ci = cfiattr_lookup(cf->cf_pspec->cfp_iattr, parent->dv_cfdriver);
                    600:        KASSERT(ci);
                    601:        nlocs = ci->ci_loclen;
                    602:        for (i = 0; i < nlocs; i++) {
                    603:                cl = &ci->ci_locdesc[i];
                    604:                /* !cld_defaultstr means no default value */
                    605:                if ((!(cl->cld_defaultstr)
                    606:                     || (cf->cf_loc[i] != cl->cld_default))
                    607:                    && cf->cf_loc[i] != locs[i])
                    608:                        return (0);
                    609:        }
                    610:
                    611:        return (config_match(parent, cf, aux));
                    612: }
                    613:
1.1       glass     614: /*
1.96      drochner  615:  * Helper function: check whether the driver supports the interface attribute
                    616:  * and return its descriptor structure.
1.91      drochner  617:  */
1.96      drochner  618: static const struct cfiattrdata *
                    619: cfdriver_get_iattr(const struct cfdriver *cd, const char *ia)
1.91      drochner  620: {
1.96      drochner  621:        const struct cfiattrdata * const *cpp;
1.91      drochner  622:
                    623:        if (cd->cd_attrs == NULL)
                    624:                return (0);
                    625:
                    626:        for (cpp = cd->cd_attrs; *cpp; cpp++) {
1.96      drochner  627:                if (STREQ((*cpp)->ci_name, ia)) {
1.91      drochner  628:                        /* Match. */
1.96      drochner  629:                        return (*cpp);
1.91      drochner  630:                }
                    631:        }
                    632:        return (0);
                    633: }
                    634:
                    635: /*
1.96      drochner  636:  * Lookup an interface attribute description by name.
                    637:  * If the driver is given, consider only its supported attributes.
                    638:  */
                    639: const struct cfiattrdata *
                    640: cfiattr_lookup(const char *name, const struct cfdriver *cd)
                    641: {
                    642:        const struct cfdriver *d;
                    643:        const struct cfiattrdata *ia;
                    644:
                    645:        if (cd)
                    646:                return (cfdriver_get_iattr(cd, name));
                    647:
                    648:        LIST_FOREACH(d, &allcfdrivers, cd_list) {
                    649:                ia = cfdriver_get_iattr(d, name);
                    650:                if (ia)
                    651:                        return (ia);
                    652:        }
                    653:        return (0);
                    654: }
                    655:
                    656: /*
1.66      thorpej   657:  * Determine if `parent' is a potential parent for a device spec based
                    658:  * on `cfp'.
                    659:  */
                    660: static int
1.102     thorpej   661: cfparent_match(const device_t parent, const struct cfparent *cfp)
1.66      thorpej   662: {
1.67      thorpej   663:        struct cfdriver *pcd;
1.70      thorpej   664:
                    665:        /* We don't match root nodes here. */
                    666:        if (cfp == NULL)
                    667:                return (0);
1.66      thorpej   668:
1.77      thorpej   669:        pcd = parent->dv_cfdriver;
1.67      thorpej   670:        KASSERT(pcd != NULL);
                    671:
1.66      thorpej   672:        /*
                    673:         * First, ensure this parent has the correct interface
                    674:         * attribute.
                    675:         */
1.96      drochner  676:        if (!cfdriver_get_iattr(pcd, cfp->cfp_iattr))
1.91      drochner  677:                return (0);
1.66      thorpej   678:
                    679:        /*
                    680:         * If no specific parent device instance was specified (i.e.
                    681:         * we're attaching to the attribute only), we're done!
                    682:         */
                    683:        if (cfp->cfp_parent == NULL)
                    684:                return (1);
                    685:
                    686:        /*
                    687:         * Check the parent device's name.
                    688:         */
1.71      thorpej   689:        if (STREQ(pcd->cd_name, cfp->cfp_parent) == 0)
1.66      thorpej   690:                return (0);     /* not the same parent */
                    691:
                    692:        /*
                    693:         * Make sure the unit number matches.
                    694:         */
1.77      thorpej   695:        if (cfp->cfp_unit == DVUNIT_ANY ||      /* wildcard */
1.66      thorpej   696:            cfp->cfp_unit == parent->dv_unit)
                    697:                return (1);
                    698:
                    699:        /* Unit numbers don't match. */
                    700:        return (0);
1.68      thorpej   701: }
                    702:
                    703: /*
1.90      drochner  704:  * Helper for config_cfdata_attach(): check all devices whether it could be
                    705:  * parent any attachment in the config data table passed, and rescan.
                    706:  */
                    707: static void
                    708: rescan_with_cfdata(const struct cfdata *cf)
                    709: {
1.102     thorpej   710:        device_t d;
1.90      drochner  711:        const struct cfdata *cf1;
                    712:
                    713:        /*
                    714:         * "alldevs" is likely longer than an LKM's cfdata, so make it
                    715:         * the outer loop.
                    716:         */
                    717:        TAILQ_FOREACH(d, &alldevs, dv_list) {
                    718:
                    719:                if (!(d->dv_cfattach->ca_rescan))
                    720:                        continue;
                    721:
                    722:                for (cf1 = cf; cf1->cf_name; cf1++) {
                    723:
                    724:                        if (!cfparent_match(d, cf1->cf_pspec))
                    725:                                continue;
                    726:
                    727:                        (*d->dv_cfattach->ca_rescan)(d,
                    728:                                cf1->cf_pspec->cfp_iattr, cf1->cf_loc);
                    729:                }
                    730:        }
                    731: }
                    732:
                    733: /*
                    734:  * Attach a supplemental config data table and rescan potential
                    735:  * parent devices if required.
                    736:  */
                    737: int
1.102     thorpej   738: config_cfdata_attach(cfdata_t cf, int scannow)
1.90      drochner  739: {
                    740:        struct cftable *ct;
                    741:
                    742:        ct = malloc(sizeof(struct cftable), M_DEVBUF, M_WAITOK);
                    743:        ct->ct_cfdata = cf;
                    744:        TAILQ_INSERT_TAIL(&allcftables, ct, ct_list);
                    745:
                    746:        if (scannow)
                    747:                rescan_with_cfdata(cf);
                    748:
                    749:        return (0);
                    750: }
                    751:
                    752: /*
                    753:  * Helper for config_cfdata_detach: check whether a device is
                    754:  * found through any attachment in the config data table.
                    755:  */
                    756: static int
                    757: dev_in_cfdata(const struct device *d, const struct cfdata *cf)
                    758: {
                    759:        const struct cfdata *cf1;
                    760:
                    761:        for (cf1 = cf; cf1->cf_name; cf1++)
                    762:                if (d->dv_cfdata == cf1)
                    763:                        return (1);
                    764:
                    765:        return (0);
                    766: }
                    767:
                    768: /*
                    769:  * Detach a supplemental config data table. Detach all devices found
                    770:  * through that table (and thus keeping references to it) before.
                    771:  */
                    772: int
1.102     thorpej   773: config_cfdata_detach(cfdata_t cf)
1.90      drochner  774: {
1.102     thorpej   775:        device_t d;
1.90      drochner  776:        int error;
                    777:        struct cftable *ct;
                    778:
                    779: again:
                    780:        TAILQ_FOREACH(d, &alldevs, dv_list) {
                    781:                if (dev_in_cfdata(d, cf)) {
                    782:                        error = config_detach(d, 0);
                    783:                        if (error) {
                    784:                                aprint_error("%s: unable to detach instance\n",
                    785:                                        d->dv_xname);
                    786:                                return (error);
                    787:                        }
                    788:                        goto again;
                    789:                }
                    790:        }
                    791:
                    792:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
                    793:                if (ct->ct_cfdata == cf) {
                    794:                        TAILQ_REMOVE(&allcftables, ct, ct_list);
                    795:                        free(ct, M_DEVBUF);
                    796:                        return (0);
                    797:                }
                    798:        }
                    799:
                    800:        /* not found -- shouldn't happen */
                    801:        return (EINVAL);
                    802: }
                    803:
                    804: /*
1.68      thorpej   805:  * Invoke the "match" routine for a cfdata entry on behalf of
                    806:  * an external caller, usually a "submatch" routine.
                    807:  */
                    808: int
1.102     thorpej   809: config_match(device_t parent, cfdata_t cf, void *aux)
1.68      thorpej   810: {
1.76      thorpej   811:        struct cfattach *ca;
                    812:
                    813:        ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname);
                    814:        if (ca == NULL) {
                    815:                /* No attachment for this entry, oh well. */
                    816:                return (0);
                    817:        }
1.68      thorpej   818:
1.76      thorpej   819:        return ((*ca->ca_match)(parent, cf, aux));
1.66      thorpej   820: }
                    821:
                    822: /*
1.1       glass     823:  * Iterate over all potential children of some device, calling the given
                    824:  * function (default being the child's match function) for each one.
                    825:  * Nonzero returns are matches; the highest value returned is considered
                    826:  * the best match.  Return the `found child' if we got a match, or NULL
                    827:  * otherwise.  The `aux' pointer is simply passed on through.
                    828:  *
                    829:  * Note that this function is designed so that it can be used to apply
                    830:  * an arbitrary function to all potential children (its return value
                    831:  * can be ignored).
                    832:  */
1.102     thorpej   833: cfdata_t
                    834: config_search_loc(cfsubmatch_t fn, device_t parent,
1.99      drochner  835:                  const char *ifattr, const int *locs, void *aux)
1.90      drochner  836: {
                    837:        struct cftable *ct;
1.102     thorpej   838:        cfdata_t cf;
1.90      drochner  839:        struct matchinfo m;
                    840:
                    841:        KASSERT(config_initialized);
1.96      drochner  842:        KASSERT(!ifattr || cfdriver_get_iattr(parent->dv_cfdriver, ifattr));
1.90      drochner  843:
1.99      drochner  844:        m.fn = fn;
1.1       glass     845:        m.parent = parent;
1.99      drochner  846:        m.locs = locs;
1.25      cgd       847:        m.aux = aux;
1.14      mycroft   848:        m.match = NULL;
1.1       glass     849:        m.pri = 0;
1.65      thorpej   850:
                    851:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67      thorpej   852:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.90      drochner  853:
                    854:                        /* We don't match root nodes here. */
                    855:                        if (!cf->cf_pspec)
                    856:                                continue;
                    857:
1.65      thorpej   858:                        /*
                    859:                         * Skip cf if no longer eligible, otherwise scan
                    860:                         * through parents for one matching `parent', and
                    861:                         * try match function.
                    862:                         */
                    863:                        if (cf->cf_fstate == FSTATE_FOUND)
                    864:                                continue;
                    865:                        if (cf->cf_fstate == FSTATE_DNOTFOUND ||
                    866:                            cf->cf_fstate == FSTATE_DSTAR)
                    867:                                continue;
1.90      drochner  868:
                    869:                        /*
                    870:                         * If an interface attribute was specified,
                    871:                         * consider only children which attach to
                    872:                         * that attribute.
                    873:                         */
                    874:                        if (ifattr && !STREQ(ifattr, cf->cf_pspec->cfp_iattr))
                    875:                                continue;
                    876:
1.66      thorpej   877:                        if (cfparent_match(parent, cf->cf_pspec))
                    878:                                mapply(&m, cf);
1.65      thorpej   879:                }
1.1       glass     880:        }
                    881:        return (m.match);
                    882: }
                    883:
1.102     thorpej   884: cfdata_t
                    885: config_search_ia(cfsubmatch_t fn, device_t parent, const char *ifattr,
                    886:     void *aux)
                    887: {
                    888:
                    889:        return (config_search_loc(fn, parent, ifattr, NULL, aux));
                    890: }
                    891:
1.16      mycroft   892: /*
1.1       glass     893:  * Find the given root device.
                    894:  * This is much like config_search, but there is no parent.
1.65      thorpej   895:  * Don't bother with multiple cfdata tables; the root node
                    896:  * must always be in the initial table.
1.1       glass     897:  */
1.102     thorpej   898: cfdata_t
1.95      drochner  899: config_rootsearch(cfsubmatch_t fn, const char *rootname, void *aux)
1.1       glass     900: {
1.102     thorpej   901:        cfdata_t cf;
1.84      matt      902:        const short *p;
1.1       glass     903:        struct matchinfo m;
                    904:
1.99      drochner  905:        m.fn = fn;
1.1       glass     906:        m.parent = ROOT;
1.25      cgd       907:        m.aux = aux;
1.14      mycroft   908:        m.match = NULL;
1.1       glass     909:        m.pri = 0;
1.114     christos  910:        m.locs = 0;
1.1       glass     911:        /*
                    912:         * Look at root entries for matching name.  We do not bother
                    913:         * with found-state here since only one root should ever be
                    914:         * searched (and it must be done first).
                    915:         */
                    916:        for (p = cfroots; *p >= 0; p++) {
                    917:                cf = &cfdata[*p];
1.67      thorpej   918:                if (strcmp(cf->cf_name, rootname) == 0)
1.16      mycroft   919:                        mapply(&m, cf);
1.1       glass     920:        }
                    921:        return (m.match);
                    922: }
                    923:
1.83      jdolecek  924: static const char * const msgs[3] = { "", " not configured\n", " unsupported\n" };
1.1       glass     925:
                    926: /*
                    927:  * The given `aux' argument describes a device that has been found
                    928:  * on the given parent, but not necessarily configured.  Locate the
1.18      cgd       929:  * configuration data for that device (using the submatch function
                    930:  * provided, or using candidates' cd_match configuration driver
                    931:  * functions) and attach it, and return true.  If the device was
1.1       glass     932:  * not configured, call the given `print' function and return 0.
                    933:  */
1.102     thorpej   934: device_t
                    935: config_found_sm_loc(device_t parent,
1.99      drochner  936:                const char *ifattr, const int *locs, void *aux,
1.95      drochner  937:                cfprint_t print, cfsubmatch_t submatch)
1.90      drochner  938: {
1.102     thorpej   939:        cfdata_t cf;
1.90      drochner  940:
1.105     jmcneill  941: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                    942:        if (splash_progress_state)
                    943:                splash_progress_update(splash_progress_state);
                    944: #endif
                    945:
1.99      drochner  946:        if ((cf = config_search_loc(submatch, parent, ifattr, locs, aux)))
                    947:                return(config_attach_loc(parent, cf, locs, aux, print));
1.90      drochner  948:        if (print) {
                    949:                if (config_do_twiddle)
                    950:                        twiddle();
                    951:                aprint_normal("%s", msgs[(*print)(aux, parent->dv_xname)]);
                    952:        }
1.105     jmcneill  953:
                    954: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                    955:        if (splash_progress_state)
                    956:                splash_progress_update(splash_progress_state);
                    957: #endif
                    958:
1.90      drochner  959:        return (NULL);
                    960: }
                    961:
1.102     thorpej   962: device_t
                    963: config_found_ia(device_t parent, const char *ifattr, void *aux,
                    964:     cfprint_t print)
                    965: {
                    966:
                    967:        return (config_found_sm_loc(parent, ifattr, NULL, aux, print, NULL));
                    968: }
                    969:
                    970: device_t
                    971: config_found(device_t parent, void *aux, cfprint_t print)
                    972: {
                    973:
                    974:        return (config_found_sm_loc(parent, NULL, NULL, aux, print, NULL));
                    975: }
                    976:
1.1       glass     977: /*
                    978:  * As above, but for root devices.
                    979:  */
1.102     thorpej   980: device_t
1.52      cgd       981: config_rootfound(const char *rootname, void *aux)
1.1       glass     982: {
1.102     thorpej   983:        cfdata_t cf;
1.25      cgd       984:
1.95      drochner  985:        if ((cf = config_rootsearch((cfsubmatch_t)NULL, rootname, aux)) != NULL)
1.25      cgd       986:                return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
1.80      thorpej   987:        aprint_error("root device %s not configured\n", rootname);
1.21      cgd       988:        return (NULL);
1.1       glass     989: }
                    990:
                    991: /* just like sprintf(buf, "%d") except that it works from the end */
                    992: static char *
1.51      cgd       993: number(char *ep, int n)
1.1       glass     994: {
                    995:
                    996:        *--ep = 0;
                    997:        while (n >= 10) {
                    998:                *--ep = (n % 10) + '0';
                    999:                n /= 10;
                   1000:        }
                   1001:        *--ep = n + '0';
                   1002:        return (ep);
                   1003: }
                   1004:
                   1005: /*
1.59      augustss 1006:  * Expand the size of the cd_devs array if necessary.
                   1007:  */
1.117     drochner 1008: static void
1.59      augustss 1009: config_makeroom(int n, struct cfdriver *cd)
                   1010: {
                   1011:        int old, new;
                   1012:        void **nsp;
                   1013:
                   1014:        if (n < cd->cd_ndevs)
                   1015:                return;
                   1016:
                   1017:        /*
                   1018:         * Need to expand the array.
                   1019:         */
                   1020:        old = cd->cd_ndevs;
1.61      thorpej  1021:        if (old == 0)
1.115     chs      1022:                new = 4;
1.59      augustss 1023:        else
                   1024:                new = old * 2;
                   1025:        while (new <= n)
                   1026:                new *= 2;
                   1027:        cd->cd_ndevs = new;
                   1028:        nsp = malloc(new * sizeof(void *), M_DEVBUF,
1.93      perry    1029:            cold ? M_NOWAIT : M_WAITOK);
1.60      augustss 1030:        if (nsp == NULL)
1.59      augustss 1031:                panic("config_attach: %sing dev array",
                   1032:                    old != 0 ? "expand" : "creat");
                   1033:        memset(nsp + old, 0, (new - old) * sizeof(void *));
1.61      thorpej  1034:        if (old != 0) {
1.59      augustss 1035:                memcpy(nsp, cd->cd_devs, old * sizeof(void *));
                   1036:                free(cd->cd_devs, M_DEVBUF);
                   1037:        }
                   1038:        cd->cd_devs = nsp;
                   1039: }
                   1040:
1.117     drochner 1041: static void
                   1042: config_devlink(device_t dev)
                   1043: {
                   1044:        struct cfdriver *cd = dev->dv_cfdriver;
                   1045:
                   1046:        /* put this device in the devices array */
                   1047:        config_makeroom(dev->dv_unit, cd);
                   1048:        if (cd->cd_devs[dev->dv_unit])
                   1049:                panic("config_attach: duplicate %s", dev->dv_xname);
                   1050:        cd->cd_devs[dev->dv_unit] = dev;
                   1051:
                   1052:        TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);      /* link up */
                   1053: }
                   1054:
                   1055: static void
                   1056: config_devunlink(device_t dev)
                   1057: {
                   1058:        struct cfdriver *cd = dev->dv_cfdriver;
                   1059:        int i;
                   1060:
                   1061:        /* Unlink from device list. */
                   1062:        TAILQ_REMOVE(&alldevs, dev, dv_list);
                   1063:
                   1064:        /* Remove from cfdriver's array. */
                   1065:        cd->cd_devs[dev->dv_unit] = NULL;
                   1066:
                   1067:        /*
                   1068:         * If the device now has no units in use, deallocate its softc array.
                   1069:         */
                   1070:        for (i = 0; i < cd->cd_ndevs; i++)
                   1071:                if (cd->cd_devs[i] != NULL)
                   1072:                        break;
                   1073:        if (i == cd->cd_ndevs) {                /* nothing found; deallocate */
                   1074:                free(cd->cd_devs, M_DEVBUF);
                   1075:                cd->cd_devs = NULL;
                   1076:                cd->cd_ndevs = 0;
                   1077:        }
                   1078: }
                   1079:
                   1080: static device_t
                   1081: config_devalloc(const device_t parent, const cfdata_t cf, const int *locs)
1.25      cgd      1082: {
1.50      augustss 1083:        struct cfdriver *cd;
1.76      thorpej  1084:        struct cfattach *ca;
1.50      augustss 1085:        size_t lname, lunit;
1.52      cgd      1086:        const char *xunit;
1.25      cgd      1087:        int myunit;
                   1088:        char num[10];
1.117     drochner 1089:        device_t dev;
1.120     joerg    1090:        void *dev_private;
1.96      drochner 1091:        const struct cfiattrdata *ia;
1.25      cgd      1092:
1.67      thorpej  1093:        cd = config_cfdriver_lookup(cf->cf_name);
1.117     drochner 1094:        if (cd == NULL)
                   1095:                return (NULL);
1.76      thorpej  1096:
                   1097:        ca = config_cfattach_lookup_cd(cd, cf->cf_atname);
1.117     drochner 1098:        if (ca == NULL)
                   1099:                return (NULL);
1.76      thorpej  1100:
1.120     joerg    1101:        if ((ca->ca_flags & DVF_PRIV_ALLOC) == 0 &&
                   1102:            ca->ca_devsize < sizeof(struct device))
1.117     drochner 1103:                panic("config_devalloc");
1.66      thorpej  1104:
1.46      cgd      1105: #ifndef __BROKEN_CONFIG_UNIT_USAGE
1.45      cgd      1106:        if (cf->cf_fstate == FSTATE_STAR) {
                   1107:                for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
                   1108:                        if (cd->cd_devs[myunit] == NULL)
                   1109:                                break;
                   1110:                /*
                   1111:                 * myunit is now the unit of the first NULL device pointer,
                   1112:                 * or max(cd->cd_ndevs,cf->cf_unit).
                   1113:                 */
                   1114:        } else {
                   1115:                myunit = cf->cf_unit;
1.117     drochner 1116:                if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL)
                   1117:                        return (NULL);
                   1118:        }
1.66      thorpej  1119: #else
1.46      cgd      1120:        myunit = cf->cf_unit;
1.66      thorpej  1121: #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */
1.25      cgd      1122:
                   1123:        /* compute length of name and decimal expansion of unit number */
                   1124:        lname = strlen(cd->cd_name);
1.30      perry    1125:        xunit = number(&num[sizeof(num)], myunit);
                   1126:        lunit = &num[sizeof(num)] - xunit;
1.64      drochner 1127:        if (lname + lunit > sizeof(dev->dv_xname))
1.117     drochner 1128:                panic("config_devalloc: device name too long");
1.25      cgd      1129:
                   1130:        /* get memory for all device vars */
1.132     matt     1131:        KASSERT((ca->ca_flags & DVF_PRIV_ALLOC) || ca->ca_devsize >= sizeof(struct device));
                   1132:        if (ca->ca_devsize > 0) {
                   1133:                dev_private = malloc(ca->ca_devsize, M_DEVBUF,
                   1134:                                     M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
                   1135:                if (dev_private == NULL)
                   1136:                        panic("config_devalloc: memory allocation for device softc failed");
                   1137:        } else {
                   1138:                KASSERT(ca->ca_flags & DVF_PRIV_ALLOC);
                   1139:                dev_private = NULL;
                   1140:        }
1.120     joerg    1141:
                   1142:        if ((ca->ca_flags & DVF_PRIV_ALLOC) != 0) {
                   1143:                dev = malloc(sizeof(struct device), M_DEVBUF,
                   1144:                             M_ZERO | (cold ? M_NOWAIT : M_WAITOK));
                   1145:        } else {
                   1146:                dev = dev_private;
                   1147:        }
                   1148:        if (dev == NULL)
                   1149:                panic("config_devalloc: memory allocation for device_t failed");
1.124     jmcneill 1150:
1.25      cgd      1151:        dev->dv_class = cd->cd_class;
                   1152:        dev->dv_cfdata = cf;
1.76      thorpej  1153:        dev->dv_cfdriver = cd;
                   1154:        dev->dv_cfattach = ca;
1.25      cgd      1155:        dev->dv_unit = myunit;
1.124     jmcneill 1156:        dev->dv_activity_count = 0;
                   1157:        dev->dv_activity_handlers = NULL;
1.120     joerg    1158:        dev->dv_private = dev_private;
1.31      perry    1159:        memcpy(dev->dv_xname, cd->cd_name, lname);
                   1160:        memcpy(dev->dv_xname + lname, xunit, lunit);
1.25      cgd      1161:        dev->dv_parent = parent;
1.124     jmcneill 1162:        if (parent != NULL)
                   1163:                dev->dv_depth = parent->dv_depth + 1;
                   1164:        else
                   1165:                dev->dv_depth = 0;
1.33      thorpej  1166:        dev->dv_flags = DVF_ACTIVE;     /* always initially active */
1.120     joerg    1167:        dev->dv_flags |= ca->ca_flags;  /* inherit flags from class */
1.97      drochner 1168:        if (locs) {
1.96      drochner 1169:                KASSERT(parent); /* no locators at root */
                   1170:                ia = cfiattr_lookup(cf->cf_pspec->cfp_iattr,
                   1171:                                    parent->dv_cfdriver);
                   1172:                dev->dv_locators = malloc(ia->ci_loclen * sizeof(int),
1.90      drochner 1173:                                          M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
1.97      drochner 1174:                memcpy(dev->dv_locators, locs, ia->ci_loclen * sizeof(int));
1.90      drochner 1175:        }
1.112     thorpej  1176:        dev->dv_properties = prop_dictionary_create();
                   1177:        KASSERT(dev->dv_properties != NULL);
1.29      thorpej  1178:
1.117     drochner 1179:        return (dev);
                   1180: }
                   1181:
                   1182: static void
                   1183: config_devdealloc(device_t dev)
                   1184: {
                   1185:
                   1186:        KASSERT(dev->dv_properties != NULL);
                   1187:        prop_object_release(dev->dv_properties);
                   1188:
1.124     jmcneill 1189:        if (dev->dv_activity_handlers)
                   1190:                panic("config_devdealloc with registered handlers");
                   1191:
1.117     drochner 1192:        if (dev->dv_locators)
                   1193:                free(dev->dv_locators, M_DEVBUF);
                   1194:
1.120     joerg    1195:        if ((dev->dv_flags & DVF_PRIV_ALLOC) != 0)
                   1196:                free(dev->dv_private, M_DEVBUF);
                   1197:
1.117     drochner 1198:        free(dev, M_DEVBUF);
                   1199: }
                   1200:
                   1201: /*
                   1202:  * Attach a found device.
                   1203:  */
                   1204: device_t
                   1205: config_attach_loc(device_t parent, cfdata_t cf,
                   1206:        const int *locs, void *aux, cfprint_t print)
                   1207: {
                   1208:        device_t dev;
                   1209:        struct cftable *ct;
                   1210:        const char *drvname;
                   1211:
                   1212: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                   1213:        if (splash_progress_state)
                   1214:                splash_progress_update(splash_progress_state);
                   1215: #endif
                   1216:
                   1217:        dev = config_devalloc(parent, cf, locs);
                   1218:        if (!dev)
                   1219:                panic("config_attach: allocation of device softc failed");
                   1220:
                   1221:        /* XXX redundant - see below? */
                   1222:        if (cf->cf_fstate != FSTATE_STAR) {
                   1223:                KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
                   1224:                cf->cf_fstate = FSTATE_FOUND;
                   1225:        }
                   1226: #ifdef __BROKEN_CONFIG_UNIT_USAGE
                   1227:          else
                   1228:                cf->cf_unit++;
                   1229: #endif
                   1230:
                   1231:        config_devlink(dev);
                   1232:
1.80      thorpej  1233:        if (config_do_twiddle)
                   1234:                twiddle();
                   1235:        else
                   1236:                aprint_naive("Found ");
                   1237:        /*
                   1238:         * We want the next two printfs for normal, verbose, and quiet,
                   1239:         * but not silent (in which case, we're twiddling, instead).
                   1240:         */
                   1241:        if (parent == ROOT) {
1.85      thorpej  1242:                aprint_naive("%s (root)", dev->dv_xname);
                   1243:                aprint_normal("%s (root)", dev->dv_xname);
1.80      thorpej  1244:        } else {
1.85      thorpej  1245:                aprint_naive("%s at %s", dev->dv_xname, parent->dv_xname);
                   1246:                aprint_normal("%s at %s", dev->dv_xname, parent->dv_xname);
1.25      cgd      1247:                if (print)
1.52      cgd      1248:                        (void) (*print)(aux, NULL);
1.25      cgd      1249:        }
                   1250:
                   1251:        /*
                   1252:         * Before attaching, clobber any unfound devices that are
1.45      cgd      1253:         * otherwise identical.
1.117     drochner 1254:         * XXX code above is redundant?
1.25      cgd      1255:         */
1.117     drochner 1256:        drvname = dev->dv_cfdriver->cd_name;
1.65      thorpej  1257:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67      thorpej  1258:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
1.117     drochner 1259:                        if (STREQ(cf->cf_name, drvname) &&
1.65      thorpej  1260:                            cf->cf_unit == dev->dv_unit) {
                   1261:                                if (cf->cf_fstate == FSTATE_NOTFOUND)
                   1262:                                        cf->cf_fstate = FSTATE_FOUND;
1.46      cgd      1263: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.66      thorpej  1264:                                /*
                   1265:                                 * Bump the unit number on all starred cfdata
                   1266:                                 * entries for this device.
                   1267:                                 */
1.65      thorpej  1268:                                if (cf->cf_fstate == FSTATE_STAR)
                   1269:                                        cf->cf_unit++;
1.46      cgd      1270: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.65      thorpej  1271:                        }
1.25      cgd      1272:                }
1.65      thorpej  1273:        }
1.49      danw     1274: #ifdef __HAVE_DEVICE_REGISTER
1.25      cgd      1275:        device_register(dev, aux);
                   1276: #endif
1.124     jmcneill 1277:
1.105     jmcneill 1278: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                   1279:        if (splash_progress_state)
                   1280:                splash_progress_update(splash_progress_state);
                   1281: #endif
1.117     drochner 1282:        (*dev->dv_cfattach->ca_attach)(parent, dev, aux);
1.105     jmcneill 1283: #if defined(SPLASHSCREEN) && defined(SPLASHSCREEN_PROGRESS)
                   1284:        if (splash_progress_state)
                   1285:                splash_progress_update(splash_progress_state);
                   1286: #endif
1.124     jmcneill 1287:
                   1288:        if (!device_pmf_is_registered(dev))
1.125     jmcneill 1289:                aprint_debug_dev(dev, "WARNING: power management not supported\n");
1.124     jmcneill 1290:
1.42      thorpej  1291:        config_process_deferred(&deferred_config_queue, dev);
1.25      cgd      1292:        return (dev);
                   1293: }
1.29      thorpej  1294:
1.102     thorpej  1295: device_t
                   1296: config_attach(device_t parent, cfdata_t cf, void *aux, cfprint_t print)
                   1297: {
                   1298:
                   1299:        return (config_attach_loc(parent, cf, NULL, aux, print));
                   1300: }
                   1301:
1.29      thorpej  1302: /*
1.77      thorpej  1303:  * As above, but for pseudo-devices.  Pseudo-devices attached in this
                   1304:  * way are silently inserted into the device tree, and their children
                   1305:  * attached.
                   1306:  *
                   1307:  * Note that because pseudo-devices are attached silently, any information
                   1308:  * the attach routine wishes to print should be prefixed with the device
                   1309:  * name by the attach routine.
                   1310:  */
1.102     thorpej  1311: device_t
                   1312: config_attach_pseudo(cfdata_t cf)
1.77      thorpej  1313: {
1.102     thorpej  1314:        device_t dev;
1.77      thorpej  1315:
1.117     drochner 1316:        dev = config_devalloc(ROOT, cf, NULL);
                   1317:        if (!dev)
1.77      thorpej  1318:                return (NULL);
                   1319:
1.117     drochner 1320:        /* XXX mark busy in cfdata */
1.77      thorpej  1321:
1.117     drochner 1322:        config_devlink(dev);
1.77      thorpej  1323:
                   1324: #if 0  /* XXXJRT not yet */
                   1325: #ifdef __HAVE_DEVICE_REGISTER
                   1326:        device_register(dev, NULL);     /* like a root node */
                   1327: #endif
                   1328: #endif
1.117     drochner 1329:        (*dev->dv_cfattach->ca_attach)(ROOT, dev, NULL);
1.77      thorpej  1330:        config_process_deferred(&deferred_config_queue, dev);
                   1331:        return (dev);
                   1332: }
                   1333:
                   1334: /*
1.33      thorpej  1335:  * Detach a device.  Optionally forced (e.g. because of hardware
                   1336:  * removal) and quiet.  Returns zero if successful, non-zero
                   1337:  * (an error code) otherwise.
                   1338:  *
                   1339:  * Note that this code wants to be run from a process context, so
                   1340:  * that the detach can sleep to allow processes which have a device
                   1341:  * open to run and unwind their stacks.
                   1342:  */
                   1343: int
1.102     thorpej  1344: config_detach(device_t dev, int flags)
1.33      thorpej  1345: {
1.65      thorpej  1346:        struct cftable *ct;
1.102     thorpej  1347:        cfdata_t cf;
1.73      thorpej  1348:        const struct cfattach *ca;
1.33      thorpej  1349:        struct cfdriver *cd;
                   1350: #ifdef DIAGNOSTIC
1.102     thorpej  1351:        device_t d;
1.33      thorpej  1352: #endif
1.117     drochner 1353:        int rv = 0;
1.33      thorpej  1354:
                   1355: #ifdef DIAGNOSTIC
1.77      thorpej  1356:        if (dev->dv_cfdata != NULL &&
                   1357:            dev->dv_cfdata->cf_fstate != FSTATE_FOUND &&
                   1358:            dev->dv_cfdata->cf_fstate != FSTATE_STAR)
1.33      thorpej  1359:                panic("config_detach: bad device fstate");
                   1360: #endif
1.77      thorpej  1361:        cd = dev->dv_cfdriver;
1.67      thorpej  1362:        KASSERT(cd != NULL);
1.76      thorpej  1363:
1.77      thorpej  1364:        ca = dev->dv_cfattach;
1.76      thorpej  1365:        KASSERT(ca != NULL);
1.33      thorpej  1366:
                   1367:        /*
                   1368:         * Ensure the device is deactivated.  If the device doesn't
                   1369:         * have an activation entry point, we allow DVF_ACTIVE to
                   1370:         * remain set.  Otherwise, if DVF_ACTIVE is still set, the
                   1371:         * device is busy, and the detach fails.
                   1372:         */
1.35      thorpej  1373:        if (ca->ca_activate != NULL)
                   1374:                rv = config_deactivate(dev);
1.33      thorpej  1375:
                   1376:        /*
                   1377:         * Try to detach the device.  If that's not possible, then
                   1378:         * we either panic() (for the forced but failed case), or
                   1379:         * return an error.
                   1380:         */
                   1381:        if (rv == 0) {
                   1382:                if (ca->ca_detach != NULL)
                   1383:                        rv = (*ca->ca_detach)(dev, flags);
                   1384:                else
                   1385:                        rv = EOPNOTSUPP;
                   1386:        }
                   1387:        if (rv != 0) {
                   1388:                if ((flags & DETACH_FORCE) == 0)
                   1389:                        return (rv);
                   1390:                else
                   1391:                        panic("config_detach: forced detach of %s failed (%d)",
                   1392:                            dev->dv_xname, rv);
                   1393:        }
                   1394:
                   1395:        /*
                   1396:         * The device has now been successfully detached.
                   1397:         */
                   1398:
                   1399: #ifdef DIAGNOSTIC
                   1400:        /*
                   1401:         * Sanity: If you're successfully detached, you should have no
                   1402:         * children.  (Note that because children must be attached
                   1403:         * after parents, we only need to search the latter part of
                   1404:         * the list.)
                   1405:         */
                   1406:        for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
1.48      enami    1407:            d = TAILQ_NEXT(d, dv_list)) {
                   1408:                if (d->dv_parent == dev) {
                   1409:                        printf("config_detach: detached device %s"
                   1410:                            " has children %s\n", dev->dv_xname, d->dv_xname);
                   1411:                        panic("config_detach");
                   1412:                }
1.33      thorpej  1413:        }
                   1414: #endif
                   1415:
1.90      drochner 1416:        /* notify the parent that the child is gone */
                   1417:        if (dev->dv_parent) {
1.102     thorpej  1418:                device_t p = dev->dv_parent;
1.90      drochner 1419:                if (p->dv_cfattach->ca_childdetached)
                   1420:                        (*p->dv_cfattach->ca_childdetached)(p, dev);
                   1421:        }
                   1422:
1.33      thorpej  1423:        /*
                   1424:         * Mark cfdata to show that the unit can be reused, if possible.
                   1425:         */
1.65      thorpej  1426:        TAILQ_FOREACH(ct, &allcftables, ct_list) {
1.67      thorpej  1427:                for (cf = ct->ct_cfdata; cf->cf_name; cf++) {
                   1428:                        if (STREQ(cf->cf_name, cd->cd_name)) {
1.65      thorpej  1429:                                if (cf->cf_fstate == FSTATE_FOUND &&
                   1430:                                    cf->cf_unit == dev->dv_unit)
                   1431:                                        cf->cf_fstate = FSTATE_NOTFOUND;
1.46      cgd      1432: #ifdef __BROKEN_CONFIG_UNIT_USAGE
1.66      thorpej  1433:                                /*
                   1434:                                 * Note that we can only re-use a starred
                   1435:                                 * unit number if the unit being detached
                   1436:                                 * had the last assigned unit number.
                   1437:                                 */
1.65      thorpej  1438:                                if (cf->cf_fstate == FSTATE_STAR &&
                   1439:                                    cf->cf_unit == dev->dv_unit + 1)
                   1440:                                        cf->cf_unit--;
1.46      cgd      1441: #endif /* __BROKEN_CONFIG_UNIT_USAGE */
1.65      thorpej  1442:                        }
1.33      thorpej  1443:                }
                   1444:        }
                   1445:
1.117     drochner 1446:        config_devunlink(dev);
1.33      thorpej  1447:
1.77      thorpej  1448:        if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0)
1.80      thorpej  1449:                aprint_normal("%s detached\n", dev->dv_xname);
1.33      thorpej  1450:
1.117     drochner 1451:        config_devdealloc(dev);
1.33      thorpej  1452:
                   1453:        return (0);
                   1454: }
                   1455:
1.126     dyoung   1456: int
                   1457: config_detach_children(device_t parent, int flags)
                   1458: {
1.130     drochner 1459:        device_t dv;
                   1460:        int progress, error = 0;
1.126     dyoung   1461:
1.130     drochner 1462:        /*
                   1463:         * config_detach() can work recursively, thus it can
                   1464:         * delete any number of devices from the linked list.
                   1465:         * For that reason, start over after each hit.
                   1466:         */
                   1467:        do {
                   1468:                progress = 0;
                   1469:                TAILQ_FOREACH(dv, &alldevs, dv_list) {
                   1470:                        if (device_parent(dv) != parent)
                   1471:                                continue;
                   1472:                        progress++;
                   1473:                        error = config_detach(dv, flags);
                   1474:                        break;
                   1475:                }
                   1476:        } while (progress && !error);
                   1477:        return error;
1.126     dyoung   1478: }
                   1479:
1.33      thorpej  1480: int
1.102     thorpej  1481: config_activate(device_t dev)
1.33      thorpej  1482: {
1.76      thorpej  1483:        const struct cfattach *ca = dev->dv_cfattach;
1.34      thorpej  1484:        int rv = 0, oflags = dev->dv_flags;
1.33      thorpej  1485:
                   1486:        if (ca->ca_activate == NULL)
                   1487:                return (EOPNOTSUPP);
                   1488:
                   1489:        if ((dev->dv_flags & DVF_ACTIVE) == 0) {
                   1490:                dev->dv_flags |= DVF_ACTIVE;
                   1491:                rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
1.34      thorpej  1492:                if (rv)
                   1493:                        dev->dv_flags = oflags;
1.33      thorpej  1494:        }
                   1495:        return (rv);
                   1496: }
                   1497:
                   1498: int
1.102     thorpej  1499: config_deactivate(device_t dev)
1.33      thorpej  1500: {
1.76      thorpej  1501:        const struct cfattach *ca = dev->dv_cfattach;
1.34      thorpej  1502:        int rv = 0, oflags = dev->dv_flags;
1.33      thorpej  1503:
                   1504:        if (ca->ca_activate == NULL)
                   1505:                return (EOPNOTSUPP);
                   1506:
                   1507:        if (dev->dv_flags & DVF_ACTIVE) {
                   1508:                dev->dv_flags &= ~DVF_ACTIVE;
                   1509:                rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
1.34      thorpej  1510:                if (rv)
                   1511:                        dev->dv_flags = oflags;
1.33      thorpej  1512:        }
                   1513:        return (rv);
                   1514: }
                   1515:
                   1516: /*
1.29      thorpej  1517:  * Defer the configuration of the specified device until all
                   1518:  * of its parent's devices have been attached.
                   1519:  */
                   1520: void
1.102     thorpej  1521: config_defer(device_t dev, void (*func)(device_t))
1.29      thorpej  1522: {
                   1523:        struct deferred_config *dc;
                   1524:
                   1525:        if (dev->dv_parent == NULL)
                   1526:                panic("config_defer: can't defer config of a root device");
                   1527:
                   1528: #ifdef DIAGNOSTIC
                   1529:        for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
                   1530:             dc = TAILQ_NEXT(dc, dc_queue)) {
                   1531:                if (dc->dc_dev == dev)
                   1532:                        panic("config_defer: deferred twice");
                   1533:        }
                   1534: #endif
                   1535:
1.43      thorpej  1536:        dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
                   1537:        if (dc == NULL)
                   1538:                panic("config_defer: unable to allocate callback");
1.29      thorpej  1539:
                   1540:        dc->dc_dev = dev;
                   1541:        dc->dc_func = func;
                   1542:        TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
1.47      thorpej  1543:        config_pending_incr();
1.29      thorpej  1544: }
                   1545:
                   1546: /*
1.42      thorpej  1547:  * Defer some autoconfiguration for a device until after interrupts
                   1548:  * are enabled.
                   1549:  */
                   1550: void
1.102     thorpej  1551: config_interrupts(device_t dev, void (*func)(device_t))
1.42      thorpej  1552: {
                   1553:        struct deferred_config *dc;
                   1554:
                   1555:        /*
                   1556:         * If interrupts are enabled, callback now.
                   1557:         */
1.43      thorpej  1558:        if (cold == 0) {
1.42      thorpej  1559:                (*func)(dev);
                   1560:                return;
                   1561:        }
                   1562:
                   1563: #ifdef DIAGNOSTIC
                   1564:        for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
                   1565:             dc = TAILQ_NEXT(dc, dc_queue)) {
                   1566:                if (dc->dc_dev == dev)
                   1567:                        panic("config_interrupts: deferred twice");
                   1568:        }
                   1569: #endif
                   1570:
1.43      thorpej  1571:        dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
                   1572:        if (dc == NULL)
                   1573:                panic("config_interrupts: unable to allocate callback");
1.42      thorpej  1574:
                   1575:        dc->dc_dev = dev;
                   1576:        dc->dc_func = func;
                   1577:        TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
1.47      thorpej  1578:        config_pending_incr();
1.42      thorpej  1579: }
                   1580:
                   1581: /*
                   1582:  * Process a deferred configuration queue.
1.29      thorpej  1583:  */
                   1584: static void
1.51      cgd      1585: config_process_deferred(struct deferred_config_head *queue,
1.102     thorpej  1586:     device_t parent)
1.29      thorpej  1587: {
                   1588:        struct deferred_config *dc, *ndc;
                   1589:
1.42      thorpej  1590:        for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
1.29      thorpej  1591:                ndc = TAILQ_NEXT(dc, dc_queue);
1.42      thorpej  1592:                if (parent == NULL || dc->dc_dev->dv_parent == parent) {
                   1593:                        TAILQ_REMOVE(queue, dc, dc_queue);
1.29      thorpej  1594:                        (*dc->dc_func)(dc->dc_dev);
                   1595:                        free(dc, M_DEVBUF);
1.47      thorpej  1596:                        config_pending_decr();
1.29      thorpej  1597:                }
                   1598:        }
1.47      thorpej  1599: }
                   1600:
                   1601: /*
                   1602:  * Manipulate the config_pending semaphore.
                   1603:  */
                   1604: void
1.51      cgd      1605: config_pending_incr(void)
1.47      thorpej  1606: {
                   1607:
                   1608:        config_pending++;
                   1609: }
                   1610:
                   1611: void
1.51      cgd      1612: config_pending_decr(void)
1.47      thorpej  1613: {
                   1614:
                   1615: #ifdef DIAGNOSTIC
                   1616:        if (config_pending == 0)
                   1617:                panic("config_pending_decr: config_pending == 0");
                   1618: #endif
                   1619:        config_pending--;
                   1620:        if (config_pending == 0)
1.94      christos 1621:                wakeup(&config_pending);
1.75      thorpej  1622: }
                   1623:
                   1624: /*
                   1625:  * Register a "finalization" routine.  Finalization routines are
                   1626:  * called iteratively once all real devices have been found during
                   1627:  * autoconfiguration, for as long as any one finalizer has done
                   1628:  * any work.
                   1629:  */
                   1630: int
1.102     thorpej  1631: config_finalize_register(device_t dev, int (*fn)(device_t))
1.75      thorpej  1632: {
                   1633:        struct finalize_hook *f;
                   1634:
                   1635:        /*
                   1636:         * If finalization has already been done, invoke the
                   1637:         * callback function now.
                   1638:         */
                   1639:        if (config_finalize_done) {
                   1640:                while ((*fn)(dev) != 0)
                   1641:                        /* loop */ ;
                   1642:        }
                   1643:
                   1644:        /* Ensure this isn't already on the list. */
                   1645:        TAILQ_FOREACH(f, &config_finalize_list, f_list) {
                   1646:                if (f->f_func == fn && f->f_dev == dev)
                   1647:                        return (EEXIST);
                   1648:        }
                   1649:
                   1650:        f = malloc(sizeof(*f), M_TEMP, M_WAITOK);
                   1651:        f->f_func = fn;
                   1652:        f->f_dev = dev;
                   1653:        TAILQ_INSERT_TAIL(&config_finalize_list, f, f_list);
                   1654:
                   1655:        return (0);
                   1656: }
                   1657:
                   1658: void
                   1659: config_finalize(void)
                   1660: {
                   1661:        struct finalize_hook *f;
                   1662:        int rv;
                   1663:
                   1664:        /* Run the hooks until none of them does any work. */
                   1665:        do {
                   1666:                rv = 0;
                   1667:                TAILQ_FOREACH(f, &config_finalize_list, f_list)
                   1668:                        rv |= (*f->f_func)(f->f_dev);
                   1669:        } while (rv != 0);
                   1670:
                   1671:        config_finalize_done = 1;
                   1672:
                   1673:        /* Now free all the hooks. */
                   1674:        while ((f = TAILQ_FIRST(&config_finalize_list)) != NULL) {
                   1675:                TAILQ_REMOVE(&config_finalize_list, f, f_list);
                   1676:                free(f, M_TEMP);
1.79      thorpej  1677:        }
                   1678: }
                   1679:
1.104     thorpej  1680: /*
1.107     thorpej  1681:  * device_lookup:
                   1682:  *
                   1683:  *     Look up a device instance for a given driver.
                   1684:  */
                   1685: void *
                   1686: device_lookup(cfdriver_t cd, int unit)
                   1687: {
                   1688:
                   1689:        if (unit < 0 || unit >= cd->cd_ndevs)
                   1690:                return (NULL);
                   1691:
                   1692:        return (cd->cd_devs[unit]);
                   1693: }
                   1694:
                   1695: /*
                   1696:  * Accessor functions for the device_t type.
                   1697:  */
                   1698: devclass_t
                   1699: device_class(device_t dev)
                   1700: {
                   1701:
                   1702:        return (dev->dv_class);
                   1703: }
                   1704:
                   1705: cfdata_t
                   1706: device_cfdata(device_t dev)
                   1707: {
                   1708:
                   1709:        return (dev->dv_cfdata);
                   1710: }
                   1711:
                   1712: cfdriver_t
                   1713: device_cfdriver(device_t dev)
                   1714: {
                   1715:
                   1716:        return (dev->dv_cfdriver);
                   1717: }
                   1718:
                   1719: cfattach_t
                   1720: device_cfattach(device_t dev)
                   1721: {
                   1722:
                   1723:        return (dev->dv_cfattach);
                   1724: }
                   1725:
                   1726: int
                   1727: device_unit(device_t dev)
                   1728: {
                   1729:
                   1730:        return (dev->dv_unit);
                   1731: }
                   1732:
                   1733: const char *
                   1734: device_xname(device_t dev)
                   1735: {
                   1736:
                   1737:        return (dev->dv_xname);
                   1738: }
                   1739:
                   1740: device_t
                   1741: device_parent(device_t dev)
                   1742: {
                   1743:
                   1744:        return (dev->dv_parent);
                   1745: }
                   1746:
1.116     thorpej  1747: bool
1.107     thorpej  1748: device_is_active(device_t dev)
                   1749: {
1.124     jmcneill 1750:        int active_flags;
                   1751:
                   1752:        active_flags = DVF_ACTIVE;
                   1753:        active_flags |= DVF_CLASS_SUSPENDED;
                   1754:        active_flags |= DVF_DRIVER_SUSPENDED;
                   1755:        active_flags |= DVF_BUS_SUSPENDED;
                   1756:
                   1757:        return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
                   1758: }
                   1759:
                   1760: bool
                   1761: device_is_enabled(device_t dev)
                   1762: {
                   1763:        return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
                   1764: }
                   1765:
                   1766: bool
                   1767: device_has_power(device_t dev)
                   1768: {
                   1769:        int active_flags;
                   1770:
                   1771:        active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
1.107     thorpej  1772:
1.124     jmcneill 1773:        return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
1.107     thorpej  1774: }
                   1775:
1.109     thorpej  1776: int
1.111     thorpej  1777: device_locator(device_t dev, u_int locnum)
1.107     thorpej  1778: {
                   1779:
1.109     thorpej  1780:        KASSERT(dev->dv_locators != NULL);
                   1781:        return (dev->dv_locators[locnum]);
1.107     thorpej  1782: }
1.108     thorpej  1783:
1.110     thorpej  1784: void *
                   1785: device_private(device_t dev)
                   1786: {
                   1787:
1.120     joerg    1788:        return (dev->dv_private);
1.110     thorpej  1789: }
                   1790:
1.112     thorpej  1791: prop_dictionary_t
                   1792: device_properties(device_t dev)
                   1793: {
                   1794:
                   1795:        return (dev->dv_properties);
                   1796: }
                   1797:
1.108     thorpej  1798: /*
                   1799:  * device_is_a:
                   1800:  *
                   1801:  *     Returns true if the device is an instance of the specified
                   1802:  *     driver.
                   1803:  */
1.116     thorpej  1804: bool
1.108     thorpej  1805: device_is_a(device_t dev, const char *dname)
                   1806: {
                   1807:
                   1808:        return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
                   1809: }
1.124     jmcneill 1810:
                   1811: /*
1.131     joerg    1812:  * device_find_by_xname:
                   1813:  *
                   1814:  *     Returns the device of the given name or NULL if it doesn't exist.
                   1815:  */
                   1816: device_t
                   1817: device_find_by_xname(const char *name)
                   1818: {
                   1819:        device_t dv;
                   1820:
                   1821:        TAILQ_FOREACH(dv, &alldevs, dv_list) {
                   1822:                if (strcmp(device_xname(dv), name) == 0)
                   1823:                        break;
                   1824:        }
                   1825:
                   1826:        return dv;
                   1827: }
                   1828:
                   1829: /*
                   1830:  * device_find_by_driver_unit:
                   1831:  *
                   1832:  *     Returns the device of the given driver name and unit or
                   1833:  *     NULL if it doesn't exist.
                   1834:  */
                   1835: device_t
                   1836: device_find_by_driver_unit(const char *name, int unit)
                   1837: {
                   1838:        struct cfdriver *cd;
                   1839:
                   1840:        if ((cd = config_cfdriver_lookup(name)) == NULL)
                   1841:                return NULL;
                   1842:        return device_lookup(cd, unit);
                   1843: }
                   1844:
                   1845: /*
1.124     jmcneill 1846:  * Power management related functions.
                   1847:  */
                   1848:
                   1849: bool
                   1850: device_pmf_is_registered(device_t dev)
                   1851: {
                   1852:        return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
                   1853: }
                   1854:
                   1855: bool
                   1856: device_pmf_driver_suspend(device_t dev)
                   1857: {
                   1858:        if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
                   1859:                return true;
                   1860:        if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
                   1861:                return false;
                   1862:        if (*dev->dv_driver_suspend != NULL &&
                   1863:            !(*dev->dv_driver_suspend)(dev))
                   1864:                return false;
                   1865:
                   1866:        dev->dv_flags |= DVF_DRIVER_SUSPENDED;
                   1867:        return true;
                   1868: }
                   1869:
                   1870: bool
                   1871: device_pmf_driver_resume(device_t dev)
                   1872: {
                   1873:        if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
                   1874:                return true;
                   1875:        if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
                   1876:                return false;
                   1877:        if (*dev->dv_driver_resume != NULL &&
                   1878:            !(*dev->dv_driver_resume)(dev))
                   1879:                return false;
                   1880:
                   1881:        dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
                   1882:        return true;
                   1883: }
                   1884:
1.133   ! drochner 1885: bool
        !          1886: device_pmf_driver_shutdown(device_t dev, int how)
        !          1887: {
        !          1888:
        !          1889:        if (*dev->dv_driver_shutdown != NULL &&
        !          1890:            !(*dev->dv_driver_shutdown)(dev, how))
        !          1891:                return false;
        !          1892:        return true;
        !          1893: }
        !          1894:
1.124     jmcneill 1895: void
                   1896: device_pmf_driver_register(device_t dev,
1.133   ! drochner 1897:     bool (*suspend)(device_t), bool (*resume)(device_t),
        !          1898:     bool (*shutdown)(device_t, int))
1.124     jmcneill 1899: {
                   1900:        dev->dv_driver_suspend = suspend;
                   1901:        dev->dv_driver_resume = resume;
1.133   ! drochner 1902:        dev->dv_driver_shutdown = shutdown;
1.124     jmcneill 1903:        dev->dv_flags |= DVF_POWER_HANDLERS;
                   1904: }
                   1905:
                   1906: void
                   1907: device_pmf_driver_deregister(device_t dev)
                   1908: {
                   1909:        dev->dv_driver_suspend = NULL;
                   1910:        dev->dv_driver_resume = NULL;
                   1911:        dev->dv_flags &= ~DVF_POWER_HANDLERS;
                   1912: }
                   1913:
                   1914: bool
                   1915: device_pmf_driver_child_register(device_t dev)
                   1916: {
                   1917:        device_t parent = device_parent(dev);
                   1918:
                   1919:        if (parent == NULL || parent->dv_driver_child_register == NULL)
                   1920:                return true;
                   1921:        return (*parent->dv_driver_child_register)(dev);
                   1922: }
                   1923:
                   1924: void
                   1925: device_pmf_driver_set_child_register(device_t dev,
                   1926:     bool (*child_register)(device_t))
                   1927: {
                   1928:        dev->dv_driver_child_register = child_register;
                   1929: }
                   1930:
                   1931: void *
                   1932: device_pmf_bus_private(device_t dev)
                   1933: {
                   1934:        return dev->dv_bus_private;
                   1935: }
                   1936:
                   1937: bool
                   1938: device_pmf_bus_suspend(device_t dev)
                   1939: {
                   1940:        if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
                   1941:                return true;
                   1942:        if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
                   1943:            (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
                   1944:                return false;
                   1945:        if (*dev->dv_bus_suspend != NULL &&
                   1946:            !(*dev->dv_bus_suspend)(dev))
                   1947:                return false;
                   1948:
                   1949:        dev->dv_flags |= DVF_BUS_SUSPENDED;
                   1950:        return true;
                   1951: }
                   1952:
                   1953: bool
                   1954: device_pmf_bus_resume(device_t dev)
                   1955: {
                   1956:        if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
                   1957:                return true;
                   1958:        if (*dev->dv_bus_resume != NULL &&
                   1959:            !(*dev->dv_bus_resume)(dev))
                   1960:                return false;
                   1961:
                   1962:        dev->dv_flags &= ~DVF_BUS_SUSPENDED;
                   1963:        return true;
                   1964: }
                   1965:
1.133   ! drochner 1966: bool
        !          1967: device_pmf_bus_shutdown(device_t dev, int how)
        !          1968: {
        !          1969:
        !          1970:        if (*dev->dv_bus_shutdown != NULL &&
        !          1971:            !(*dev->dv_bus_shutdown)(dev, how))
        !          1972:                return false;
        !          1973:        return true;
        !          1974: }
        !          1975:
1.124     jmcneill 1976: void
                   1977: device_pmf_bus_register(device_t dev, void *priv,
                   1978:     bool (*suspend)(device_t), bool (*resume)(device_t),
1.133   ! drochner 1979:     bool (*shutdown)(device_t, int), void (*deregister)(device_t))
1.124     jmcneill 1980: {
                   1981:        dev->dv_bus_private = priv;
                   1982:        dev->dv_bus_resume = resume;
                   1983:        dev->dv_bus_suspend = suspend;
1.133   ! drochner 1984:        dev->dv_bus_shutdown = shutdown;
1.124     jmcneill 1985:        dev->dv_bus_deregister = deregister;
                   1986: }
                   1987:
                   1988: void
                   1989: device_pmf_bus_deregister(device_t dev)
                   1990: {
                   1991:        if (dev->dv_bus_deregister == NULL)
                   1992:                return;
                   1993:        (*dev->dv_bus_deregister)(dev);
                   1994:        dev->dv_bus_private = NULL;
                   1995:        dev->dv_bus_suspend = NULL;
                   1996:        dev->dv_bus_resume = NULL;
                   1997:        dev->dv_bus_deregister = NULL;
                   1998: }
                   1999:
                   2000: void *
                   2001: device_pmf_class_private(device_t dev)
                   2002: {
                   2003:        return dev->dv_class_private;
                   2004: }
                   2005:
                   2006: bool
                   2007: device_pmf_class_suspend(device_t dev)
                   2008: {
                   2009:        if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
                   2010:                return true;
                   2011:        if (*dev->dv_class_suspend != NULL &&
                   2012:            !(*dev->dv_class_suspend)(dev))
                   2013:                return false;
                   2014:
                   2015:        dev->dv_flags |= DVF_CLASS_SUSPENDED;
                   2016:        return true;
                   2017: }
                   2018:
                   2019: bool
                   2020: device_pmf_class_resume(device_t dev)
                   2021: {
                   2022:        if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
                   2023:                return true;
                   2024:        if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
                   2025:            (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
                   2026:                return false;
                   2027:        if (*dev->dv_class_resume != NULL &&
                   2028:            !(*dev->dv_class_resume)(dev))
                   2029:                return false;
                   2030:
                   2031:        dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
                   2032:        return true;
                   2033: }
                   2034:
                   2035: void
                   2036: device_pmf_class_register(device_t dev, void *priv,
                   2037:     bool (*suspend)(device_t), bool (*resume)(device_t),
                   2038:     void (*deregister)(device_t))
                   2039: {
                   2040:        dev->dv_class_private = priv;
                   2041:        dev->dv_class_suspend = suspend;
                   2042:        dev->dv_class_resume = resume;
                   2043:        dev->dv_class_deregister = deregister;
                   2044: }
                   2045:
                   2046: void
                   2047: device_pmf_class_deregister(device_t dev)
                   2048: {
                   2049:        if (dev->dv_class_deregister == NULL)
                   2050:                return;
                   2051:        (*dev->dv_class_deregister)(dev);
                   2052:        dev->dv_class_private = NULL;
                   2053:        dev->dv_class_suspend = NULL;
                   2054:        dev->dv_class_resume = NULL;
                   2055:        dev->dv_class_deregister = NULL;
                   2056: }
                   2057:
                   2058: bool
                   2059: device_active(device_t dev, devactive_t type)
                   2060: {
                   2061:        size_t i;
                   2062:
                   2063:        if (dev->dv_activity_count == 0)
                   2064:                return false;
                   2065:
                   2066:        for (i = 0; i < dev->dv_activity_count; ++i)
                   2067:                (*dev->dv_activity_handlers[i])(dev, type);
                   2068:
                   2069:        return true;
                   2070: }
                   2071:
                   2072: bool
                   2073: device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
                   2074: {
                   2075:        void (**new_handlers)(device_t, devactive_t);
                   2076:        void (**old_handlers)(device_t, devactive_t);
                   2077:        size_t i, new_size;
                   2078:        int s;
                   2079:
                   2080:        old_handlers = dev->dv_activity_handlers;
                   2081:
                   2082:        for (i = 0; i < dev->dv_activity_count; ++i) {
                   2083:                if (old_handlers[i] == handler)
                   2084:                        panic("Double registering of idle handlers");
                   2085:        }
                   2086:
                   2087:        new_size = dev->dv_activity_count + 1;
                   2088:        new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF, M_WAITOK);
                   2089:
                   2090:        memcpy(new_handlers, old_handlers,
                   2091:            sizeof(void *) * dev->dv_activity_count);
                   2092:        new_handlers[new_size - 1] = handler;
                   2093:
                   2094:        s = splhigh();
                   2095:        dev->dv_activity_count = new_size;
                   2096:        dev->dv_activity_handlers = new_handlers;
                   2097:        splx(s);
                   2098:
                   2099:        if (old_handlers != NULL)
                   2100:                free(old_handlers, M_DEVBUF);
                   2101:
                   2102:        return true;
                   2103: }
                   2104:
                   2105: void
                   2106: device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
                   2107: {
                   2108:        void (**new_handlers)(device_t, devactive_t);
                   2109:        void (**old_handlers)(device_t, devactive_t);
                   2110:        size_t i, new_size;
                   2111:        int s;
                   2112:
                   2113:        old_handlers = dev->dv_activity_handlers;
                   2114:
                   2115:        for (i = 0; i < dev->dv_activity_count; ++i) {
                   2116:                if (old_handlers[i] == handler)
                   2117:                        break;
                   2118:        }
                   2119:
                   2120:        if (i == dev->dv_activity_count)
                   2121:                return; /* XXX panic? */
                   2122:
                   2123:        new_size = dev->dv_activity_count - 1;
                   2124:
                   2125:        if (new_size == 0) {
                   2126:                new_handlers = NULL;
                   2127:        } else {
                   2128:                new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF,
                   2129:                    M_WAITOK);
                   2130:                memcpy(new_handlers, old_handlers, sizeof(void *) * i);
                   2131:                memcpy(new_handlers + i, old_handlers + i + 1,
                   2132:                    sizeof(void *) * (new_size - i));
                   2133:        }
                   2134:
                   2135:        s = splhigh();
                   2136:        dev->dv_activity_count = new_size;
                   2137:        dev->dv_activity_handlers = new_handlers;
                   2138:        splx(s);
                   2139:
                   2140:        free(old_handlers, M_DEVBUF);
                   2141: }

CVSweb <webmaster@jp.NetBSD.org>