File: [local] / funnyos / kern / kern_devconfig.c (download)
Revision 1.11, Sun Dec 16 23:16:09 2007 UTC (16 years, 6 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD Changes since 1.10: +2 -2 lines
change interrupt establishing semantic:
now instead of '0' drivers should use '-1' in config.c to signalize that they won't use intrs.
attach gpiobtn at sapio/0 while here.
|
/*
* $Id: kern_devconfig.c,v 1.11 2007/12/16 23:16:09 nbrk Exp $
*/
#include <sys/types.h>
#include <sys/device.h>
#include <sys/kern_devconfig.h>
#include <sys/mem.h>
#include <sys/kern_irq.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
/* 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();
}
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 != 0)
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.
* 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", aip->ai_cname);
/* NOTREACHED */
/* increment number of driver's instances */
dip->di_ninstances++;
cdevp->dv_name = dip->di_dname;
cdevp->dv_minor = dip->di_ninstances;
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 != 0) {
/*
* Attachment failed.
*/
/* XXX what should we do? */
printf("disabling %s/%d\n", cdevp->dv_name, cdevp->dv_minor);
/* TODO kfree devdata and device */
/* next aip */
aip++;
continue;
/* NOTREACHED */
}
/*
* Attachment completed.
*/
/* activate device */
cdevp->dv_active = 1;
/* if device has interrupt handler, establish it */
if (drp->dr_interrupt != NULL && aip->ai_intrno != -1) {
DPRINTF("devconfig_attach_childs: establishing interrupt %d for %s/%d\n",
aip->ai_intrno, cdevp->dv_name, cdevp->dv_minor);
intr_establish(aip->ai_intrno, cdevp, drp->dr_interrupt);
}
/* recursive attach this child's children */
devconfig_attach_childs(cdevp);
}
/* next attachinfo in table */
aip++;
}
}
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);
}