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