freebsd-dev/sys/boot/common/pnp.c
Warner Losh 75a63b2de3 Really make WITHOUT_FORTH (MK_FORTH==no) work. The recent inclusion of
FICL definitions not in ficl/ficl32 files broke this generally. This
makes that stuff conditional on BOOT_FORTH. Also, move definitions
related to the architecture (FICL_CPUARCH and friends) into
Makefile.ficl that all parts of the tree that include files with ficl
need to include (but only if MK_FORTH == yes). In addition, had to fix
library ordering issue with LIBSTAND to keep it last. Without boot
forth, there's no references to memset to bring in memset.o from
libstand.a to satisfy libgeliboot.a's use of it. Listing libstand last
solves this issue (and it's the proper place for libstand to boot).
2016-10-25 17:31:57 +00:00

237 lines
4.6 KiB
C

/*
* 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