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

1.1       glass       1: /*
                      2:  * Copyright (c) 1992 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This software was developed by the Computer Systems Engineering group
                      6:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                      7:  * contributed to Berkeley.
                      8:  *
                      9:  * All advertising materials mentioning features or use of this software
                     10:  * must display the following acknowledgement:
                     11:  *     This product includes software developed by the University of
                     12:  *     California, Lawrence Berkeley Laboratories.
                     13:  *
                     14:  * %sccs.include.redist.c%
                     15:  *
                     16:  *     %W% (Berkeley) %G%
                     17:  *
1.3.2.2 ! mycroft    18:  * from: $Header: /b/source/CVS/src/sys/kern/subr_autoconf.c,v 1.3.2.1 1993/09/14 18:24:21 mycroft Exp $ (LBL)
1.1       glass      19:  */
                     20:
1.3.2.2 ! mycroft    21: #include <sys/param.h>
        !            22: #include <sys/device.h>
        !            23: #include <sys/malloc.h>
1.1       glass      24:
                     25: /*
                     26:  * Autoconfiguration subroutines.
                     27:  */
                     28:
                     29: /*
                     30:  * ioconf.c exports exactly two names: cfdata and cfroots.  All system
                     31:  * devices and drivers are found via these tables.
                     32:  */
                     33: extern struct cfdata cfdata[];
                     34: extern short cfroots[];
                     35:
                     36: #define        ROOT ((struct device *)NULL)
                     37:
                     38: struct matchinfo {
                     39:        cfmatch_t fn;
                     40:        struct  device *parent;
                     41:        void    *aux;
                     42:        struct  cfdata *match;
                     43:        int     pri;
                     44: };
                     45:
                     46: /*
                     47:  * Apply the matching function and choose the best.  This is used
                     48:  * a few times and we want to keep the code small.
                     49:  */
                     50: static void
                     51: mapply(m, cf)
                     52:        register struct matchinfo *m;
                     53:        register struct cfdata *cf;
                     54: {
                     55:        register int pri;
                     56:
                     57:        if (m->fn != NULL)
                     58:                pri = (*m->fn)(m->parent, cf, m->aux);
1.3       glass      59:        else {
                     60:                if (!cf->cf_driver->cd_match) {
                     61:                    printf("mapply: no match function for '%s' device\n",
                     62:                           cf->cf_driver->cd_name);
1.3.2.1   mycroft    63:                    panic("mapply: no match function\n");
1.3       glass      64:                }
1.1       glass      65:                pri = (*cf->cf_driver->cd_match)(m->parent, cf, m->aux);
1.3       glass      66:        }
1.1       glass      67:        if (pri > m->pri) {
                     68:                m->match = cf;
                     69:                m->pri = pri;
                     70:        }
                     71: }
                     72:
                     73: /*
                     74:  * Iterate over all potential children of some device, calling the given
                     75:  * function (default being the child's match function) for each one.
                     76:  * Nonzero returns are matches; the highest value returned is considered
                     77:  * the best match.  Return the `found child' if we got a match, or NULL
                     78:  * otherwise.  The `aux' pointer is simply passed on through.
                     79:  *
                     80:  * Note that this function is designed so that it can be used to apply
                     81:  * an arbitrary function to all potential children (its return value
                     82:  * can be ignored).
                     83:  */
                     84: struct cfdata *
                     85: config_search(fn, parent, aux)
                     86:        cfmatch_t fn;
                     87:        register struct device *parent;
                     88:        void *aux;
                     89: {
                     90:        register struct cfdata *cf;
                     91:        register short *p;
                     92:        struct matchinfo m;
                     93:
                     94:        m.fn = fn;
                     95:        m.parent = parent;
                     96:        m.aux = aux;
                     97:        m.match = NULL;
                     98:        m.pri = 0;
                     99:        for (cf = cfdata; cf->cf_driver; cf++) {
                    100:                /*
                    101:                 * Skip cf if no longer eligible, otherwise scan through
                    102:                 * parents for one matching `parent', and try match function.
                    103:                 */
                    104:                if (cf->cf_fstate == FSTATE_FOUND)
                    105:                        continue;
                    106:                for (p = cf->cf_parents; *p >= 0; p++)
                    107:                        if (parent->dv_cfdata == &cfdata[*p])
                    108:                                mapply(&m, cf);
                    109:        }
                    110:        return (m.match);
                    111: }
                    112:
                    113: /*
                    114:  * Find the given root device.
                    115:  * This is much like config_search, but there is no parent.
                    116:  */
                    117: struct cfdata *
                    118: config_rootsearch(fn, rootname, aux)
                    119:        register cfmatch_t fn;
                    120:        register char *rootname;
                    121:        register void *aux;
                    122: {
                    123:        register struct cfdata *cf;
                    124:        register short *p;
                    125:        struct matchinfo m;
                    126:
                    127:        m.fn = fn;
                    128:        m.parent = ROOT;
                    129:        m.aux = aux;
                    130:        m.match = NULL;
                    131:        m.pri = 0;
                    132:        /*
                    133:         * Look at root entries for matching name.  We do not bother
                    134:         * with found-state here since only one root should ever be
                    135:         * searched (and it must be done first).
                    136:         */
                    137:        for (p = cfroots; *p >= 0; p++) {
                    138:                cf = &cfdata[*p];
                    139:                if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
                    140:                        mapply(&m, cf);
                    141:        }
                    142:        return (m.match);
                    143: }
                    144:
                    145: static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
                    146:
                    147: /*
                    148:  * The given `aux' argument describes a device that has been found
                    149:  * on the given parent, but not necessarily configured.  Locate the
                    150:  * configuration data for that device (using the cd_match configuration
                    151:  * driver function) and attach it, and return true.  If the device was
                    152:  * not configured, call the given `print' function and return 0.
                    153:  */
                    154: int
                    155: config_found(parent, aux, print)
                    156:        struct device *parent;
                    157:        void *aux;
                    158:        cfprint_t print;
                    159: {
                    160:        struct cfdata *cf;
                    161:
                    162:        if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) {
                    163:                config_attach(parent, cf, aux, print);
                    164:                return (1);
                    165:        }
