HAMMER 59C/Many: Stabilization pass - fixes for large file issues
[dragonfly.git] / sys / boot / common / pnp.c
blobb69b4adef3ce90ee530680ea7b1af439543ab790
1 /*
2 * mjs copyright
4 * $FreeBSD: src/sys/boot/common/pnp.c,v 1.16 2003/08/25 23:30:41 obrien Exp $
5 * $DragonFly: src/sys/boot/common/pnp.c,v 1.3 2003/11/10 06:08:31 dillon Exp $
6 */
8 /*
9 * "Plug and Play" functionality.
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.
16 #include <stand.h>
17 #include <string.h>
18 #include <bootstrap.h>
20 struct pnpinfo_stql pnp_devices;
21 static int pnp_devices_initted = 0;
23 static void pnp_discard(void);
26 * Perform complete enumeration sweep
29 COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan);
31 static int
32 pnp_scan(int argc, char *argv[])
34 struct pnpinfo *pi;
35 int hdlr;
36 int verbose;
37 int ch;
39 if (pnp_devices_initted == 0) {
40 STAILQ_INIT(&pnp_devices);
41 pnp_devices_initted = 1;
44 verbose = 0;
45 optind = 1;
46 optreset = 1;
47 while ((ch = getopt(argc, argv, "v")) != -1) {
48 switch(ch) {
49 case 'v':
50 verbose = 1;
51 break;
52 case '?':
53 default:
54 /* getopt has already reported an error */
55 return(CMD_OK);
59 /* forget anything we think we knew */
60 pnp_discard();
62 /* iterate over all of the handlers */
63 for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) {
64 if (verbose)
65 printf("Probing %s...\n", pnphandlers[hdlr]->pp_name);
66 pnphandlers[hdlr]->pp_enumerate();
68 if (verbose) {
69 pager_open();
70 pager_output("PNP scan summary:\n");
71 STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
72 pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident); /* first ident should be canonical */
73 if (pi->pi_desc != NULL) {
74 pager_output(" : ");
75 pager_output(pi->pi_desc);
77 pager_output("\n");
79 pager_close();
81 return(CMD_OK);
84 #if 0
86 * Try to load outstanding modules (eg. after disk change)
88 COMMAND_SET(pnpload, "pnpload", "load modules for PnP devices", pnp_load);
90 static int
91 pnp_load(int argc, char *argv[])
93 struct pnpinfo *pi;
94 char *modfname;
96 /* find anything? */
97 if (STAILQ_FIRST(&pnp_devices) != NULL) {
99 /* check for kernel, assign modules handled by static drivers there */
100 if (pnp_scankernel()) {
101 command_errmsg = "cannot load drivers until kernel loaded";
102 return(CMD_ERROR);
104 if (fname == NULL) {
105 /* default paths */
106 pnp_readconf("/boot/pnpdata.local");
107 pnp_readconf("/boot/pnpdata");
108 } else {
109 if (pnp_readconf(fname)) {
110 sprintf(command_errbuf, "can't read PnP information from '%s'", fname);
111 return(CMD_ERROR);
115 /* try to load any modules that have been nominated */
116 STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
117 /* Already loaded? */
118 if ((pi->pi_module != NULL) && (file_findfile(pi->pi_module, NULL) == NULL)) {
119 modfname = malloc(strlen(pi->pi_module) + 4);
120 sprintf(modfname, "%s.ko", pi->pi_module); /* XXX implicit knowledge of KLD module filenames */
121 if (mod_load(pi->pi_module, pi->pi_argc, pi->pi_argv))
122 printf("Could not load module '%s' for device '%s'\n", modfname, STAILQ_FIRST(&pi->pi_ident)->id_ident);
123 free(modfname);
127 return(CMD_OK);
129 #endif
131 * Throw away anything we think we know about PnP devices.
133 static void
134 pnp_discard(void)
136 struct pnpinfo *pi;
138 while (STAILQ_FIRST(&pnp_devices) != NULL) {
139 pi = STAILQ_FIRST(&pnp_devices);
140 STAILQ_REMOVE_HEAD(&pnp_devices, pi_link);
141 pnp_freeinfo(pi);
144 #if 0
146 * The PnP configuration database consists of a flat text file with
147 * entries one per line. Valid lines are:
149 * # <text>
151 * This line is a comment, and ignored.
153 * [<name>]
155 * Entries following this line are for devices connected to the
156 * bus <name>, At least one such entry must be encountered
157 * before identifiers are recognised.
159 * ident=<identifier> rev=<revision> module=<module> args=<arguments>
161 * This line describes an identifier:module mapping. The 'ident'
162 * and 'module' fields are required; the 'rev' field is currently
163 * ignored (but should be used), and the 'args' field must come
164 * last.
166 * Comments may be appended to lines; any character including or following
167 * '#' on a line is ignored.
169 static int
170 pnp_readconf(char *path)
172 struct pnpinfo *pi;
173 struct pnpident *id;
174 int fd, line;
175 char lbuf[128], *currbus, *ident, *revision, *module, *args;
176 char *cp, *ep, *tp, c;
178 /* try to open the file */
179 if ((fd = open(path, O_RDONLY)) >= 0) {
180 line = 0;
181 currbus = NULL;
183 while (fgetstr(lbuf, sizeof(lbuf), fd) > 0) {
184 line++;
185 /* Find the first non-space character on the line */
186 for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
189 /* keep/discard? */
190 if ((*cp == 0) || (*cp == '#'))
191 continue;
193 /* cut trailing comment? */
194 if ((ep = strchr(cp, '#')) != NULL)
195 *ep = 0;
197 /* bus declaration? */
198 if (*cp == '[') {
199 if (((ep = strchr(cp, ']')) == NULL) || ((ep - cp) < 2)) {
200 printf("%s line %d: bad bus specification\n", path, line);
201 } else {
202 if (currbus != NULL)
203 free(currbus);
204 *ep = 0;
205 currbus = strdup(cp + 1);
207 continue;
210 /* XXX should we complain? */
211 if (currbus == NULL)
212 continue;
214 /* mapping */
215 for (ident = module = args = revision = NULL; *cp != 0;) {
217 /* discard leading whitespace */
218 if (isspace(*cp)) {
219 cp++;
220 continue;
223 /* scan for terminator, separator */
224 for (ep = cp; (*ep != 0) && (*ep != '=') && !isspace(*ep); ep++)
227 if (*ep == '=') {
228 *ep = 0;
229 for (tp = ep + 1; (*tp != 0) && !isspace(*tp); tp++)
231 c = *tp;
232 *tp = 0;
233 if ((ident == NULL) && !strcmp(cp, "ident")) {
234 ident = ep + 1;
235 } else if ((revision == NULL) && !strcmp(cp, "revision")) {
236 revision = ep + 1;
237 } else if ((args == NULL) && !strcmp(cp, "args")) {
238 *tp = c;
239 while (*tp != 0) /* skip to end of string */
240 tp++;
241 args = ep + 1;
242 } else {
243 /* XXX complain? */
245 cp = tp;
246 continue;
249 /* it's garbage or a keyword - ignore it for now */
250 cp = ep;
253 /* we must have at least ident and module set to be interesting */
254 if ((ident == NULL) || (module == NULL))
255 continue;
258 * Loop looking for module/bus that might match this, but aren't already
259 * assigned.
260 * XXX no revision parse/test here yet.
262 STAILQ_FOREACH(pi, &pnp_devices, pi_link) {
264 /* no driver assigned, bus matches OK */
265 if ((pi->pi_module == NULL) &&
266 !strcmp(pi->pi_handler->pp_name, currbus)) {
268 /* scan idents, take first match */
269 STAILQ_FOREACH(id, &pi->pi_ident, id_link)
270 if (!strcmp(id->id_ident, ident))
271 break;
273 /* find a match? */
274 if (id != NULL) {
275 if (args != NULL)
276 if (parse(&pi->pi_argc, &pi->pi_argv, args)) {
277 printf("%s line %d: bad arguments\n", path, line);
278 continue;
280 pi->pi_module = strdup(module);
281 printf("use module '%s' for %s:%s\n", module, pi->pi_handler->pp_name, id->id_ident);
286 close(fd);
288 return(CMD_OK);
291 static int
292 pnp_scankernel(void)
294 return(CMD_OK);
296 #endif
298 * Add a unique identifier to (pi)
300 void
301 pnp_addident(struct pnpinfo *pi, char *ident)
303 struct pnpident *id;
305 STAILQ_FOREACH(id, &pi->pi_ident, id_link)
306 if (!strcmp(id->id_ident, ident))
307 return; /* already have this one */
309 id = malloc(sizeof(struct pnpident));
310 id->id_ident = strdup(ident);
311 STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link);
315 * Allocate a new pnpinfo struct
317 struct pnpinfo *
318 pnp_allocinfo(void)
320 struct pnpinfo *pi;
322 pi = malloc(sizeof(struct pnpinfo));
323 bzero(pi, sizeof(struct pnpinfo));
324 STAILQ_INIT(&pi->pi_ident);
325 return(pi);
329 * Release storage held by a pnpinfo struct
331 void
332 pnp_freeinfo(struct pnpinfo *pi)
334 struct pnpident *id;
336 while (!STAILQ_EMPTY(&pi->pi_ident)) {
337 id = STAILQ_FIRST(&pi->pi_ident);
338 STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link);
339 free(id->id_ident);
340 free(id);
342 if (pi->pi_desc)
343 free(pi->pi_desc);
344 if (pi->pi_module)
345 free(pi->pi_module);
346 if (pi->pi_argv)
347 free(pi->pi_argv);
348 free(pi);
352 * Add a new pnpinfo struct to the list.
354 void
355 pnp_addinfo(struct pnpinfo *pi)
357 STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link);
362 * Format an EISA id as a string in standard ISA PnP format, AAAIIRR
363 * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID.
365 char *
366 pnp_eisaformat(u_int8_t *data)
368 static char idbuf[8];
369 const char hextoascii[] = "0123456789abcdef";
371 idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
372 idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
373 idbuf[2] = '@' + (data[1] & 0x1f);
374 idbuf[3] = hextoascii[(data[2] >> 4)];
375 idbuf[4] = hextoascii[(data[2] & 0xf)];
376 idbuf[5] = hextoascii[(data[3] >> 4)];
377 idbuf[6] = hextoascii[(data[3] & 0xf)];
378 idbuf[7] = 0;
379 return(idbuf);