xref: /freebsd/stand/common/pnp.c (revision 224e0c2f)
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 #ifdef BOOT_FORTH
21 #include "ficl.h"
22 #endif
23 
24 static struct pnpinfo_stql pnp_devices;
25 static int		pnp_devices_initted = 0;
26 
27 static void		pnp_discard(void);
28 
29 /*
30  * Perform complete enumeration sweep
31  */
32 
33 COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan);
34 
35 static int
36 pnp_scan(int argc, char *argv[])
37 {
38     struct pnpinfo	*pi;
39     int			hdlr;
40     int			verbose;
41     int			ch;
42 
43     if (pnp_devices_initted == 0) {
44 	STAILQ_INIT(&pnp_devices);
45 	pnp_devices_initted = 1;
46     }
47 
48     verbose = 0;
49     optind = 1;
50     optreset = 1;
51     while ((ch = getopt(argc, argv, "v")) != -1) {
52 	switch(ch) {
53 	case 'v':
54 	    verbose = 1;
55 	    break;
56 	case '?':
57 	default:
58 	    /* getopt has already reported an error */
59 	    return(CMD_OK);
60 	}
61     }
62 
63     /* forget anything we think we knew */
64     pnp_discard();
65 
66     /* iterate over all of the handlers */
67     for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) {
68 	if (verbose)
69 	    printf("Probing %s...\n", pnphandlers[hdlr]->pp_name);
70 	pnphandlers[hdlr]->pp_enumerate();
71     }
72     if (verbose) {
73 	pager_open();
74 	if (pager_output("PNP scan summary:\n"))
75 		goto out;
76 	STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
77 	    pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident);	/* first ident should be canonical */
78 	    if (pi->pi_desc != NULL) {
79 		pager_output(" : ");
80 		pager_output(pi->pi_desc);
81 	    }
82 	    if (pager_output("\n"))
83 		    break;
84 	}
85 out:
86 	pager_close();
87     }
88     return(CMD_OK);
89 }
90 
91 /*
92  * Throw away anything we think we know about PnP devices.
93  */
94 static void
95 pnp_discard(void)
96 {
97     struct pnpinfo	*pi;
98 
99     while (STAILQ_FIRST(&pnp_devices) != NULL) {
100 	pi = STAILQ_FIRST(&pnp_devices);
101 	STAILQ_REMOVE_HEAD(&pnp_devices, pi_link);
102 	pnp_freeinfo(pi);
103     }
104 }
105 
106 /*
107  * Add a unique identifier to (pi)
108  */
109 void
110 pnp_addident(struct pnpinfo *pi, char *ident)
111 {
112     struct pnpident	*id;
113 
114     STAILQ_FOREACH(id, &pi->pi_ident, id_link)
115 	if (!strcmp(id->id_ident, ident))
116 	    return;			/* already have this one */
117 
118     id = malloc(sizeof(struct pnpident));
119     id->id_ident = strdup(ident);
120     STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link);
121 }
122 
123 /*
124  * Allocate a new pnpinfo struct
125  */
126 struct pnpinfo *
127 pnp_allocinfo(void)
128 {
129     struct pnpinfo	*pi;
130 
131     pi = malloc(sizeof(struct pnpinfo));
132     bzero(pi, sizeof(struct pnpinfo));
133     STAILQ_INIT(&pi->pi_ident);
134     return(pi);
135 }
136 
137 /*
138  * Release storage held by a pnpinfo struct
139  */
140 void
141 pnp_freeinfo(struct pnpinfo *pi)
142 {
143     struct pnpident	*id;
144 
145     while (!STAILQ_EMPTY(&pi->pi_ident)) {
146 	id = STAILQ_FIRST(&pi->pi_ident);
147 	STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link);
148 	free(id->id_ident);
149 	free(id);
150     }
151     if (pi->pi_desc)
152 	free(pi->pi_desc);
153     if (pi->pi_module)
154 	free(pi->pi_module);
155     if (pi->pi_argv)
156 	free(pi->pi_argv);
157     free(pi);
158 }
159 
160 /*
161  * Add a new pnpinfo struct to the list.
162  */
163 void
164 pnp_addinfo(struct pnpinfo *pi)
165 {
166     STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link);
167 }
168 
169 
170 /*
171  * Format an EISA id as a string in standard ISA PnP format, AAAIIRR
172  * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID.
173  */
174 char *
175 pnp_eisaformat(u_int8_t *data)
176 {
177     static char	idbuf[8];
178     const char	hextoascii[] = "0123456789abcdef";
179 
180     idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
181     idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
182     idbuf[2] = '@' + (data[1] & 0x1f);
183     idbuf[3] = hextoascii[(data[2] >> 4)];
184     idbuf[4] = hextoascii[(data[2] & 0xf)];
185     idbuf[5] = hextoascii[(data[3] >> 4)];
186     idbuf[6] = hextoascii[(data[3] & 0xf)];
187     idbuf[7] = 0;
188     return(idbuf);
189 }
190 
191 #ifdef BOOT_FORTH
192 void
193 ficlPnpdevices(FICL_VM *pVM)
194 {
195 	static int pnp_devices_initted = 0;
196 #if FICL_ROBUST > 1
197 	vmCheckStack(pVM, 0, 1);
198 #endif
199 
200 	if(!pnp_devices_initted) {
201 		STAILQ_INIT(&pnp_devices);
202 		pnp_devices_initted = 1;
203 	}
204 
205 	stackPushPtr(pVM->pStack, &pnp_devices);
206 
207 	return;
208 }
209 
210 void
211 ficlPnphandlers(FICL_VM *pVM)
212 {
213 #if FICL_ROBUST > 1
214 	vmCheckStack(pVM, 0, 1);
215 #endif
216 
217 	stackPushPtr(pVM->pStack, pnphandlers);
218 
219 	return;
220 }
221 
222 /*
223  * Glue function to add the appropriate forth words to access pnp BIOS
224  * functionality.
225  */
226 static void ficlCompilePnp(FICL_SYSTEM *pSys)
227 {
228     FICL_DICT *dp = pSys->dp;
229     assert (dp);
230 
231     dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT);
232     dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
233 }
234 
235 FICL_COMPILE_SET(ficlCompilePnp);
236 #endif
237