xref: /freebsd/sys/kern/subr_hints.c (revision 2398f0cd1d0f4da5f2004d4630b4bcbb11808c87)
12398f0cdSPeter Wemm /*-
22398f0cdSPeter Wemm  * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
32398f0cdSPeter Wemm  * All rights reserved.
42398f0cdSPeter Wemm  *
52398f0cdSPeter Wemm  * Redistribution and use in source and binary forms, with or without
62398f0cdSPeter Wemm  * modification, are permitted provided that the following conditions
72398f0cdSPeter Wemm  * are met:
82398f0cdSPeter Wemm  * 1. Redistributions of source code must retain the above copyright
92398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer.
102398f0cdSPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
112398f0cdSPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
122398f0cdSPeter Wemm  *    documentation and/or other materials provided with the distribution.
132398f0cdSPeter Wemm  *
142398f0cdSPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152398f0cdSPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162398f0cdSPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172398f0cdSPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182398f0cdSPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192398f0cdSPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202398f0cdSPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212398f0cdSPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222398f0cdSPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232398f0cdSPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242398f0cdSPeter Wemm  * SUCH DAMAGE.
252398f0cdSPeter Wemm  *
262398f0cdSPeter Wemm  * $FreeBSD$
272398f0cdSPeter Wemm  */
282398f0cdSPeter Wemm 
292398f0cdSPeter Wemm #include <sys/param.h>
302398f0cdSPeter Wemm #include <sys/systm.h>
312398f0cdSPeter Wemm #include <sys/bus.h>
322398f0cdSPeter Wemm 
332398f0cdSPeter Wemm /*
342398f0cdSPeter Wemm  * Access functions for device resources.
352398f0cdSPeter Wemm  */
362398f0cdSPeter Wemm 
372398f0cdSPeter Wemm extern char static_hints[];		/* by config for now */
382398f0cdSPeter Wemm 
392398f0cdSPeter Wemm /*
402398f0cdSPeter Wemm  * Evil wildcarding resource string lookup.
412398f0cdSPeter Wemm  * This walks the supplied env string table and returns a match.
422398f0cdSPeter Wemm  * The start point can be remembered for incremental searches.
432398f0cdSPeter Wemm  */
442398f0cdSPeter Wemm static int
452398f0cdSPeter Wemm res_find(const char *cp, int *line, int *startln,
462398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
472398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
482398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
492398f0cdSPeter Wemm {
502398f0cdSPeter Wemm 	int n = 0, hit;
512398f0cdSPeter Wemm 	char r_name[32];
522398f0cdSPeter Wemm 	int r_unit;
532398f0cdSPeter Wemm 	char r_resname[32];
542398f0cdSPeter Wemm 	char r_value[128];
552398f0cdSPeter Wemm 	const char *s;
562398f0cdSPeter Wemm 	char *p;
572398f0cdSPeter Wemm 
582398f0cdSPeter Wemm 	while (cp) {
592398f0cdSPeter Wemm 		hit = 1;
602398f0cdSPeter Wemm 		(*line)++;
612398f0cdSPeter Wemm 		if (strncmp(cp, "hint.", 5) != 0)
622398f0cdSPeter Wemm 			hit = 0;
632398f0cdSPeter Wemm 		else
642398f0cdSPeter Wemm 			n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
652398f0cdSPeter Wemm 			    r_name, &r_unit, r_resname, r_value);
662398f0cdSPeter Wemm 		if (hit && n != 4) {
672398f0cdSPeter Wemm 			printf("CONFIG: invalid hint '%s'\n", cp);
682398f0cdSPeter Wemm 			/* XXX: abuse bogus index() declaration */
692398f0cdSPeter Wemm 			p = index(cp, 'h');
702398f0cdSPeter Wemm 			*p = 'H';
712398f0cdSPeter Wemm 			hit = 0;
722398f0cdSPeter Wemm 		}
732398f0cdSPeter Wemm 		if (hit && startln && *startln >= 0 && *line < *startln)
742398f0cdSPeter Wemm 			hit = 0;
752398f0cdSPeter Wemm 		if (hit && name && strcmp(name, r_name) != 0)
762398f0cdSPeter Wemm 			hit = 0;
772398f0cdSPeter Wemm 		if (hit && unit && *unit != r_unit)
782398f0cdSPeter Wemm 			hit = 0;
792398f0cdSPeter Wemm 		if (hit && resname && strcmp(resname, r_resname) != 0)
802398f0cdSPeter Wemm 			hit = 0;
812398f0cdSPeter Wemm 		if (hit && value && strcmp(value, r_value) != 0)
822398f0cdSPeter Wemm 			hit = 0;
832398f0cdSPeter Wemm 		if (hit)
842398f0cdSPeter Wemm 			break;
852398f0cdSPeter Wemm 		while (*cp != '\0')
862398f0cdSPeter Wemm 			cp++;
872398f0cdSPeter Wemm 		cp++;
882398f0cdSPeter Wemm 		if (*cp == '\0') {
892398f0cdSPeter Wemm 			cp = NULL;
902398f0cdSPeter Wemm 			break;
912398f0cdSPeter Wemm 		}
922398f0cdSPeter Wemm 	}
932398f0cdSPeter Wemm 	if (cp == NULL)
942398f0cdSPeter Wemm 		return ENOENT;
952398f0cdSPeter Wemm 
962398f0cdSPeter Wemm 	s = cp;
972398f0cdSPeter Wemm 	/* This is a bit of a hack, but at least is reentrant */
982398f0cdSPeter Wemm 	/* Note that it returns some !unterminated! strings. */
992398f0cdSPeter Wemm 	s = index(s, '.') + 1;		/* start of device */
1002398f0cdSPeter Wemm 	if (ret_name)
1012398f0cdSPeter Wemm 		*ret_name = s;
1022398f0cdSPeter Wemm 	s = index(s, '.') + 1;		/* start of unit */
1032398f0cdSPeter Wemm 	if (ret_namelen)
1042398f0cdSPeter Wemm 		*ret_namelen = s - *ret_name - 1; /* device length */
1052398f0cdSPeter Wemm 	if (ret_unit)
1062398f0cdSPeter Wemm 		*ret_unit = r_unit;
1072398f0cdSPeter Wemm 	s = index(s, '.') + 1;		/* start of resname */
1082398f0cdSPeter Wemm 	if (ret_resname)
1092398f0cdSPeter Wemm 		*ret_resname = s;
1102398f0cdSPeter Wemm 	s = index(s, '=') + 1;		/* start of value */
1112398f0cdSPeter Wemm 	if (ret_resnamelen)
1122398f0cdSPeter Wemm 		*ret_resnamelen = s - *ret_resname - 1; /* value len */
1132398f0cdSPeter Wemm 	if (ret_value)
1142398f0cdSPeter Wemm 		*ret_value = s;
1152398f0cdSPeter Wemm 	if (startln)			/* line number for anchor */
1162398f0cdSPeter Wemm 		*startln = *line + 1;
1172398f0cdSPeter Wemm 	return 0;
1182398f0cdSPeter Wemm }
1192398f0cdSPeter Wemm 
1202398f0cdSPeter Wemm /*
1212398f0cdSPeter Wemm  * Search all the data sources for matches to our query.  We look for
1222398f0cdSPeter Wemm  * dynamic hints first as overrides for static or fallback hints.
1232398f0cdSPeter Wemm  */
1242398f0cdSPeter Wemm static int
1252398f0cdSPeter Wemm resource_find(int *line, int *startln,
1262398f0cdSPeter Wemm     const char *name, int *unit, const char *resname, const char *value,
1272398f0cdSPeter Wemm     const char **ret_name, int *ret_namelen, int *ret_unit,
1282398f0cdSPeter Wemm     const char **ret_resname, int *ret_resnamelen, const char **ret_value)
1292398f0cdSPeter Wemm {
1302398f0cdSPeter Wemm 	int i;
1312398f0cdSPeter Wemm 	int un;
1322398f0cdSPeter Wemm 
1332398f0cdSPeter Wemm 	*line = 0;
1342398f0cdSPeter Wemm 
1352398f0cdSPeter Wemm 	/* Search for exact unit matches first */
1362398f0cdSPeter Wemm 	i = res_find(kern_envp, line, startln, name, unit, resname, value,
1372398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
1382398f0cdSPeter Wemm 	    ret_value);
1392398f0cdSPeter Wemm 	if (i == 0)
1402398f0cdSPeter Wemm 		return 0;
1412398f0cdSPeter Wemm 	i = res_find(static_hints, line, startln, name, unit, resname, value,
1422398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
1432398f0cdSPeter Wemm 	    ret_value);
1442398f0cdSPeter Wemm 	if (i == 0)
1452398f0cdSPeter Wemm 		return 0;
1462398f0cdSPeter Wemm 	if (unit == NULL)
1472398f0cdSPeter Wemm 		return ENOENT;
1482398f0cdSPeter Wemm 	/* If we are still here, search for wildcard matches */
1492398f0cdSPeter Wemm 	un = -1;
1502398f0cdSPeter Wemm 	i = res_find(kern_envp, line, startln, name, &un, resname, value,
1512398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
1522398f0cdSPeter Wemm 	    ret_value);
1532398f0cdSPeter Wemm 	if (i == 0)
1542398f0cdSPeter Wemm 		return 0;
1552398f0cdSPeter Wemm 	un = -1;
1562398f0cdSPeter Wemm 	i = res_find(static_hints, line, startln, name, &un, resname, value,
1572398f0cdSPeter Wemm 	    ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
1582398f0cdSPeter Wemm 	    ret_value);
1592398f0cdSPeter Wemm 	if (i == 0)
1602398f0cdSPeter Wemm 		return 0;
1612398f0cdSPeter Wemm 	return ENOENT;
1622398f0cdSPeter Wemm }
1632398f0cdSPeter Wemm 
1642398f0cdSPeter Wemm int
1652398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result)
1662398f0cdSPeter Wemm {
1672398f0cdSPeter Wemm 	int error;
1682398f0cdSPeter Wemm 	const char *str;
1692398f0cdSPeter Wemm 	char *op;
1702398f0cdSPeter Wemm 	unsigned long val;
1712398f0cdSPeter Wemm 	int line;
1722398f0cdSPeter Wemm 
1732398f0cdSPeter Wemm 	line = 0;
1742398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
1752398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
1762398f0cdSPeter Wemm 	if (error)
1772398f0cdSPeter Wemm 		return error;
1782398f0cdSPeter Wemm 	if (*str == '\0')
1792398f0cdSPeter Wemm 		return EFTYPE;
1802398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
1812398f0cdSPeter Wemm 	if (*op != '\0')
1822398f0cdSPeter Wemm 		return EFTYPE;
1832398f0cdSPeter Wemm 	*result = val;
1842398f0cdSPeter Wemm 	return 0;
1852398f0cdSPeter Wemm }
1862398f0cdSPeter Wemm 
1872398f0cdSPeter Wemm int
1882398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname,
1892398f0cdSPeter Wemm     long *result)
1902398f0cdSPeter Wemm {
1912398f0cdSPeter Wemm 	int error;
1922398f0cdSPeter Wemm 	const char *str;
1932398f0cdSPeter Wemm 	char *op;
1942398f0cdSPeter Wemm 	unsigned long val;
1952398f0cdSPeter Wemm 	int line;
1962398f0cdSPeter Wemm 
1972398f0cdSPeter Wemm 	line = 0;
1982398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
1992398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
2002398f0cdSPeter Wemm 	if (error)
2012398f0cdSPeter Wemm 		return error;
2022398f0cdSPeter Wemm 	if (*str == '\0')
2032398f0cdSPeter Wemm 		return EFTYPE;
2042398f0cdSPeter Wemm 	val = strtoul(str, &op, 0);
2052398f0cdSPeter Wemm 	if (*op != '\0')
2062398f0cdSPeter Wemm 		return EFTYPE;
2072398f0cdSPeter Wemm 	*result = val;
2082398f0cdSPeter Wemm 	return 0;
2092398f0cdSPeter Wemm }
2102398f0cdSPeter Wemm 
2112398f0cdSPeter Wemm int
2122398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname,
2132398f0cdSPeter Wemm     const char **result)
2142398f0cdSPeter Wemm {
2152398f0cdSPeter Wemm 	int error;
2162398f0cdSPeter Wemm 	const char *str;
2172398f0cdSPeter Wemm 	int line;
2182398f0cdSPeter Wemm 
2192398f0cdSPeter Wemm 	line = 0;
2202398f0cdSPeter Wemm 	error = resource_find(&line, NULL, name, &unit, resname, NULL,
2212398f0cdSPeter Wemm 	    NULL, NULL, NULL, NULL, NULL, &str);
2222398f0cdSPeter Wemm 	if (error)
2232398f0cdSPeter Wemm 		return error;
2242398f0cdSPeter Wemm 	*result = str;
2252398f0cdSPeter Wemm 	return 0;
2262398f0cdSPeter Wemm }
2272398f0cdSPeter Wemm 
2282398f0cdSPeter Wemm /*
2292398f0cdSPeter Wemm  * This is a bit nasty, but allows us to not modify the env strings.
2302398f0cdSPeter Wemm  */
2312398f0cdSPeter Wemm static const char *
2322398f0cdSPeter Wemm resource_string_copy(const char *s, int len)
2332398f0cdSPeter Wemm {
2342398f0cdSPeter Wemm 	static char stringbuf[256];
2352398f0cdSPeter Wemm 	static int offset = 0;
2362398f0cdSPeter Wemm 	const char *ret;
2372398f0cdSPeter Wemm 
2382398f0cdSPeter Wemm 	if (len == 0)
2392398f0cdSPeter Wemm 		len = strlen(s);
2402398f0cdSPeter Wemm 	if (len > 255)
2412398f0cdSPeter Wemm 		return NULL;
2422398f0cdSPeter Wemm 	if ((offset + len + 1) > 255)
2432398f0cdSPeter Wemm 		offset = 0;
2442398f0cdSPeter Wemm 	bcopy(s, &stringbuf[offset], len);
2452398f0cdSPeter Wemm 	stringbuf[offset + len] = '\0';
2462398f0cdSPeter Wemm 	ret = &stringbuf[offset];
2472398f0cdSPeter Wemm 	offset += len + 1;
2482398f0cdSPeter Wemm 	return ret;
2492398f0cdSPeter Wemm }
2502398f0cdSPeter Wemm 
2512398f0cdSPeter Wemm /*
2522398f0cdSPeter Wemm  * err = resource_find_at(&anchor, &name, &unit, resname, value)
2532398f0cdSPeter Wemm  * Iteratively fetch a list of devices wired "at" something
2542398f0cdSPeter Wemm  * res and value are restrictions.  eg: "at", "scbus0".
2552398f0cdSPeter Wemm  * For practical purposes, res = required, value = optional.
2562398f0cdSPeter Wemm  * *name and *unit are set.
2572398f0cdSPeter Wemm  * set *anchor to zero before starting.
2582398f0cdSPeter Wemm  */
2592398f0cdSPeter Wemm int
2602398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit,
2612398f0cdSPeter Wemm     const char *resname, const char *value)
2622398f0cdSPeter Wemm {
2632398f0cdSPeter Wemm 	const char *found_name;
2642398f0cdSPeter Wemm 	int found_namelen;
2652398f0cdSPeter Wemm 	int found_unit;
2662398f0cdSPeter Wemm 	int ret;
2672398f0cdSPeter Wemm 	int newln;
2682398f0cdSPeter Wemm 
2692398f0cdSPeter Wemm 	newln = *anchor;
2702398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
2712398f0cdSPeter Wemm 	    &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
2722398f0cdSPeter Wemm 	if (ret == 0) {
2732398f0cdSPeter Wemm 		*name = resource_string_copy(found_name, found_namelen);
2742398f0cdSPeter Wemm 		*unit = found_unit;
2752398f0cdSPeter Wemm 	}
2762398f0cdSPeter Wemm 	*anchor = newln;
2772398f0cdSPeter Wemm 	return ret;
2782398f0cdSPeter Wemm }
2792398f0cdSPeter Wemm 
2802398f0cdSPeter Wemm 
2812398f0cdSPeter Wemm /*
2822398f0cdSPeter Wemm  * err = resource_find_dev(&anchor, name, &unit, res, value);
2832398f0cdSPeter Wemm  * Iterate through a list of devices, returning their unit numbers.
2842398f0cdSPeter Wemm  * res and value are optional restrictions.  eg: "at", "scbus0".
2852398f0cdSPeter Wemm  * *unit is set to the value.
2862398f0cdSPeter Wemm  * set *anchor to zero before starting.
2872398f0cdSPeter Wemm  */
2882398f0cdSPeter Wemm int
2892398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit,
2902398f0cdSPeter Wemm     const char *resname, const char *value)
2912398f0cdSPeter Wemm {
2922398f0cdSPeter Wemm 	int found_unit;
2932398f0cdSPeter Wemm 	int newln;
2942398f0cdSPeter Wemm 	int ret;
2952398f0cdSPeter Wemm 
2962398f0cdSPeter Wemm 	newln = *anchor;
2972398f0cdSPeter Wemm 	ret = resource_find(anchor, &newln, name, NULL, resname, value,
2982398f0cdSPeter Wemm 	    NULL, NULL, &found_unit, NULL, NULL, NULL);
2992398f0cdSPeter Wemm 	if (ret == 0) {
3002398f0cdSPeter Wemm 		*unit = found_unit;
3012398f0cdSPeter Wemm 	}
3022398f0cdSPeter Wemm 	*anchor = newln;
3032398f0cdSPeter Wemm 	return ret;
3042398f0cdSPeter Wemm }
305