Generic plug-and-play enumerator infrastructure. Query supplied

enumerators, crossreference returned identifiers with a text-format
database and automatically load corresponding modules and dependancies.
This commit is contained in:
msmith 1998-09-04 02:43:26 +00:00
parent 0b2fb72464
commit b10e3917e3
4 changed files with 249 additions and 5 deletions

View File

@ -1,4 +1,4 @@
# $Id: Makefile.inc,v 1.2 1998/08/31 21:10:42 msmith Exp $
# $Id: Makefile.inc,v 1.3 1998/09/01 00:41:24 msmith Exp $
SRCS+= boot.c commands.c console.c devopen.c interp.c interp_backslash.c
SRCS+= interp_parse.c load_aout.c ls.c misc.c module.c panic.c
SRCS+= interp_parse.c load_aout.c ls.c misc.c module.c panic.c # pnp.c

View File

@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: bootstrap.h,v 1.2 1998/08/31 21:10:42 msmith Exp $
* $Id: bootstrap.h,v 1.3 1998/09/03 02:10:07 msmith Exp $
*/
#include <sys/types.h>
@ -86,6 +86,29 @@ struct console
extern struct console *consoles[];
extern void cons_probe(void);
/*
* Plug-and-play enumerator/configurator interface.
*/
struct pnpinfo
{
char *pi_ident; /* ASCII identifier, actual format varies with bus/handler */
int pi_revision; /* optional revision (or -1) if not supported */
char *pi_module; /* module/args nominated to handle device */
int pi_argc; /* module arguments */
char **pi_argv;
int pi_handler; /* handler which detected this device */
struct pnpinfo *pi_next;
}
struct pnphandler
{
char *pp_name; /* handler/bus name */
struct pnpinfo *(pp_enumerate *)(int index); /* return a string identifying device (index) */
};
extern struct pnphandler *pnphandlers[]; /* provided by MD code */
/*
* Module metadata header.
*

View File

@ -11,7 +11,7 @@
* Jordan K. Hubbard
* 29 August 1998
*
* $Id: interp_parse.c,v 1.1 1998/09/01 00:41:24 msmith Exp $
* $Id: interp_parse.c,v 1.2 1998/09/03 06:14:41 jkh Exp $
*
* The meat of the simple parser.
*/
@ -147,7 +147,7 @@ parse(int *argc, char ***argv, char *str)
int len = strlen(val);
strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1));
i += min(len, sizeof(buf) - 1);
i += min(len, PARSE_BUFSIZE - 1);
}
*q = tmp; /* restore value */
p = q + (token ? 1 : 0);

221
sys/boot/common/pnp.c Normal file
View File