1.3       glass     166:        if (print)
                    167:            printf(msgs[(*print)(aux, parent->dv_xname)]);
1.1       glass     168:        return (0);
                    169: }
                    170:
                    171: /*
                    172:  * As above, but for root devices.
                    173:  */
                    174: int
                    175: config_rootfound(rootname, aux)
                    176:        char *rootname;
                    177:        void *aux;
                    178: {
                    179:        struct cfdata *cf;
                    180:
                    181:        if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) {
                    182:                config_attach(ROOT, cf, aux, (cfprint_t)NULL);
                    183:                return (1);
                    184:        }
                    185:        printf("root device %s not configured\n", rootname);
                    186:        return (0);
                    187: }
                    188:
                    189: /* just like sprintf(buf, "%d") except that it works from the end */
                    190: static char *
                    191: number(ep, n)
                    192:        register char *ep;
                    193:        register int n;
                    194: {
                    195:
                    196:        *--ep = 0;
                    197:        while (n >= 10) {
                    198:                *--ep = (n % 10) + '0';
                    199:                n /= 10;
                    200:        }
                    201:        *--ep = n + '0';
                    202:        return (ep);
                    203: }
                    204:
                    205: /*
                    206:  * Attach a found device.  Allocates memory for device variables.
                    207:  */
                    208: void
                    209: config_attach(parent, cf, aux, print)
                    210:        register struct device *parent;
                    211:        register struct cfdata *cf;
                    212:        register void *aux;
                    213:        cfprint_t print;
                    214: {
                    215:        register struct device *dev;
                    216:        register struct cfdriver *cd;
                    217:        register size_t lname, lunit;
                    218:        register char *xunit;
                    219:        int myunit;
                    220:        char num[10];
                    221:        static struct device **nextp = &alldevs;
                    222:
                    223:        cd = cf->cf_driver;
                    224:        if (cd->cd_devsize < sizeof(struct device))
                    225:                panic("config_attach");
                    226:        myunit = cf->cf_unit;
                    227:        if (cf->cf_fstate == FSTATE_NOTFOUND)
                    228:                cf->cf_fstate = FSTATE_FOUND;
                    229:        else
                    230:                cf->cf_unit++;
                    231:
                    232:        /* compute length of name and decimal expansion of unit number */
                    233:        lname = strlen(cd->cd_name);
                    234:        xunit = number(&num[sizeof num], myunit);
                    235:        lunit = &num[sizeof num] - xunit;
                    236:        if (lname + lunit >= sizeof(dev->dv_xname))
                    237:                panic("config_attach: device name too long");
                    238:
                    239:        /* get memory for all device vars */
1.3       glass     240:        dev = (struct device *)malloc(cd->cd_devsize, M_DEVBUF, M_NOWAIT);
                    241:        if (!dev)
                    242:            panic("config_attach: memory allocation for device softc failed");
1.1       glass     243:        bzero(dev, cd->cd_devsize);
                    244:        *nextp = dev;                   /* link up */
                    245:        nextp = &dev->dv_next;
                    246:        dev->dv_class = cd->cd_class;
                    247:        dev->dv_cfdata = cf;
                    248:        dev->dv_unit = myunit;
                    249:        bcopy(cd->cd_name, dev->dv_xname, lname);
                    250:        bcopy(xunit, dev->dv_xname + lname, lunit);
                    251:        dev->dv_parent = parent;
                    252:        if (parent == ROOT)
                    253:                printf("%s (root)", dev->dv_xname);
                    254:        else {
                    255:                printf("%s at %s", dev->dv_xname, parent->dv_xname);
1.3       glass     256:                if (print)
                    257:                    (void) (*print)(aux, (char *)0);
1.1       glass     258:        }
                    259:
                    260:        /* put this device in the devices array */
                    261:        if (dev->dv_unit >= cd->cd_ndevs) {
                    262:                /*
                    263:                 * Need to expand the array.
                    264:                 */
                    265:                int old = cd->cd_ndevs, oldbytes, new, newbytes;
                    266:                void **nsp;
                    267:
                    268:                if (old == 0) {
1.3       glass     269:                        nsp = malloc(MINALLOCSIZE, M_DEVBUF, M_NOWAIT);
                    270:                        if (!nsp)
                    271:                            panic("config_attach: expanding dev array");
1.1       glass     272:                        bzero(nsp, MINALLOCSIZE);
                    273:                        cd->cd_ndevs = MINALLOCSIZE / sizeof(void *);
                    274:                } else {
                    275:                        new = cd->cd_ndevs;
                    276:                        do {
                    277:                                new *= 2;
                    278:                        } while (new <= dev->dv_unit);
                    279:                        cd->cd_ndevs = new;
                    280:                        oldbytes = old * sizeof(void *);
                    281:                        newbytes = new * sizeof(void *);
1.3       glass     282:                        nsp = malloc(newbytes, M_DEVBUF, M_NOWAIT);
                    283:                        if (!nsp)
                    284:                            panic("config_attach: expanding dev array (2)");
1.1       glass     285:                        bcopy(cd->cd_devs, nsp, oldbytes);
                    286:                        bzero(&nsp[old], newbytes - oldbytes);
                    287:                        free(cd->cd_devs, M_DEVBUF);
                    288:                }
                    289:                cd->cd_devs = nsp;
                    290:        }
                    291:        if (cd->cd_devs[dev->dv_unit])
                    292:                panic("config_attach: duplicate %s", dev->dv_xname);
                    293:        cd->cd_devs[dev->dv_unit] = dev;
                    294:
                    295:        /*
                    296:         * Before attaching, clobber any unfound devices that are
                    297:         * otherwise identical.
                    298:         */
                    299:        for (cf = cfdata; cf->cf_driver; cf++)
                    300:                if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit &&
                    301:                    cf->cf_fstate == FSTATE_NOTFOUND)
                    302:                        cf->cf_fstate = FSTATE_FOUND;
                    303:        (*cd->cd_attach)(parent, dev, aux);
                    304: }
                    305:
                    306: /*
                    307:  * Attach an event.  These must come from initially-zero space (see
                    308:  * commented-out assignments below), but that occurs naturally for
                    309:  * device instance variables.
                    310:  */
                    311: void
                    312: evcnt_attach(dev, name, ev)
                    313:        struct device *dev;
                    314:        const char *name;
                    315:        struct evcnt *ev;
                    316: {
                    317:        static struct evcnt **nextp = &allevents;
                    318:
                    319: #ifdef DIAGNOSTIC
                    320:        if (strlen(name) >= sizeof(ev->ev_name))
                    321:                panic("evcnt_attach");
                    322: #endif
                    323:        /* ev->ev_next = NULL; */
                    324:        ev->ev_dev = dev;
                    325:        /* ev->ev_count = 0; */
                    326:        strcpy(ev->ev_name, name);
                    327:        *nextp = ev;
                    328:        nextp = &ev->ev_next;
                    329: }

CVSweb <webmaster@jp.NetBSD.org>