pnp.c revision 199767f8919635c4928607450d9e0abb932109ce
/*
* 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>
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();
pager_output("PNP scan summary:\n");
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);
}
pager_output("\n");
}
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);
}