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> 34bc683a89SWarner Losh #include <sys/kenv.h> 3539d44f7fSKyle Evans #include <sys/kernel.h> 3670da14c4SAleksandr Rybalko #include <sys/malloc.h> 37e3546a75SScott Long #include <sys/mutex.h> 3870da14c4SAleksandr Rybalko #include <sys/sysctl.h> 391bccd863SAleksandr Rybalko #include <sys/systm.h> 402398f0cdSPeter Wemm #include <sys/bus.h> 412398f0cdSPeter Wemm 4239d44f7fSKyle Evans #define FBACK_MDENV 0 /* MD env (e.g. loader.conf) */ 4339d44f7fSKyle Evans #define FBACK_STENV 1 /* Static env */ 4439d44f7fSKyle Evans #define FBACK_STATIC 2 /* static_hints */ 4539d44f7fSKyle Evans 4639d44f7fSKyle Evans /* 4739d44f7fSKyle Evans * We'll use hintenv_merged to indicate that the dynamic environment has been 4839d44f7fSKyle Evans * properly prepared for hint usage. This implies that the dynamic environment 4939d44f7fSKyle Evans * has already been setup (dynamic_kenv) and that we have added any supplied 5039d44f7fSKyle Evans * static_hints to the dynamic environment. 5139d44f7fSKyle Evans */ 52dc4446dfSKyle Evans static bool hintenv_merged; 530f46005eSKyle Evans /* Static environment and static hints cannot change, so we'll skip known bad */ 540f46005eSKyle Evans static bool stenv_skip; 550f46005eSKyle Evans static bool sthints_skip; 562398f0cdSPeter Wemm /* 572398f0cdSPeter Wemm * Access functions for device resources. 582398f0cdSPeter Wemm */ 592398f0cdSPeter Wemm 6039d44f7fSKyle Evans static void 6139d44f7fSKyle Evans static_hints_to_env(void *data __unused) 6270da14c4SAleksandr Rybalko { 6370da14c4SAleksandr Rybalko const char *cp; 6470da14c4SAleksandr Rybalko char *line, *eq; 6539d44f7fSKyle Evans int eqidx, i; 6670da14c4SAleksandr Rybalko 67770488d2SKyle Evans cp = static_hints; 68770488d2SKyle Evans while (cp && *cp != '\0') { 6970da14c4SAleksandr Rybalko eq = strchr(cp, '='); 701bccd863SAleksandr Rybalko if (eq == NULL) 7170da14c4SAleksandr Rybalko /* Bad hint value */ 7270da14c4SAleksandr Rybalko continue; 7370da14c4SAleksandr Rybalko eqidx = eq - cp; 7470da14c4SAleksandr Rybalko 75770488d2SKyle Evans i = strlen(cp); 7670da14c4SAleksandr Rybalko line = malloc(i + 1, M_TEMP, M_WAITOK); 7770da14c4SAleksandr Rybalko strcpy(line, cp); 7839d44f7fSKyle Evans line[eqidx] = line[i] = '\0'; 7939d44f7fSKyle Evans /* 8039d44f7fSKyle Evans * Before adding a hint to the dynamic environment, check if 8139d44f7fSKyle Evans * another value for said hint has already been added. This is 8239d44f7fSKyle Evans * needed because static environment overrides static hints and 8339d44f7fSKyle Evans * dynamic environment overrides all. 8439d44f7fSKyle Evans */ 8539d44f7fSKyle Evans if (testenv(line) == 0) 862be111bfSDavide Italiano kern_setenv(line, line + eqidx + 1); 8770da14c4SAleksandr Rybalko free(line, M_TEMP); 8870da14c4SAleksandr Rybalko cp += i + 1; 8970da14c4SAleksandr Rybalko } 90dc4446dfSKyle Evans hintenv_merged = true; 9170da14c4SAleksandr Rybalko } 9270da14c4SAleksandr Rybalko 9339d44f7fSKyle Evans /* Any time after dynamic env is setup */ 94cae22dd9SKyle Evans SYSINIT(hintenv, SI_SUB_KMEM + 1, SI_ORDER_SECOND, static_hints_to_env, NULL); 9539d44f7fSKyle Evans 9639d44f7fSKyle Evans /* 9739d44f7fSKyle Evans * Checks the environment to see if we even have any hints. If it has no hints, 9839d44f7fSKyle Evans * then res_find can take the hint that there's no point in searching it and 9939d44f7fSKyle Evans * either move on to the next environment or fail early. 10039d44f7fSKyle Evans */ 10139d44f7fSKyle Evans static bool 10239d44f7fSKyle Evans _res_checkenv(char *envp) 10339d44f7fSKyle Evans { 10439d44f7fSKyle Evans char *cp; 10539d44f7fSKyle Evans 10639d44f7fSKyle Evans cp = envp; 10739d44f7fSKyle Evans while (cp) { 10839d44f7fSKyle Evans if (strncmp(cp, "hint.", 5) == 0) 10939d44f7fSKyle Evans return (true); 11039d44f7fSKyle Evans while (*cp != '\0') 11139d44f7fSKyle Evans cp++; 11239d44f7fSKyle Evans cp++; 11339d44f7fSKyle Evans if (*cp == '\0') 11439d44f7fSKyle Evans break; 11539d44f7fSKyle Evans } 11639d44f7fSKyle Evans return (false); 11739d44f7fSKyle Evans } 11870da14c4SAleksandr Rybalko 11970da14c4SAleksandr Rybalko /* 1202398f0cdSPeter Wemm * Evil wildcarding resource string lookup. 1212398f0cdSPeter Wemm * This walks the supplied env string table and returns a match. 1222398f0cdSPeter Wemm * The start point can be remembered for incremental searches. 1232398f0cdSPeter Wemm */ 1242398f0cdSPeter Wemm static int 12539d44f7fSKyle Evans res_find(char **hintp_cookie, 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 { 130*696fca3fSAlexander Motin int fbacklvl = FBACK_MDENV, i = 0, n = 0, namelen; 1312398f0cdSPeter Wemm char r_name[32]; 13239d44f7fSKyle Evans int r_unit; 1332398f0cdSPeter Wemm char r_resname[32]; 1342398f0cdSPeter Wemm char r_value[128]; 1359516fbd6SPeter Wemm const char *s, *cp; 13639d44f7fSKyle Evans char *hintp, *p; 137dc4446dfSKyle Evans bool dyn_used = false; 1382398f0cdSPeter Wemm 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 177d529de87SKyle Evans switch (fbacklvl) { 178d529de87SKyle Evans case FBACK_MDENV: 17939d44f7fSKyle Evans fbacklvl++; 180d529de87SKyle Evans if (_res_checkenv(md_envp)) { 181d529de87SKyle Evans hintp = md_envp; 182d529de87SKyle Evans break; 183d529de87SKyle Evans } 18439d44f7fSKyle Evans 185d529de87SKyle Evans /* FALLTHROUGH */ 186d529de87SKyle Evans case FBACK_STENV: 187d529de87SKyle Evans fbacklvl++; 188d529de87SKyle Evans if (!stenv_skip && _res_checkenv(kern_envp)) { 18939d44f7fSKyle Evans hintp = kern_envp; 190d529de87SKyle Evans break; 1910f46005eSKyle Evans } else 1920f46005eSKyle Evans stenv_skip = true; 1930f46005eSKyle Evans 194d529de87SKyle Evans /* FALLTHROUGH */ 195d529de87SKyle Evans case FBACK_STATIC: 19639d44f7fSKyle Evans fbacklvl++; 19739d44f7fSKyle Evans /* We'll fallback to static_hints if needed/can */ 198d529de87SKyle Evans if (!sthints_skip && 19939d44f7fSKyle Evans _res_checkenv(static_hints)) 2009516fbd6SPeter Wemm hintp = static_hints; 2010f46005eSKyle Evans else 2020f46005eSKyle Evans sthints_skip = true; 203d529de87SKyle Evans 204d529de87SKyle Evans break; 205d529de87SKyle Evans default: 206d529de87SKyle Evans return (ENOENT); 207d529de87SKyle Evans } 208d786139cSMaxime Henrion } 2099516fbd6SPeter Wemm 21039d44f7fSKyle Evans if (hintp == NULL) 21139d44f7fSKyle Evans return (ENOENT); 21239d44f7fSKyle Evans *hintp_cookie = hintp; 21339d44f7fSKyle Evans } else { 21439d44f7fSKyle Evans hintp = *hintp_cookie; 21539d44f7fSKyle Evans if (hintenv_merged && hintp == kenvp[0]) 216dc4446dfSKyle Evans dyn_used = true; 21739d44f7fSKyle Evans else 21839d44f7fSKyle Evans /* 21939d44f7fSKyle Evans * If we aren't using the dynamic environment, we need 22039d44f7fSKyle Evans * to run through the proper fallback procedure again. 22139d44f7fSKyle Evans * This is so that we do continuations right if we're 22239d44f7fSKyle Evans * working with *line and *startln. 22339d44f7fSKyle Evans */ 22439d44f7fSKyle Evans goto fallback; 22539d44f7fSKyle Evans } 22639d44f7fSKyle Evans 22739d44f7fSKyle Evans if (dyn_used) { 228e3546a75SScott Long mtx_lock(&kenv_lock); 229d786139cSMaxime Henrion i = 0; 230d786139cSMaxime Henrion } 23139d44f7fSKyle Evans 232*696fca3fSAlexander Motin if (name) 233*696fca3fSAlexander Motin namelen = strlen(name); 2349516fbd6SPeter Wemm cp = hintp; 2352398f0cdSPeter Wemm while (cp) { 2362398f0cdSPeter Wemm (*line)++; 2372398f0cdSPeter Wemm if (strncmp(cp, "hint.", 5) != 0) 2385768da6cSKyle Evans goto nexthint; 239*696fca3fSAlexander Motin if (name && strncmp(cp + 5, name, namelen) != 0) 240*696fca3fSAlexander Motin goto nexthint; 241*696fca3fSAlexander Motin n = sscanf(cp + 5, "%32[^.].%d.%32[^=]=%127s", r_name, &r_unit, 2425768da6cSKyle Evans r_resname, r_value); 24339d44f7fSKyle Evans if (n != 4) { 2442398f0cdSPeter Wemm printf("CONFIG: invalid hint '%s'\n", cp); 245dc15eac0SEd Schouten p = strchr(cp, 'h'); 2462398f0cdSPeter Wemm *p = 'H'; 2475768da6cSKyle Evans goto nexthint; 2482398f0cdSPeter Wemm } 2495768da6cSKyle Evans if (startln && *startln >= 0 && *line < *startln) 2505768da6cSKyle Evans goto nexthint; 2515768da6cSKyle Evans if (name && strcmp(name, r_name) != 0) 2525768da6cSKyle Evans goto nexthint; 2535768da6cSKyle Evans if (unit && *unit != r_unit) 2545768da6cSKyle Evans goto nexthint; 2555768da6cSKyle Evans if (resname && strcmp(resname, r_resname) != 0) 2565768da6cSKyle Evans goto nexthint; 2575768da6cSKyle Evans if (value && strcmp(value, r_value) != 0) 2585768da6cSKyle Evans goto nexthint; 2595768da6cSKyle Evans /* Successfully found a hint matching all criteria */ 2602398f0cdSPeter Wemm break; 2615768da6cSKyle Evans nexthint: 26239d44f7fSKyle Evans if (dyn_used) { 263d786139cSMaxime Henrion cp = kenvp[++i]; 2644f033348SPeter Wemm if (cp == NULL) 2654f033348SPeter Wemm break; 2664f033348SPeter Wemm } else { 2672398f0cdSPeter Wemm while (*cp != '\0') 2682398f0cdSPeter Wemm cp++; 2692398f0cdSPeter Wemm cp++; 2702398f0cdSPeter Wemm if (*cp == '\0') { 2712398f0cdSPeter Wemm cp = NULL; 2722398f0cdSPeter Wemm break; 2732398f0cdSPeter Wemm } 2742398f0cdSPeter Wemm } 2754f033348SPeter Wemm } 27639d44f7fSKyle Evans if (dyn_used) 277e3546a75SScott Long mtx_unlock(&kenv_lock); 2782398f0cdSPeter Wemm if (cp == NULL) 27939d44f7fSKyle Evans goto fallback; 2802398f0cdSPeter Wemm 2812398f0cdSPeter Wemm s = cp; 2822398f0cdSPeter Wemm /* This is a bit of a hack, but at least is reentrant */ 2832398f0cdSPeter Wemm /* Note that it returns some !unterminated! strings. */ 284dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of device */ 2852398f0cdSPeter Wemm if (ret_name) 2862398f0cdSPeter Wemm *ret_name = s; 287dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of unit */ 28885c36f3dSJohn Baldwin if (ret_namelen && ret_name) 2892398f0cdSPeter Wemm *ret_namelen = s - *ret_name - 1; /* device length */ 2902398f0cdSPeter Wemm if (ret_unit) 2912398f0cdSPeter Wemm *ret_unit = r_unit; 292dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of resname */ 2932398f0cdSPeter Wemm if (ret_resname) 2942398f0cdSPeter Wemm *ret_resname = s; 295dc15eac0SEd Schouten s = strchr(s, '=') + 1; /* start of value */ 29685c36f3dSJohn Baldwin if (ret_resnamelen && ret_resname) 2972398f0cdSPeter Wemm *ret_resnamelen = s - *ret_resname - 1; /* value len */ 2982398f0cdSPeter Wemm if (ret_value) 2992398f0cdSPeter Wemm *ret_value = s; 3002398f0cdSPeter Wemm if (startln) /* line number for anchor */ 3012398f0cdSPeter Wemm *startln = *line + 1; 3022398f0cdSPeter Wemm return 0; 3032398f0cdSPeter Wemm } 3042398f0cdSPeter Wemm 3052398f0cdSPeter Wemm /* 3062398f0cdSPeter Wemm * Search all the data sources for matches to our query. We look for 3072398f0cdSPeter Wemm * dynamic hints first as overrides for static or fallback hints. 3082398f0cdSPeter Wemm */ 3092398f0cdSPeter Wemm static int 3102398f0cdSPeter Wemm resource_find(int *line, int *startln, 3112398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 3122398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 3132398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 3142398f0cdSPeter Wemm { 3152398f0cdSPeter Wemm int i; 3162398f0cdSPeter Wemm int un; 31739d44f7fSKyle Evans char *hintp; 3182398f0cdSPeter Wemm 3192398f0cdSPeter Wemm *line = 0; 32039d44f7fSKyle Evans hintp = NULL; 3212398f0cdSPeter Wemm 3222398f0cdSPeter Wemm /* Search for exact unit matches first */ 32339d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, unit, resname, value, 3242398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3252398f0cdSPeter Wemm ret_value); 3262398f0cdSPeter Wemm if (i == 0) 3272398f0cdSPeter Wemm return 0; 3282398f0cdSPeter Wemm if (unit == NULL) 3292398f0cdSPeter Wemm return ENOENT; 3302398f0cdSPeter Wemm /* If we are still here, search for wildcard matches */ 3312398f0cdSPeter Wemm un = -1; 33239d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, &un, resname, value, 3332398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3342398f0cdSPeter Wemm ret_value); 3352398f0cdSPeter Wemm if (i == 0) 3362398f0cdSPeter Wemm return 0; 3372398f0cdSPeter Wemm return ENOENT; 3382398f0cdSPeter Wemm } 3392398f0cdSPeter Wemm 3402398f0cdSPeter Wemm int 3412398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result) 3422398f0cdSPeter Wemm { 3432398f0cdSPeter Wemm int error; 3442398f0cdSPeter Wemm const char *str; 3452398f0cdSPeter Wemm char *op; 3462398f0cdSPeter Wemm unsigned long val; 3472398f0cdSPeter Wemm int line; 3482398f0cdSPeter Wemm 3492398f0cdSPeter Wemm line = 0; 3502398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3512398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3522398f0cdSPeter Wemm if (error) 3532398f0cdSPeter Wemm return error; 3542398f0cdSPeter Wemm if (*str == '\0') 3552398f0cdSPeter Wemm return EFTYPE; 3562398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3572398f0cdSPeter Wemm if (*op != '\0') 3582398f0cdSPeter Wemm return EFTYPE; 3592398f0cdSPeter Wemm *result = val; 3602398f0cdSPeter Wemm return 0; 3612398f0cdSPeter Wemm } 3622398f0cdSPeter Wemm 3632398f0cdSPeter Wemm int 3642398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname, 3652398f0cdSPeter Wemm long *result) 3662398f0cdSPeter Wemm { 3672398f0cdSPeter Wemm int error; 3682398f0cdSPeter Wemm const char *str; 3692398f0cdSPeter Wemm char *op; 3702398f0cdSPeter Wemm unsigned long val; 3712398f0cdSPeter Wemm int line; 3722398f0cdSPeter Wemm 3732398f0cdSPeter Wemm line = 0; 3742398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3752398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3762398f0cdSPeter Wemm if (error) 3772398f0cdSPeter Wemm return error; 3782398f0cdSPeter Wemm if (*str == '\0') 3792398f0cdSPeter Wemm return EFTYPE; 3802398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3812398f0cdSPeter Wemm if (*op != '\0') 3822398f0cdSPeter Wemm return EFTYPE; 3832398f0cdSPeter Wemm *result = val; 3842398f0cdSPeter Wemm return 0; 3852398f0cdSPeter Wemm } 3862398f0cdSPeter Wemm 3872398f0cdSPeter Wemm int 3882398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname, 3892398f0cdSPeter Wemm const char **result) 3902398f0cdSPeter Wemm { 3912398f0cdSPeter Wemm int error; 3922398f0cdSPeter Wemm const char *str; 3932398f0cdSPeter Wemm int line; 3942398f0cdSPeter Wemm 3952398f0cdSPeter Wemm line = 0; 3962398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3972398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3982398f0cdSPeter Wemm if (error) 3992398f0cdSPeter Wemm return error; 4002398f0cdSPeter Wemm *result = str; 4012398f0cdSPeter Wemm return 0; 4022398f0cdSPeter Wemm } 4032398f0cdSPeter Wemm 4042398f0cdSPeter Wemm /* 4052398f0cdSPeter Wemm * This is a bit nasty, but allows us to not modify the env strings. 4062398f0cdSPeter Wemm */ 4072398f0cdSPeter Wemm static const char * 4082398f0cdSPeter Wemm resource_string_copy(const char *s, int len) 4092398f0cdSPeter Wemm { 4102398f0cdSPeter Wemm static char stringbuf[256]; 4112398f0cdSPeter Wemm static int offset = 0; 4122398f0cdSPeter Wemm const char *ret; 4132398f0cdSPeter Wemm 4142398f0cdSPeter Wemm if (len == 0) 4152398f0cdSPeter Wemm len = strlen(s); 4162398f0cdSPeter Wemm if (len > 255) 4172398f0cdSPeter Wemm return NULL; 4182398f0cdSPeter Wemm if ((offset + len + 1) > 255) 4192398f0cdSPeter Wemm offset = 0; 4202398f0cdSPeter Wemm bcopy(s, &stringbuf[offset], len); 4212398f0cdSPeter Wemm stringbuf[offset + len] = '\0'; 4222398f0cdSPeter Wemm ret = &stringbuf[offset]; 4232398f0cdSPeter Wemm offset += len + 1; 4242398f0cdSPeter Wemm return ret; 4252398f0cdSPeter Wemm } 4262398f0cdSPeter Wemm 4272398f0cdSPeter Wemm /* 42874e62047SJohn-Mark Gurney * err = resource_find_match(&anchor, &name, &unit, resname, value) 4292398f0cdSPeter Wemm * Iteratively fetch a list of devices wired "at" something 4302398f0cdSPeter Wemm * res and value are restrictions. eg: "at", "scbus0". 4312398f0cdSPeter Wemm * For practical purposes, res = required, value = optional. 4322398f0cdSPeter Wemm * *name and *unit are set. 4332398f0cdSPeter Wemm * set *anchor to zero before starting. 4342398f0cdSPeter Wemm */ 4352398f0cdSPeter Wemm int 4362398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit, 4372398f0cdSPeter Wemm const char *resname, const char *value) 4382398f0cdSPeter Wemm { 4392398f0cdSPeter Wemm const char *found_name; 4402398f0cdSPeter Wemm int found_namelen; 4412398f0cdSPeter Wemm int found_unit; 4422398f0cdSPeter Wemm int ret; 4432398f0cdSPeter Wemm int newln; 4442398f0cdSPeter Wemm 4452398f0cdSPeter Wemm newln = *anchor; 4462398f0cdSPeter Wemm ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 4472398f0cdSPeter Wemm &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 4482398f0cdSPeter Wemm if (ret == 0) { 4492398f0cdSPeter Wemm *name = resource_string_copy(found_name, found_namelen); 4502398f0cdSPeter Wemm *unit = found_unit; 4512398f0cdSPeter Wemm } 4522398f0cdSPeter Wemm *anchor = newln; 4532398f0cdSPeter Wemm return ret; 4542398f0cdSPeter Wemm } 4552398f0cdSPeter Wemm 4562398f0cdSPeter Wemm /* 4572398f0cdSPeter Wemm * err = resource_find_dev(&anchor, name, &unit, res, value); 4582398f0cdSPeter Wemm * Iterate through a list of devices, returning their unit numbers. 4592398f0cdSPeter Wemm * res and value are optional restrictions. eg: "at", "scbus0". 4602398f0cdSPeter Wemm * *unit is set to the value. 4612398f0cdSPeter Wemm * set *anchor to zero before starting. 4622398f0cdSPeter Wemm */ 4632398f0cdSPeter Wemm int 4642398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit, 4652398f0cdSPeter Wemm const char *resname, const char *value) 4662398f0cdSPeter Wemm { 4672398f0cdSPeter Wemm int found_unit; 4682398f0cdSPeter Wemm int newln; 4692398f0cdSPeter Wemm int ret; 4702398f0cdSPeter Wemm 4712398f0cdSPeter Wemm newln = *anchor; 4722398f0cdSPeter Wemm ret = resource_find(anchor, &newln, name, NULL, resname, value, 4732398f0cdSPeter Wemm NULL, NULL, &found_unit, NULL, NULL, NULL); 4742398f0cdSPeter Wemm if (ret == 0) { 4752398f0cdSPeter Wemm *unit = found_unit; 4762398f0cdSPeter Wemm } 4772398f0cdSPeter Wemm *anchor = newln; 4782398f0cdSPeter Wemm return ret; 4792398f0cdSPeter Wemm } 4806591b310SJohn Baldwin 4816591b310SJohn Baldwin /* 4826591b310SJohn Baldwin * Check to see if a device is disabled via a disabled hint. 4836591b310SJohn Baldwin */ 4846591b310SJohn Baldwin int 4856591b310SJohn Baldwin resource_disabled(const char *name, int unit) 4866591b310SJohn Baldwin { 4876591b310SJohn Baldwin int error, value; 4886591b310SJohn Baldwin 4896591b310SJohn Baldwin error = resource_int_value(name, unit, "disabled", &value); 4906591b310SJohn Baldwin if (error) 4916591b310SJohn Baldwin return (0); 4926591b310SJohn Baldwin return (value); 4936591b310SJohn Baldwin } 49464de8019SJohn Baldwin 49564de8019SJohn Baldwin /* 49664de8019SJohn Baldwin * Clear a value associated with a device by removing it from 49764de8019SJohn Baldwin * the kernel environment. This only removes a hint for an 49864de8019SJohn Baldwin * exact unit. 49964de8019SJohn Baldwin */ 50064de8019SJohn Baldwin int 50164de8019SJohn Baldwin resource_unset_value(const char *name, int unit, const char *resname) 50264de8019SJohn Baldwin { 50364de8019SJohn Baldwin char varname[128]; 50464de8019SJohn Baldwin const char *retname, *retvalue; 50564de8019SJohn Baldwin int error, line; 50664de8019SJohn Baldwin size_t len; 50764de8019SJohn Baldwin 50864de8019SJohn Baldwin line = 0; 50964de8019SJohn Baldwin error = resource_find(&line, NULL, name, &unit, resname, NULL, 51064de8019SJohn Baldwin &retname, NULL, NULL, NULL, NULL, &retvalue); 51164de8019SJohn Baldwin if (error) 51264de8019SJohn Baldwin return (error); 51364de8019SJohn Baldwin 51464de8019SJohn Baldwin retname -= strlen("hint."); 51564de8019SJohn Baldwin len = retvalue - retname - 1; 51664de8019SJohn Baldwin if (len > sizeof(varname) - 1) 51764de8019SJohn Baldwin return (ENAMETOOLONG); 51864de8019SJohn Baldwin memcpy(varname, retname, len); 51964de8019SJohn Baldwin varname[len] = '\0'; 52064de8019SJohn Baldwin return (kern_unsetenv(varname)); 52164de8019SJohn Baldwin } 522