/*
* $Id: kern_devconfig.c,v 1.1 2007/10/16 08:41:04 init Exp $
*/
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kern_devconfig.h>
#include <sys/mem.h>
#include <libkern/string.h>
#include <libkern/printf.h>
#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);
}