12398f0cdSPeter Wemm /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 42398f0cdSPeter Wemm * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org> 52398f0cdSPeter Wemm * All rights reserved. 62398f0cdSPeter Wemm * 72398f0cdSPeter Wemm * Redistribution and use in source and binary forms, with or without 82398f0cdSPeter Wemm * modification, are permitted provided that the following conditions 92398f0cdSPeter Wemm * are met: 102398f0cdSPeter Wemm * 1. Redistributions of source code must retain the above copyright 112398f0cdSPeter Wemm * notice, this list of conditions and the following disclaimer. 122398f0cdSPeter Wemm * 2. Redistributions in binary form must reproduce the above copyright 132398f0cdSPeter Wemm * notice, this list of conditions and the following disclaimer in the 142398f0cdSPeter Wemm * documentation and/or other materials provided with the distribution. 152398f0cdSPeter Wemm * 162398f0cdSPeter Wemm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 172398f0cdSPeter Wemm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 182398f0cdSPeter Wemm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 192398f0cdSPeter Wemm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 202398f0cdSPeter Wemm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 212398f0cdSPeter Wemm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 222398f0cdSPeter Wemm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 232398f0cdSPeter Wemm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 242398f0cdSPeter Wemm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 252398f0cdSPeter Wemm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 262398f0cdSPeter Wemm * SUCH DAMAGE. 272398f0cdSPeter Wemm */ 282398f0cdSPeter Wemm 29677b542eSDavid E. O'Brien #include <sys/cdefs.h> 30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 31677b542eSDavid E. O'Brien 322398f0cdSPeter Wemm #include <sys/param.h> 33d786139cSMaxime Henrion #include <sys/lock.h> 3439d44f7fSKyle Evans #include <sys/kernel.h> 3570da14c4SAleksandr Rybalko #include <sys/malloc.h> 36e3546a75SScott Long #include <sys/mutex.h> 3770da14c4SAleksandr Rybalko #include <sys/sysctl.h> 381bccd863SAleksandr Rybalko #include <sys/systm.h> 392398f0cdSPeter Wemm #include <sys/bus.h> 402398f0cdSPeter Wemm 4139d44f7fSKyle Evans #define FBACK_MDENV 0 /* MD env (e.g. loader.conf) */ 4239d44f7fSKyle Evans #define FBACK_STENV 1 /* Static env */ 4339d44f7fSKyle Evans #define FBACK_STATIC 2 /* static_hints */ 4439d44f7fSKyle Evans 4539d44f7fSKyle Evans /* 4639d44f7fSKyle Evans * We'll use hintenv_merged to indicate that the dynamic environment has been 4739d44f7fSKyle Evans * properly prepared for hint usage. This implies that the dynamic environment 4839d44f7fSKyle Evans * has already been setup (dynamic_kenv) and that we have added any supplied 4939d44f7fSKyle Evans * static_hints to the dynamic environment. 5039d44f7fSKyle Evans */ 51dc4446dfSKyle Evans static bool hintenv_merged; 52*0f46005eSKyle Evans /* Static environment and static hints cannot change, so we'll skip known bad */ 53*0f46005eSKyle Evans static bool stenv_skip; 54*0f46005eSKyle Evans static bool sthints_skip; 552398f0cdSPeter Wemm /* 562398f0cdSPeter Wemm * Access functions for device resources. 572398f0cdSPeter Wemm */ 582398f0cdSPeter Wemm 5939d44f7fSKyle Evans static void 6039d44f7fSKyle Evans static_hints_to_env(void *data __unused) 6170da14c4SAleksandr Rybalko { 6270da14c4SAleksandr Rybalko const char *cp; 6370da14c4SAleksandr Rybalko char *line, *eq; 6439d44f7fSKyle Evans int eqidx, i; 6570da14c4SAleksandr Rybalko 66770488d2SKyle Evans cp = static_hints; 67770488d2SKyle Evans while (cp && *cp != '\0') { 6870da14c4SAleksandr Rybalko eq = strchr(cp, '='); 691bccd863SAleksandr Rybalko if (eq == NULL) 7070da14c4SAleksandr Rybalko /* Bad hint value */ 7170da14c4SAleksandr Rybalko continue; 7270da14c4SAleksandr Rybalko eqidx = eq - cp; 7370da14c4SAleksandr Rybalko 74770488d2SKyle Evans i = strlen(cp); 7570da14c4SAleksandr Rybalko line = malloc(i + 1, M_TEMP, M_WAITOK); 7670da14c4SAleksandr Rybalko strcpy(line, cp); 7739d44f7fSKyle Evans line[eqidx] = line[i] = '\0'; 7839d44f7fSKyle Evans /* 7939d44f7fSKyle Evans * Before adding a hint to the dynamic environment, check if 8039d44f7fSKyle Evans * another value for said hint has already been added. This is 8139d44f7fSKyle Evans * needed because static environment overrides static hints and 8239d44f7fSKyle Evans * dynamic environment overrides all. 8339d44f7fSKyle Evans */ 8439d44f7fSKyle Evans if (testenv(line) == 0) 852be111bfSDavide Italiano kern_setenv(line, line + eqidx + 1); 8670da14c4SAleksandr Rybalko free(line, M_TEMP); 8770da14c4SAleksandr Rybalko cp += i + 1; 8870da14c4SAleksandr Rybalko } 89dc4446dfSKyle Evans hintenv_merged = true; 9070da14c4SAleksandr Rybalko } 9170da14c4SAleksandr Rybalko 9239d44f7fSKyle Evans /* Any time after dynamic env is setup */ 93cae22dd9SKyle Evans SYSINIT(hintenv, SI_SUB_KMEM + 1, SI_ORDER_SECOND, static_hints_to_env, NULL); 9439d44f7fSKyle Evans 9539d44f7fSKyle Evans /* 9639d44f7fSKyle Evans * Checks the environment to see if we even have any hints. If it has no hints, 9739d44f7fSKyle Evans * then res_find can take the hint that there's no point in searching it and 9839d44f7fSKyle Evans * either move on to the next environment or fail early. 9939d44f7fSKyle Evans */ 10039d44f7fSKyle Evans static bool 10139d44f7fSKyle Evans _res_checkenv(char *envp) 10239d44f7fSKyle Evans { 10339d44f7fSKyle Evans char *cp; 10439d44f7fSKyle Evans 10539d44f7fSKyle Evans cp = envp; 10639d44f7fSKyle Evans while (cp) { 10739d44f7fSKyle Evans if (strncmp(cp, "hint.", 5) == 0) 10839d44f7fSKyle Evans return (true); 10939d44f7fSKyle Evans while (*cp != '\0') 11039d44f7fSKyle Evans cp++; 11139d44f7fSKyle Evans cp++; 11239d44f7fSKyle Evans if (*cp == '\0') 11339d44f7fSKyle Evans break; 11439d44f7fSKyle Evans } 11539d44f7fSKyle Evans return (false); 11639d44f7fSKyle Evans } 11770da14c4SAleksandr Rybalko 11870da14c4SAleksandr Rybalko /* 1192398f0cdSPeter Wemm * Evil wildcarding resource string lookup. 1202398f0cdSPeter Wemm * This walks the supplied env string table and returns a match. 1212398f0cdSPeter Wemm * The start point can be remembered for incremental searches. 1222398f0cdSPeter Wemm */ 1232398f0cdSPeter Wemm static int 12439d44f7fSKyle Evans res_find(char **hintp_cookie, int *line, int *startln, 1252398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 1262398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 1272398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 1282398f0cdSPeter Wemm { 129dc4446dfSKyle Evans int fbacklvl = FBACK_MDENV, i = 0, n = 0; 1302398f0cdSPeter Wemm char r_name[32]; 13139d44f7fSKyle Evans int r_unit; 1322398f0cdSPeter Wemm char r_resname[32]; 1332398f0cdSPeter Wemm char r_value[128]; 1349516fbd6SPeter Wemm const char *s, *cp; 13539d44f7fSKyle Evans char *hintp, *p; 136dc4446dfSKyle Evans bool dyn_used = false; 1372398f0cdSPeter Wemm 13839d44f7fSKyle Evans 13939d44f7fSKyle Evans /* 14039d44f7fSKyle Evans * We are expecting that the caller will pass us a hintp_cookie that 14139d44f7fSKyle Evans * they are tracking. Upon entry, if *hintp_cookie is *not* set, this 14239d44f7fSKyle Evans * indicates to us that we should be figuring out based on the current 14339d44f7fSKyle Evans * environment where to search. This keeps us sane throughout the 14439d44f7fSKyle Evans * entirety of a single search. 14539d44f7fSKyle Evans */ 14639d44f7fSKyle Evans if (*hintp_cookie == NULL) { 14732069af6SAlexander Leidinger hintp = NULL; 14839d44f7fSKyle Evans if (hintenv_merged) { 14939d44f7fSKyle Evans /* 15039d44f7fSKyle Evans * static_hints, if it was previously used, has 15139d44f7fSKyle Evans * already been folded in to the environment 15239d44f7fSKyle Evans * by this point. 15339d44f7fSKyle Evans */ 154e3546a75SScott Long mtx_lock(&kenv_lock); 155d786139cSMaxime Henrion cp = kenvp[0]; 156d786139cSMaxime Henrion for (i = 0; cp != NULL; cp = kenvp[++i]) { 157d786139cSMaxime Henrion if (!strncmp(cp, "hint.", 5)) { 15839d44f7fSKyle Evans hintp = kenvp[0]; 159d786139cSMaxime Henrion break; 160d786139cSMaxime Henrion } 161d786139cSMaxime Henrion } 162e3546a75SScott Long mtx_unlock(&kenv_lock); 163dc4446dfSKyle Evans dyn_used = true; 164d786139cSMaxime Henrion } else { 16539d44f7fSKyle Evans /* 16639d44f7fSKyle Evans * We'll have a chance to keep coming back here until 16739d44f7fSKyle Evans * we've actually exhausted all of our possibilities. 16839d44f7fSKyle Evans * We might have chosen the MD/Static env because it 16939d44f7fSKyle Evans * had some kind of hints, but perhaps it didn't have 17039d44f7fSKyle Evans * the hint we are looking for. We don't provide any 17139d44f7fSKyle Evans * fallback when searching the dynamic environment. 17239d44f7fSKyle Evans */ 17339d44f7fSKyle Evans fallback: 17439d44f7fSKyle Evans if (dyn_used || fbacklvl >= FBACK_STATIC) 17539d44f7fSKyle Evans return (ENOENT); 17639d44f7fSKyle Evans 17739d44f7fSKyle Evans if (fbacklvl <= FBACK_MDENV && 17839d44f7fSKyle Evans _res_checkenv(md_envp)) { 17939d44f7fSKyle Evans hintp = md_envp; 18039d44f7fSKyle Evans goto found; 1818ef58863SKyle Evans } 18239d44f7fSKyle Evans fbacklvl++; 18339d44f7fSKyle Evans 184*0f46005eSKyle Evans if (!stenv_skip && fbacklvl <= FBACK_STENV && 18539d44f7fSKyle Evans _res_checkenv(kern_envp)) { 18639d44f7fSKyle Evans hintp = kern_envp; 18739d44f7fSKyle Evans goto found; 188*0f46005eSKyle Evans } else 189*0f46005eSKyle Evans stenv_skip = true; 190*0f46005eSKyle Evans 19139d44f7fSKyle Evans fbacklvl++; 19239d44f7fSKyle Evans 19339d44f7fSKyle Evans /* We'll fallback to static_hints if needed/can */ 194*0f46005eSKyle Evans if (!sthints_skip && fbacklvl <= FBACK_STATIC && 19539d44f7fSKyle Evans _res_checkenv(static_hints)) 1969516fbd6SPeter Wemm hintp = static_hints; 197*0f46005eSKyle Evans else 198*0f46005eSKyle Evans sthints_skip = true; 19939d44f7fSKyle Evans found: 20039d44f7fSKyle Evans fbacklvl++; 201d786139cSMaxime Henrion } 2029516fbd6SPeter Wemm 20339d44f7fSKyle Evans if (hintp == NULL) 20439d44f7fSKyle Evans return (ENOENT); 20539d44f7fSKyle Evans *hintp_cookie = hintp; 20639d44f7fSKyle Evans } else { 20739d44f7fSKyle Evans hintp = *hintp_cookie; 20839d44f7fSKyle Evans if (hintenv_merged && hintp == kenvp[0]) 209dc4446dfSKyle Evans dyn_used = true; 21039d44f7fSKyle Evans else 21139d44f7fSKyle Evans /* 21239d44f7fSKyle Evans * If we aren't using the dynamic environment, we need 21339d44f7fSKyle Evans * to run through the proper fallback procedure again. 21439d44f7fSKyle Evans * This is so that we do continuations right if we're 21539d44f7fSKyle Evans * working with *line and *startln. 21639d44f7fSKyle Evans */ 21739d44f7fSKyle Evans goto fallback; 21839d44f7fSKyle Evans } 21939d44f7fSKyle Evans 22039d44f7fSKyle Evans if (dyn_used) { 221e3546a75SScott Long mtx_lock(&kenv_lock); 222d786139cSMaxime Henrion i = 0; 223d786139cSMaxime Henrion } 22439d44f7fSKyle Evans 2259516fbd6SPeter Wemm cp = hintp; 2262398f0cdSPeter Wemm while (cp) { 2272398f0cdSPeter Wemm (*line)++; 2282398f0cdSPeter Wemm if (strncmp(cp, "hint.", 5) != 0) 2295768da6cSKyle Evans goto nexthint; 2305768da6cSKyle Evans n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s", r_name, &r_unit, 2315768da6cSKyle Evans r_resname, r_value); 23239d44f7fSKyle Evans if (n != 4) { 2332398f0cdSPeter Wemm printf("CONFIG: invalid hint '%s'\n", cp); 234dc15eac0SEd Schouten p = strchr(cp, 'h'); 2352398f0cdSPeter Wemm *p = 'H'; 2365768da6cSKyle Evans goto nexthint; 2372398f0cdSPeter Wemm } 2385768da6cSKyle Evans if (startln && *startln >= 0 && *line < *startln) 2395768da6cSKyle Evans goto nexthint; 2405768da6cSKyle Evans if (name && strcmp(name, r_name) != 0) 2415768da6cSKyle Evans goto nexthint; 2425768da6cSKyle Evans if (unit && *unit != r_unit) 2435768da6cSKyle Evans goto nexthint; 2445768da6cSKyle Evans if (resname && strcmp(resname, r_resname) != 0) 2455768da6cSKyle Evans goto nexthint; 2465768da6cSKyle Evans if (value && strcmp(value, r_value) != 0) 2475768da6cSKyle Evans goto nexthint; 2485768da6cSKyle Evans /* Successfully found a hint matching all criteria */ 2492398f0cdSPeter Wemm break; 2505768da6cSKyle Evans nexthint: 25139d44f7fSKyle Evans if (dyn_used) { 252d786139cSMaxime Henrion cp = kenvp[++i]; 2534f033348SPeter Wemm if (cp == NULL) 2544f033348SPeter Wemm break; 2554f033348SPeter Wemm } else { 2562398f0cdSPeter Wemm while (*cp != '\0') 2572398f0cdSPeter Wemm cp++; 2582398f0cdSPeter Wemm cp++; 2592398f0cdSPeter Wemm if (*cp == '\0') { 2602398f0cdSPeter Wemm cp = NULL; 2612398f0cdSPeter Wemm break; 2622398f0cdSPeter Wemm } 2632398f0cdSPeter Wemm } 2644f033348SPeter Wemm } 26539d44f7fSKyle Evans if (dyn_used) 266e3546a75SScott Long mtx_unlock(&kenv_lock); 2672398f0cdSPeter Wemm if (cp == NULL) 26839d44f7fSKyle Evans goto fallback; 2692398f0cdSPeter Wemm 2702398f0cdSPeter Wemm s = cp; 2712398f0cdSPeter Wemm /* This is a bit of a hack, but at least is reentrant */ 2722398f0cdSPeter Wemm /* Note that it returns some !unterminated! strings. */ 273dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of device */ 2742398f0cdSPeter Wemm if (ret_name) 2752398f0cdSPeter Wemm *ret_name = s; 276dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of unit */ 27785c36f3dSJohn Baldwin if (ret_namelen && ret_name) 2782398f0cdSPeter Wemm *ret_namelen = s - *ret_name - 1; /* device length */ 2792398f0cdSPeter Wemm if (ret_unit) 2802398f0cdSPeter Wemm *ret_unit = r_unit; 281dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of resname */ 2822398f0cdSPeter Wemm if (ret_resname) 2832398f0cdSPeter Wemm *ret_resname = s; 284dc15eac0SEd Schouten s = strchr(s, '=') + 1; /* start of value */ 28585c36f3dSJohn Baldwin if (ret_resnamelen && ret_resname) 2862398f0cdSPeter Wemm *ret_resnamelen = s - *ret_resname - 1; /* value len */ 2872398f0cdSPeter Wemm if (ret_value) 2882398f0cdSPeter Wemm *ret_value = s; 2892398f0cdSPeter Wemm if (startln) /* line number for anchor */ 2902398f0cdSPeter Wemm *startln = *line + 1; 2912398f0cdSPeter Wemm return 0; 2922398f0cdSPeter Wemm } 2932398f0cdSPeter Wemm 2942398f0cdSPeter Wemm /* 2952398f0cdSPeter Wemm * Search all the data sources for matches to our query. We look for 2962398f0cdSPeter Wemm * dynamic hints first as overrides for static or fallback hints. 2972398f0cdSPeter Wemm */ 2982398f0cdSPeter Wemm static int 2992398f0cdSPeter Wemm resource_find(int *line, int *startln, 3002398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 3012398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 3022398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 3032398f0cdSPeter Wemm { 3042398f0cdSPeter Wemm int i; 3052398f0cdSPeter Wemm int un; 30639d44f7fSKyle Evans char *hintp; 3072398f0cdSPeter Wemm 3082398f0cdSPeter Wemm *line = 0; 30939d44f7fSKyle Evans hintp = NULL; 3102398f0cdSPeter Wemm 3112398f0cdSPeter Wemm /* Search for exact unit matches first */ 31239d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, unit, resname, value, 3132398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3142398f0cdSPeter Wemm ret_value); 3152398f0cdSPeter Wemm if (i == 0) 3162398f0cdSPeter Wemm return 0; 3172398f0cdSPeter Wemm if (unit == NULL) 3182398f0cdSPeter Wemm return ENOENT; 3192398f0cdSPeter Wemm /* If we are still here, search for wildcard matches */ 3202398f0cdSPeter Wemm un = -1; 32139d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, &un, resname, value, 3222398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3232398f0cdSPeter Wemm ret_value); 3242398f0cdSPeter Wemm if (i == 0) 3252398f0cdSPeter Wemm return 0; 3262398f0cdSPeter Wemm return ENOENT; 3272398f0cdSPeter Wemm } 3282398f0cdSPeter Wemm 3292398f0cdSPeter Wemm int 3302398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result) 3312398f0cdSPeter Wemm { 3322398f0cdSPeter Wemm int error; 3332398f0cdSPeter Wemm const char *str; 3342398f0cdSPeter Wemm char *op; 3352398f0cdSPeter Wemm unsigned long val; 3362398f0cdSPeter Wemm int line; 3372398f0cdSPeter Wemm 3382398f0cdSPeter Wemm line = 0; 3392398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3402398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3412398f0cdSPeter Wemm if (error) 3422398f0cdSPeter Wemm return error; 3432398f0cdSPeter Wemm if (*str == '\0') 3442398f0cdSPeter Wemm return EFTYPE; 3452398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3462398f0cdSPeter Wemm if (*op != '\0') 3472398f0cdSPeter Wemm return EFTYPE; 3482398f0cdSPeter Wemm *result = val; 3492398f0cdSPeter Wemm return 0; 3502398f0cdSPeter Wemm } 3512398f0cdSPeter Wemm 3522398f0cdSPeter Wemm int 3532398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname, 3542398f0cdSPeter Wemm long *result) 3552398f0cdSPeter Wemm { 3562398f0cdSPeter Wemm int error; 3572398f0cdSPeter Wemm const char *str; 3582398f0cdSPeter Wemm char *op; 3592398f0cdSPeter Wemm unsigned long val; 3602398f0cdSPeter Wemm int line; 3612398f0cdSPeter Wemm 3622398f0cdSPeter Wemm line = 0; 3632398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3642398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3652398f0cdSPeter Wemm if (error) 3662398f0cdSPeter Wemm return error; 3672398f0cdSPeter Wemm if (*str == '\0') 3682398f0cdSPeter Wemm return EFTYPE; 3692398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3702398f0cdSPeter Wemm if (*op != '\0') 3712398f0cdSPeter Wemm return EFTYPE; 3722398f0cdSPeter Wemm *result = val; 3732398f0cdSPeter Wemm return 0; 3742398f0cdSPeter Wemm } 3752398f0cdSPeter Wemm 3762398f0cdSPeter Wemm int 3772398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname, 3782398f0cdSPeter Wemm const char **result) 3792398f0cdSPeter Wemm { 3802398f0cdSPeter Wemm int error; 3812398f0cdSPeter Wemm const char *str; 3822398f0cdSPeter Wemm int line; 3832398f0cdSPeter Wemm 3842398f0cdSPeter Wemm line = 0; 3852398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3862398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3872398f0cdSPeter Wemm if (error) 3882398f0cdSPeter Wemm return error; 3892398f0cdSPeter Wemm *result = str; 3902398f0cdSPeter Wemm return 0; 3912398f0cdSPeter Wemm } 3922398f0cdSPeter Wemm 3932398f0cdSPeter Wemm /* 3942398f0cdSPeter Wemm * This is a bit nasty, but allows us to not modify the env strings. 3952398f0cdSPeter Wemm */ 3962398f0cdSPeter Wemm static const char * 3972398f0cdSPeter Wemm resource_string_copy(const char *s, int len) 3982398f0cdSPeter Wemm { 3992398f0cdSPeter Wemm static char stringbuf[256]; 4002398f0cdSPeter Wemm static int offset = 0; 4012398f0cdSPeter Wemm const char *ret; 4022398f0cdSPeter Wemm 4032398f0cdSPeter Wemm if (len == 0) 4042398f0cdSPeter Wemm len = strlen(s); 4052398f0cdSPeter Wemm if (len > 255) 4062398f0cdSPeter Wemm return NULL; 4072398f0cdSPeter Wemm if ((offset + len + 1) > 255) 4082398f0cdSPeter Wemm offset = 0; 4092398f0cdSPeter Wemm bcopy(s, &stringbuf[offset], len); 4102398f0cdSPeter Wemm stringbuf[offset + len] = '\0'; 4112398f0cdSPeter Wemm ret = &stringbuf[offset]; 4122398f0cdSPeter Wemm offset += len + 1; 4132398f0cdSPeter Wemm return ret; 4142398f0cdSPeter Wemm } 4152398f0cdSPeter Wemm 4162398f0cdSPeter Wemm /* 41774e62047SJohn-Mark Gurney * err = resource_find_match(&anchor, &name, &unit, resname, value) 4182398f0cdSPeter Wemm * Iteratively fetch a list of devices wired "at" something 4192398f0cdSPeter Wemm * res and value are restrictions. eg: "at", "scbus0". 4202398f0cdSPeter Wemm * For practical purposes, res = required, value = optional. 4212398f0cdSPeter Wemm * *name and *unit are set. 4222398f0cdSPeter Wemm * set *anchor to zero before starting. 4232398f0cdSPeter Wemm */ 4242398f0cdSPeter Wemm int 4252398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit, 4262398f0cdSPeter Wemm const char *resname, const char *value) 4272398f0cdSPeter Wemm { 4282398f0cdSPeter Wemm const char *found_name; 4292398f0cdSPeter Wemm int found_namelen; 4302398f0cdSPeter Wemm int found_unit; 4312398f0cdSPeter Wemm int ret; 4322398f0cdSPeter Wemm int newln; 4332398f0cdSPeter Wemm 4342398f0cdSPeter Wemm newln = *anchor; 4352398f0cdSPeter Wemm ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 4362398f0cdSPeter Wemm &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 4372398f0cdSPeter Wemm if (ret == 0) { 4382398f0cdSPeter Wemm *name = resource_string_copy(found_name, found_namelen); 4392398f0cdSPeter Wemm *unit = found_unit; 4402398f0cdSPeter Wemm } 4412398f0cdSPeter Wemm *anchor = newln; 4422398f0cdSPeter Wemm return ret; 4432398f0cdSPeter Wemm } 4442398f0cdSPeter Wemm 4452398f0cdSPeter Wemm 4462398f0cdSPeter Wemm /* 4472398f0cdSPeter Wemm * err = resource_find_dev(&anchor, name, &unit, res, value); 4482398f0cdSPeter Wemm * Iterate through a list of devices, returning their unit numbers. 4492398f0cdSPeter Wemm * res and value are optional restrictions. eg: "at", "scbus0". 4502398f0cdSPeter Wemm * *unit is set to the value. 4512398f0cdSPeter Wemm * set *anchor to zero before starting. 4522398f0cdSPeter Wemm */ 4532398f0cdSPeter Wemm int 4542398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit, 4552398f0cdSPeter Wemm const char *resname, const char *value) 4562398f0cdSPeter Wemm { 4572398f0cdSPeter Wemm int found_unit; 4582398f0cdSPeter Wemm int newln; 4592398f0cdSPeter Wemm int ret; 4602398f0cdSPeter Wemm 4612398f0cdSPeter Wemm newln = *anchor; 4622398f0cdSPeter Wemm ret = resource_find(anchor, &newln, name, NULL, resname, value, 4632398f0cdSPeter Wemm NULL, NULL, &found_unit, NULL, NULL, NULL); 4642398f0cdSPeter Wemm if (ret == 0) { 4652398f0cdSPeter Wemm *unit = found_unit; 4662398f0cdSPeter Wemm } 4672398f0cdSPeter Wemm *anchor = newln; 4682398f0cdSPeter Wemm return ret; 4692398f0cdSPeter Wemm } 4706591b310SJohn Baldwin 4716591b310SJohn Baldwin /* 4726591b310SJohn Baldwin * Check to see if a device is disabled via a disabled hint. 4736591b310SJohn Baldwin */ 4746591b310SJohn Baldwin int 4756591b310SJohn Baldwin resource_disabled(const char *name, int unit) 4766591b310SJohn Baldwin { 4776591b310SJohn Baldwin int error, value; 4786591b310SJohn Baldwin 4796591b310SJohn Baldwin error = resource_int_value(name, unit, "disabled", &value); 4806591b310SJohn Baldwin if (error) 4816591b310SJohn Baldwin return (0); 4826591b310SJohn Baldwin return (value); 4836591b310SJohn Baldwin } 48464de8019SJohn Baldwin 48564de8019SJohn Baldwin /* 48664de8019SJohn Baldwin * Clear a value associated with a device by removing it from 48764de8019SJohn Baldwin * the kernel environment. This only removes a hint for an 48864de8019SJohn Baldwin * exact unit. 48964de8019SJohn Baldwin */ 49064de8019SJohn Baldwin int 49164de8019SJohn Baldwin resource_unset_value(const char *name, int unit, const char *resname) 49264de8019SJohn Baldwin { 49364de8019SJohn Baldwin char varname[128]; 49464de8019SJohn Baldwin const char *retname, *retvalue; 49564de8019SJohn Baldwin int error, line; 49664de8019SJohn Baldwin size_t len; 49764de8019SJohn Baldwin 49864de8019SJohn Baldwin line = 0; 49964de8019SJohn Baldwin error = resource_find(&line, NULL, name, &unit, resname, NULL, 50064de8019SJohn Baldwin &retname, NULL, NULL, NULL, NULL, &retvalue); 50164de8019SJohn Baldwin if (error) 50264de8019SJohn Baldwin return (error); 50364de8019SJohn Baldwin 50464de8019SJohn Baldwin retname -= strlen("hint."); 50564de8019SJohn Baldwin len = retvalue - retname - 1; 50664de8019SJohn Baldwin if (len > sizeof(varname) - 1) 50764de8019SJohn Baldwin return (ENAMETOOLONG); 50864de8019SJohn Baldwin memcpy(varname, retname, len); 50964de8019SJohn Baldwin varname[len] = '\0'; 51064de8019SJohn Baldwin return (kern_unsetenv(varname)); 51164de8019SJohn Baldwin } 512