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