summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_hints.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2001-06-12 09:40:04 +0000
committerpeter <peter@FreeBSD.org>2001-06-12 09:40:04 +0000
commitbbbe8875f0844bdf4e10cbc01dc9c7f2a2c8368a (patch)
treeddf23af998adfeb85fbbf912b89e3fa83f84fd4b /sys/kern/subr_hints.c
parentb44fc46ed5521eb3028aafbc0c4aef220ed24141 (diff)
downloadFreeBSD-src-bbbe8875f0844bdf4e10cbc01dc9c7f2a2c8368a.zip
FreeBSD-src-bbbe8875f0844bdf4e10cbc01dc9c7f2a2c8368a.tar.gz
Hints overhaul:
- Replace some very poorly thought out API hacks that should have been fixed a long while ago. - Provide some much more flexible search functions (resource_find_*()) - Use strings for storage instead of an outgrowth of the rather inconvenient temporary ioconf table from config(). We already had a fallback to using strings before malloc/vm was running anyway.
Diffstat (limited to 'sys/kern/subr_hints.c')
-rw-r--r--sys/kern/subr_hints.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/sys/kern/subr_hints.c b/sys/kern/subr_hints.c
new file mode 100644
index 0000000..a201fa0
--- /dev/null
+++ b/sys/kern/subr_hints.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+/*
+ * Access functions for device resources.
+ */
+
+extern char static_hints[]; /* by config for now */
+
+/*
+ * Evil wildcarding resource string lookup.
+ * This walks the supplied env string table and returns a match.
+ * The start point can be remembered for incremental searches.
+ */
+static int
+res_find(const char *cp, int *line, int *startln,
+ const char *name, int *unit, const char *resname, const char *value,
+ const char **ret_name, int *ret_namelen, int *ret_unit,
+ const char **ret_resname, int *ret_resnamelen, const char **ret_value)
+{
+ int n = 0, hit;
+ char r_name[32];
+ int r_unit;
+ char r_resname[32];
+ char r_value[128];
+ const char *s;
+ char *p;
+
+ while (cp) {
+ hit = 1;
+ (*line)++;
+ if (strncmp(cp, "hint.", 5) != 0)
+ hit = 0;
+ else
+ n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
+ r_name, &r_unit, r_resname, r_value);
+ if (hit && n != 4) {
+ printf("CONFIG: invalid hint '%s'\n", cp);
+ /* XXX: abuse bogus index() declaration */
+ p = index(cp, 'h');
+ *p = 'H';
+ hit = 0;
+ }
+ if (hit && startln && *startln >= 0 && *line < *startln)
+ hit = 0;
+ if (hit && name && strcmp(name, r_name) != 0)
+ hit = 0;
+ if (hit && unit && *unit != r_unit)
+ hit = 0;
+ if (hit && resname && strcmp(resname, r_resname) != 0)
+ hit = 0;
+ if (hit && value && strcmp(value, r_value) != 0)
+ hit = 0;
+ if (hit)
+ break;
+ while (*cp != '\0')
+ cp++;
+ cp++;
+ if (*cp == '\0') {
+ cp = NULL;
+ break;
+ }
+ }
+ if (cp == NULL)
+ return ENOENT;
+
+ s = cp;
+ /* This is a bit of a hack, but at least is reentrant */
+ /* Note that it returns some !unterminated! strings. */
+ s = index(s, '.') + 1; /* start of device */
+ if (ret_name)
+ *ret_name = s;
+ s = index(s, '.') + 1; /* start of unit */
+ if (ret_namelen)
+ *ret_namelen = s - *ret_name - 1; /* device length */
+ if (ret_unit)
+ *ret_unit = r_unit;
+ s = index(s, '.') + 1; /* start of resname */
+ if (ret_resname)
+ *ret_resname = s;
+ s = index(s, '=') + 1; /* start of value */
+ if (ret_resnamelen)
+ *ret_resnamelen = s - *ret_resname - 1; /* value len */
+ if (ret_value)
+ *ret_value = s;
+ if (startln) /* line number for anchor */
+ *startln = *line + 1;
+ return 0;
+}
+
+/*
+ * Search all the data sources for matches to our query. We look for
+ * dynamic hints first as overrides for static or fallback hints.
+ */
+static int
+resource_find(int *line, int *startln,
+ const char *name, int *unit, const char *resname, const char *value,
+ const char **ret_name, int *ret_namelen, int *ret_unit,
+ const char **ret_resname, int *ret_resnamelen, const char **ret_value)
+{
+ int i;
+ int un;
+
+ *line = 0;
+
+ /* Search for exact unit matches first */
+ i = res_find(kern_envp, line, startln, name, unit, resname, value,
+ ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
+ ret_value);
+ if (i == 0)
+ return 0;
+ i = res_find(static_hints, line, startln, name, unit, resname, value,
+ ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
+ ret_value);
+ if (i == 0)
+ return 0;
+ if (unit == NULL)
+ return ENOENT;
+ /* If we are still here, search for wildcard matches */
+ un = -1;
+ i = res_find(kern_envp, line, startln, name, &un, resname, value,
+ ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
+ ret_value);
+ if (i == 0)
+ return 0;
+ un = -1;
+ i = res_find(static_hints, line, startln, name, &un, resname, value,
+ ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
+ ret_value);
+ if (i == 0)
+ return 0;
+ return ENOENT;
+}
+
+int
+resource_int_value(const char *name, int unit, const char *resname, int *result)
+{
+ int error;
+ const char *str;
+ char *op;
+ unsigned long val;
+ int line;
+
+ line = 0;
+ error = resource_find(&line, NULL, name, &unit, resname, NULL,
+ NULL, NULL, NULL, NULL, NULL, &str);
+ if (error)
+ return error;
+ if (*str == '\0')
+ return EFTYPE;
+ val = strtoul(str, &op, 0);
+ if (*op != '\0')
+ return EFTYPE;
+ *result = val;
+ return 0;
+}
+
+int
+resource_long_value(const char *name, int unit, const char *resname,
+ long *result)
+{
+ int error;
+ const char *str;
+ char *op;
+ unsigned long val;
+ int line;
+
+ line = 0;
+ error = resource_find(&line, NULL, name, &unit, resname, NULL,
+ NULL, NULL, NULL, NULL, NULL, &str);
+ if (error)
+ return error;
+ if (*str == '\0')
+ return EFTYPE;
+ val = strtoul(str, &op, 0);
+ if (*op != '\0')
+ return EFTYPE;
+ *result = val;
+ return 0;
+}
+
+int
+resource_string_value(const char *name, int unit, const char *resname,
+ const char **result)
+{
+ int error;
+ const char *str;
+ int line;
+
+ line = 0;
+ error = resource_find(&line, NULL, name, &unit, resname, NULL,
+ NULL, NULL, NULL, NULL, NULL, &str);
+ if (error)
+ return error;
+ *result = str;
+ return 0;
+}
+
+/*
+ * This is a bit nasty, but allows us to not modify the env strings.
+ */
+static const char *
+resource_string_copy(const char *s, int len)
+{
+ static char stringbuf[256];
+ static int offset = 0;
+ const char *ret;
+
+ if (len == 0)
+ len = strlen(s);
+ if (len > 255)
+ return NULL;
+ if ((offset + len + 1) > 255)
+ offset = 0;
+ bcopy(s, &stringbuf[offset], len);
+ stringbuf[offset + len] = '\0';
+ ret = &stringbuf[offset];
+ offset += len + 1;
+ return ret;
+}
+
+/*
+ * err = resource_find_at(&anchor, &name, &unit, resname, value)
+ * Iteratively fetch a list of devices wired "at" something
+ * res and value are restrictions. eg: "at", "scbus0".
+ * For practical purposes, res = required, value = optional.
+ * *name and *unit are set.
+ * set *anchor to zero before starting.
+ */
+int
+resource_find_match(int *anchor, const char **name, int *unit,
+ const char *resname, const char *value)
+{
+ const char *found_name;
+ int found_namelen;
+ int found_unit;
+ int ret;
+ int newln;
+
+ newln = *anchor;
+ ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
+ &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
+ if (ret == 0) {
+ *name = resource_string_copy(found_name, found_namelen);
+ *unit = found_unit;
+ }
+ *anchor = newln;
+ return ret;
+}
+
+
+/*
+ * err = resource_find_dev(&anchor, name, &unit, res, value);
+ * Iterate through a list of devices, returning their unit numbers.
+ * res and value are optional restrictions. eg: "at", "scbus0".
+ * *unit is set to the value.
+ * set *anchor to zero before starting.
+ */
+int
+resource_find_dev(int *anchor, const char *name, int *unit,
+ const char *resname, const char *value)
+{
+ int found_unit;
+ int newln;
+ int ret;
+
+ newln = *anchor;
+ ret = resource_find(anchor, &newln, name, NULL, resname, value,
+ NULL, NULL, &found_unit, NULL, NULL, NULL);
+ if (ret == 0) {
+ *unit = found_unit;
+ }
+ *anchor = newln;
+ return ret;
+}
OpenPOWER on IntegriCloud