subr_hints.c revision 95592
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 * $FreeBSD: head/sys/kern/subr_hints.c 95592 2002-04-27 22:25:13Z peter $ 2778135Speter */ 2878135Speter 2978135Speter#include <sys/param.h> 3094936Smux#include <sys/lock.h> 3194936Smux#include <sys/sx.h> 3278135Speter#include <sys/systm.h> 3378135Speter#include <sys/bus.h> 3478135Speter 3578135Speter/* 3678135Speter * Access functions for device resources. 3778135Speter */ 3878135Speter 3994936Smuxstatic int checkmethod = 1; 4079696Speterstatic char *hintp; 4178135Speter 4278135Speter/* 4378135Speter * Evil wildcarding resource string lookup. 4478135Speter * This walks the supplied env string table and returns a match. 4578135Speter * The start point can be remembered for incremental searches. 4678135Speter */ 4778135Speterstatic int 4879696Speterres_find(int *line, int *startln, 4978135Speter const char *name, int *unit, const char *resname, const char *value, 5078135Speter const char **ret_name, int *ret_namelen, int *ret_unit, 5178135Speter const char **ret_resname, int *ret_resnamelen, const char **ret_value) 5278135Speter{ 5394936Smux int n = 0, hit, use_kenv, i = 0; 5478135Speter char r_name[32]; 5578135Speter int r_unit; 5678135Speter char r_resname[32]; 5778135Speter char r_value[128]; 5879696Speter const char *s, *cp; 5978135Speter char *p; 6078135Speter 6194936Smux use_kenv = 0; 6294936Smux if (checkmethod) { 6379696Speter switch (hintmode) { 6479696Speter case 0: /* config supplied nothing */ 6579696Speter break; 6679696Speter case 1: /* static hints only */ 6779696Speter hintp = static_hints; 6894936Smux checkmethod = 0; 6979696Speter break; 7079696Speter case 2: /* fallback mode */ 7194936Smux if (dynamic_kenv) { 7294936Smux sx_slock(&kenv_lock); 7394936Smux cp = kenvp[0]; 7494936Smux for (i = 0; cp != NULL; cp = kenvp[++i]) { 7594936Smux if (!strncmp(cp, "hint.", 5)) { 7694936Smux use_kenv = 1; 7794936Smux checkmethod = 0; 7894936Smux break; 7994936Smux } 8079696Speter } 8194936Smux sx_sunlock(&kenv_lock); 8294936Smux } else { 8394936Smux cp = kern_envp; 8494936Smux while (cp) { 8594936Smux if (strncmp(cp, "hint.", 5) == 0) { 8694936Smux cp = NULL; 8794936Smux hintp = kern_envp; 8894936Smux break; 8994936Smux } 9094936Smux while (*cp != '\0') 9194936Smux cp++; 9279696Speter cp++; 9394936Smux if (*cp == '\0') { 9494936Smux cp = NULL; 9594936Smux hintp = static_hints; 9694936Smux break; 9794936Smux } 9879696Speter } 9979696Speter } 10079696Speter break; 10179696Speter default: 10279696Speter break; 10379696Speter } 10494936Smux if (hintp == NULL) { 10594936Smux if (dynamic_kenv) { 10694936Smux use_kenv = 1; 10794936Smux checkmethod = 0; 10894936Smux } else 10994936Smux hintp = kern_envp; 11094936Smux } 11179696Speter } 11279696Speter 11394936Smux if (use_kenv) { 11494936Smux sx_slock(&kenv_lock); 11594936Smux i = 0; 11694936Smux cp = kenvp[0]; 11794936Smux if (cp == NULL) { 11894936Smux sx_sunlock(&kenv_lock); 11994936Smux return (ENOENT); 12094936Smux } 12194936Smux } else { 12294936Smux cp = hintp; 12394936Smux } 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; 15194936Smux if (use_kenv) 15294936Smux cp = kenvp[++i]; 15395592Speter else { 15495592Speter while (*cp != '\0') 15595592Speter cp++; 15678135Speter cp++; 15795592Speter } 15878135Speter if (*cp == '\0') { 15978135Speter cp = NULL; 16078135Speter break; 16178135Speter } 16278135Speter } 16394936Smux if (use_kenv) 16494936Smux sx_sunlock(&kenv_lock); 16578135Speter if (cp == NULL) 16678135Speter return ENOENT; 16778135Speter 16878135Speter s = cp; 16978135Speter /* This is a bit of a hack, but at least is reentrant */ 17078135Speter /* Note that it returns some !unterminated! strings. */ 17178135Speter s = index(s, '.') + 1; /* start of device */ 17278135Speter if (ret_name) 17378135Speter *ret_name = s; 17478135Speter s = index(s, '.') + 1; /* start of unit */ 17578135Speter if (ret_namelen) 17678135Speter *ret_namelen = s - *ret_name - 1; /* device length */ 17778135Speter if (ret_unit) 17878135Speter *ret_unit = r_unit; 17978135Speter s = index(s, '.') + 1; /* start of resname */ 18078135Speter if (ret_resname) 18178135Speter *ret_resname = s; 18278135Speter s = index(s, '=') + 1; /* start of value */ 18378135Speter if (ret_resnamelen) 18478135Speter *ret_resnamelen = s - *ret_resname - 1; /* value len */ 18578135Speter if (ret_value) 18678135Speter *ret_value = s; 18778135Speter if (startln) /* line number for anchor */ 18878135Speter *startln = *line + 1; 18978135Speter return 0; 19078135Speter} 19178135Speter 19278135Speter/* 19378135Speter * Search all the data sources for matches to our query. We look for 19478135Speter * dynamic hints first as overrides for static or fallback hints. 19578135Speter */ 19678135Speterstatic int 19778135Speterresource_find(int *line, int *startln, 19878135Speter const char *name, int *unit, const char *resname, const char *value, 19978135Speter const char **ret_name, int *ret_namelen, int *ret_unit, 20078135Speter const char **ret_resname, int *ret_resnamelen, const char **ret_value) 20178135Speter{ 20278135Speter int i; 20378135Speter int un; 20478135Speter 20578135Speter *line = 0; 20678135Speter 20778135Speter /* Search for exact unit matches first */ 20879696Speter i = res_find(line, startln, name, unit, resname, value, 20978135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 21078135Speter ret_value); 21178135Speter if (i == 0) 21278135Speter return 0; 21378135Speter if (unit == NULL) 21478135Speter return ENOENT; 21578135Speter /* If we are still here, search for wildcard matches */ 21678135Speter un = -1; 21779696Speter i = res_find(line, startln, name, &un, resname, value, 21878135Speter ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 21978135Speter ret_value); 22078135Speter if (i == 0) 22178135Speter return 0; 22278135Speter return ENOENT; 22378135Speter} 22478135Speter 22578135Speterint 22678135Speterresource_int_value(const char *name, int unit, const char *resname, int *result) 22778135Speter{ 22878135Speter int error; 22978135Speter const char *str; 23078135Speter char *op; 23178135Speter unsigned long val; 23278135Speter int line; 23378135Speter 23478135Speter line = 0; 23578135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 23678135Speter NULL, NULL, NULL, NULL, NULL, &str); 23778135Speter if (error) 23878135Speter return error; 23978135Speter if (*str == '\0') 24078135Speter return EFTYPE; 24178135Speter val = strtoul(str, &op, 0); 24278135Speter if (*op != '\0') 24378135Speter return EFTYPE; 24478135Speter *result = val; 24578135Speter return 0; 24678135Speter} 24778135Speter 24878135Speterint 24978135Speterresource_long_value(const char *name, int unit, const char *resname, 25078135Speter long *result) 25178135Speter{ 25278135Speter int error; 25378135Speter const char *str; 25478135Speter char *op; 25578135Speter unsigned long val; 25678135Speter int line; 25778135Speter 25878135Speter line = 0; 25978135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 26078135Speter NULL, NULL, NULL, NULL, NULL, &str); 26178135Speter if (error) 26278135Speter return error; 26378135Speter if (*str == '\0') 26478135Speter return EFTYPE; 26578135Speter val = strtoul(str, &op, 0); 26678135Speter if (*op != '\0') 26778135Speter return EFTYPE; 26878135Speter *result = val; 26978135Speter return 0; 27078135Speter} 27178135Speter 27278135Speterint 27378135Speterresource_string_value(const char *name, int unit, const char *resname, 27478135Speter const char **result) 27578135Speter{ 27678135Speter int error; 27778135Speter const char *str; 27878135Speter int line; 27978135Speter 28078135Speter line = 0; 28178135Speter error = resource_find(&line, NULL, name, &unit, resname, NULL, 28278135Speter NULL, NULL, NULL, NULL, NULL, &str); 28378135Speter if (error) 28478135Speter return error; 28578135Speter *result = str; 28678135Speter return 0; 28778135Speter} 28878135Speter 28978135Speter/* 29078135Speter * This is a bit nasty, but allows us to not modify the env strings. 29178135Speter */ 29278135Speterstatic const char * 29378135Speterresource_string_copy(const char *s, int len) 29478135Speter{ 29578135Speter static char stringbuf[256]; 29678135Speter static int offset = 0; 29778135Speter const char *ret; 29878135Speter 29978135Speter if (len == 0) 30078135Speter len = strlen(s); 30178135Speter if (len > 255) 30278135Speter return NULL; 30378135Speter if ((offset + len + 1) > 255) 30478135Speter offset = 0; 30578135Speter bcopy(s, &stringbuf[offset], len); 30678135Speter stringbuf[offset + len] = '\0'; 30778135Speter ret = &stringbuf[offset]; 30878135Speter offset += len + 1; 30978135Speter return ret; 31078135Speter} 31178135Speter 31278135Speter/* 31378135Speter * err = resource_find_at(&anchor, &name, &unit, resname, value) 31478135Speter * Iteratively fetch a list of devices wired "at" something 31578135Speter * res and value are restrictions. eg: "at", "scbus0". 31678135Speter * For practical purposes, res = required, value = optional. 31778135Speter * *name and *unit are set. 31878135Speter * set *anchor to zero before starting. 31978135Speter */ 32078135Speterint 32178135Speterresource_find_match(int *anchor, const char **name, int *unit, 32278135Speter const char *resname, const char *value) 32378135Speter{ 32478135Speter const char *found_name; 32578135Speter int found_namelen; 32678135Speter int found_unit; 32778135Speter int ret; 32878135Speter int newln; 32978135Speter 33078135Speter newln = *anchor; 33178135Speter ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 33278135Speter &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 33378135Speter if (ret == 0) { 33478135Speter *name = resource_string_copy(found_name, found_namelen); 33578135Speter *unit = found_unit; 33678135Speter } 33778135Speter *anchor = newln; 33878135Speter return ret; 33978135Speter} 34078135Speter 34178135Speter 34278135Speter/* 34378135Speter * err = resource_find_dev(&anchor, name, &unit, res, value); 34478135Speter * Iterate through a list of devices, returning their unit numbers. 34578135Speter * res and value are optional restrictions. eg: "at", "scbus0". 34678135Speter * *unit is set to the value. 34778135Speter * set *anchor to zero before starting. 34878135Speter */ 34978135Speterint 35078135Speterresource_find_dev(int *anchor, const char *name, int *unit, 35178135Speter const char *resname, const char *value) 35278135Speter{ 35378135Speter int found_unit; 35478135Speter int newln; 35578135Speter int ret; 35678135Speter 35778135Speter newln = *anchor; 35878135Speter ret = resource_find(anchor, &newln, name, NULL, resname, value, 35978135Speter NULL, NULL, &found_unit, NULL, NULL, NULL); 36078135Speter if (ret == 0) { 36178135Speter *unit = found_unit; 36278135Speter } 36378135Speter *anchor = newln; 36478135Speter return ret; 36578135Speter} 366