[BACK]Return to config_search.c CVS log [TXT][DIR] Up to [local] / prex-old / dev / core

File: [local] / prex-old / dev / core / config_search.c (download)

Revision 1.1, Fri Aug 8 12:37:11 2008 UTC (15 years, 9 months ago) by nbrk
Branch: MAIN

Heads up! Implement universal device attachment and autoconfiguration machinery.
This is somewhat similar to traditional BSD autoconf but much more simple.
Three basic data structures involved in autoconfiguration process are:
struct device, which represents abstract device and its private (driver softc) data;
struct driver, which holds {attach,match,detach} entries, name and softc size;
struct attachment, which tells us how drivers are interacted with each other.
Attachment basically describes how to attach devices in system.
Machine specified part should export arrays config_table[] and *drivers[] for config.

This might have broken i386 & gba tree, but there is only a question of time.

/*
 * $Id: config_search.c,v 1.1 2008/08/08 12:37:11 nbrk Exp $
 */
#include <driver.h>

/* #define AUTOCONF_DEBUG */

#ifndef AUTOCONF_DEBUG
#define DPRINTF(fmt...)  do {} while (0)
#else
#define DPRINTF(fmt...)	do { printk(fmt); } while (0)
#endif /* !AUTOCONF_DEBUG */

extern struct driver	*drivers[];
extern struct attachment	config_table[];

int
config_search_children(struct device *parent, void *aux)
{
	struct attachment	*atp;
	struct driver	*chdrvp, *hedrvp;
	struct device	*self;
	int	retval;
	int	ndevs;

	DPRINTF("config_search_children: enter, name=%s\n", parent->dv_xname);
	atp = config_table;

	/*
	 * Look through the table.
	 */
	while (atp->at_childname != NULL) {
		DPRINTF("config_table: trying %s at %s%u via %s\n", atp->at_childname, atp->at_parentname,
				atp->at_parentunit == -1 ? "*" : atp->at_parentunit,
				atp->at_helpername != NULL ? atp->at_helpername : "(self)");

		if (atp->at_parentname == NULL)
			panic("config: bogus config table (no parent given for %s)", 
					atp->at_childname);

		if (strncmp(atp->at_parentname, parent->dv_xname, CONFIG_XNAMELEN) == 0) {
			/*
			 * Names are matched.
			 */
			/* see if parent unit is specified */
			if (atp->at_parentunit != -1 && parent->dv_unit != atp->at_parentunit)
				/* child didn't like our unit number */
				break;

			/*
			 * This is our child device.
			 */
			/* locate child driver */
			chdrvp = config_find_driver(atp->at_childname);

			/*
			 * See if helper is specified.
			 */
			if (atp->at_helpername != NULL) {
				/* locate helper driver */
				hedrvp = config_find_driver(atp->at_helpername);

				/* match helper */
				if (hedrvp->dr_match != NULL && hedrvp->dr_match(parent, parent->dv_data) < 1)
					break;	/* not matched */
			}

			/* match device */
			if (chdrvp->dr_match != NULL && chdrvp->dr_match(parent, parent->dv_data) < 1)
				break;	/* not matched */

			/* allocate device */
			self = config_alloc_device(chdrvp);

			/* increase units number in driver */
			chdrvp->dr_nunits++;

			/* initialize device */
			self->dv_xname = chdrvp->dr_name;
			self->dv_unit = chdrvp->dr_nunits;
			self->dv_flags = atp->at_flags;
			self->dv_parent = parent;

			printk("%s%u at %s%u via %s flags 0x%x: ", self->dv_xname, self->dv_unit,
				parent->dv_xname, parent->dv_unit,
				atp->at_helpername != NULL ? atp->at_helpername : "(self)", self->dv_flags);

			/*
			 * Attach device directly or via its helper.
			 * If there is helper, call its attach routine instead of child's one.
			 */
			if (atp->at_helpername != NULL) {
				if (hedrvp->dr_attach == NULL)
					panic("config: no attach entry for driver '%s'", hedrvp->dr_name);

				retval = hedrvp->dr_attach(parent, self, aux);
			} else {
				/* no helper, direct attach */
				if (chdrvp->dr_attach == NULL)
					panic("config: no attach entry for driver '%s'", chdrvp->dr_name);

				retval = chdrvp->dr_attach(parent, self, aux);
			}

			/*
			 * Attachment is done. See if it's succeeded.
			 */
			if (retval != 0) {
				/* attachment failed */
				config_free_device(self);

				/* decrement nunits in driver */
				chdrvp->dr_nunits--;
			}

		}
		/* okay, see next line in config_table */
		atp++;
		ndevs++;
	}

	return(ndevs);
}


struct driver
*config_find_driver(const char *name)
{
	/*
	 * Return pointer to driver for given 'name'.
	 */
	struct driver	*drvp;
	int	i;

#if 0
	drvp = drivers[0];

	while (drvp != NULL) {
		DPRINTFg("drvp->dr_name %s\n", drvp->dr_name);
		if (strncmp(drvp->dr_name, name, CONFIG_XNAMELEN) == 0) {
			DPRINTF("config: found driver for %s\n", drvp->dr_name);
			return(drvp);
		}

		drvp += sizeof(struct driver *);
	}
#endif
	for (i = 0; i < 100; i++) {
		drvp = drivers[i];
		if (drvp == NULL)
			break;

		if (strncmp(drvp->dr_name, name, CONFIG_XNAMELEN) == 0) {
			return(drvp);
		}
	}

	panic("config: can't find driver for name '%s'", name);
}