@ -0,0 +1,221 @@
/*
* mjs copyright
*/
/*
* "Plug and Play" functionality.
*
* We use the PnP enumerators to obtain identifiers for installed hardware,
* and the contents of a database to determine modules to be loaded to support
* such hardware.
*/
#include <stand.h>
#include <bootstrap.h>
static struct pnpinfo *pnp_devices = NULL;
static void pnp_discard(void);
/*
* Perform complete enumeration sweep, and load required module(s) if possible.
*/
int
pnp_autoload(void)
{
int hdlr, idx;
/* forget anything we think we knew */
pnp_discard();
/* iterate over all of the handlers */
for (hdlr = 0; pnphandlers[hdlr]->pp_name != NULL; i++) {
printf("Probing bus '%s'...\n", pnphandlers[hdlr]->pp_name);
idx = 0;
while ((pi = pnphandlers[hdlr]->pp_enumerate(idx++)) != NULL) {
printf(" %s\n", pi->pi_ident);
pi->pi_handler = hdlr;
pi->pi_next = pnp_devices;
pnp_devices = pi;
}
}
/* find anything? */
if (pnp_devices != NULL) {
/* XXX hardcoded paths! should use loaddev? */
pnp_readconf("/boot/pnpdata.local");
pnp_readconf("/boot/pnpdata");
pnp_reload();
}
}
/*
* Try to load outstanding modules (eg. after disk change)
*/
int
pnp_reload(void)
{
struct pnpinfo *pi;
char *modfname;
/* try to load any modules that have been nominated */
for (pi = pnp_devices; pi != NULL; pi = pi->pi_next) {
/* Already loaded? */
if ((pi->pi_module != NULL) && (mod_findmodule(pi->pi_module, NULL) == NULL)) {
modfname = malloc(strlen(pi->pi_module + 3));
sprintf(modfname, "%s.ko", pi->pi_module); /* XXX implicit knowledge of KLD module filenames */
if (mod_load(pi->pi_module, pi->pi_argc, pi->pi_argv))
printf("Could not load module '%s' for device '%s'\n", modfname, pi->pi_ident);
free(modfname);
}
}
}
/*
* Throw away anything we think we know about PnP devices
*/
static void
pnp_discard(void)
{
struct pnpinfo *pi;
while (pnp_devices != NULL) {
pi = pnp_devices;
pnp_devices = pnp_devices->pi_next;
if (pi->pi_ident)
free(pi->pi_ident);
if (pi->pi_module)
free(pi->pi_module);
if (pi->pi_argv)
free(pi->pi_argv);
free(pi);
}
}
/*
* The PnP configuration database consists of a flat text file with
* entries one per line. Valid lines are:
*
* # <text>
*
* This line is a comment, and ignored.
*
* [<name>]
*
* Entries following this line are for devices connected to the
* bus <name>, At least one such entry must be encountered
* before identifiers are recognised.
*
* ident=<identifier> rev=<revision> module=<module> args=<arguments>
*
* This line describes an identifier:module mapping. The 'ident'
* and 'module' fields are required; the 'rev' field is currently
* ignored (but should be used), and the 'args' field must come
* last.
*/
static void
pnp_readconf(char *path)
{
struct pnpinfo *pi;
int fd, line;
char lbuf[128], *currbus, *ident, *revision, *module, *args;
char *cp, *ep, *tp, c;
/* try to open the file */
if ((fd = open(path, O_RDONLY)) >= 0) {
line = 0;
currbus = NULL;
while (fgetstr(lbuf, sizeof(lbuf), fd) > 0) {
line++;
/* Find the first non-space character on the line */
for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
;
/* keep/discard? */
if ((*cp == 0) || (*cp == '#'))
continue;
/* bus declaration? */
if (*cp == '[') {
if (((ep = strchr(cp, ']')) == NULL) || ((ep - cp) < 2)) {
printf("%s line %d: bad bus specification\n", path, line);
} else {
if (currbus != NULL)
free(currbus);
*ep = 0;
currbus = strdup(cp + 1);
}
continue;
}
/* XXX should we complain? */
if (currbus == NULL)
continue;
/* mapping */
for (ident = module = args = NULL; *cp != 0;) {
/* discard leading whitespace */
if (isspace(*cp)) {
cp++;
continue;
}
/* scan for terminator, separator */
for (ep = cp; (*ep != 0) && (*ep != '=') && !isspace(ep); ep++)
;
if (*ep == '=') {
*ep = 0;
for (tp = ep + 1; (*tp != 0) && !isspace(tp); tp++)
;
c = *tp;
*tp = 0;
if ((ident == NULL) && !strcmp(cp, "ident")) {
ident = ep + 1;
} else if ((revision == NULL) && !strcmp(cp, "revision")) {
revision = ep + 1;
} else if ((args == NULL) && !strcmp(cp, "args")) {
*tp = c;
while (*tp != 0) /* skip to end of string */
tp++;
args = ep + 1;
} else {
/* XXX complain? */
}
cp = tp;
continue;
}
/* it's garbage or a keyword - ignore it for now */
cp = ep;
}
/* we must have at least ident and module set */
if ((ident == NULL) || (module == NULL)) {
printf("%s line %d: bad mapping\n", path, line);
continue;
}
/*
* Loop looking for module/bus that might match this
* XXX no revision parse/test here yet.
*/
for (pi = pnp_modules; pi != NULL; pi = pi->pi_next) {
if (!strcmp(pnphandlers[pi->pi_handler]->pp_name, currbus) &&
!strcmp(pi->pi_indent, ident)) {
if (args != NULL)
if (parse(&pi->pi_argc, &pi->pi_argv, args)) {
printf("%s line %d: bad arguments\n", path, line);
break;
}
pi->pi_module = strdup(module);
}
}
}
close(fd);
}
}