/* * $Id: kern_devconfig.c,v 1.1 2007/10/16 08:41:04 init Exp $ */ #include #include #include #include #include #include #define DEVCONFIG_DEBUG #ifdef DEVCONFIG_DEBUG #define DPRINTF(x...) do { printf(x); } while (0) #else #define DPRINTF(x...) { } #endif //extern struct device devlist[]; //extern uint8_t ndevices; /* system root device */ extern struct device *rootdev; /* config stuff */ extern struct attachinfo config_attachinfo[]; extern struct driverinfo config_driverinfo[]; void devconfig_recurse(void) { /* * Recursive attach all device tree. * Steps involved: * - find root device in device list and attach it * - for every root's child do: * - attach this child * - for every child's child do: * - attach that child * - ...and so on. */ devconfig_attach_root(); // devconfig_attach(&rootdev); } void devconfig_attach_root(void) { /* * Attach root and call devconfig_attach on itself (proceeding with its children). */ int retval; struct driver *drp; struct driverinfo *dip; DPRINTF("devconfig_attach_root: entering\n"); /* allocate memory for root device */ rootdev = kmalloc(sizeof(struct device)); if (rootdev == NULL) panic("failed to allocate space for rootdev\n"); /* NOTREACHED */ /* find root's driverinfo */ dip = devconfig_finddriverinfo("root"); drp = dip->di_driverp; /* allocate space for root's devdata */ rootdev->dv_devdata = kmalloc(drp->dr_ddsize); if(rootdev->dv_devdata == NULL) panic("failed to allocate space for rootdev devdata\n"); /* NOTREACHED */ /* increment number of this driver's instances */ dip->di_ninstances++; rootdev->dv_minor = dip->di_ninstances; rootdev->dv_name = dip->di_dname; /* link dv_parent into root itself */ rootdev->dv_parent = rootdev; printf("%s/%d at %s/%d loc 0x%x flags 0x%x: ", rootdev->dv_name, rootdev->dv_minor, rootdev->dv_parent->dv_name, rootdev->dv_parent->dv_minor, 0, 0); /* attach root; should never fail */ retval = drp->dr_attach(rootdev, 0, 0); if (retval == -1) panic("failed to attach rootdev\n"); /* NOTREACHED */ /* rootdev has been attached, so activate it */ rootdev->dv_active = 1; /* attach all other devices */ devconfig_attach_childs(rootdev); } int devconfig_attach_childs(struct device *pdevp) { /* * Attach device childs, if any. * XXX Allocate space for struct device and its xxx_dd */ int retval; struct device *cdevp; struct driver *drp; struct driverinfo *dip; struct attachinfo *aip = config_attachinfo; DPRINTF("devconfig_attach_childs: entering for %s/%d\n", pdevp->dv_name, pdevp->dv_minor); /* look for potential children in config_attachinfo table */ while(aip->ai_cname != NULL) { if (strncmp(aip->ai_pname, pdevp->dv_name, DVNAMELEN - 1) == 0 && aip->ai_pminor == pdevp->dv_minor) { /* * It is our child. */ /* find child's driverinfo */ dip = devconfig_finddriverinfo(aip->ai_cname); /* allocate space for child's device */ cdevp = kmalloc(sizeof(struct device)); if (cdevp == NULL) panic("failed to allocate space for %s device\n", aip->ai_cname); /* NOTREACHED */ /* link with parent */ cdevp->dv_parent = pdevp; drp = dip->di_driverp; /* allocate space for device's devdata */ cdevp->dv_devdata = kmalloc(drp->dr_ddsize); if (cdevp->dv_devdata == NULL) panic("failed to allocate space for %s devdata\n"); /* NOTREACHED */ /* increment number of driver's instances */ dip->di_ninstances++; cdevp->dv_name = dip->di_dname; cdevp->dv_minor = dip->di_ninstances; /* XXX what about locator (aip->ai_locator)? */ printf("%s/%d at %s/%d loc 0x%x flags 0x%x: ", cdevp->dv_name, cdevp->dv_minor, pdevp->dv_name, pdevp->dv_minor, aip->ai_locator, aip->ai_flags); /* try to attach this device */ retval = drp->dr_attach(cdevp, aip->ai_locator, aip->ai_flags); if (retval == -1) { /* * Attachment failed. */ /* XXX what should we do? */ printf("disabling %s/%d\n", cdevp->dv_name, cdevp->dv_minor); /* TODO kfree devdata and device */ continue; /* NOTREACHED */ } /* * Attachment completed. */ /* activate device */ cdevp->dv_active = 1; /* XXX think about recursion */ /* recursive attach this child's children */ //devconfig_attach_childs(cdevp); } /* next attachinfo in table */ aip++; } } #if 0 void devconfig_iterate(void) { struct device *devp = devlist; printf("Entered devconfig phase\n"); while(devp->dv_attach != NULL) { /* * Iterative attach all devices in list. */ if (! devp->dv_active && (devp->dv_parent->dv_active || devp->dv_parent == devp)) { printf("%s/%d at %s/%d loc 0x%x: ", devp->dv_name, devp->dv_minor, devp->dv_parent->dv_name, devp->dv_parent->dv_minor, devp->dv_locator); /* call attach_subr and activate device if it returns 0 */ if (devp->dv_attach(devp) == 0) { /* driver returns okay; mark device as active */ devp->dv_active = 1; } else { /* attachment failed */ printf("disabling %s/%d\n", devp->dv_name, devp->dv_minor); } } devp++; } printf("Exited devconfig phase\n"); } int devconfig_target(struct device *devp) { /* * Recursive attach (subtree) nodes upto already active parent or (root). */ if (devp == NULL) return(-1); /* attach parent if it's not (root) or not activated yet */ if (devp->dv_parent != devp && ! devp->dv_parent->dv_active) { if (devconfig_target(devp->dv_parent) == -1) return(-1); } printf("%s/%d at %s/%d\n", devp->dv_name, devp->dv_minor, devp->dv_parent->dv_name, devp->dv_parent->dv_minor); if (devp->dv_attach(devp) == 0) { /* attached */ devp->dv_active = 1; return(0); } else { /* failed */ printf("disabling %s/%d\n", devp->dv_name, devp->dv_minor); /* XXX maybe it is easier to panic here? */ /* panic(XXX) */ return(-1); } } struct device *devconfig_findbyname(const char *dv_name, const uint8_t dv_minor) { /* * Return pointer to device dv_name/dv_minor. */ struct device *devp = devlist; while(devp->dv_name) { if (strncmp(devp->dv_name, dv_name, DVNAMELEN - 1) == 0 && devp->dv_minor == dv_minor) return (devp); } /* nothing has been found */ return(NULL); } #endif /* not 0 */ struct driverinfo *devconfig_finddriverinfo(const char *dname) { /* * Return associated with dname driver (from config_driverinfo[]) * Will cause SYSTEM PANIC if can't find associated driver. */ struct driverinfo *dip = config_driverinfo; while(dip->di_dname != NULL) { if (strncmp(dname, dip->di_dname, DVNAMELEN - 1) == 0) return(dip); dip++; } panic("failed to find driverinfo entry for %s\n", dname); /* NOTREACHED */ return(NULL); }