[BACK]Return to kern_devconfig.c CVS log [TXT][DIR] Up to [local] / funnyos / kern

File: [local] / funnyos / kern / kern_devconfig.c (download)

Revision 1.11, Sun Dec 16 23:16:09 2007 UTC (16 years, 3 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);
}