[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.1, Tue Oct 16 08:41:04 2007 UTC (16 years, 6 months ago) by init
Branch: MAIN

Initial revision

/*
 * $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);
}