2 * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34 #include <sys/sysctl.h>
35 #include <sys/systm.h>
39 * Access functions for device resources.
42 static int checkmethod = 1;
47 * Define kern.hintmode sysctl, which only accept value 2, that cause to
48 * switch from Static KENV mode to Dynamic KENV. So systems that have hints
49 * compiled into kernel will be able to see/modify KENV (and hints too).
53 sysctl_hintmode(SYSCTL_HANDLER_ARGS)
57 int eqidx, error, from_kenv, i, value;
63 /* Fetch candidate for new hintmode value */
64 error = sysctl_handle_int(oidp, &value, 0, req);
65 if (error || req->newptr == NULL)
69 /* Only accept swithing to hintmode 2 */
72 /* Migrate from static to dynamic hints */
77 * Already here. But assign hintmode to 2, to not
78 * check it in the future.
90 /* Nothing to do, hintmode already 2 */
99 if (strncmp(cp, "hint.", 5) != 0)
100 /* kenv can have not only hints */
103 eq = strchr(cp, '=');
109 line = malloc(i+1, M_TEMP, M_WAITOK);
112 setenv(line, line + eqidx + 1);
122 SYSCTL_PROC(_kern, OID_AUTO, hintmode, CTLTYPE_INT|CTLFLAG_RW,
123 &hintmode, 0, sysctl_hintmode, "I", "Get/set current hintmode");
126 * Evil wildcarding resource string lookup.
127 * This walks the supplied env string table and returns a match.
128 * The start point can be remembered for incremental searches.
131 res_find(int *line, int *startln,
132 const char *name, int *unit, const char *resname, const char *value,
133 const char **ret_name, int *ret_namelen, int *ret_unit,
134 const char **ret_resname, int *ret_resnamelen, const char **ret_value)
136 int n = 0, hit, i = 0;
148 case 0: /* loader hints in environment only */
150 case 1: /* static hints only */
151 hintp = static_hints;
154 case 2: /* fallback mode */
156 mtx_lock(&kenv_lock);
158 for (i = 0; cp != NULL; cp = kenvp[++i]) {
159 if (!strncmp(cp, "hint.", 5)) {
165 mtx_unlock(&kenv_lock);
169 if (strncmp(cp, "hint.", 5) == 0) {
179 hintp = static_hints;
198 mtx_lock(&kenv_lock);
202 mtx_unlock(&kenv_lock);
210 if (strncmp(cp, "hint.", 5) != 0)
213 n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s",
214 r_name, &r_unit, r_resname, r_value);
216 printf("CONFIG: invalid hint '%s'\n", cp);
221 if (hit && startln && *startln >= 0 && *line < *startln)
223 if (hit && name && strcmp(name, r_name) != 0)
225 if (hit && unit && *unit != r_unit)
227 if (hit && resname && strcmp(resname, r_resname) != 0)
229 if (hit && value && strcmp(value, r_value) != 0)
248 mtx_unlock(&kenv_lock);
253 /* This is a bit of a hack, but at least is reentrant */
254 /* Note that it returns some !unterminated! strings. */
255 s = strchr(s, '.') + 1; /* start of device */
258 s = strchr(s, '.') + 1; /* start of unit */
259 if (ret_namelen && ret_name)
260 *ret_namelen = s - *ret_name - 1; /* device length */
263 s = strchr(s, '.') + 1; /* start of resname */
266 s = strchr(s, '=') + 1; /* start of value */
267 if (ret_resnamelen && ret_resname)
268 *ret_resnamelen = s - *ret_resname - 1; /* value len */
271 if (startln) /* line number for anchor */
272 *startln = *line + 1;
277 * Search all the data sources for matches to our query. We look for
278 * dynamic hints first as overrides for static or fallback hints.
281 resource_find(int *line, int *startln,
282 const char *name, int *unit, const char *resname, const char *value,
283 const char **ret_name, int *ret_namelen, int *ret_unit,
284 const char **ret_resname, int *ret_resnamelen, const char **ret_value)
291 /* Search for exact unit matches first */
292 i = res_find(line, startln, name, unit, resname, value,
293 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
299 /* If we are still here, search for wildcard matches */
301 i = res_find(line, startln, name, &un, resname, value,
302 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen,
310 resource_int_value(const char *name, int unit, const char *resname, int *result)
319 error = resource_find(&line, NULL, name, &unit, resname, NULL,
320 NULL, NULL, NULL, NULL, NULL, &str);
325 val = strtoul(str, &op, 0);
333 resource_long_value(const char *name, int unit, const char *resname,
343 error = resource_find(&line, NULL, name, &unit, resname, NULL,
344 NULL, NULL, NULL, NULL, NULL, &str);
349 val = strtoul(str, &op, 0);
357 resource_string_value(const char *name, int unit, const char *resname,
365 error = resource_find(&line, NULL, name, &unit, resname, NULL,
366 NULL, NULL, NULL, NULL, NULL, &str);
374 * This is a bit nasty, but allows us to not modify the env strings.
377 resource_string_copy(const char *s, int len)
379 static char stringbuf[256];
380 static int offset = 0;
387 if ((offset + len + 1) > 255)
389 bcopy(s, &stringbuf[offset], len);
390 stringbuf[offset + len] = '\0';
391 ret = &stringbuf[offset];
397 * err = resource_find_match(&anchor, &name, &unit, resname, value)
398 * Iteratively fetch a list of devices wired "at" something
399 * res and value are restrictions. eg: "at", "scbus0".
400 * For practical purposes, res = required, value = optional.
401 * *name and *unit are set.
402 * set *anchor to zero before starting.
405 resource_find_match(int *anchor, const char **name, int *unit,
406 const char *resname, const char *value)
408 const char *found_name;
415 ret = resource_find(anchor, &newln, NULL, NULL, resname, value,
416 &found_name, &found_namelen, &found_unit, NULL, NULL, NULL);
418 *name = resource_string_copy(found_name, found_namelen);
427 * err = resource_find_dev(&anchor, name, &unit, res, value);
428 * Iterate through a list of devices, returning their unit numbers.
429 * res and value are optional restrictions. eg: "at", "scbus0".
430 * *unit is set to the value.
431 * set *anchor to zero before starting.
434 resource_find_dev(int *anchor, const char *name, int *unit,
435 const char *resname, const char *value)
442 ret = resource_find(anchor, &newln, name, NULL, resname, value,
443 NULL, NULL, &found_unit, NULL, NULL, NULL);
452 * Check to see if a device is disabled via a disabled hint.
455 resource_disabled(const char *name, int unit)
459 error = resource_int_value(name, unit, "disabled", &value);