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> 30d786139cSMaxime Henrion #include <sys/lock.h> 31d786139cSMaxime Henrion #include <sys/sx.h> 322398f0cdSPeter Wemm #include <sys/systm.h> 332398f0cdSPeter Wemm #include <sys/bus.h> 342398f0cdSPeter Wemm 352398f0cdSPeter Wemm /* 362398f0cdSPeter Wemm * Access functions for device resources. 372398f0cdSPeter Wemm */ 382398f0cdSPeter Wemm 39d786139cSMaxime Henrion static int checkmethod = 1; 409516fbd6SPeter Wemm static char *hintp; 412398f0cdSPeter Wemm 422398f0cdSPeter Wemm /* 432398f0cdSPeter Wemm * Evil wildcarding resource string lookup. 442398f0cdSPeter Wemm * This walks the supplied env string table and returns a match. 452398f0cdSPeter Wemm * The start point can be remembered for incremental searches. 462398f0cdSPeter Wemm */ 472398f0cdSPeter Wemm static int 489516fbd6SPeter Wemm res_find(int *line, int *startln, 492398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 502398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 512398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 522398f0cdSPeter Wemm { 53d786139cSMaxime Henrion int n = 0, hit, use_kenv, i = 0; 542398f0cdSPeter Wemm char r_name[32]; 552398f0cdSPeter Wemm int r_unit; 562398f0cdSPeter Wemm char r_resname[32]; 572398f0cdSPeter Wemm char r_value[128]; 589516fbd6SPeter Wemm const char *s, *cp; 592398f0cdSPeter Wemm char *p; 602398f0cdSPeter Wemm 61d786139cSMaxime Henrion use_kenv = 0; 62d786139cSMaxime Henrion if (checkmethod) { 639516fbd6SPeter Wemm switch (hintmode) { 649516fbd6SPeter Wemm case 0: /* config supplied nothing */ 659516fbd6SPeter Wemm break; 669516fbd6SPeter Wemm case 1: /* static hints only */ 679516fbd6SPeter Wemm hintp = static_hints; 68d786139cSMaxime Henrion checkmethod = 0; 699516fbd6SPeter Wemm break; 709516fbd6SPeter Wemm case 2: /* fallback mode */ 71d786139cSMaxime Henrion if (dynamic_kenv) { 72d786139cSMaxime Henrion sx_slock(&kenv_lock); 73d786139cSMaxime Henrion cp = kenvp[0]; 74d786139cSMaxime Henrion for (i = 0; cp != NULL; cp = kenvp[++i]) { 75d786139cSMaxime Henrion if (!strncmp(cp, "hint.", 5)) { 76d786139cSMaxime Henrion use_kenv = 1; 77d786139cSMaxime Henrion checkmethod = 0; 78d786139cSMaxime Henrion break; 79d786139cSMaxime Henrion } 80d786139cSMaxime Henrion } 81d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 82d786139cSMaxime Henrion } else { 839516fbd6SPeter Wemm cp = kern_envp; 849516fbd6SPeter Wemm while (cp) { 859516fbd6SPeter Wemm if (strncmp(cp, "hint.", 5) == 0) { 869516fbd6SPeter Wemm cp = NULL; 879516fbd6SPeter Wemm hintp = kern_envp; 889516fbd6SPeter Wemm break; 899516fbd6SPeter Wemm } 909516fbd6SPeter Wemm while (*cp != '\0') 919516fbd6SPeter Wemm cp++; 929516fbd6SPeter Wemm cp++; 939516fbd6SPeter Wemm if (*cp == '\0') { 949516fbd6SPeter Wemm cp = NULL; 959516fbd6SPeter Wemm hintp = static_hints; 969516fbd6SPeter Wemm break; 979516fbd6SPeter Wemm } 989516fbd6SPeter Wemm } 99d786139cSMaxime Henrion } 1009516fbd6SPeter Wemm break; 1019516fbd6SPeter Wemm default: 1029516fbd6SPeter Wemm break; 1039516fbd6SPeter Wemm } 104d786139cSMaxime Henrion if (hintp == NULL) { 105d786139cSMaxime Henrion if (dynamic_kenv) { 106d786139cSMaxime Henrion use_kenv = 1; 107d786139cSMaxime Henrion checkmethod = 0; 108d786139cSMaxime Henrion } else 1099516fbd6SPeter Wemm hintp = kern_envp; 1109516fbd6SPeter Wemm } 111d786139cSMaxime Henrion } 1129516fbd6SPeter Wemm 113d786139cSMaxime Henrion if (use_kenv) { 114d786139cSMaxime Henrion sx_slock(&kenv_lock); 115d786139cSMaxime Henrion i = 0; 116d786139cSMaxime Henrion cp = kenvp[0]; 117d786139cSMaxime Henrion if (cp == NULL) { 118d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 119d786139cSMaxime Henrion return (ENOENT); 120d786139cSMaxime Henrion } 121d786139cSMaxime Henrion } else { 1229516fbd6SPeter Wemm cp = hintp; 123d786139cSMaxime Henrion } 1242398f0cdSPeter Wemm while (cp) { 1252398f0cdSPeter Wemm hit = 1; 1262398f0cdSPeter Wemm (*line)++; 1272398f0cdSPeter Wemm if (strncmp(cp, "hint.", 5) != 0) 1282398f0cdSPeter Wemm hit = 0; 1292398f0cdSPeter Wemm else 1302398f0cdSPeter Wemm n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s", 1312398f0cdSPeter Wemm r_name, &r_unit, r_resname, r_value); 1322398f0cdSPeter Wemm if (hit && n != 4) { 1332398f0cdSPeter Wemm printf("CONFIG: invalid hint '%s'\n", cp); 1342398f0cdSPeter Wemm /* XXX: abuse bogus index() declaration */ 1352398f0cdSPeter Wemm p = index(cp, 'h'); 1362398f0cdSPeter Wemm *p = 'H'; 1372398f0cdSPeter Wemm hit = 0; 1382398f0cdSPeter Wemm } 1392398f0cdSPeter Wemm if (hit && startln && *startln >= 0 && *line < *startln) 1402398f0cdSPeter Wemm hit = 0; 1412398f0cdSPeter Wemm if (hit && name && strcmp(name, r_name) != 0) 1422398f0cdSPeter Wemm hit = 0; 1432398f0cdSPeter Wemm if (hit && unit && *unit != r_unit) 1442398f0cdSPeter Wemm hit = 0; 1452398f0cdSPeter Wemm if (hit && resname && strcmp(resname, r_resname) != 0) 1462398f0cdSPeter Wemm hit = 0; 1472398f0cdSPeter Wemm if (hit && value && strcmp(value, r_value) != 0) 1482398f0cdSPeter Wemm hit = 0; 1492398f0cdSPeter Wemm if (hit) 1502398f0cdSPeter Wemm break; 151d786139cSMaxime Henrion if (use_kenv) 152d786139cSMaxime Henrion cp = kenvp[++i]; 1532398f0cdSPeter Wemm while (*cp != '\0') 1542398f0cdSPeter Wemm cp++; 1552398f0cdSPeter Wemm cp++; 1562398f0cdSPeter Wemm if (*cp == '\0') { 1572398f0cdSPeter Wemm cp = NULL; 1582398f0cdSPeter Wemm break; 1592398f0cdSPeter Wemm } 1602398f0cdSPeter Wemm } 161d786139cSMaxime Henrion if (use_kenv) 162d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 1632398f0cdSPeter Wemm if (cp == NULL) 1642398f0cdSPeter Wemm return ENOENT; 1652398f0cdSPeter Wemm 1662398f0cdSPeter Wemm s = cp; 1672398f0cdSPeter Wemm /* This is a bit of a hack, but at least is reentrant */ 1682398f0cdSPeter Wemm /* Note that it returns some !unterminated! strings. */ 1692398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of device */ 1702398f0cdSPeter Wemm if (ret_name) 1712398f0cdSPeter Wemm *ret_name = s; 1722398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of unit */ 1732398f0cdSPeter Wemm if (ret_namelen) 1742398f0cdSPeter Wemm *ret_namelen = s - *ret_name - 1; /* device length */ 1752398f0cdSPeter Wemm if (ret_unit) 1762398f0cdSPeter Wemm *ret_unit = r_unit; 1772398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of resname */ 1782398f0cdSPeter Wemm if (ret_resname) 1792398f0cdSPeter Wemm *ret_resname = s; 1802398f0cdSPeter Wemm s = index(s, '=') + 1; /* start of value */ 1812398f0cdSPeter Wemm if (ret_resnamelen) 1822398f0cdSPeter Wemm *ret_resnamelen = s - *ret_resname - 1; /* value len */ 1832398f0cdSPeter Wemm if (ret_value) 1842398f0cdSPeter Wemm *ret_value = s; 1852398f0cdSPeter Wemm if (startln) /* line number for anchor */ 1862398f0cdSPeter Wemm *startln = *line + 1; 1872398f0cdSPeter Wemm return 0; 1882398f0cdSPeter Wemm } 1892398f0cdSPeter Wemm 1902398f0cdSPeter Wemm /* 1912398f0cdSPeter Wemm * Search all the data sources for matches to our query. We look for 1922398f0cdSPeter Wemm * dynamic hints first as overrides for static or fallback hints. 1932398f0cdSPeter Wemm */ 1942398f0cdSPeter Wemm static int 1952398f0cdSPeter Wemm resource_find(int *line, int *startln, 1962398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 1972398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 1982398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 1992398f0cdSPeter Wemm { 2002398f0cdSPeter Wemm int i; 2012398f0cdSPeter Wemm int un; 2022398f0cdSPeter Wemm 2032398f0cdSPeter Wemm *line = 0; 2042398f0cdSPeter Wemm 2052398f0cdSPeter Wemm /* Search for exact unit matches first */ 2069516fbd6SPeter Wemm i = res_find(line, startln, name, unit, resname, value, 2072398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 2082398f0cdSPeter Wemm ret_value); 2092398f0cdSPeter Wemm if (i == 0) 2102398f0cdSPeter Wemm return 0; 2112398f0cdSPeter Wemm if (unit == NULL) 2122398f0cdSPeter Wemm return ENOENT; 2132398f0cdSPeter Wemm /* If we are still here, search for wildcard matches */ 2142398f0cdSPeter Wemm un = -1; 2159516fbd6SPeter Wemm i = res_find(line, startln, name, &un, resname, value, 2162398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 2172398f0cdSPeter Wemm ret_value); 2182398f0cdSPeter Wemm if (i == 0) 2192398f0cdSPeter Wemm return 0; 2202398f0cdSPeter Wemm return ENOENT; 2212398f0cdSPeter Wemm } 2222398f0cdSPeter Wemm 2232398f0cdSPeter Wemm int 2242398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result) 2252398f0cdSPeter Wemm { 2262398f0cdSPeter Wemm int error; 2272398f0cdSPeter Wemm const char *str; 2282398f0cdSPeter Wemm char *op; 2292398f0cdSPeter Wemm unsigned long val; 2302398f0cdSPeter Wemm int line; 2312398f0cdSPeter Wemm 2322398f0cdSPeter Wemm line = 0; 2332398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2342398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2352398f0cdSPeter Wemm if (error) 2362398f0cdSPeter Wemm return error; 2372398f0cdSPeter Wemm if (*str == '\0') 2382398f0cdSPeter Wemm return EFTYPE; 2392398f0cdSPeter Wemm val = strtoul(str, &op, 0); 2402398f0cdSPeter Wemm if (*op != '\0') 2412398f0cdSPeter Wemm return EFTYPE; 2422398f0cdSPeter Wemm *result = val; 2432398f0cdSPeter Wemm return 0; 2442398f0cdSPeter Wemm } 2452398f0cdSPeter Wemm 2462398f0cdSPeter Wemm int 2472398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname, 2482398f0cdSPeter Wemm long *result) 2492398f0cdSPeter Wemm { 2502398f0cdSPeter Wemm int error; 2512398f0cdSPeter Wemm const char *str; 2522398f0cdSPeter Wemm char *op; 2532398f0cdSPeter Wemm unsigned long val; 2542398f0cdSPeter Wemm int line; 2552398f0cdSPeter Wemm 2562398f0cdSPeter Wemm line = 0; 2572398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2582398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2592398f0cdSPeter Wemm if (error) 2602398f0cdSPeter Wemm return error; 2612398f0cdSPeter Wemm if (*str == '\0') 2622398f0cdSPeter Wemm return EFTYPE; 2632398f0cdSPeter Wemm val = strtoul(str, &op, 0); 2642398f0cdSPeter Wemm if (*op != '\0') 2652398f0cdSPeter Wemm return EFTYPE; 2662398f0cdSPeter Wemm *result = val; 2672398f0cdSPeter Wemm return 0; 2682398f0cdSPeter Wemm } 2692398f0cdSPeter Wemm 2702398f0cdSPeter Wemm int 2712398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname, 2722398f0cdSPeter Wemm const char **result) 2732398f0cdSPeter Wemm { 2742398f0cdSPeter Wemm int error; 2752398f0cdSPeter Wemm const char *str; 2762398f0cdSPeter Wemm int line; 2772398f0cdSPeter Wemm 2782398f0cdSPeter Wemm line = 0; 2792398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2802398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2812398f0cdSPeter Wemm if (error) 2822398f0cdSPeter Wemm return error; 2832398f0cdSPeter Wemm *result = str; 2842398f0cdSPeter Wemm return 0; 2852398f0cdSPeter Wemm } 2862398f0cdSPeter Wemm 2872398f0cdSPeter Wemm /* 2882398f0cdSPeter Wemm * This is a bit nasty, but allows us to not modify the env strings. 2892398f0cdSPeter Wemm */ 2902398f0cdSPeter Wemm static const char * 2912398f0cdSPeter Wemm resource_string_copy(const char *s, int len) 2922398f0cdSPeter Wemm { 2932398f0cdSPeter Wemm static char stringbuf[256]; 2942398f0cdSPeter Wemm static int offset = 0; 2952398f0cdSPeter Wemm const char *ret; 2962398f0cdSPeter Wemm 2972398f0cdSPeter Wemm if (len == 0) 2982398f0cdSPeter Wemm len = strlen(s); 2992398f0cdSPeter Wemm if (len > 255) 3002398f0cdSPeter Wemm return NULL; 3012398f0cdSPeter Wemm if ((offset + len + 1) > 255) 3022398f0cdSPeter Wemm offset = 0; 3032398f0cdSPeter Wemm bcopy(s, &stringbuf[offset], len); 3042398f0cdSPeter Wemm stringbuf[offset + len] = '\0'; 3052398f0cdSPeter Wemm ret = &stringbuf[offset]; 3062398f0cdSPeter Wemm offset += len + 1; 3072398f0cdSPeter Wemm return ret; 3082398f0cdSPeter Wemm } 3092398f0cdSPeter Wemm 3102398f0cdSPeter Wemm /* 3112398f0cdSPeter Wemm * err = resource_find_at(&anchor, &name, &unit, resname, value) 3122398f0cdSPeter Wemm * Iteratively fetch a list of devices wired "at" something 3132398f0cdSPeter Wemm * res and value are restrictions. eg: "at", "scbus0". 3142398f0cdSPeter Wemm * For practical purposes, res = required, value = optional. 3152398f0cdSPeter Wemm * *name and *unit are set. 3162398f0cdSPeter Wemm * set *anchor to zero before starting. 3172398f0cdSPeter Wemm */ 3182398f0cdSPeter Wemm int 3192398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit, 3202398f0cdSPeter Wemm const char *resname, const char *value) 3212398f0cdSPeter Wemm { 3222398f0cdSPeter Wemm const char *found_name; 3232398f0cdSPeter Wemm int found_namelen; 3242398f0cdSPeter Wemm int found_unit; 3252398f0cdSPeter Wemm int ret; 3262398f0cdSPeter Wemm int newln; 3272398f0cdSPeter Wemm 3282398f0cdSPeter Wemm newln = *anchor; 3292398f0cdSPeter Wemm ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 3302398f0cdSPeter Wemm &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 3312398f0cdSPeter Wemm if (ret == 0) { 3322398f0cdSPeter Wemm *name = resource_string_copy(found_name, found_namelen); 3332398f0cdSPeter Wemm *unit = found_unit; 3342398f0cdSPeter Wemm } 3352398f0cdSPeter Wemm *anchor = newln; 3362398f0cdSPeter Wemm return ret; 3372398f0cdSPeter Wemm } 3382398f0cdSPeter Wemm 3392398f0cdSPeter Wemm 3402398f0cdSPeter Wemm /* 3412398f0cdSPeter Wemm * err = resource_find_dev(&anchor, name, &unit, res, value); 3422398f0cdSPeter Wemm * Iterate through a list of devices, returning their unit numbers. 3432398f0cdSPeter Wemm * res and value are optional restrictions. eg: "at", "scbus0". 3442398f0cdSPeter Wemm * *unit is set to the value. 3452398f0cdSPeter Wemm * set *anchor to zero before starting. 3462398f0cdSPeter Wemm */ 3472398f0cdSPeter Wemm int 3482398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit, 3492398f0cdSPeter Wemm const char *resname, const char *value) 3502398f0cdSPeter Wemm { 3512398f0cdSPeter Wemm int found_unit; 3522398f0cdSPeter Wemm int newln; 3532398f0cdSPeter Wemm int ret; 3542398f0cdSPeter Wemm 3552398f0cdSPeter Wemm newln = *anchor; 3562398f0cdSPeter Wemm ret = resource_find(anchor, &newln, name, NULL, resname, value, 3572398f0cdSPeter Wemm NULL, NULL, &found_unit, NULL, NULL, NULL); 3582398f0cdSPeter Wemm if (ret == 0) { 3592398f0cdSPeter Wemm *unit = found_unit; 3602398f0cdSPeter Wemm } 3612398f0cdSPeter Wemm *anchor = newln; 3622398f0cdSPeter Wemm return ret; 3632398f0cdSPeter Wemm } 364