subr_autoconf.c revision 45739
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1992, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This software was developed by the Computer Systems Engineering group
61541Srgrimes * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
71541Srgrimes * contributed to Berkeley.
81541Srgrimes *
91541Srgrimes * All advertising materials mentioning features or use of this software
101541Srgrimes * must display the following acknowledgement:
111541Srgrimes *	This product includes software developed by the University of
121541Srgrimes *	California, Lawrence Berkeley Laboratories.
131541Srgrimes *
141541Srgrimes * Redistribution and use in source and binary forms, with or without
151541Srgrimes * modification, are permitted provided that the following conditions
161541Srgrimes * are met:
171541Srgrimes * 1. Redistributions of source code must retain the above copyright
181541Srgrimes *    notice, this list of conditions and the following disclaimer.
191541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
201541Srgrimes *    notice, this list of conditions and the following disclaimer in the
211541Srgrimes *    documentation and/or other materials provided with the distribution.
221541Srgrimes * 3. All advertising materials mentioning features or use of this software
231541Srgrimes *    must display the following acknowledgement:
241541Srgrimes *	This product includes software developed by the University of
251541Srgrimes *	California, Berkeley and its contributors.
261541Srgrimes * 4. Neither the name of the University nor the names of its contributors
271541Srgrimes *    may be used to endorse or promote products derived from this software
281541Srgrimes *    without specific prior written permission.
291541Srgrimes *
301541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
311541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
321541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
331541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
341541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
351541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
361541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
371541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
381541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
391541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
401541Srgrimes * SUCH DAMAGE.
411541Srgrimes *
421541Srgrimes *	@(#)subr_autoconf.c	8.1 (Berkeley) 6/10/93
431541Srgrimes *
4445739Speter * $Id: subr_autoconf.c,v 1.8 1999/01/08 17:31:11 eivind Exp $
451541Srgrimes */
461541Srgrimes
471541Srgrimes#include <sys/param.h>
4829680Sgibbs#include <sys/kernel.h>
4929680Sgibbs#include <sys/systm.h>
501541Srgrimes#include <sys/device.h>
5131260Sbde#ifdef UNUSED
521541Srgrimes#include <sys/malloc.h>
5331260Sbde#endif
541541Srgrimes
551541Srgrimes/*
561541Srgrimes * Autoconfiguration subroutines.
571541Srgrimes */
581541Srgrimes
5929680Sgibbs#ifdef UNUSED
601541Srgrimes/*
611541Srgrimes * ioconf.c exports exactly two names: cfdata and cfroots.  All system
621541Srgrimes * devices and drivers are found via these tables.
631541Srgrimes */
641541Srgrimesextern struct cfdata cfdata[];
651541Srgrimesextern short cfroots[];
661541Srgrimes
671541Srgrimes#define	ROOT ((struct device *)NULL)
681541Srgrimes
691541Srgrimesstruct matchinfo {
701541Srgrimes	cfmatch_t fn;
711541Srgrimes	struct	device *parent;
721541Srgrimes	void	*aux;
731541Srgrimes	struct	cfdata *match;
741541Srgrimes	int	pri;
751541Srgrimes};
761541Srgrimes
771541Srgrimes/*
781541Srgrimes * Apply the matching function and choose the best.  This is used
791541Srgrimes * a few times and we want to keep the code small.
801541Srgrimes */
811541Srgrimesstatic void
821541Srgrimesmapply(m, cf)
831541Srgrimes	register struct matchinfo *m;
841541Srgrimes	register struct cfdata *cf;
851541Srgrimes{
861541Srgrimes	register int pri;
871541Srgrimes
881541Srgrimes	if (m->fn != NULL)
891541Srgrimes		pri = (*m->fn)(m->parent, cf, m->aux);
901541Srgrimes	else
911541Srgrimes		pri = (*cf->cf_driver->cd_match)(m->parent, cf, m->aux);
921541Srgrimes	if (pri > m->pri) {
931541Srgrimes		m->match = cf;
941541Srgrimes		m->pri = pri;
951541Srgrimes	}
961541Srgrimes}
971541Srgrimes
981541Srgrimes/*
991541Srgrimes * Iterate over all potential children of some device, calling the given
1001541Srgrimes * function (default being the child's match function) for each one.
1011541Srgrimes * Nonzero returns are matches; the highest value returned is considered
1021541Srgrimes * the best match.  Return the `found child' if we got a match, or NULL
1031541Srgrimes * otherwise.  The `aux' pointer is simply passed on through.
1041541Srgrimes *
1051541Srgrimes * Note that this function is designed so that it can be used to apply
1061541Srgrimes * an arbitrary function to all potential children (its return value
1071541Srgrimes * can be ignored).
1081541Srgrimes */
1091541Srgrimesstruct cfdata *
1101541Srgrimesconfig_search(fn, parent, aux)
1111541Srgrimes	cfmatch_t fn;
1121541Srgrimes	register struct device *parent;
1131541Srgrimes	void *aux;
1141541Srgrimes{
1151541Srgrimes	register struct cfdata *cf;
1161541Srgrimes	register short *p;
1171541Srgrimes	struct matchinfo m;
1181541Srgrimes
1191541Srgrimes	m.fn = fn;
1201541Srgrimes	m.parent = parent;
1211541Srgrimes	m.aux = aux;
1221541Srgrimes	m.match = NULL;
1231541Srgrimes	m.pri = 0;
1241541Srgrimes	for (cf = cfdata; cf->cf_driver; cf++) {
1251541Srgrimes		/*
1261541Srgrimes		 * Skip cf if no longer eligible, otherwise scan through
1271541Srgrimes		 * parents for one matching `parent', and try match function.
1281541Srgrimes		 */
1291541Srgrimes		if (cf->cf_fstate == FSTATE_FOUND)
1301541Srgrimes			continue;
1311541Srgrimes		for (p = cf->cf_parents; *p >= 0; p++)
1321541Srgrimes			if (parent->dv_cfdata == &cfdata[*p])
1331541Srgrimes				mapply(&m, cf);
1341541Srgrimes	}
1351541Srgrimes	return (m.match);
1361541Srgrimes}
1371541Srgrimes
1381541Srgrimes/*
1391541Srgrimes * Find the given root device.
1401541Srgrimes * This is much like config_search, but there is no parent.
1411541Srgrimes */
1421541Srgrimesstruct cfdata *
1431541Srgrimesconfig_rootsearch(fn, rootname, aux)
1441541Srgrimes	register cfmatch_t fn;
1451541Srgrimes	register char *rootname;
1461541Srgrimes	register void *aux;
1471541Srgrimes{
1481541Srgrimes	register struct cfdata *cf;
1491541Srgrimes	register short *p;
1501541Srgrimes	struct matchinfo m;
1511541Srgrimes
1521541Srgrimes	m.fn = fn;
1531541Srgrimes	m.parent = ROOT;
1541541Srgrimes	m.aux = aux;
1551541Srgrimes	m.match = NULL;
1561541Srgrimes	m.pri = 0;
1571541Srgrimes	/*
1581541Srgrimes	 * Look at root entries for matching name.  We do not bother
1591541Srgrimes	 * with found-state here since only one root should ever be
1601541Srgrimes	 * searched (and it must be done first).
1611541Srgrimes	 */
1621541Srgrimes	for (p = cfroots; *p >= 0; p++) {
1631541Srgrimes		cf = &cfdata[*p];
1641541Srgrimes		if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
1651541Srgrimes			mapply(&m, cf);
1661541Srgrimes	}
1671541Srgrimes	return (m.match);
1681541Srgrimes}
1691541Srgrimes
1701541Srgrimesstatic char *msgs[3] = { "", " not configured\n", " unsupported\n" };
1711541Srgrimes
1721541Srgrimes/*
1731541Srgrimes * The given `aux' argument describes a device that has been found
1741541Srgrimes * on the given parent, but not necessarily configured.  Locate the
1751541Srgrimes * configuration data for that device (using the cd_match configuration
1761541Srgrimes * driver function) and attach it, and return true.  If the device was
1771541Srgrimes * not configured, call the given `print' function and return 0.
1781541Srgrimes */
1791541Srgrimesint
1801541Srgrimesconfig_found(parent, aux, print)
1811541Srgrimes	struct device *parent;
1821541Srgrimes	void *aux;
1831541Srgrimes	cfprint_t print;
1841541Srgrimes{
1851541Srgrimes	struct cfdata *cf;
1861541Srgrimes
1871541Srgrimes	if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) {
1881541Srgrimes		config_attach(parent, cf, aux, print);
1891541Srgrimes		return (1);
1901541Srgrimes	}
1911541Srgrimes	printf(msgs[(*print)(aux, parent->dv_xname)]);
1921541Srgrimes	return (0);
1931541Srgrimes}
1941541Srgrimes
1951541Srgrimes/*
1961541Srgrimes * As above, but for root devices.
1971541Srgrimes */
1981541Srgrimesint
1991541Srgrimesconfig_rootfound(rootname, aux)
2001541Srgrimes	char *rootname;
2011541Srgrimes	void *aux;
2021541Srgrimes{
2031541Srgrimes	struct cfdata *cf;
2041541Srgrimes
2051541Srgrimes	if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) {
2061541Srgrimes		config_attach(ROOT, cf, aux, (cfprint_t)NULL);
2071541Srgrimes		return (1);
2081541Srgrimes	}
2091541Srgrimes	printf("root device %s not configured\n", rootname);
2101541Srgrimes	return (0);
2111541Srgrimes}
2121541Srgrimes
2131541Srgrimes/* just like sprintf(buf, "%d") except that it works from the end */
2141541Srgrimesstatic char *
2151541Srgrimesnumber(ep, n)
2161541Srgrimes	register char *ep;
2171541Srgrimes	register int n;
2181541Srgrimes{
2191541Srgrimes
2201541Srgrimes	*--ep = 0;
2211541Srgrimes	while (n >= 10) {
2221541Srgrimes		*--ep = (n % 10) + '0';
2231541Srgrimes		n /= 10;
2241541Srgrimes	}
2251541Srgrimes	*--ep = n + '0';
2261541Srgrimes	return (ep);
2271541Srgrimes}
2281541Srgrimes
2291541Srgrimes/*
2301541Srgrimes * Attach a found device.  Allocates memory for device variables.
2311541Srgrimes */
2321541Srgrimesvoid
2331541Srgrimesconfig_attach(parent, cf, aux, print)
2341541Srgrimes	register struct device *parent;
2351541Srgrimes	register struct cfdata *cf;
2361541Srgrimes	register void *aux;
2371541Srgrimes	cfprint_t print;
2381541Srgrimes{
2391541Srgrimes	register struct device *dev;
2401541Srgrimes	register struct cfdriver *cd;
2411541Srgrimes	register size_t lname, lunit;
2421541Srgrimes	register char *xunit;
2431541Srgrimes	int myunit;
2441541Srgrimes	char num[10];
2451541Srgrimes	static struct device **nextp = &alldevs;
2461541Srgrimes
2471541Srgrimes	cd = cf->cf_driver;
2481541Srgrimes	if (cd->cd_devsize < sizeof(struct device))
2491541Srgrimes		panic("config_attach");
2501541Srgrimes	myunit = cf->cf_unit;
2511541Srgrimes	if (cf->cf_fstate == FSTATE_NOTFOUND)
2521541Srgrimes		cf->cf_fstate = FSTATE_FOUND;
2531541Srgrimes	else
2541541Srgrimes		cf->cf_unit++;
2551541Srgrimes
2561541Srgrimes	/* compute length of name and decimal expansion of unit number */
2571541Srgrimes	lname = strlen(cd->cd_name);
2581541Srgrimes	xunit = number(&num[sizeof num], myunit);
2591541Srgrimes	lunit = &num[sizeof num] - xunit;
2601541Srgrimes	if (lname + lunit >= sizeof(dev->dv_xname))
2611541Srgrimes		panic("config_attach: device name too long");
2621541Srgrimes
2631541Srgrimes	/* get memory for all device vars */
2641541Srgrimes	dev = (struct device *)malloc(cd->cd_devsize, M_DEVBUF, M_WAITOK);
2651541Srgrimes					/* XXX cannot wait! */
2661541Srgrimes	bzero(dev, cd->cd_devsize);
2671541Srgrimes	*nextp = dev;			/* link up */
2681541Srgrimes	nextp = &dev->dv_next;
2691541Srgrimes	dev->dv_class = cd->cd_class;
2701541Srgrimes	dev->dv_cfdata = cf;
2711541Srgrimes	dev->dv_unit = myunit;
2721541Srgrimes	bcopy(cd->cd_name, dev->dv_xname, lname);
2731541Srgrimes	bcopy(xunit, dev->dv_xname + lname, lunit);
2741541Srgrimes	dev->dv_parent = parent;
2751541Srgrimes	if (parent == ROOT)
2761541Srgrimes		printf("%s (root)", dev->dv_xname);
2771541Srgrimes	else {
2781541Srgrimes		printf("%s at %s", dev->dv_xname, parent->dv_xname);
2791541Srgrimes		(void) (*print)(aux, (char *)0);
2801541Srgrimes	}
2811541Srgrimes
2821541Srgrimes	/* put this device in the devices array */
2831541Srgrimes	if (dev->dv_unit >= cd->cd_ndevs) {
2841541Srgrimes		/*
2851541Srgrimes		 * Need to expand the array.
2861541Srgrimes		 */
2871541Srgrimes		int old = cd->cd_ndevs, oldbytes, new, newbytes;
2881541Srgrimes		void **nsp;
2891541Srgrimes
2901541Srgrimes		if (old == 0) {
2911541Srgrimes			nsp = malloc(MINALLOCSIZE, M_DEVBUF, M_WAITOK);	/*XXX*/
2921541Srgrimes			bzero(nsp, MINALLOCSIZE);
2931541Srgrimes			cd->cd_ndevs = MINALLOCSIZE / sizeof(void *);
2941541Srgrimes		} else {
2951541Srgrimes			new = cd->cd_ndevs;
2961541Srgrimes			do {
2971541Srgrimes				new *= 2;
2981541Srgrimes			} while (new <= dev->dv_unit);
2991541Srgrimes			cd->cd_ndevs = new;
3001541Srgrimes			oldbytes = old * sizeof(void *);
3011541Srgrimes			newbytes = new * sizeof(void *);
3021541Srgrimes			nsp = malloc(newbytes, M_DEVBUF, M_WAITOK);	/*XXX*/
3031541Srgrimes			bcopy(cd->cd_devs, nsp, oldbytes);
3041541Srgrimes			bzero(&nsp[old], newbytes - oldbytes);
3051541Srgrimes			free(cd->cd_devs, M_DEVBUF);
3061541Srgrimes		}
3071541Srgrimes		cd->cd_devs = nsp;
3081541Srgrimes	}
3091541Srgrimes	if (cd->cd_devs[dev->dv_unit])
3101541Srgrimes		panic("config_attach: duplicate %s", dev->dv_xname);
3111541Srgrimes	cd->cd_devs[dev->dv_unit] = dev;
3121541Srgrimes
3131541Srgrimes	/*
3141541Srgrimes	 * Before attaching, clobber any unfound devices that are
3151541Srgrimes	 * otherwise identical.
3161541Srgrimes	 */
3171541Srgrimes	for (cf = cfdata; cf->cf_driver; cf++)
3181541Srgrimes		if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit &&
3191541Srgrimes		    cf->cf_fstate == FSTATE_NOTFOUND)
3201541Srgrimes			cf->cf_fstate = FSTATE_FOUND;
3211541Srgrimes	(*cd->cd_attach)(parent, dev, aux);
3221541Srgrimes}
3231541Srgrimes
3241541Srgrimes/*
3251541Srgrimes * Attach an event.  These must come from initially-zero space (see
3261541Srgrimes * commented-out assignments below), but that occurs naturally for
3271541Srgrimes * device instance variables.
3281541Srgrimes */
3291541Srgrimesvoid
3301541Srgrimesevcnt_attach(dev, name, ev)
3311541Srgrimes	struct device *dev;
3321541Srgrimes	const char *name;
3331541Srgrimes	struct evcnt *ev;
3341541Srgrimes{
3351541Srgrimes	static struct evcnt **nextp = &allevents;
3361541Srgrimes
33742408Seivind	KASSERT(strlen(name) < sizeof(ev->ev_name), ("evcnt_attach"));
33842408Seivind
3391541Srgrimes	/* ev->ev_next = NULL; */
3401541Srgrimes	ev->ev_dev = dev;
3411541Srgrimes	/* ev->ev_count = 0; */
34241514Sarchie	snprintf(ev->ev_name, sizeof(ev->ev_name), "%s", name);
3431541Srgrimes	*nextp = ev;
3441541Srgrimes	nextp = &ev->ev_next;
3451541Srgrimes}
34629680Sgibbs
34729680Sgibbs#endif
34829680Sgibbs
34929680Sgibbs/*
35029680Sgibbs * "Interrupt driven config" functions.
35129680Sgibbs */
35229680Sgibbsstatic TAILQ_HEAD(, intr_config_hook) intr_config_hook_list =
35329680Sgibbs	TAILQ_HEAD_INITIALIZER(intr_config_hook_list);
35429680Sgibbs
35529680Sgibbs
35629680Sgibbs/* ARGSUSED */
35729680Sgibbsstatic void run_interrupt_driven_config_hooks __P((void *dummy));
35829680Sgibbsstatic void
35929680Sgibbsrun_interrupt_driven_config_hooks(dummy)
36029680Sgibbs	void *dummy;
36129680Sgibbs{
36229680Sgibbs	struct intr_config_hook *hook;
36329680Sgibbs
36429680Sgibbs	for (hook = intr_config_hook_list.tqh_first; hook != NULL;
36529680Sgibbs	     hook = hook->ich_links.tqe_next) {
36629680Sgibbs		(*hook->ich_func)(hook->ich_arg);
36729680Sgibbs	}
36829680Sgibbs
36929680Sgibbs	while (intr_config_hook_list.tqh_first != NULL) {
37029680Sgibbs		tsleep(&intr_config_hook_list, PCONFIG, "conifhk", 0);
37129680Sgibbs	}
37229680Sgibbs}
37329680SgibbsSYSINIT(intr_config_hooks, SI_SUB_INT_CONFIG_HOOKS, SI_ORDER_FIRST,
37429680Sgibbs	run_interrupt_driven_config_hooks, NULL)
37529680Sgibbs
37629680Sgibbs/*
37729680Sgibbs * Register a hook that will be called after "cold"
37829680Sgibbs * autoconfiguration is complete and interrupts can
37929680Sgibbs * be used to complete initialization.
38029680Sgibbs */
38129680Sgibbsint
38229680Sgibbsconfig_intrhook_establish(hook)
38329680Sgibbs	struct intr_config_hook *hook;
38429680Sgibbs{
38529680Sgibbs	struct intr_config_hook *hook_entry;
38629680Sgibbs
38729680Sgibbs	for (hook_entry = intr_config_hook_list.tqh_first; hook_entry != NULL;
38829680Sgibbs	     hook_entry = hook_entry->ich_links.tqe_next)
38929680Sgibbs		if (hook_entry == hook)
39029680Sgibbs			break;
39129680Sgibbs	if (hook_entry != NULL) {
39229680Sgibbs		printf("config_intrhook_establish: establishing an "
39329680Sgibbs		       "already established hook.\n");
39429680Sgibbs		return (1);
39529680Sgibbs	}
39629680Sgibbs	TAILQ_INSERT_TAIL(&intr_config_hook_list, hook, ich_links);
39729680Sgibbs	if (cold == 0)
39845739Speter		/* XXX Sufficient for modules loaded after initial config??? */
39929680Sgibbs		run_interrupt_driven_config_hooks(NULL);
40029680Sgibbs	return (0);
40129680Sgibbs}
40229680Sgibbs
40329680Sgibbsvoid
40429680Sgibbsconfig_intrhook_disestablish(hook)
40529680Sgibbs	struct intr_config_hook *hook;
40629680Sgibbs{
40729680Sgibbs	struct intr_config_hook *hook_entry;
40829680Sgibbs
40929680Sgibbs	for (hook_entry = intr_config_hook_list.tqh_first; hook_entry != NULL;
41029680Sgibbs	     hook_entry = hook_entry->ich_links.tqe_next)
41129680Sgibbs		if (hook_entry == hook)
41229680Sgibbs			break;
41329680Sgibbs	if (hook_entry == NULL)
41429680Sgibbs		panic("config_intrhook_disestablish: disestablishing an "
41529680Sgibbs		      "unestablished hook");
41629680Sgibbs
41729680Sgibbs	TAILQ_REMOVE(&intr_config_hook_list, hook, ich_links);
41829680Sgibbs	/* Wakeup anyone watching the list */
41929680Sgibbs	wakeup(&intr_config_hook_list);
42029680Sgibbs}
421