1/*
2 * mjs copyright
3 *
4 */
5
6#include <sys/cdefs.h>
7__FBSDID("$FreeBSD$");
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
21struct 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	pager_output("PNP scan summary:\n");
72	STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
73	    pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident);	/* first ident should be canonical */
74	    if (pi->pi_desc != NULL) {
75		pager_output(" : ");
76		pager_output(pi->pi_desc);
77	    }
78	    pager_output("\n");
79	}
80	pager_close();
81    }
82    return(CMD_OK);
83}
84
85/*
86 * Throw away anything we think we know about PnP devices.
87 */
88static void
89pnp_discard(void)
90{
91    struct pnpinfo	*pi;
92
93    while (STAILQ_FIRST(&pnp_devices) != NULL) {
94	pi = STAILQ_FIRST(&pnp_devices);
95	STAILQ_REMOVE_HEAD(&pnp_devices, pi_link);
96	pnp_freeinfo(pi);
97    }
98}
99
100/*
101 * Add a unique identifier to (pi)
102 */
103void
104pnp_addident(struct pnpinfo *pi, char *ident)
105{
106    struct pnpident	*id;
107
108    STAILQ_FOREACH(id, &pi->pi_ident, id_link)
109	if (!strcmp(id->id_ident, ident))
110	    return;			/* already have this one */
111
112    id = malloc(sizeof(struct pnpident));
113    id->id_ident = strdup(ident);
114    STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link);
115}
116
117/*
118 * Allocate a new pnpinfo struct
119 */
120struct pnpinfo *
121pnp_allocinfo(void)
122{
123    struct pnpinfo	*pi;
124
125    pi = malloc(sizeof(struct pnpinfo));
126    bzero(pi, sizeof(struct pnpinfo));
127    STAILQ_INIT(&pi->pi_ident);
128    return(pi);
129}
130
131/*
132 * Release storage held by a pnpinfo struct
133 */
134void
135pnp_freeinfo(struct pnpinfo *pi)
136{
137    struct pnpident	*id;
138
139    while (!STAILQ_EMPTY(&pi->pi_ident)) {
140	id = STAILQ_FIRST(&pi->pi_ident);
141	STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link);
142	free(id->id_ident);
143	free(id);
144    }
145    if (pi->pi_desc)
146	free(pi->pi_desc);
147    if (pi->pi_module)
148	free(pi->pi_module);
149    if (pi->pi_argv)
150	free(pi->pi_argv);
151    free(pi);
152}
153
154/*
155 * Add a new pnpinfo struct to the list.
156 */
157void
158pnp_addinfo(struct pnpinfo *pi)
159{
160    STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link);
161}
162
163
164/*
165 * Format an EISA id as a string in standard ISA PnP format, AAAIIRR
166 * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID.
167 */
168char *
169pnp_eisaformat(u_int8_t *data)
170{
171    static char	idbuf[8];
172    const char	hextoascii[] = "0123456789abcdef";
173
174    idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
175    idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
176    idbuf[2] = '@' + (data[1] & 0x1f);
177    idbuf[3] = hextoascii[(data[2] >> 4)];
178    idbuf[4] = hextoascii[(data[2] & 0xf)];
179    idbuf[5] = hextoascii[(data[3] >> 4)];
180    idbuf[6] = hextoascii[(data[3] & 0xf)];
181    idbuf[7] = 0;
182    return(idbuf);
183}
184
185