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$"); 29116182Sobrien 3078135Speter#include <sys/param.h> 3194936Smux#include <sys/lock.h> 32160217Sscottl#include <sys/mutex.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) { 64148586Snetchild hintp = NULL; 65148586Snetchild 6679696Speter switch (hintmode) { 6795839Speter case 0: /* loader hints in environment only */ 6879696Speter break; 6979696Speter case 1: /* static hints only */ 7079696Speter hintp = static_hints; 7194936Smux checkmethod = 0; 7279696Speter break; 7379696Speter case 2: /* fallback mode */ 7494936Smux if (dynamic_kenv) { 75160217Sscottl mtx_lock(&kenv_lock); 7694936Smux cp = kenvp[0]; 7794936Smux for (i = 0; cp != NULL; cp = kenvp[++i]) { 7894936Smux if (!strncmp(cp, "hint.", 5)) { 7994936Smux use_kenv = 1; 8094936Smux checkmethod = 0; 8194936Smux break; 8294936Smux } 8379696Speter } 84160217Sscottl mtx_unlock(&kenv_lock); 8594936Smux } else { 8694936Smux cp = kern_envp; 8794936Smux while (cp) { 8894936Smux if (strncmp(cp, "hint.", 5) == 0) { 8994936Smux cp = NULL; 9094936Smux hintp = kern_envp; 9194936Smux break; 9294936Smux } 9394936Smux while (*cp != '\0') 9494936Smux cp++; 9579696Speter cp++; 9694936Smux if (*cp == '\0') { 9794936Smux cp = NULL; 9894936Smux hintp = static_hints; 9994936Smux break; 10094936Smux } 10179696Speter } 10279696Speter } 10379696Speter break; 10479696Speter default: 10579696Speter break; 10679696Speter } 10794936Smux if (hintp == NULL) { 10894936Smux if (dynamic_kenv) { 10994936Smux use_kenv = 1; 11094936Smux checkmethod = 0; 11194936Smux } else 11294936Smux hintp = kern_envp; 11394936Smux } 11479696Speter } 11579696Speter 11694936Smux if (use_kenv) { 117160217Sscottl mtx_lock(&kenv_lock); 11894936Smux i = 0; 11994936Smux cp = kenvp[0]; 12094936Smux if (cp == NULL) { 121160217Sscottl mtx_unlock(&kenv_lock); 12294936Smux return (ENOENT); 12394936Smux } 12495839Speter } else 12594936Smux cp = hintp; 12678135Speter while (cp) { 12778135Speter hit = 1; 12878135Speter (*line)++; 12978135Speter if (strncmp(cp, "hint.", 5) != 0) 13078135Speter hit = 0; 13178135Speter else 13278135Speter n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s", 13378135Speter r_name, &r_unit, r_resname, r_value); 13478135Speter if (hit && n != 4) { 13578135Speter printf("CONFIG: invalid hint '%s'\n", cp); 13678135Speter /* XXX: abuse bogus index() declaration */ 13778135Speter p = index(cp, 'h'); 13878135Speter *p = 'H'; 13978135Speter hit = 0; 14078135Speter } 14178135Speter if (hit && startln && *startln >= 0 && *line < *startln) 14278135Speter hit = 0; 14378135Speter if (hit && name && strcmp(name, r_name) != 0) 14478135Speter hit = 0; 14578135Speter if (hit && unit && *unit != r_unit) 14678135Speter hit = 0; 14778135Speter if (hit && resname && strcmp(resname, r_resname) != 0) 14878135Speter hit = 0; 14978135Speter if (hit && value && strcmp(value, r_value) != 0) 15078135Speter hit = 0; 15178135Speter if (hit) 15278135Speter break; 15395593Speter if (use_kenv) { 15494936Smux cp = kenvp[++i]; 15595593Speter if (cp == NULL) 15695593Speter break; 15795593Speter } else { 15895592Speter while (*cp != '\0') 15995592Speter cp++; 16078135Speter cp++; 16195593Speter if (*cp == '\0') { 16295593Speter cp = NULL; 16395593Speter break; 16495593Speter } 16595592Speter } 16678135Speter } 16794936Smux if (use_kenv) 168160217Sscottl mtx_unlock(&kenv_lock); 16978135Speter if (cp == NULL) 17078135Speter return ENOENT; 17178135Speter 17278135Speter s = cp; 17378135Speter /* This is a bit of a hack, but at least is reentrant */ 17478135Speter /* Note that it returns some !unterminated! strings. */ 17578135Speter s = index(s, '.') + 1; /* start of device */ 17678135Speter if (ret_name) 17778135Speter *ret_name = s; 17878135Speter s = index(s, '.') + 1; /* start of unit */ 179144077Sjhb if (ret_namelen && ret_name) 18078135Speter *ret_namelen = s - *ret_name - 1; /* device length */ 18178135Speter if (ret_unit) 18278135Speter *ret_unit = r_unit; 18378135Speter s = index(s, '.') + 1; /* start of resname */ 18478135Speter if (ret_resname) 18578135Speter *ret_resname = s; 18678135Speter s = index(s, '=') + 1; /* start of value */ 187144077Sjhb if (ret_resnamelen && ret_resname) 18878135Speter *ret_resnamelen = s - *ret_resname - 1; /* value len */ 18978135Speter if (ret_value) 19078135Speter *ret_value = s; 19178135Speter if (startln) /* line number for anchor */ 19278135Speter *startln = *line + 1; 19378135Speter return 0; 19478135Speter} 19578135Speter 19678135Speter/* 19778135Speter * Search all the data sources for matches to our query. We look for 19878135Speter * dynamic hints first as overrides for static or fallback hints. 19978135Speter */ 20078135Speterstatic int 20178135Speterresource_find(int *line, int *startln, 20278135Speter const char *name, int *unit, const char *resname, const char *value, 20378135Speter const char **ret_name, int *ret_namelen, int *ret_unit, 20478135Speter const char **ret_resname, int *ret_resnamelen, const char **ret_value) 20578135Speter{ 20678135Speter int i; 20778135Speter int un; 20878135Speter 20978135Speter *line = 0; 21078135Speter 21178135Speter /* Search for exact unit matches first */ 21279696Speter i = res_find(line, startln, name, unit, resname, value, 21378135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 21478135Speter ret_value); 21578135Speter if (i == 0) 21678135Speter return 0; 21778135Speter if (unit == NULL) 21878135Speter return ENOENT; 21978135Speter /* If we are still here, search for wildcard matches */ 22078135Speter un = -1; 22179696Speter i = res_find(line, startln, name, &un, resname, value, 22278135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 22378135Speter ret_value); 22478135Speter if (i == 0) 22578135Speter return 0; 22678135Speter return ENOENT; 22778135Speter} 22878135Speter 22978135Speterint 23078135Speterresource_int_value(const char *name, int unit, const char *resname, int *result) 23178135Speter{ 23278135Speter int error; 23378135Speter const char *str; 23478135Speter char *op; 23578135Speter unsigned long val; 23678135Speter int line; 23778135Speter 23878135Speter line = 0; 23978135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 24078135Speter NULL, NULL, NULL, NULL, NULL, &str); 24178135Speter if (error) 24278135Speter return error; 24378135Speter if (*str == '\0') 24478135Speter return EFTYPE; 24578135Speter val = strtoul(str, &op, 0); 24678135Speter if (*op != '\0') 24778135Speter return EFTYPE; 24878135Speter *result = val; 24978135Speter return 0; 25078135Speter} 25178135Speter 25278135Speterint 25378135Speterresource_long_value(const char *name, int unit, const char *resname, 25478135Speter long *result) 25578135Speter{ 25678135Speter int error; 25778135Speter const char *str; 25878135Speter char *op; 25978135Speter unsigned long val; 26078135Speter int line; 26178135Speter 26278135Speter line = 0; 26378135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 26478135Speter NULL, NULL, NULL, NULL, NULL, &str); 26578135Speter if (error) 26678135Speter return error; 26778135Speter if (*str == '\0') 26878135Speter return EFTYPE; 26978135Speter val = strtoul(str, &op, 0); 27078135Speter if (*op != '\0') 27178135Speter return EFTYPE; 27278135Speter *result = val; 27378135Speter return 0; 27478135Speter} 27578135Speter 27678135Speterint 27778135Speterresource_string_value(const char *name, int unit, const char *resname, 27878135Speter const char **result) 27978135Speter{ 28078135Speter int error; 28178135Speter const char *str; 28278135Speter int line; 28378135Speter 28478135Speter line = 0; 28578135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 28678135Speter NULL, NULL, NULL, NULL, NULL, &str); 28778135Speter if (error) 28878135Speter return error; 28978135Speter *result = str; 29078135Speter return 0; 29178135Speter} 29278135Speter 29378135Speter/* 29478135Speter * This is a bit nasty, but allows us to not modify the env strings. 29578135Speter */ 29678135Speterstatic const char * 29778135Speterresource_string_copy(const char *s, int len) 29878135Speter{ 29978135Speter static char stringbuf[256]; 30078135Speter static int offset = 0; 30178135Speter const char *ret; 30278135Speter 30378135Speter if (len == 0) 30478135Speter len = strlen(s); 30578135Speter if (len > 255) 30678135Speter return NULL; 30778135Speter if ((offset + len + 1) > 255) 30878135Speter offset = 0; 30978135Speter bcopy(s, &stringbuf[offset], len); 31078135Speter stringbuf[offset + len] = '\0'; 31178135Speter ret = &stringbuf[offset]; 31278135Speter offset += len + 1; 31378135Speter return ret; 31478135Speter} 31578135Speter 31678135Speter/* 317143386Sjmg * err = resource_find_match(&anchor, &name, &unit, resname, value) 31878135Speter * Iteratively fetch a list of devices wired "at" something 31978135Speter * res and value are restrictions. eg: "at", "scbus0". 32078135Speter * For practical purposes, res = required, value = optional. 32178135Speter * *name and *unit are set. 32278135Speter * set *anchor to zero before starting. 32378135Speter */ 32478135Speterint 32578135Speterresource_find_match(int *anchor, const char **name, int *unit, 32678135Speter const char *resname, const char *value) 32778135Speter{ 32878135Speter const char *found_name; 32978135Speter int found_namelen; 33078135Speter int found_unit; 33178135Speter int ret; 33278135Speter int newln; 33378135Speter 33478135Speter newln = *anchor; 33578135Speter ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 33678135Speter &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 33778135Speter if (ret == 0) { 33878135Speter *name = resource_string_copy(found_name, found_namelen); 33978135Speter *unit = found_unit; 34078135Speter } 34178135Speter *anchor = newln; 34278135Speter return ret; 34378135Speter} 34478135Speter 34578135Speter 34678135Speter/* 34778135Speter * err = resource_find_dev(&anchor, name, &unit, res, value); 34878135Speter * Iterate through a list of devices, returning their unit numbers. 34978135Speter * res and value are optional restrictions. eg: "at", "scbus0". 35078135Speter * *unit is set to the value. 35178135Speter * set *anchor to zero before starting. 35278135Speter */ 35378135Speterint 35478135Speterresource_find_dev(int *anchor, const char *name, int *unit, 35578135Speter const char *resname, const char *value) 35678135Speter{ 35778135Speter int found_unit; 35878135Speter int newln; 35978135Speter int ret; 36078135Speter 36178135Speter newln = *anchor; 36278135Speter ret = resource_find(anchor, &newln, name, NULL, resname, value, 36378135Speter NULL, NULL, &found_unit, NULL, NULL, NULL); 36478135Speter if (ret == 0) { 36578135Speter *unit = found_unit; 36678135Speter } 36778135Speter *anchor = newln; 36878135Speter return ret; 36978135Speter} 370117166Sjhb 371117166Sjhb/* 372117166Sjhb * Check to see if a device is disabled via a disabled hint. 373117166Sjhb */ 374117166Sjhbint 375117166Sjhbresource_disabled(const char *name, int unit) 376117166Sjhb{ 377117166Sjhb int error, value; 378117166Sjhb 379117166Sjhb error = resource_int_value(name, unit, "disabled", &value); 380117166Sjhb if (error) 381117166Sjhb return (0); 382117166Sjhb return (value); 383117166Sjhb} 384