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 */ 51*dc4446dfSKyle Evans static bool hintenv_merged; 52770488d2SKyle Evans 532398f0cdSPeter Wemm /* 542398f0cdSPeter Wemm * Access functions for device resources. 552398f0cdSPeter Wemm */ 562398f0cdSPeter Wemm 5739d44f7fSKyle Evans static void 5839d44f7fSKyle Evans static_hints_to_env(void *data __unused) 5970da14c4SAleksandr Rybalko { 6070da14c4SAleksandr Rybalko const char *cp; 6170da14c4SAleksandr Rybalko char *line, *eq; 6239d44f7fSKyle Evans int eqidx, i; 6370da14c4SAleksandr Rybalko 64770488d2SKyle Evans cp = static_hints; 65770488d2SKyle Evans while (cp && *cp != '\0') { 6670da14c4SAleksandr Rybalko eq = strchr(cp, '='); 671bccd863SAleksandr Rybalko if (eq == NULL) 6870da14c4SAleksandr Rybalko /* Bad hint value */ 6970da14c4SAleksandr Rybalko continue; 7070da14c4SAleksandr Rybalko eqidx = eq - cp; 7170da14c4SAleksandr Rybalko 72770488d2SKyle Evans i = strlen(cp); 7370da14c4SAleksandr Rybalko line = malloc(i + 1, M_TEMP, M_WAITOK); 7470da14c4SAleksandr Rybalko strcpy(line, cp); 7539d44f7fSKyle Evans line[eqidx] = line[i] = '\0'; 7639d44f7fSKyle Evans /* 7739d44f7fSKyle Evans * Before adding a hint to the dynamic environment, check if 7839d44f7fSKyle Evans * another value for said hint has already been added. This is 7939d44f7fSKyle Evans * needed because static environment overrides static hints and 8039d44f7fSKyle Evans * dynamic environment overrides all. 8139d44f7fSKyle Evans */ 8239d44f7fSKyle Evans if (testenv(line) == 0) 832be111bfSDavide Italiano kern_setenv(line, line + eqidx + 1); 8470da14c4SAleksandr Rybalko free(line, M_TEMP); 8570da14c4SAleksandr Rybalko cp += i + 1; 8670da14c4SAleksandr Rybalko } 87*dc4446dfSKyle Evans hintenv_merged = true; 8870da14c4SAleksandr Rybalko } 8970da14c4SAleksandr Rybalko 9039d44f7fSKyle Evans /* Any time after dynamic env is setup */ 91cae22dd9SKyle Evans SYSINIT(hintenv, SI_SUB_KMEM + 1, SI_ORDER_SECOND, static_hints_to_env, NULL); 9239d44f7fSKyle Evans 9339d44f7fSKyle Evans /* 9439d44f7fSKyle Evans * Checks the environment to see if we even have any hints. If it has no hints, 9539d44f7fSKyle Evans * then res_find can take the hint that there's no point in searching it and 9639d44f7fSKyle Evans * either move on to the next environment or fail early. 9739d44f7fSKyle Evans */ 9839d44f7fSKyle Evans static bool 9939d44f7fSKyle Evans _res_checkenv(char *envp) 10039d44f7fSKyle Evans { 10139d44f7fSKyle Evans char *cp; 10239d44f7fSKyle Evans 10339d44f7fSKyle Evans cp = envp; 10439d44f7fSKyle Evans while (cp) { 10539d44f7fSKyle Evans if (strncmp(cp, "hint.", 5) == 0) 10639d44f7fSKyle Evans return (true); 10739d44f7fSKyle Evans while (*cp != '\0') 10839d44f7fSKyle Evans cp++; 10939d44f7fSKyle Evans cp++; 11039d44f7fSKyle Evans if (*cp == '\0') 11139d44f7fSKyle Evans break; 11239d44f7fSKyle Evans } 11339d44f7fSKyle Evans return (false); 11439d44f7fSKyle Evans } 11570da14c4SAleksandr Rybalko 11670da14c4SAleksandr Rybalko /* 1172398f0cdSPeter Wemm * Evil wildcarding resource string lookup. 1182398f0cdSPeter Wemm * This walks the supplied env string table and returns a match. 1192398f0cdSPeter Wemm * The start point can be remembered for incremental searches. 1202398f0cdSPeter Wemm */ 1212398f0cdSPeter Wemm static int 12239d44f7fSKyle Evans res_find(char **hintp_cookie, int *line, int *startln, 1232398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 1242398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 1252398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 1262398f0cdSPeter Wemm { 127*dc4446dfSKyle Evans int fbacklvl = FBACK_MDENV, i = 0, n = 0; 1282398f0cdSPeter Wemm char r_name[32]; 12939d44f7fSKyle Evans int r_unit; 1302398f0cdSPeter Wemm char r_resname[32]; 1312398f0cdSPeter Wemm char r_value[128]; 1329516fbd6SPeter Wemm const char *s, *cp; 13339d44f7fSKyle Evans char *hintp, *p; 134*dc4446dfSKyle Evans bool dyn_used = false; 1352398f0cdSPeter Wemm 13639d44f7fSKyle Evans 13739d44f7fSKyle Evans /* 13839d44f7fSKyle Evans * We are expecting that the caller will pass us a hintp_cookie that 13939d44f7fSKyle Evans * they are tracking. Upon entry, if *hintp_cookie is *not* set, this 14039d44f7fSKyle Evans * indicates to us that we should be figuring out based on the current 14139d44f7fSKyle Evans * environment where to search. This keeps us sane throughout the 14239d44f7fSKyle Evans * entirety of a single search. 14339d44f7fSKyle Evans */ 14439d44f7fSKyle Evans if (*hintp_cookie == NULL) { 14532069af6SAlexander Leidinger hintp = NULL; 14639d44f7fSKyle Evans if (hintenv_merged) { 14739d44f7fSKyle Evans /* 14839d44f7fSKyle Evans * static_hints, if it was previously used, has 14939d44f7fSKyle Evans * already been folded in to the environment 15039d44f7fSKyle Evans * by this point. 15139d44f7fSKyle Evans */ 152e3546a75SScott Long mtx_lock(&kenv_lock); 153d786139cSMaxime Henrion cp = kenvp[0]; 154d786139cSMaxime Henrion for (i = 0; cp != NULL; cp = kenvp[++i]) { 155d786139cSMaxime Henrion if (!strncmp(cp, "hint.", 5)) { 15639d44f7fSKyle Evans hintp = kenvp[0]; 157d786139cSMaxime Henrion break; 158d786139cSMaxime Henrion } 159d786139cSMaxime Henrion } 160e3546a75SScott Long mtx_unlock(&kenv_lock); 161*dc4446dfSKyle Evans dyn_used = true; 162d786139cSMaxime Henrion } else { 16339d44f7fSKyle Evans /* 16439d44f7fSKyle Evans * We'll have a chance to keep coming back here until 16539d44f7fSKyle Evans * we've actually exhausted all of our possibilities. 16639d44f7fSKyle Evans * We might have chosen the MD/Static env because it 16739d44f7fSKyle Evans * had some kind of hints, but perhaps it didn't have 16839d44f7fSKyle Evans * the hint we are looking for. We don't provide any 16939d44f7fSKyle Evans * fallback when searching the dynamic environment. 17039d44f7fSKyle Evans */ 17139d44f7fSKyle Evans fallback: 17239d44f7fSKyle Evans if (dyn_used || fbacklvl >= FBACK_STATIC) 17339d44f7fSKyle Evans return (ENOENT); 17439d44f7fSKyle Evans 17539d44f7fSKyle Evans if (fbacklvl <= FBACK_MDENV && 17639d44f7fSKyle Evans _res_checkenv(md_envp)) { 17739d44f7fSKyle Evans hintp = md_envp; 17839d44f7fSKyle Evans goto found; 1798ef58863SKyle Evans } 18039d44f7fSKyle Evans fbacklvl++; 18139d44f7fSKyle Evans 18239d44f7fSKyle Evans if (fbacklvl <= FBACK_STENV && 18339d44f7fSKyle Evans _res_checkenv(kern_envp)) { 18439d44f7fSKyle Evans hintp = kern_envp; 18539d44f7fSKyle Evans goto found; 18639d44f7fSKyle Evans } 18739d44f7fSKyle Evans fbacklvl++; 18839d44f7fSKyle Evans 18939d44f7fSKyle Evans /* We'll fallback to static_hints if needed/can */ 19039d44f7fSKyle Evans if (fbacklvl <= FBACK_STATIC && 19139d44f7fSKyle Evans _res_checkenv(static_hints)) 1929516fbd6SPeter Wemm hintp = static_hints; 19339d44f7fSKyle Evans found: 19439d44f7fSKyle Evans fbacklvl++; 195d786139cSMaxime Henrion } 1969516fbd6SPeter Wemm 19739d44f7fSKyle Evans if (hintp == NULL) 19839d44f7fSKyle Evans return (ENOENT); 19939d44f7fSKyle Evans *hintp_cookie = hintp; 20039d44f7fSKyle Evans } else { 20139d44f7fSKyle Evans hintp = *hintp_cookie; 20239d44f7fSKyle Evans if (hintenv_merged && hintp == kenvp[0]) 203*dc4446dfSKyle Evans dyn_used = true; 20439d44f7fSKyle Evans else 20539d44f7fSKyle Evans /* 20639d44f7fSKyle Evans * If we aren't using the dynamic environment, we need 20739d44f7fSKyle Evans * to run through the proper fallback procedure again. 20839d44f7fSKyle Evans * This is so that we do continuations right if we're 20939d44f7fSKyle Evans * working with *line and *startln. 21039d44f7fSKyle Evans */ 21139d44f7fSKyle Evans goto fallback; 21239d44f7fSKyle Evans } 21339d44f7fSKyle Evans 21439d44f7fSKyle Evans if (dyn_used) { 215e3546a75SScott Long mtx_lock(&kenv_lock); 216d786139cSMaxime Henrion i = 0; 217d786139cSMaxime Henrion } 21839d44f7fSKyle Evans 2199516fbd6SPeter Wemm cp = hintp; 2202398f0cdSPeter Wemm while (cp) { 2212398f0cdSPeter Wemm (*line)++; 2222398f0cdSPeter Wemm if (strncmp(cp, "hint.", 5) != 0) 2235768da6cSKyle Evans goto nexthint; 2245768da6cSKyle Evans n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%127s", r_name, &r_unit, 2255768da6cSKyle Evans r_resname, r_value); 22639d44f7fSKyle Evans if (n != 4) { 2272398f0cdSPeter Wemm printf("CONFIG: invalid hint '%s'\n", cp); 228dc15eac0SEd Schouten p = strchr(cp, 'h'); 2292398f0cdSPeter Wemm *p = 'H'; 2305768da6cSKyle Evans goto nexthint; 2312398f0cdSPeter Wemm } 2325768da6cSKyle Evans if (startln && *startln >= 0 && *line < *startln) 2335768da6cSKyle Evans goto nexthint; 2345768da6cSKyle Evans if (name && strcmp(name, r_name) != 0) 2355768da6cSKyle Evans goto nexthint; 2365768da6cSKyle Evans if (unit && *unit != r_unit) 2375768da6cSKyle Evans goto nexthint; 2385768da6cSKyle Evans if (resname && strcmp(resname, r_resname) != 0) 2395768da6cSKyle Evans goto nexthint; 2405768da6cSKyle Evans if (value && strcmp(value, r_value) != 0) 2415768da6cSKyle Evans goto nexthint; 2425768da6cSKyle Evans /* Successfully found a hint matching all criteria */ 2432398f0cdSPeter Wemm break; 2445768da6cSKyle Evans nexthint: 24539d44f7fSKyle Evans if (dyn_used) { 246d786139cSMaxime Henrion cp = kenvp[++i]; 2474f033348SPeter Wemm if (cp == NULL) 2484f033348SPeter Wemm break; 2494f033348SPeter Wemm } else { 2502398f0cdSPeter Wemm while (*cp != '\0') 2512398f0cdSPeter Wemm cp++; 2522398f0cdSPeter Wemm cp++; 2532398f0cdSPeter Wemm if (*cp == '\0') { 2542398f0cdSPeter Wemm cp = NULL; 2552398f0cdSPeter Wemm break; 2562398f0cdSPeter Wemm } 2572398f0cdSPeter Wemm } 2584f033348SPeter Wemm } 25939d44f7fSKyle Evans if (dyn_used) 260e3546a75SScott Long mtx_unlock(&kenv_lock); 2612398f0cdSPeter Wemm if (cp == NULL) 26239d44f7fSKyle Evans goto fallback; 2632398f0cdSPeter Wemm 2642398f0cdSPeter Wemm s = cp; 2652398f0cdSPeter Wemm /* This is a bit of a hack, but at least is reentrant */ 2662398f0cdSPeter Wemm /* Note that it returns some !unterminated! strings. */ 267dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of device */ 2682398f0cdSPeter Wemm if (ret_name) 2692398f0cdSPeter Wemm *ret_name = s; 270dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of unit */ 27185c36f3dSJohn Baldwin if (ret_namelen && ret_name) 2722398f0cdSPeter Wemm *ret_namelen = s - *ret_name - 1; /* device length */ 2732398f0cdSPeter Wemm if (ret_unit) 2742398f0cdSPeter Wemm *ret_unit = r_unit; 275dc15eac0SEd Schouten s = strchr(s, '.') + 1; /* start of resname */ 2762398f0cdSPeter Wemm if (ret_resname) 2772398f0cdSPeter Wemm *ret_resname = s; 278dc15eac0SEd Schouten s = strchr(s, '=') + 1; /* start of value */ 27985c36f3dSJohn Baldwin if (ret_resnamelen && ret_resname) 2802398f0cdSPeter Wemm *ret_resnamelen = s - *ret_resname - 1; /* value len */ 2812398f0cdSPeter Wemm if (ret_value) 2822398f0cdSPeter Wemm *ret_value = s; 2832398f0cdSPeter Wemm if (startln) /* line number for anchor */ 2842398f0cdSPeter Wemm *startln = *line + 1; 2852398f0cdSPeter Wemm return 0; 2862398f0cdSPeter Wemm } 2872398f0cdSPeter Wemm 2882398f0cdSPeter Wemm /* 2892398f0cdSPeter Wemm * Search all the data sources for matches to our query. We look for 2902398f0cdSPeter Wemm * dynamic hints first as overrides for static or fallback hints. 2912398f0cdSPeter Wemm */ 2922398f0cdSPeter Wemm static int 2932398f0cdSPeter Wemm resource_find(int *line, int *startln, 2942398f0cdSPeter Wemm const char *name, int *unit, const char *resname, const char *value, 2952398f0cdSPeter Wemm const char **ret_name, int *ret_namelen, int *ret_unit, 2962398f0cdSPeter Wemm const char **ret_resname, int *ret_resnamelen, const char **ret_value) 2972398f0cdSPeter Wemm { 2982398f0cdSPeter Wemm int i; 2992398f0cdSPeter Wemm int un; 30039d44f7fSKyle Evans char *hintp; 3012398f0cdSPeter Wemm 3022398f0cdSPeter Wemm *line = 0; 30339d44f7fSKyle Evans hintp = NULL; 3042398f0cdSPeter Wemm 3052398f0cdSPeter Wemm /* Search for exact unit matches first */ 30639d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, unit, resname, value, 3072398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3082398f0cdSPeter Wemm ret_value); 3092398f0cdSPeter Wemm if (i == 0) 3102398f0cdSPeter Wemm return 0; 3112398f0cdSPeter Wemm if (unit == NULL) 3122398f0cdSPeter Wemm return ENOENT; 3132398f0cdSPeter Wemm /* If we are still here, search for wildcard matches */ 3142398f0cdSPeter Wemm un = -1; 31539d44f7fSKyle Evans i = res_find(&hintp, line, startln, name, &un, resname, value, 3162398f0cdSPeter Wemm ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 3172398f0cdSPeter Wemm ret_value); 3182398f0cdSPeter Wemm if (i == 0) 3192398f0cdSPeter Wemm return 0; 3202398f0cdSPeter Wemm return ENOENT; 3212398f0cdSPeter Wemm } 3222398f0cdSPeter Wemm 3232398f0cdSPeter Wemm int 3242398f0cdSPeter Wemm resource_int_value(const char *name, int unit, const char *resname, int *result) 3252398f0cdSPeter Wemm { 3262398f0cdSPeter Wemm int error; 3272398f0cdSPeter Wemm const char *str; 3282398f0cdSPeter Wemm char *op; 3292398f0cdSPeter Wemm unsigned long val; 3302398f0cdSPeter Wemm int line; 3312398f0cdSPeter Wemm 3322398f0cdSPeter Wemm line = 0; 3332398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3342398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3352398f0cdSPeter Wemm if (error) 3362398f0cdSPeter Wemm return error; 3372398f0cdSPeter Wemm if (*str == '\0') 3382398f0cdSPeter Wemm return EFTYPE; 3392398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3402398f0cdSPeter Wemm if (*op != '\0') 3412398f0cdSPeter Wemm return EFTYPE; 3422398f0cdSPeter Wemm *result = val; 3432398f0cdSPeter Wemm return 0; 3442398f0cdSPeter Wemm } 3452398f0cdSPeter Wemm 3462398f0cdSPeter Wemm int 3472398f0cdSPeter Wemm resource_long_value(const char *name, int unit, const char *resname, 3482398f0cdSPeter Wemm long *result) 3492398f0cdSPeter Wemm { 3502398f0cdSPeter Wemm int error; 3512398f0cdSPeter Wemm const char *str; 3522398f0cdSPeter Wemm char *op; 3532398f0cdSPeter Wemm unsigned long val; 3542398f0cdSPeter Wemm int line; 3552398f0cdSPeter Wemm 3562398f0cdSPeter Wemm line = 0; 3572398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3582398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3592398f0cdSPeter Wemm if (error) 3602398f0cdSPeter Wemm return error; 3612398f0cdSPeter Wemm if (*str == '\0') 3622398f0cdSPeter Wemm return EFTYPE; 3632398f0cdSPeter Wemm val = strtoul(str, &op, 0); 3642398f0cdSPeter Wemm if (*op != '\0') 3652398f0cdSPeter Wemm return EFTYPE; 3662398f0cdSPeter Wemm *result = val; 3672398f0cdSPeter Wemm return 0; 3682398f0cdSPeter Wemm } 3692398f0cdSPeter Wemm 3702398f0cdSPeter Wemm int 3712398f0cdSPeter Wemm resource_string_value(const char *name, int unit, const char *resname, 3722398f0cdSPeter Wemm const char **result) 3732398f0cdSPeter Wemm { 3742398f0cdSPeter Wemm int error; 3752398f0cdSPeter Wemm const char *str; 3762398f0cdSPeter Wemm int line; 3772398f0cdSPeter Wemm 3782398f0cdSPeter Wemm line = 0; 3792398f0cdSPeter Wemm error = resource_find(&line, NULL, name, &unit, resname, NULL, 3802398f0cdSPeter Wemm NULL, NULL, NULL, NULL, NULL, &str); 3812398f0cdSPeter Wemm if (error) 3822398f0cdSPeter Wemm return error; 3832398f0cdSPeter Wemm *result = str; 3842398f0cdSPeter Wemm return 0; 3852398f0cdSPeter Wemm } 3862398f0cdSPeter Wemm 3872398f0cdSPeter Wemm /* 3882398f0cdSPeter Wemm * This is a bit nasty, but allows us to not modify the env strings. 3892398f0cdSPeter Wemm */ 3902398f0cdSPeter Wemm static const char * 3912398f0cdSPeter Wemm resource_string_copy(const char *s, int len) 3922398f0cdSPeter Wemm { 3932398f0cdSPeter Wemm static char stringbuf[256]; 3942398f0cdSPeter Wemm static int offset = 0; 3952398f0cdSPeter Wemm const char *ret; 3962398f0cdSPeter Wemm 3972398f0cdSPeter Wemm if (len == 0) 3982398f0cdSPeter Wemm len = strlen(s); 3992398f0cdSPeter Wemm if (len > 255) 4002398f0cdSPeter Wemm return NULL; 4012398f0cdSPeter Wemm if ((offset + len + 1) > 255) 4022398f0cdSPeter Wemm offset = 0; 4032398f0cdSPeter Wemm bcopy(s, &stringbuf[offset], len); 4042398f0cdSPeter Wemm stringbuf[offset + len] = '\0'; 4052398f0cdSPeter Wemm ret = &stringbuf[offset]; 4062398f0cdSPeter Wemm offset += len + 1; 4072398f0cdSPeter Wemm return ret; 4082398f0cdSPeter Wemm } 4092398f0cdSPeter Wemm 4102398f0cdSPeter Wemm /* 41174e62047SJohn-Mark Gurney * err = resource_find_match(&anchor, &name, &unit, resname, value) 4122398f0cdSPeter Wemm * Iteratively fetch a list of devices wired "at" something 4132398f0cdSPeter Wemm * res and value are restrictions. eg: "at", "scbus0". 4142398f0cdSPeter Wemm * For practical purposes, res = required, value = optional. 4152398f0cdSPeter Wemm * *name and *unit are set. 4162398f0cdSPeter Wemm * set *anchor to zero before starting. 4172398f0cdSPeter Wemm */ 4182398f0cdSPeter Wemm int 4192398f0cdSPeter Wemm resource_find_match(int *anchor, const char **name, int *unit, 4202398f0cdSPeter Wemm const char *resname, const char *value) 4212398f0cdSPeter Wemm { 4222398f0cdSPeter Wemm const char *found_name; 4232398f0cdSPeter Wemm int found_namelen; 4242398f0cdSPeter Wemm int found_unit; 4252398f0cdSPeter Wemm int ret; 4262398f0cdSPeter Wemm int newln; 4272398f0cdSPeter Wemm 4282398f0cdSPeter Wemm newln = *anchor; 4292398f0cdSPeter Wemm ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 4302398f0cdSPeter Wemm &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 4312398f0cdSPeter Wemm if (ret == 0) { 4322398f0cdSPeter Wemm *name = resource_string_copy(found_name, found_namelen); 4332398f0cdSPeter Wemm *unit = found_unit; 4342398f0cdSPeter Wemm } 4352398f0cdSPeter Wemm *anchor = newln; 4362398f0cdSPeter Wemm return ret; 4372398f0cdSPeter Wemm } 4382398f0cdSPeter Wemm 4392398f0cdSPeter Wemm 4402398f0cdSPeter Wemm /* 4412398f0cdSPeter Wemm * err = resource_find_dev(&anchor, name, &unit, res, value); 4422398f0cdSPeter Wemm * Iterate through a list of devices, returning their unit numbers. 4432398f0cdSPeter Wemm * res and value are optional restrictions. eg: "at", "scbus0". 4442398f0cdSPeter Wemm * *unit is set to the value. 4452398f0cdSPeter Wemm * set *anchor to zero before starting. 4462398f0cdSPeter Wemm */ 4472398f0cdSPeter Wemm int 4482398f0cdSPeter Wemm resource_find_dev(int *anchor, const char *name, int *unit, 4492398f0cdSPeter Wemm const char *resname, const char *value) 4502398f0cdSPeter Wemm { 4512398f0cdSPeter Wemm int found_unit; 4522398f0cdSPeter Wemm int newln; 4532398f0cdSPeter Wemm int ret; 4542398f0cdSPeter Wemm 4552398f0cdSPeter Wemm newln = *anchor; 4562398f0cdSPeter Wemm ret = resource_find(anchor, &newln, name, NULL, resname, value, 4572398f0cdSPeter Wemm NULL, NULL, &found_unit, NULL, NULL, NULL); 4582398f0cdSPeter Wemm if (ret == 0) { 4592398f0cdSPeter Wemm *unit = found_unit; 4602398f0cdSPeter Wemm } 4612398f0cdSPeter Wemm *anchor = newln; 4622398f0cdSPeter Wemm return ret; 4632398f0cdSPeter Wemm } 4646591b310SJohn Baldwin 4656591b310SJohn Baldwin /* 4666591b310SJohn Baldwin * Check to see if a device is disabled via a disabled hint. 4676591b310SJohn Baldwin */ 4686591b310SJohn Baldwin int 4696591b310SJohn Baldwin resource_disabled(const char *name, int unit) 4706591b310SJohn Baldwin { 4716591b310SJohn Baldwin int error, value; 4726591b310SJohn Baldwin 4736591b310SJohn Baldwin error = resource_int_value(name, unit, "disabled", &value); 4746591b310SJohn Baldwin if (error) 4756591b310SJohn Baldwin return (0); 4766591b310SJohn Baldwin return (value); 4776591b310SJohn Baldwin } 47864de8019SJohn Baldwin 47964de8019SJohn Baldwin /* 48064de8019SJohn Baldwin * Clear a value associated with a device by removing it from 48164de8019SJohn Baldwin * the kernel environment. This only removes a hint for an 48264de8019SJohn Baldwin * exact unit. 48364de8019SJohn Baldwin */ 48464de8019SJohn Baldwin int 48564de8019SJohn Baldwin resource_unset_value(const char *name, int unit, const char *resname) 48664de8019SJohn Baldwin { 48764de8019SJohn Baldwin char varname[128]; 48864de8019SJohn Baldwin const char *retname, *retvalue; 48964de8019SJohn Baldwin int error, line; 49064de8019SJohn Baldwin size_t len; 49164de8019SJohn Baldwin 49264de8019SJohn Baldwin line = 0; 49364de8019SJohn Baldwin error = resource_find(&line, NULL, name, &unit, resname, NULL, 49464de8019SJohn Baldwin &retname, NULL, NULL, NULL, NULL, &retvalue); 49564de8019SJohn Baldwin if (error) 49664de8019SJohn Baldwin return (error); 49764de8019SJohn Baldwin 49864de8019SJohn Baldwin retname -= strlen("hint."); 49964de8019SJohn Baldwin len = retvalue - retname - 1; 50064de8019SJohn Baldwin if (len > sizeof(varname) - 1) 50164de8019SJohn Baldwin return (ENAMETOOLONG); 50264de8019SJohn Baldwin memcpy(varname, retname, len); 50364de8019SJohn Baldwin varname[len] = '\0'; 50464de8019SJohn Baldwin return (kern_unsetenv(varname)); 50564de8019SJohn Baldwin } 506