152592Smckusick /* 252592Smckusick * Copyright (c) 1992 Regents of the University of California. 352592Smckusick * All rights reserved. 452592Smckusick * 554121Smckusick * This software was developed by the Computer Systems Engineering group 654121Smckusick * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 754121Smckusick * contributed to Berkeley. 852592Smckusick * 956896Storek * All advertising materials mentioning features or use of this software 1056896Storek * must display the following acknowledgement: 1156896Storek * This product includes software developed by the University of 1256896Storek * California, Lawrence Berkeley Laboratories. 1356896Storek * 1452592Smckusick * %sccs.include.redist.c% 1552592Smckusick * 16*57761Storek * @(#)subr_autoconf.c 7.6 (Berkeley) 02/01/93 1752592Smckusick * 18*57761Storek * from: $Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp $ (LBL) 1952592Smckusick */ 2052592Smckusick 2156517Sbostic #include <sys/param.h> 2256517Sbostic #include <sys/device.h> 2356517Sbostic #include <sys/malloc.h> 2452592Smckusick 2552592Smckusick /* 2652592Smckusick * Autoconfiguration subroutines. 2752592Smckusick */ 2852592Smckusick 2956896Storek /* 3056896Storek * ioconf.c exports exactly two names: cfdata and cfroots. All system 3156896Storek * devices and drivers are found via these tables. 3256896Storek */ 3356896Storek extern struct cfdata cfdata[]; 3456896Storek extern short cfroots[]; 3552592Smckusick 3652592Smckusick #define ROOT ((struct device *)NULL) 3752592Smckusick 3854121Smckusick struct matchinfo { 3954121Smckusick cfmatch_t fn; 4054121Smckusick struct device *parent; 4154121Smckusick void *aux; 4254121Smckusick struct cfdata *match; 4354121Smckusick int pri; 4454121Smckusick }; 4554121Smckusick 4652592Smckusick /* 4754121Smckusick * Apply the matching function and choose the best. This is used 4854121Smckusick * a few times and we want to keep the code small. 4954121Smckusick */ 5054121Smckusick static void 5154121Smckusick mapply(m, cf) 5254121Smckusick register struct matchinfo *m; 5354121Smckusick register struct cfdata *cf; 5454121Smckusick { 5554121Smckusick register int pri; 5654121Smckusick 5754121Smckusick if (m->fn != NULL) 5854121Smckusick pri = (*m->fn)(m->parent, cf, m->aux); 5954121Smckusick else 6054121Smckusick pri = (*cf->cf_driver->cd_match)(m->parent, cf, m->aux); 6154121Smckusick if (pri > m->pri) { 6254121Smckusick m->match = cf; 6354121Smckusick m->pri = pri; 6454121Smckusick } 6554121Smckusick } 6654121Smckusick 6754121Smckusick /* 6852592Smckusick * Iterate over all potential children of some device, calling the given 6952592Smckusick * function (default being the child's match function) for each one. 7052592Smckusick * Nonzero returns are matches; the highest value returned is considered 7152592Smckusick * the best match. Return the `found child' if we got a match, or NULL 7252592Smckusick * otherwise. The `aux' pointer is simply passed on through. 7352592Smckusick * 7452592Smckusick * Note that this function is designed so that it can be used to apply 7552592Smckusick * an arbitrary function to all potential children (its return value 7652592Smckusick * can be ignored). 7752592Smckusick */ 7852592Smckusick struct cfdata * 7954121Smckusick config_search(fn, parent, aux) 8054121Smckusick cfmatch_t fn; 8154121Smckusick register struct device *parent; 8254121Smckusick void *aux; 8352592Smckusick { 8456896Storek register struct cfdata *cf; 8552592Smckusick register short *p; 8654121Smckusick struct matchinfo m; 8752592Smckusick 8854121Smckusick m.fn = fn; 8954121Smckusick m.parent = parent; 9054121Smckusick m.aux = aux; 9154121Smckusick m.match = NULL; 9254121Smckusick m.pri = 0; 9352592Smckusick for (cf = cfdata; cf->cf_driver; cf++) { 9452592Smckusick /* 9556896Storek * Skip cf if no longer eligible, otherwise scan through 9656896Storek * parents for one matching `parent', and try match function. 9752592Smckusick */ 9856896Storek if (cf->cf_fstate == FSTATE_FOUND) 9952592Smckusick continue; 10056896Storek for (p = cf->cf_parents; *p >= 0; p++) 10156896Storek if (parent->dv_cfdata == &cfdata[*p]) 10254121Smckusick mapply(&m, cf); 10352592Smckusick } 10454121Smckusick return (m.match); 10552592Smckusick } 10652592Smckusick 10752592Smckusick /* 10852592Smckusick * Find the given root device. 10952592Smckusick * This is much like config_search, but there is no parent. 11052592Smckusick */ 11152592Smckusick struct cfdata * 11252592Smckusick config_rootsearch(fn, rootname, aux) 11352592Smckusick register cfmatch_t fn; 11452592Smckusick register char *rootname; 11552592Smckusick register void *aux; 11652592Smckusick { 11754121Smckusick register struct cfdata *cf; 11856896Storek register short *p; 11954121Smckusick struct matchinfo m; 12052592Smckusick 12154121Smckusick m.fn = fn; 12254121Smckusick m.parent = ROOT; 12354121Smckusick m.aux = aux; 12454121Smckusick m.match = NULL; 12554121Smckusick m.pri = 0; 12654121Smckusick /* 12754121Smckusick * Look at root entries for matching name. We do not bother 12856896Storek * with found-state here since only one root should ever be 12956896Storek * searched (and it must be done first). 13054121Smckusick */ 13156896Storek for (p = cfroots; *p >= 0; p++) { 13256896Storek cf = &cfdata[*p]; 13356896Storek if (strcmp(cf->cf_driver->cd_name, rootname) == 0) 13454121Smckusick mapply(&m, cf); 13556896Storek } 13654121Smckusick return (m.match); 13752592Smckusick } 13852592Smckusick 13952592Smckusick static char *msgs[3] = { "", " not configured\n", " unsupported\n" }; 14052592Smckusick 14152592Smckusick /* 14252592Smckusick * The given `aux' argument describes a device that has been found 14352592Smckusick * on the given parent, but not necessarily configured. Locate the 14452592Smckusick * configuration data for that device (using the cd_match configuration 14552592Smckusick * driver function) and attach it, and return true. If the device was 14652592Smckusick * not configured, call the given `print' function and return 0. 14752592Smckusick */ 14852592Smckusick int 14952592Smckusick config_found(parent, aux, print) 15052592Smckusick struct device *parent; 15152592Smckusick void *aux; 15252592Smckusick cfprint_t print; 15352592Smckusick { 15452592Smckusick struct cfdata *cf; 15552592Smckusick 15652592Smckusick if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) { 15752592Smckusick config_attach(parent, cf, aux, print); 15852592Smckusick return (1); 15952592Smckusick } 16052592Smckusick printf(msgs[(*print)(aux, parent->dv_xname)]); 16152592Smckusick return (0); 16252592Smckusick } 16352592Smckusick 16452592Smckusick /* 16552592Smckusick * As above, but for root devices. 16652592Smckusick */ 16752592Smckusick int 16852592Smckusick config_rootfound(rootname, aux) 16952592Smckusick char *rootname; 17052592Smckusick void *aux; 17152592Smckusick { 17252592Smckusick struct cfdata *cf; 17352592Smckusick 17452592Smckusick if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) { 17552592Smckusick config_attach(ROOT, cf, aux, (cfprint_t)NULL); 17652592Smckusick return (1); 17752592Smckusick } 17852592Smckusick printf("root device %s not configured\n", rootname); 17952592Smckusick return (0); 18052592Smckusick } 18152592Smckusick 18252592Smckusick /* just like sprintf(buf, "%d") except that it works from the end */ 18352592Smckusick static char * 18452592Smckusick number(ep, n) 18552592Smckusick register char *ep; 18652592Smckusick register int n; 18752592Smckusick { 18852592Smckusick 18952592Smckusick *--ep = 0; 19052592Smckusick while (n >= 10) { 19152592Smckusick *--ep = (n % 10) + '0'; 19252592Smckusick n /= 10; 19352592Smckusick } 19452592Smckusick *--ep = n + '0'; 19552592Smckusick return (ep); 19652592Smckusick } 19752592Smckusick 19852592Smckusick /* 19952592Smckusick * Attach a found device. Allocates memory for device variables. 20052592Smckusick */ 20152592Smckusick void 20252592Smckusick config_attach(parent, cf, aux, print) 20352592Smckusick register struct device *parent; 20452592Smckusick register struct cfdata *cf; 20552592Smckusick register void *aux; 20652592Smckusick cfprint_t print; 20752592Smckusick { 20852592Smckusick register struct device *dev; 20952592Smckusick register struct cfdriver *cd; 21052592Smckusick register size_t lname, lunit; 21152592Smckusick register char *xunit; 21254121Smckusick int myunit; 21352592Smckusick char num[10]; 21454121Smckusick static struct device **nextp = &alldevs; 21552592Smckusick 21652592Smckusick cd = cf->cf_driver; 21752592Smckusick if (cd->cd_devsize < sizeof(struct device)) 21852592Smckusick panic("config_attach"); 21954121Smckusick myunit = cf->cf_unit; 22052592Smckusick if (cf->cf_fstate == FSTATE_NOTFOUND) 22152592Smckusick cf->cf_fstate = FSTATE_FOUND; 22254121Smckusick else 22354121Smckusick cf->cf_unit++; 22452592Smckusick 22552592Smckusick /* compute length of name and decimal expansion of unit number */ 22652592Smckusick lname = strlen(cd->cd_name); 22754121Smckusick xunit = number(&num[sizeof num], myunit); 22852592Smckusick lunit = &num[sizeof num] - xunit; 22956896Storek if (lname + lunit >= sizeof(dev->dv_xname)) 23056896Storek panic("config_attach: device name too long"); 23152592Smckusick 23256896Storek /* get memory for all device vars */ 23356896Storek dev = (struct device *)malloc(cd->cd_devsize, M_DEVBUF, M_WAITOK); 23456896Storek /* XXX cannot wait! */ 23552592Smckusick bzero(dev, cd->cd_devsize); 23654121Smckusick *nextp = dev; /* link up */ 23754121Smckusick nextp = &dev->dv_next; 23854121Smckusick dev->dv_class = cd->cd_class; 23954121Smckusick dev->dv_cfdata = cf; 24054121Smckusick dev->dv_unit = myunit; 24156896Storek bcopy(cd->cd_name, dev->dv_xname, lname); 24252592Smckusick bcopy(xunit, dev->dv_xname + lname, lunit); 24352592Smckusick dev->dv_parent = parent; 24452592Smckusick if (parent == ROOT) 24552592Smckusick printf("%s (root)", dev->dv_xname); 24652592Smckusick else { 24752592Smckusick printf("%s at %s", dev->dv_xname, parent->dv_xname); 24852592Smckusick (void) (*print)(aux, (char *)0); 24952592Smckusick } 25052592Smckusick 25152592Smckusick /* put this device in the devices array */ 25252592Smckusick if (dev->dv_unit >= cd->cd_ndevs) { 25352592Smckusick /* 25452592Smckusick * Need to expand the array. 25552592Smckusick */ 25652592Smckusick int old = cd->cd_ndevs, oldbytes, new, newbytes; 25752592Smckusick void **nsp; 25852592Smckusick 25952592Smckusick if (old == 0) { 26052592Smckusick nsp = malloc(MINALLOCSIZE, M_DEVBUF, M_WAITOK); /*XXX*/ 26152592Smckusick bzero(nsp, MINALLOCSIZE); 26252592Smckusick cd->cd_ndevs = MINALLOCSIZE / sizeof(void *); 26352592Smckusick } else { 26452592Smckusick new = cd->cd_ndevs; 26552592Smckusick do { 26652592Smckusick new *= 2; 26752592Smckusick } while (new <= dev->dv_unit); 26852592Smckusick cd->cd_ndevs = new; 26952592Smckusick oldbytes = old * sizeof(void *); 27052592Smckusick newbytes = new * sizeof(void *); 27152592Smckusick nsp = malloc(newbytes, M_DEVBUF, M_WAITOK); /*XXX*/ 27252592Smckusick bcopy(cd->cd_devs, nsp, oldbytes); 27352592Smckusick bzero(&nsp[old], newbytes - oldbytes); 27452592Smckusick free(cd->cd_devs, M_DEVBUF); 27552592Smckusick } 27652592Smckusick cd->cd_devs = nsp; 27752592Smckusick } 27854121Smckusick if (cd->cd_devs[dev->dv_unit]) 27954121Smckusick panic("config_attach: duplicate %s", dev->dv_xname); 28052592Smckusick cd->cd_devs[dev->dv_unit] = dev; 28156896Storek 28256896Storek /* 28356896Storek * Before attaching, clobber any unfound devices that are 28456896Storek * otherwise identical. 28556896Storek */ 28656896Storek for (cf = cfdata; cf->cf_driver; cf++) 28756896Storek if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit && 28856896Storek cf->cf_fstate == FSTATE_NOTFOUND) 28956896Storek cf->cf_fstate = FSTATE_FOUND; 29052592Smckusick (*cd->cd_attach)(parent, dev, aux); 29152592Smckusick } 292*57761Storek 293*57761Storek /* 294*57761Storek * Attach an event. These must come from initially-zero space (see 295*57761Storek * commented-out assignments below), but that occurs naturally for 296*57761Storek * device instance variables. 297*57761Storek */ 298*57761Storek void 299*57761Storek evcnt_attach(dev, name, ev) 300*57761Storek struct device *dev; 301*57761Storek const char *name; 302*57761Storek struct evcnt *ev; 303*57761Storek { 304*57761Storek static struct evcnt **nextp = &allevents; 305*57761Storek 306*57761Storek #ifdef DIAGNOSTIC 307*57761Storek if (strlen(name) >= sizeof(ev->ev_name)) 308*57761Storek panic("evcnt_attach"); 309*57761Storek #endif 310*57761Storek /* ev->ev_next = NULL; */ 311*57761Storek ev->ev_dev = dev; 312*57761Storek /* ev->ev_count = 0; */ 313*57761Storek strcpy(ev->ev_name, name); 314*57761Storek *nextp = ev; 315*57761Storek nextp = &ev->ev_next; 316*57761Storek } 317