subr_hints.c revision 143386
178135Speter/*- 278135Speter * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org> 378135Speter * All rights reserved. 478135Speter * 578135Speter * Redistribution and use in source and binary forms, with or without 678135Speter * modification, are permitted provided that the following conditions 778135Speter * are met: 878135Speter * 1. Redistributions of source code must retain the above copyright 978135Speter * notice, this list of conditions and the following disclaimer. 1078135Speter * 2. Redistributions in binary form must reproduce the above copyright 1178135Speter * notice, this list of conditions and the following disclaimer in the 1278135Speter * documentation and/or other materials provided with the distribution. 1378135Speter * 1478135Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1578135Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1678135Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1778135Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1878135Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1978135Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2078135Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2178135Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2278135Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2378135Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2478135Speter * SUCH DAMAGE. 2578135Speter */ 2678135Speter 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/subr_hints.c 143386 2005-03-10 21:23:06Z jmg $"); 29116182Sobrien 3078135Speter#include <sys/param.h> 3194936Smux#include <sys/lock.h> 3294936Smux#include <sys/sx.h> 3378135Speter#include <sys/systm.h> 3478135Speter#include <sys/bus.h> 3578135Speter 3678135Speter/* 3778135Speter * Access functions for device resources. 3878135Speter */ 3978135Speter 4094936Smuxstatic int checkmethod = 1; 4195593Speterstatic int use_kenv; 4279696Speterstatic char *hintp; 4378135Speter 4478135Speter/* 4578135Speter * Evil wildcarding resource string lookup. 4678135Speter * This walks the supplied env string table and returns a match. 4778135Speter * The start point can be remembered for incremental searches. 4878135Speter */ 4978135Speterstatic int 5079696Speterres_find(int *line, int *startln, 5178135Speter const char *name, int *unit, const char *resname, const char *value, 5278135Speter const char **ret_name, int *ret_namelen, int *ret_unit, 5378135Speter const char **ret_resname, int *ret_resnamelen, const char **ret_value) 5478135Speter{ 5595593Speter int n = 0, hit, i = 0; 5678135Speter char r_name[32]; 5778135Speter int r_unit; 5878135Speter char r_resname[32]; 5978135Speter char r_value[128]; 6079696Speter const char *s, *cp; 6178135Speter char *p; 6278135Speter 6394936Smux if (checkmethod) { 6479696Speter switch (hintmode) { 6595839Speter case 0: /* loader hints in environment only */ 6679696Speter break; 6779696Speter case 1: /* static hints only */ 6879696Speter hintp = static_hints; 6994936Smux checkmethod = 0; 7079696Speter break; 7179696Speter case 2: /* fallback mode */ 7294936Smux if (dynamic_kenv) { 7394936Smux sx_slock(&kenv_lock); 7494936Smux cp = kenvp[0]; 7594936Smux for (i = 0; cp != NULL; cp = kenvp[++i]) { 7694936Smux if (!strncmp(cp, "hint.", 5)) { 7794936Smux use_kenv = 1; 7894936Smux checkmethod = 0; 7994936Smux break; 8094936Smux } 8179696Speter } 8294936Smux sx_sunlock(&kenv_lock); 8394936Smux } else { 8494936Smux cp = kern_envp; 8594936Smux while (cp) { 8694936Smux if (strncmp(cp, "hint.", 5) == 0) { 8794936Smux cp = NULL; 8894936Smux hintp = kern_envp; 8994936Smux break; 9094936Smux } 9194936Smux while (*cp != '\0') 9294936Smux cp++; 9379696Speter cp++; 9494936Smux if (*cp == '\0') { 9594936Smux cp = NULL; 9694936Smux hintp = static_hints; 9794936Smux break; 9894936Smux } 9979696Speter } 10079696Speter } 10179696Speter break; 10279696Speter default: 10379696Speter break; 10479696Speter } 10594936Smux if (hintp == NULL) { 10694936Smux if (dynamic_kenv) { 10794936Smux use_kenv = 1; 10894936Smux checkmethod = 0; 10994936Smux } else 11094936Smux hintp = kern_envp; 11194936Smux } 11279696Speter } 11379696Speter 11494936Smux if (use_kenv) { 11594936Smux sx_slock(&kenv_lock); 11694936Smux i = 0; 11794936Smux cp = kenvp[0]; 11894936Smux if (cp == NULL) { 11994936Smux sx_sunlock(&kenv_lock); 12094936Smux return (ENOENT); 12194936Smux } 12295839Speter } else 12394936Smux cp = hintp; 12478135Speter while (cp) { 12578135Speter hit = 1; 12678135Speter (*line)++; 12778135Speter if (strncmp(cp, "hint.", 5) != 0) 12878135Speter hit = 0; 12978135Speter else 13078135Speter n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s", 13178135Speter r_name, &r_unit, r_resname, r_value); 13278135Speter if (hit && n != 4) { 13378135Speter printf("CONFIG: invalid hint '%s'\n", cp); 13478135Speter /* XXX: abuse bogus index() declaration */ 13578135Speter p = index(cp, 'h'); 13678135Speter *p = 'H'; 13778135Speter hit = 0; 13878135Speter } 13978135Speter if (hit && startln && *startln >= 0 && *line < *startln) 14078135Speter hit = 0; 14178135Speter if (hit && name && strcmp(name, r_name) != 0) 14278135Speter hit = 0; 14378135Speter if (hit && unit && *unit != r_unit) 14478135Speter hit = 0; 14578135Speter if (hit && resname && strcmp(resname, r_resname) != 0) 14678135Speter hit = 0; 14778135Speter if (hit && value && strcmp(value, r_value) != 0) 14878135Speter hit = 0; 14978135Speter if (hit) 15078135Speter break; 15195593Speter if (use_kenv) { 15294936Smux cp = kenvp[++i]; 15395593Speter if (cp == NULL) 15495593Speter break; 15595593Speter } else { 15695592Speter while (*cp != '\0') 15795592Speter cp++; 15878135Speter cp++; 15995593Speter if (*cp == '\0') { 16095593Speter cp = NULL; 16195593Speter break; 16295593Speter } 16395592Speter } 16478135Speter } 16594936Smux if (use_kenv) 16694936Smux sx_sunlock(&kenv_lock); 16778135Speter if (cp == NULL) 16878135Speter return ENOENT; 16978135Speter 17078135Speter s = cp; 17178135Speter /* This is a bit of a hack, but at least is reentrant */ 17278135Speter /* Note that it returns some !unterminated! strings. */ 17378135Speter s = index(s, '.') + 1; /* start of device */ 17478135Speter if (ret_name) 17578135Speter *ret_name = s; 17678135Speter s = index(s, '.') + 1; /* start of unit */ 17778135Speter if (ret_namelen) 17878135Speter *ret_namelen = s - *ret_name - 1; /* device length */ 17978135Speter if (ret_unit) 18078135Speter *ret_unit = r_unit; 18178135Speter s = index(s, '.') + 1; /* start of resname */ 18278135Speter if (ret_resname) 18378135Speter *ret_resname = s; 18478135Speter s = index(s, '=') + 1; /* start of value */ 18578135Speter if (ret_resnamelen) 18678135Speter *ret_resnamelen = s - *ret_resname - 1; /* value len */ 18778135Speter if (ret_value) 18878135Speter *ret_value = s; 18978135Speter if (startln) /* line number for anchor */ 19078135Speter *startln = *line + 1; 19178135Speter return 0; 19278135Speter} 19378135Speter 19478135Speter/* 19578135Speter * Search all the data sources for matches to our query. We look for 19678135Speter * dynamic hints first as overrides for static or fallback hints. 19778135Speter */ 19878135Speterstatic int 19978135Speterresource_find(int *line, int *startln, 20078135Speter const char *name, int *unit, const char *resname, const char *value, 20178135Speter const char **ret_name, int *ret_namelen, int *ret_unit, 20278135Speter const char **ret_resname, int *ret_resnamelen, const char **ret_value) 20378135Speter{ 20478135Speter int i; 20578135Speter int un; 20678135Speter 20778135Speter *line = 0; 20878135Speter 20978135Speter /* Search for exact unit matches first */ 21079696Speter i = res_find(line, startln, name, unit, resname, value, 21178135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 21278135Speter ret_value); 21378135Speter if (i == 0) 21478135Speter return 0; 21578135Speter if (unit == NULL) 21678135Speter return ENOENT; 21778135Speter /* If we are still here, search for wildcard matches */ 21878135Speter un = -1; 21979696Speter i = res_find(line, startln, name, &un, resname, value, 22078135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 22178135Speter ret_value); 22278135Speter if (i == 0) 22378135Speter return 0; 22478135Speter return ENOENT; 22578135Speter} 22678135Speter 22778135Speterint 22878135Speterresource_int_value(const char *name, int unit, const char *resname, int *result) 22978135Speter{ 23078135Speter int error; 23178135Speter const char *str; 23278135Speter char *op; 23378135Speter unsigned long val; 23478135Speter int line; 23578135Speter 23678135Speter line = 0; 23778135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 23878135Speter NULL, NULL, NULL, NULL, NULL, &str); 23978135Speter if (error) 24078135Speter return error; 24178135Speter if (*str == '\0') 24278135Speter return EFTYPE; 24378135Speter val = strtoul(str, &op, 0); 24478135Speter if (*op != '\0') 24578135Speter return EFTYPE; 24678135Speter *result = val; 24778135Speter return 0; 24878135Speter} 24978135Speter 25078135Speterint 25178135Speterresource_long_value(const char *name, int unit, const char *resname, 25278135Speter long *result) 25378135Speter{ 25478135Speter int error; 25578135Speter const char *str; 25678135Speter char *op; 25778135Speter unsigned long val; 25878135Speter int line; 25978135Speter 26078135Speter line = 0; 26178135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 26278135Speter NULL, NULL, NULL, NULL, NULL, &str); 26378135Speter if (error) 26478135Speter return error; 26578135Speter if (*str == '\0') 26678135Speter return EFTYPE; 26778135Speter val = strtoul(str, &op, 0); 26878135Speter if (*op != '\0') 26978135Speter return EFTYPE; 27078135Speter *result = val; 27178135Speter return 0; 27278135Speter} 27378135Speter 27478135Speterint 27578135Speterresource_string_value(const char *name, int unit, const char *resname, 27678135Speter const char **result) 27778135Speter{ 27878135Speter int error; 27978135Speter const char *str; 28078135Speter int line; 28178135Speter 28278135Speter line = 0; 28378135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 28478135Speter NULL, NULL, NULL, NULL, NULL, &str); 28578135Speter if (error) 28678135Speter return error; 28778135Speter *result = str; 28878135Speter return 0; 28978135Speter} 29078135Speter 29178135Speter/* 29278135Speter * This is a bit nasty, but allows us to not modify the env strings. 29378135Speter */ 29478135Speterstatic const char * 29578135Speterresource_string_copy(const char *s, int len) 29678135Speter{ 29778135Speter static char stringbuf[256]; 29878135Speter static int offset = 0; 29978135Speter const char *ret; 30078135Speter 30178135Speter if (len == 0) 30278135Speter len = strlen(s); 30378135Speter if (len > 255) 30478135Speter return NULL; 30578135Speter if ((offset + len + 1) > 255) 30678135Speter offset = 0; 30778135Speter bcopy(s, &stringbuf[offset], len); 30878135Speter stringbuf[offset + len] = '\0'; 30978135Speter ret = &stringbuf[offset]; 31078135Speter offset += len + 1; 31178135Speter return ret; 31278135Speter} 31378135Speter 31478135Speter/* 315143386Sjmg * err = resource_find_match(&anchor, &name, &unit, resname, value) 31678135Speter * Iteratively fetch a list of devices wired "at" something 31778135Speter * res and value are restrictions. eg: "at", "scbus0". 31878135Speter * For practical purposes, res = required, value = optional. 31978135Speter * *name and *unit are set. 32078135Speter * set *anchor to zero before starting. 32178135Speter */ 32278135Speterint 32378135Speterresource_find_match(int *anchor, const char **name, int *unit, 32478135Speter const char *resname, const char *value) 32578135Speter{ 32678135Speter const char *found_name; 32778135Speter int found_namelen; 32878135Speter int found_unit; 32978135Speter int ret; 33078135Speter int newln; 33178135Speter 33278135Speter newln = *anchor; 33378135Speter ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 33478135Speter &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 33578135Speter if (ret == 0) { 33678135Speter *name = resource_string_copy(found_name, found_namelen); 33778135Speter *unit = found_unit; 33878135Speter } 33978135Speter *anchor = newln; 34078135Speter return ret; 34178135Speter} 34278135Speter 34378135Speter 34478135Speter/* 34578135Speter * err = resource_find_dev(&anchor, name, &unit, res, value); 34678135Speter * Iterate through a list of devices, returning their unit numbers. 34778135Speter * res and value are optional restrictions. eg: "at", "scbus0". 34878135Speter * *unit is set to the value. 34978135Speter * set *anchor to zero before starting. 35078135Speter */ 35178135Speterint 35278135Speterresource_find_dev(int *anchor, const char *name, int *unit, 35378135Speter const char *resname, const char *value) 35478135Speter{ 35578135Speter int found_unit; 35678135Speter int newln; 35778135Speter int ret; 35878135Speter 35978135Speter newln = *anchor; 36078135Speter ret = resource_find(anchor, &newln, name, NULL, resname, value, 36178135Speter NULL, NULL, &found_unit, NULL, NULL, NULL); 36278135Speter if (ret == 0) { 36378135Speter *unit = found_unit; 36478135Speter } 36578135Speter *anchor = newln; 36678135Speter return ret; 36778135Speter} 368117166Sjhb 369117166Sjhb/* 370117166Sjhb * Check to see if a device is disabled via a disabled hint. 371117166Sjhb */ 372117166Sjhbint 373117166Sjhbresource_disabled(const char *name, int unit) 374117166Sjhb{ 375117166Sjhb int error, value; 376117166Sjhb 377117166Sjhb error = resource_int_value(name, unit, "disabled", &value); 378117166Sjhb if (error) 379117166Sjhb return (0); 380117166Sjhb return (value); 381117166Sjhb} 382