pnp.c revision 332154
1/*
2 * mjs copyright
3 *
4 */
5
6#include <sys/cdefs.h>
7__FBSDID("$FreeBSD: stable/11/stand/common/pnp.c 332154 2018-04-06 21:37:25Z kevans $");
8
9/*
10 * "Plug and Play" functionality.
11 *
12 * We use the PnP enumerators to obtain identifiers for installed hardware,
13 * and the contents of a database to determine modules to be loaded to support
14 * such hardware.
15 */
16
17#include <stand.h>
18#include <string.h>
19#include <bootstrap.h>
20
21static struct pnpinfo_stql pnp_devices;
22static int		pnp_devices_initted = 0;
23
24static void		pnp_discard(void);
25
26/*
27 * Perform complete enumeration sweep
28 */
29
30COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan);
31
32static int
33pnp_scan(int argc, char *argv[])
34{
35    struct pnpinfo	*pi;
36    int			hdlr;
37    int			verbose;
38    int			ch;
39
40    if (pnp_devices_initted == 0) {
41	STAILQ_INIT(&pnp_devices);
42	pnp_devices_initted = 1;
43    }
44
45    verbose = 0;
46    optind = 1;
47    optreset = 1;
48    while ((ch = getopt(argc, argv, "v")) != -1) {
49	switch(ch) {
50	case 'v':
51	    verbose = 1;
52	    break;
53	case '?':
54	default:
55	    /* getopt has already reported an error */
56	    return(CMD_OK);
57	}
58    }
59
60    /* forget anything we think we knew */
61    pnp_discard();
62
63    /* iterate over all of the handlers */
64    for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) {
65	if (verbose)
66	    printf("Probing %s...\n", pnphandlers[hdlr]->pp_name);
67	pnphandlers[hdlr]->pp_enumerate();
68    }
69    if (verbose) {
70	pager_open();
71	if (pager_output("PNP scan summary:\n"))
72		goto out;
73	STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
74	    pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident);	/* first ident should be canonical */
75	    if (pi->pi_desc != NULL) {
76		pager_output(" : ");
77		pager_output(pi->pi_desc);
78	    }
79	    if (pager_output("\n"))
80		    break;
81	}
82out:
83	pager_close();
84    }
85    return(CMD_OK);
86}
87
88/*
89 * Throw away anything we think we know about PnP devices.
90 */
91static void
92pnp_discard(void)
93{
94    struct pnpinfo	*pi;
95
96    while (STAILQ_FIRST(&pnp_devices) != NULL) {
97	pi = STAILQ_FIRST(&pnp_devices);
98	STAILQ_REMOVE_HEAD(&pnp_devices, pi_link);
99	pnp_freeinfo(pi);
100    }
101}
102
103/*
104 * Add a unique identifier to (pi)
105 */
106void
107pnp_addident(struct pnpinfo *pi, char *ident)
108{
109    struct pnpident	*id;
110
111    STAILQ_FOREACH(id, &pi->pi_ident, id_link)
112	if (!strcmp(id->id_ident, ident))
113	    return;			/* already have this one */
114
115    id = malloc(sizeof(struct pnpident));
116    id->id_ident = strdup(ident);
117    STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link);
118}
119
120/*
121 * Allocate a new pnpinfo struct
122 */
123struct pnpinfo *
124pnp_allocinfo(void)
125{
126    struct pnpinfo	*pi;
127
128    pi = malloc(sizeof(struct pnpinfo));
129    bzero(pi, sizeof(struct pnpinfo));
130    STAILQ_INIT(&pi->pi_ident);
131    return(pi);
132}
133
134/*
135 * Release storage held by a pnpinfo struct
136 */
137void
138pnp_freeinfo(struct pnpinfo *pi)
139{
140    struct pnpident	*id;
141
142    while (!STAILQ_EMPTY(&pi->pi_ident)) {
143	id = STAILQ_FIRST(&pi->pi_ident);
144	STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link);
145	free(id->id_ident);
146	free(id);
147    }
148    if (pi->pi_desc)
149	free(pi->pi_desc);
150    if (pi->pi_module)
151	free(pi->pi_module);
152    if (pi->pi_argv)
153	free(pi->pi_argv);
154    free(pi);
155}
156
157/*
158 * Add a new pnpinfo struct to the list.
159 */
160void
161pnp_addinfo(struct pnpinfo *pi)
162{
163    STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link);
164}
165
166
167/*
168 * Format an EISA id as a string in standard ISA PnP format, AAAIIRR
169 * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID.
170 */
171char *
172pnp_eisaformat(uint8_t *data)
173{
174    static char	idbuf[8];
175    const char	hextoascii[] = "0123456789abcdef";
176
177    idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
178    idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
179    idbuf[2] = '@' + (data[1] & 0x1f);
180    idbuf[3] = hextoascii[(data[2] >> 4)];
181    idbuf[4] = hextoascii[(data[2] & 0xf)];
182    idbuf[5] = hextoascii[(data[3] >> 4)];
183    idbuf[6] = hextoascii[(data[3] & 0xf)];
184    idbuf[7] = 0;
185    return(idbuf);
186}
187