/* * $Id: config_search.c,v 1.2 2008/08/12 11:30:52 nbrk Exp $ */ #include /* #define AUTOCONF_DEBUG */ #ifndef AUTOCONF_DEBUG #define DPRINTF(fmt...) do {} while (0) #else #define DPRINTF(fmt...) do { printk(fmt); } while (0) #endif /* !AUTOCONF_DEBUG */ extern struct driver *drivers[]; extern struct attachment config_table[]; int config_search_children(struct device *parent, void *aux) { struct attachment *atp; struct driver *chdrvp, *hedrvp; struct device *self; int retval; int ndevs; DPRINTF("config_search_children: enter, name=%s\n", parent->dv_xname); atp = config_table; /* * Look through the table. */ while (atp->at_childname != NULL) { DPRINTF("config_table: trying %s at %s%u via %s\n", atp->at_childname, atp->at_parentname, atp->at_parentunit == -1 ? "*" : atp->at_parentunit, atp->at_helpername != NULL ? atp->at_helpername : "(self)"); if (atp->at_parentname == NULL) panic("config: bogus config table (no parent given for %s)", atp->at_childname); if (strncmp(atp->at_parentname, parent->dv_xname, CONFIG_XNAMELEN) == 0) { /* * Names are matched. */ /* see if parent unit is specified */ if (atp->at_parentunit != -1 && parent->dv_unit != atp->at_parentunit) /* child didn't like our unit number */ break; /* * This is our child device. */ /* locate child driver */ chdrvp = config_find_driver(atp->at_childname); /* * See if helper is specified. */ if (atp->at_helpername != NULL) { /* locate helper driver */ hedrvp = config_find_driver(atp->at_helpername); /* match helper */ if (hedrvp->dr_match != NULL && hedrvp->dr_match(parent, aux) < 1) break; /* not matched */ } /* match device */ if (chdrvp->dr_match != NULL && chdrvp->dr_match(parent, aux) < 1) break; /* not matched */ /* allocate device */ self = config_alloc_device(chdrvp); /* increase units number in driver */ chdrvp->dr_nunits++; /* initialize device */ self->dv_xname = chdrvp->dr_name; self->dv_unit = chdrvp->dr_nunits; self->dv_flags = atp->at_flags; self->dv_parent = parent; printk("%s%u at %s%u via %s flags 0x%x: ", self->dv_xname, self->dv_unit, parent->dv_xname, parent->dv_unit, atp->at_helpername != NULL ? atp->at_helpername : "(self)", self->dv_flags); /* * Attach device directly or via its helper. * If there is helper, call its attach routine instead of child's one. */ if (atp->at_helpername != NULL) { if (hedrvp->dr_attach == NULL) panic("config: no attach entry for driver '%s'", hedrvp->dr_name); retval = hedrvp->dr_attach(parent, self, aux); } else { /* no helper, direct attach */ if (chdrvp->dr_attach == NULL) panic("config: no attach entry for driver '%s'", chdrvp->dr_name); retval = chdrvp->dr_attach(parent, self, aux); } /* * Attachment is done. See if it's succeeded. */ if (retval != 0) { /* attachment failed */ config_free_device(self); /* decrement nunits in driver */ chdrvp->dr_nunits--; } } /* okay, see next line in config_table */ atp++; ndevs++; } return(ndevs); } struct driver *config_find_driver(const char *name) { /* * Return pointer to driver for given 'name'. */ struct driver *drvp; int i; #if 0 drvp = drivers[0]; while (drvp != NULL) { DPRINTFg("drvp->dr_name %s\n", drvp->dr_name); if (strncmp(drvp->dr_name, name, CONFIG_XNAMELEN) == 0) { DPRINTF("config: found driver for %s\n", drvp->dr_name); return(drvp); } drvp += sizeof(struct driver *); } #endif for (i = 0; i < 100; i++) { drvp = drivers[i]; if (drvp == NULL) break; if (strncmp(drvp->dr_name, name, CONFIG_XNAMELEN) == 0) { return(drvp); } } panic("config: can't find driver for name '%s'", name); }