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 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 302398f0cdSPeter Wemm #include <sys/param.h> 31d786139cSMaxime Henrion #include <sys/lock.h> 32d786139cSMaxime Henrion #include <sys/sx.h> 332398f0cdSPeter Wemm #include <sys/systm.h> 342398f0cdSPeter Wemm #include <sys/bus.h> 352398f0cdSPeter Wemm 362398f0cdSPeter Wemm /* 372398f0cdSPeter Wemm * Access functions for device resources. 382398f0cdSPeter Wemm */ 392398f0cdSPeter Wemm 40d786139cSMaxime Henrion static int checkmethod = 1; 414f033348SPeter Wemm static int use_kenv; 429516fbd6SPeter Wemm static char *hintp; 432398f0cdSPeter Wemm 442398f0cdSPeter Wemm /* 452398f0cdSPeter Wemm * Evil wildcarding resource string lookup. 462398f0cdSPeter Wemm * This walks the supplied env string table and returns a match. 472398f0cdSPeter Wemm * The start point can be remembered for incremental searches. 482398f0cdSPeter Wemm */ 492398f0cdSPeter Wemm static int 509516fbd6SPeter Wemm res_find(int *line, int *startln, 512398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 522398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 532398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 542398f0cdSPeter Wemm { 554f033348SPeter Wemm int n = 0, hit, i = 0; 562398f0cdSPeter Wemm char r_name[32]; 572398f0cdSPeter Wemm int r_unit; 582398f0cdSPeter Wemm char r_resname[32]; 592398f0cdSPeter Wemm char r_value[128]; 609516fbd6SPeter Wemm const char *s, *cp; 612398f0cdSPeter Wemm char *p; 622398f0cdSPeter Wemm 63d786139cSMaxime Henrion if (checkmethod) { 649516fbd6SPeter Wemm switch (hintmode) { 656692ac66SPeter Wemm case 0: /* loader hints in environment only */ 669516fbd6SPeter Wemm break; 679516fbd6SPeter Wemm case 1: /* static hints only */ 689516fbd6SPeter Wemm hintp = static_hints; 69d786139cSMaxime Henrion checkmethod = 0; 709516fbd6SPeter Wemm break; 719516fbd6SPeter Wemm case 2: /* fallback mode */ 72d786139cSMaxime Henrion if (dynamic_kenv) { 73d786139cSMaxime Henrion sx_slock(&kenv_lock); 74d786139cSMaxime Henrion cp = kenvp[0]; 75d786139cSMaxime Henrion for (i = 0; cp != NULL; cp = kenvp[++i]) { 76d786139cSMaxime Henrion if (!strncmp(cp, "hint.", 5)) { 77d786139cSMaxime Henrion use_kenv = 1; 78d786139cSMaxime Henrion checkmethod = 0; 79d786139cSMaxime Henrion break; 80d786139cSMaxime Henrion } 81d786139cSMaxime Henrion } 82d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 83d786139cSMaxime Henrion } else { 849516fbd6SPeter Wemm cp = kern_envp; 859516fbd6SPeter Wemm while (cp) { 869516fbd6SPeter Wemm if (strncmp(cp, "hint.", 5) == 0) { 879516fbd6SPeter Wemm cp = NULL; 889516fbd6SPeter Wemm hintp = kern_envp; 899516fbd6SPeter Wemm break; 909516fbd6SPeter Wemm } 919516fbd6SPeter Wemm while (*cp != '\0') 929516fbd6SPeter Wemm cp++; 939516fbd6SPeter Wemm cp++; 949516fbd6SPeter Wemm if (*cp == '\0') { 959516fbd6SPeter Wemm cp = NULL; 969516fbd6SPeter Wemm hintp = static_hints; 979516fbd6SPeter Wemm break; 989516fbd6SPeter Wemm } 999516fbd6SPeter Wemm } 100d786139cSMaxime Henrion } 1019516fbd6SPeter Wemm break; 1029516fbd6SPeter Wemm default: 1039516fbd6SPeter Wemm break; 1049516fbd6SPeter Wemm } 105d786139cSMaxime Henrion if (hintp == NULL) { 106d786139cSMaxime Henrion if (dynamic_kenv) { 107d786139cSMaxime Henrion use_kenv = 1; 108d786139cSMaxime Henrion checkmethod = 0; 109d786139cSMaxime Henrion } else 1109516fbd6SPeter Wemm hintp = kern_envp; 1119516fbd6SPeter Wemm } 112d786139cSMaxime Henrion } 1139516fbd6SPeter Wemm 114d786139cSMaxime Henrion if (use_kenv) { 115d786139cSMaxime Henrion sx_slock(&kenv_lock); 116d786139cSMaxime Henrion i = 0; 117d786139cSMaxime Henrion cp = kenvp[0]; 118d786139cSMaxime Henrion if (cp == NULL) { 119d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 120d786139cSMaxime Henrion return (ENOENT); 121d786139cSMaxime Henrion } 1226692ac66SPeter Wemm } else 1239516fbd6SPeter Wemm cp = hintp; 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; 1514f033348SPeter Wemm if (use_kenv) { 152d786139cSMaxime Henrion cp = kenvp[++i]; 1534f033348SPeter Wemm if (cp == NULL) 1544f033348SPeter Wemm break; 1554f033348SPeter Wemm } else { 1562398f0cdSPeter Wemm while (*cp != '\0') 1572398f0cdSPeter Wemm cp++; 1582398f0cdSPeter Wemm cp++; 1592398f0cdSPeter Wemm if (*cp == '\0') { 1602398f0cdSPeter Wemm cp = NULL; 1612398f0cdSPeter Wemm break; 1622398f0cdSPeter Wemm } 1632398f0cdSPeter Wemm } 1644f033348SPeter Wemm } 165d786139cSMaxime Henrion if (use_kenv) 166d786139cSMaxime Henrion sx_sunlock(&kenv_lock); 1672398f0cdSPeter Wemm if (cp == NULL) 1682398f0cdSPeter Wemm return ENOENT; 1692398f0cdSPeter Wemm 1702398f0cdSPeter Wemm s = cp; 1712398f0cdSPeter Wemm /* This is a bit of a hack, but at least is reentrant */ 1722398f0cdSPeter Wemm /* Note that it returns some !unterminated! strings. */ 1732398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of device */ 1742398f0cdSPeter Wemm if (ret_name) 1752398f0cdSPeter Wemm *ret_name = s; 1762398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of unit */ 1772398f0cdSPeter Wemm if (ret_namelen) 1782398f0cdSPeter Wemm *ret_namelen = s - *ret_name - 1; /* device length */ 1792398f0cdSPeter Wemm if (ret_unit) 1802398f0cdSPeter Wemm *ret_unit = r_unit; 1812398f0cdSPeter Wemm s = index(s, '.') + 1; /* start of resname */ 1822398f0cdSPeter Wemm if (ret_resname) 1832398f0cdSPeter Wemm *ret_resname = s; 1842398f0cdSPeter Wemm s = index(s, '=') + 1; /* start of value */ 1852398f0cdSPeter Wemm if (ret_resnamelen) 1862398f0cdSPeter Wemm *ret_resnamelen = s - *ret_resname - 1; /* value len */ 1872398f0cdSPeter Wemm if (ret_value) 1882398f0cdSPeter Wemm *ret_value = s; 1892398f0cdSPeter Wemm if (startln) /* line number for anchor */ 1902398f0cdSPeter Wemm *startln = *line + 1; 1912398f0cdSPeter Wemm return 0; 1922398f0cdSPeter Wemm } 1932398f0cdSPeter Wemm 1942398f0cdSPeter Wemm /* 1952398f0cdSPeter Wemm * Search all the data sources for matches to our query. We look for 1962398f0cdSPeter Wemm * dynamic hints first as overrides for static or fallback hints. 1972398f0cdSPeter Wemm */ 1982398f0cdSPeter Wemm static int 1992398f0cdSPeter Wemm resource_find(int *line, int *startln, 2002398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 2012398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 2022398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 2032398f0cdSPeter Wemm { 2042398f0cdSPeter Wemm int i; 2052398f0cdSPeter Wemm int un; 2062398f0cdSPeter Wemm 2072398f0cdSPeter Wemm *line = 0; 2082398f0cdSPeter Wemm 2092398f0cdSPeter Wemm /* Search for exact unit matches first */ 2109516fbd6SPeter Wemm i = res_find(line, startln, name, unit, resname, value, 2112398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 2122398f0cdSPeter Wemm ret_value); 2132398f0cdSPeter Wemm if (i == 0) 2142398f0cdSPeter Wemm return 0; 2152398f0cdSPeter Wemm if (unit == NULL) 2162398f0cdSPeter Wemm return ENOENT; 2172398f0cdSPeter Wemm /* If we are still here, search for wildcard matches */ 2182398f0cdSPeter Wemm un = -1; 2199516fbd6SPeter Wemm i = res_find(line, startln, name, &un, resname, value, 2202398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 2212398f0cdSPeter Wemm ret_value); 2222398f0cdSPeter Wemm if (i == 0) 2232398f0cdSPeter Wemm return 0; 2242398f0cdSPeter Wemm return ENOENT; 2252398f0cdSPeter Wemm } 2262398f0cdSPeter Wemm 2272398f0cdSPeter Wemm int 2282398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result) 2292398f0cdSPeter Wemm { 2302398f0cdSPeter Wemm int error; 2312398f0cdSPeter Wemm const char *str; 2322398f0cdSPeter Wemm char *op; 2332398f0cdSPeter Wemm unsigned long val; 2342398f0cdSPeter Wemm int line; 2352398f0cdSPeter Wemm 2362398f0cdSPeter Wemm line = 0; 2372398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2382398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2392398f0cdSPeter Wemm if (error) 2402398f0cdSPeter Wemm return error; 2412398f0cdSPeter Wemm if (*str == '\0') 2422398f0cdSPeter Wemm return EFTYPE; 2432398f0cdSPeter Wemm val = strtoul(str, &op, 0); 2442398f0cdSPeter Wemm if (*op != '\0') 2452398f0cdSPeter Wemm return EFTYPE; 2462398f0cdSPeter Wemm *result = val; 2472398f0cdSPeter Wemm return 0; 2482398f0cdSPeter Wemm } 2492398f0cdSPeter Wemm 2502398f0cdSPeter Wemm int 2512398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname, 2522398f0cdSPeter Wemm long *result) 2532398f0cdSPeter Wemm { 2542398f0cdSPeter Wemm int error; 2552398f0cdSPeter Wemm const char *str; 2562398f0cdSPeter Wemm char *op; 2572398f0cdSPeter Wemm unsigned long val; 2582398f0cdSPeter Wemm int line; 2592398f0cdSPeter Wemm 2602398f0cdSPeter Wemm line = 0; 2612398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2622398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2632398f0cdSPeter Wemm if (error) 2642398f0cdSPeter Wemm return error; 2652398f0cdSPeter Wemm if (*str == '\0') 2662398f0cdSPeter Wemm return EFTYPE; 2672398f0cdSPeter Wemm val = strtoul(str, &op, 0); 2682398f0cdSPeter Wemm if (*op != '\0') 2692398f0cdSPeter Wemm return EFTYPE; 2702398f0cdSPeter Wemm *result = val; 2712398f0cdSPeter Wemm return 0; 2722398f0cdSPeter Wemm } 2732398f0cdSPeter Wemm 2742398f0cdSPeter Wemm int 2752398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname, 2762398f0cdSPeter Wemm const char **result) 2772398f0cdSPeter Wemm { 2782398f0cdSPeter Wemm int error; 2792398f0cdSPeter Wemm const char *str; 2802398f0cdSPeter Wemm int line; 2812398f0cdSPeter Wemm 2822398f0cdSPeter Wemm line = 0; 2832398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 2842398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 2852398f0cdSPeter Wemm if (error) 2862398f0cdSPeter Wemm return error; 2872398f0cdSPeter Wemm *result = str; 2882398f0cdSPeter Wemm return 0; 2892398f0cdSPeter Wemm } 2902398f0cdSPeter Wemm 2912398f0cdSPeter Wemm /* 2922398f0cdSPeter Wemm * This is a bit nasty, but allows us to not modify the env strings. 2932398f0cdSPeter Wemm */ 2942398f0cdSPeter Wemm static const char * 2952398f0cdSPeter Wemm resource_string_copy(const char *s, int len) 2962398f0cdSPeter Wemm { 2972398f0cdSPeter Wemm static char stringbuf[256]; 2982398f0cdSPeter Wemm static int offset = 0; 2992398f0cdSPeter Wemm const char *ret; 3002398f0cdSPeter Wemm 3012398f0cdSPeter Wemm if (len == 0) 3022398f0cdSPeter Wemm len = strlen(s); 3032398f0cdSPeter Wemm if (len > 255) 3042398f0cdSPeter Wemm return NULL; 3052398f0cdSPeter Wemm if ((offset + len + 1) > 255) 3062398f0cdSPeter Wemm offset = 0; 3072398f0cdSPeter Wemm bcopy(s, &stringbuf[offset], len); 3082398f0cdSPeter Wemm stringbuf[offset + len] = '\0'; 3092398f0cdSPeter Wemm ret = &stringbuf[offset]; 3102398f0cdSPeter Wemm offset += len + 1; 3112398f0cdSPeter Wemm return ret; 3122398f0cdSPeter Wemm } 3132398f0cdSPeter Wemm 3142398f0cdSPeter Wemm /* 31574e62047SJohn-Mark Gurney * err = resource_find_match(&anchor, &name, &unit, resname, value) 3162398f0cdSPeter Wemm * Iteratively fetch a list of devices wired "at" something 3172398f0cdSPeter Wemm * res and value are restrictions. eg: "at", "scbus0". 3182398f0cdSPeter Wemm * For practical purposes, res = required, value = optional. 3192398f0cdSPeter Wemm * *name and *unit are set. 3202398f0cdSPeter Wemm * set *anchor to zero before starting. 3212398f0cdSPeter Wemm */ 3222398f0cdSPeter Wemm int 3232398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit, 3242398f0cdSPeter Wemm const char *resname, const char *value) 3252398f0cdSPeter Wemm { 3262398f0cdSPeter Wemm const char *found_name; 3272398f0cdSPeter Wemm int found_namelen; 3282398f0cdSPeter Wemm int found_unit; 3292398f0cdSPeter Wemm int ret; 3302398f0cdSPeter Wemm int newln; 3312398f0cdSPeter Wemm 3322398f0cdSPeter Wemm newln = *anchor; 3332398f0cdSPeter Wemm ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 3342398f0cdSPeter Wemm &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 3352398f0cdSPeter Wemm if (ret == 0) { 3362398f0cdSPeter Wemm *name = resource_string_copy(found_name, found_namelen); 3372398f0cdSPeter Wemm *unit = found_unit; 3382398f0cdSPeter Wemm } 3392398f0cdSPeter Wemm *anchor = newln; 3402398f0cdSPeter Wemm return ret; 3412398f0cdSPeter Wemm } 3422398f0cdSPeter Wemm 3432398f0cdSPeter Wemm 3442398f0cdSPeter Wemm /* 3452398f0cdSPeter Wemm * err = resource_find_dev(&anchor, name, &unit, res, value); 3462398f0cdSPeter Wemm * Iterate through a list of devices, returning their unit numbers. 3472398f0cdSPeter Wemm * res and value are optional restrictions. eg: "at", "scbus0". 3482398f0cdSPeter Wemm * *unit is set to the value. 3492398f0cdSPeter Wemm * set *anchor to zero before starting. 3502398f0cdSPeter Wemm */ 3512398f0cdSPeter Wemm int 3522398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit, 3532398f0cdSPeter Wemm const char *resname, const char *value) 3542398f0cdSPeter Wemm { 3552398f0cdSPeter Wemm int found_unit; 3562398f0cdSPeter Wemm int newln; 3572398f0cdSPeter Wemm int ret; 3582398f0cdSPeter Wemm 3592398f0cdSPeter Wemm newln = *anchor; 3602398f0cdSPeter Wemm ret = resource_find(anchor, &newln, name, NULL, resname, value, 3612398f0cdSPeter Wemm NULL, NULL, &found_unit, NULL, NULL, NULL); 3622398f0cdSPeter Wemm if (ret == 0) { 3632398f0cdSPeter Wemm *unit = found_unit; 3642398f0cdSPeter Wemm } 3652398f0cdSPeter Wemm *anchor = newln; 3662398f0cdSPeter Wemm return ret; 3672398f0cdSPeter Wemm } 3686591b310SJohn Baldwin 3696591b310SJohn Baldwin /* 3706591b310SJohn Baldwin * Check to see if a device is disabled via a disabled hint. 3716591b310SJohn Baldwin */ 3726591b310SJohn Baldwin int 3736591b310SJohn Baldwin resource_disabled(const char *name, int unit) 3746591b310SJohn Baldwin { 3756591b310SJohn Baldwin int error, value; 3766591b310SJohn Baldwin 3776591b310SJohn Baldwin error = resource_int_value(name, unit, "disabled", &value); 3786591b310SJohn Baldwin if (error) 3796591b310SJohn Baldwin return (0); 3806591b310SJohn Baldwin return (value); 3816591b310SJohn Baldwin } 382