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