xref: /illumos-gate/usr/src/boot/common/pnp.c (revision d4039345c8fe6e54a31d17d91e86e393fdcf401b)
1 /*
2  * mjs copyright
3  *
4  */
5 
6 #include <sys/cdefs.h>
7 
8 /*
9  * "Plug and Play" functionality.
10  *
11  * We use the PnP enumerators to obtain identifiers for installed hardware,
12  * and the contents of a database to determine modules to be loaded to support
13  * such hardware.
14  */
15 
16 #include <stand.h>
17 #include <string.h>
18 #include <bootstrap.h>
19 #include "ficl.h"
20 
21 static struct pnpinfo_stql pnp_devices;
22 static int		pnp_devices_initted = 0;
23 
24 static void		pnp_discard(void);
25 
26 /*
27  * Perform complete enumeration sweep
28  */
29 
30 COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan);
31 
32 static int
33 pnp_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  */
88 static void
89 pnp_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  */
103 void
104 pnp_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  */
120 struct pnpinfo *
121 pnp_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  */
134 void
135 pnp_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  */
157 void
158 pnp_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  */
168 char *
169 pnp_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 void
186 ficlPnpdevices(ficlVm *pVM)
187 {
188 	static int pnp_devices_initted = 0;
189 
190 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
191 
192 	if (!pnp_devices_initted) {
193 		STAILQ_INIT(&pnp_devices);
194 		pnp_devices_initted = 1;
195 	}
196 
197 	ficlStackPushPointer(ficlVmGetDataStack(pVM), &pnp_devices);
198 }
199 
200 void
201 ficlPnphandlers(ficlVm *pVM)
202 {
203 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
204 
205 	ficlStackPushPointer(ficlVmGetDataStack(pVM), pnphandlers);
206 }
207 
208 /*
209  * Glue function to add the appropriate forth words to access pnp BIOS
210  * functionality.
211  */
212 static void
213 ficlCompilePnp(ficlSystem *pSys)
214 {
215 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
216 
217 	FICL_SYSTEM_ASSERT(pSys, dp);
218 
219 	ficlDictionarySetPrimitive(dp, "pnpdevices", ficlPnpdevices,
220 	    FICL_WORD_DEFAULT);
221 	ficlDictionarySetPrimitive(dp, "pnphandlers", ficlPnphandlers,
222 	    FICL_WORD_DEFAULT);
223 }
224 
225 FICL_COMPILE_SET(ficlCompilePnp);
226