diff options
Diffstat (limited to 'stand/common/pnp.c')
-rw-r--r-- | stand/common/pnp.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/stand/common/pnp.c b/stand/common/pnp.c new file mode 100644 index 0000000..6197776 --- /dev/null +++ b/stand/common/pnp.c @@ -0,0 +1,236 @@ +/* + * mjs copyright + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * "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 <string.h> +#include <bootstrap.h> +#ifdef BOOT_FORTH +#include "ficl.h" +#endif + +static struct pnpinfo_stql pnp_devices; +static int pnp_devices_initted = 0; + +static void pnp_discard(void); + +/* + * Perform complete enumeration sweep + */ + +COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan); + +static int +pnp_scan(int argc, char *argv[]) +{ + struct pnpinfo *pi; + int hdlr; + int verbose; + int ch; + + if (pnp_devices_initted == 0) { + STAILQ_INIT(&pnp_devices); + pnp_devices_initted = 1; + } + + verbose = 0; + optind = 1; + optreset = 1; + while ((ch = getopt(argc, argv, "v")) != -1) { + switch(ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + + /* forget anything we think we knew */ + pnp_discard(); + + /* iterate over all of the handlers */ + for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) { + if (verbose) + printf("Probing %s...\n", pnphandlers[hdlr]->pp_name); + pnphandlers[hdlr]->pp_enumerate(); + } + if (verbose) { + pager_open(); + if (pager_output("PNP scan summary:\n")) + goto out; + STAILQ_FOREACH(pi, &pnp_devices, pi_link) { + pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident); /* first ident should be canonical */ + if (pi->pi_desc != NULL) { + pager_output(" : "); + pager_output(pi->pi_desc); + } + if (pager_output("\n")) + break; + } +out: + pager_close(); + } + return(CMD_OK); +} + +/* + * Throw away anything we think we know about PnP devices. + */ +static void +pnp_discard(void) +{ + struct pnpinfo *pi; + + while (STAILQ_FIRST(&pnp_devices) != NULL) { + pi = STAILQ_FIRST(&pnp_devices); + STAILQ_REMOVE_HEAD(&pnp_devices, pi_link); + pnp_freeinfo(pi); + } +} + +/* + * Add a unique identifier to (pi) + */ +void +pnp_addident(struct pnpinfo *pi, char *ident) +{ + struct pnpident *id; + + STAILQ_FOREACH(id, &pi->pi_ident, id_link) + if (!strcmp(id->id_ident, ident)) + return; /* already have this one */ + + id = malloc(sizeof(struct pnpident)); + id->id_ident = strdup(ident); + STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link); +} + +/* + * Allocate a new pnpinfo struct + */ +struct pnpinfo * +pnp_allocinfo(void) +{ + struct pnpinfo *pi; + + pi = malloc(sizeof(struct pnpinfo)); + bzero(pi, sizeof(struct pnpinfo)); + STAILQ_INIT(&pi->pi_ident); + return(pi); +} + +/* + * Release storage held by a pnpinfo struct + */ +void +pnp_freeinfo(struct pnpinfo *pi) +{ + struct pnpident *id; + + while (!STAILQ_EMPTY(&pi->pi_ident)) { + id = STAILQ_FIRST(&pi->pi_ident); + STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link); + free(id->id_ident); + free(id); + } + if (pi->pi_desc) + free(pi->pi_desc); + if (pi->pi_module) + free(pi->pi_module); + if (pi->pi_argv) + free(pi->pi_argv); + free(pi); +} + +/* + * Add a new pnpinfo struct to the list. + */ +void +pnp_addinfo(struct pnpinfo *pi) +{ + STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link); +} + + +/* + * Format an EISA id as a string in standard ISA PnP format, AAAIIRR + * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID. + */ +char * +pnp_eisaformat(u_int8_t *data) +{ + static char idbuf[8]; + const char hextoascii[] = "0123456789abcdef"; + + idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); + idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); + idbuf[2] = '@' + (data[1] & 0x1f); + idbuf[3] = hextoascii[(data[2] >> 4)]; + idbuf[4] = hextoascii[(data[2] & 0xf)]; + idbuf[5] = hextoascii[(data[3] >> 4)]; + idbuf[6] = hextoascii[(data[3] & 0xf)]; + idbuf[7] = 0; + return(idbuf); +} + +#ifdef BOOT_FORTH +void +ficlPnpdevices(FICL_VM *pVM) +{ + static int pnp_devices_initted = 0; +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif + + if(!pnp_devices_initted) { + STAILQ_INIT(&pnp_devices); + pnp_devices_initted = 1; + } + + stackPushPtr(pVM->pStack, &pnp_devices); + + return; +} + +void +ficlPnphandlers(FICL_VM *pVM) +{ +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 0, 1); +#endif + + stackPushPtr(pVM->pStack, pnphandlers); + + return; +} + +/* + * Glue function to add the appropriate forth words to access pnp BIOS + * functionality. + */ +static void ficlCompilePnp(FICL_SYSTEM *pSys) +{ + FICL_DICT *dp = pSys->dp; + assert (dp); + + dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT); + dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT); +} + +FICL_COMPILE_SET(ficlCompilePnp); +#endif |