1/* 2 * mjs copyright 3 */ 4/* 5 * "Plug and Play" functionality. 6 * 7 * We use the PnP enumerators to obtain identifiers for installed hardware, 8 * and the contents of a database to determine modules to be loaded to support 9 * such hardware. 10 */ 11 12#include <stand.h>
| 1/* 2 * mjs copyright 3 */ 4/* 5 * "Plug and Play" functionality. 6 * 7 * We use the PnP enumerators to obtain identifiers for installed hardware, 8 * and the contents of a database to determine modules to be loaded to support 9 * such hardware. 10 */ 11 12#include <stand.h>
|
| 13#include <string.h>
|
13#include <bootstrap.h> 14 15static struct pnpinfo *pnp_devices = NULL; 16
| 14#include <bootstrap.h> 15 16static struct pnpinfo *pnp_devices = NULL; 17
|
17static void pnp_discard(void);
| 18static void pnp_discard(struct pnpinfo **list); 19static int pnp_readconf(char *path); 20static int pnp_scankernel(void);
|
18 19/* 20 * Perform complete enumeration sweep, and load required module(s) if possible. 21 */ 22
| 21 22/* 23 * Perform complete enumeration sweep, and load required module(s) if possible. 24 */ 25
|
| 26COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan); 27
|
23int
| 28int
|
24pnp_autoload(void)
| 29pnp_scan(int argc, char *argv[])
|
25{
| 30{
|
26 int hdlr, idx;
| 31 int hdlr;
|
27 28 /* forget anything we think we knew */
| 32 33 /* forget anything we think we knew */
|
29 pnp_discard();
| 34 pnp_discard(&pnp_devices);
|
30 31 /* iterate over all of the handlers */
| 35 36 /* iterate over all of the handlers */
|
32 for (hdlr = 0; pnphandlers[hdlr]->pp_name != NULL; i++) {
| 37 for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) {
|
33 printf("Probing bus '%s'...\n", pnphandlers[hdlr]->pp_name);
| 38 printf("Probing bus '%s'...\n", pnphandlers[hdlr]->pp_name);
|
34 idx = 0; 35 while ((pi = pnphandlers[hdlr]->pp_enumerate(idx++)) != NULL) { 36 printf(" %s\n", pi->pi_ident); 37 pi->pi_handler = hdlr; 38 pi->pi_next = pnp_devices; 39 pnp_devices = pi; 40 }
| 39 pnphandlers[hdlr]->pp_enumerate(&pnp_devices);
|
41 }
| 40 }
|
42 /* find anything? */ 43 if (pnp_devices != NULL) { 44 /* XXX hardcoded paths! should use loaddev? */ 45 pnp_readconf("/boot/pnpdata.local"); 46 pnp_readconf("/boot/pnpdata"); 47 48 pnp_reload(); 49 }
| 41 return(CMD_OK);
|
50} 51 52/* 53 * Try to load outstanding modules (eg. after disk change) 54 */ 55int
| 42} 43 44/* 45 * Try to load outstanding modules (eg. after disk change) 46 */ 47int
|
56pnp_reload(void)
| 48pnp_reload(char *fname)
|
57{ 58 struct pnpinfo *pi; 59 char *modfname; 60
| 49{ 50 struct pnpinfo *pi; 51 char *modfname; 52
|
61 /* try to load any modules that have been nominated */ 62 for (pi = pnp_devices; pi != NULL; pi = pi->pi_next) { 63 /* Already loaded? */ 64 if ((pi->pi_module != NULL) && (mod_findmodule(pi->pi_module, NULL) == NULL)) { 65 modfname = malloc(strlen(pi->pi_module + 3)); 66 sprintf(modfname, "%s.ko", pi->pi_module); /* XXX implicit knowledge of KLD module filenames */ 67 if (mod_load(pi->pi_module, pi->pi_argc, pi->pi_argv)) 68 printf("Could not load module '%s' for device '%s'\n", modfname, pi->pi_ident); 69 free(modfname);
| 53 /* find anything? */ 54 if (pnp_devices != NULL) { 55 56 /* check for kernel, assign modules handled by static drivers there */ 57 if (pnp_scankernel()) { 58 command_errmsg = "cannot load drivers until kernel loaded"; 59 return(CMD_ERROR);
|
70 }
| 60 }
|
| 61 if (fname == NULL) { 62 /* default paths */ 63 pnp_readconf("/boot/pnpdata.local"); 64 pnp_readconf("/boot/pnpdata"); 65 } else { 66 if (pnp_readconf("fname")) { 67 sprintf(command_errbuf, "can't read PnP information from '%s'", fname); 68 return(CMD_ERROR); 69 } 70 } 71 72 /* try to load any modules that have been nominated */ 73 for (pi = pnp_devices; pi != NULL; pi = pi->pi_next) { 74 /* Already loaded? */ 75 if ((pi->pi_module != NULL) && (mod_findmodule(pi->pi_module, NULL) == NULL)) { 76 modfname = malloc(strlen(pi->pi_module + 3)); 77 sprintf(modfname, "%s.ko", pi->pi_module); /* XXX implicit knowledge of KLD module filenames */ 78 if (mod_load(pi->pi_module, pi->pi_argc, pi->pi_argv)) 79 printf("Could not load module '%s' for device '%s'\n", modfname, pi->pi_ident->id_ident); 80 free(modfname); 81 } 82 }
|
71 }
| 83 }
|
| 84 return(CMD_OK);
|
72} 73
| 85} 86
|
74
| |
75/*
| 87/*
|
76 * Throw away anything we think we know about PnP devices
| 88 * Throw away anything we think we know about PnP devices on (list)
|
77 */ 78static void
| 89 */ 90static void
|
79pnp_discard(void)
| 91pnp_discard(struct pnpinfo **list)
|
80{ 81 struct pnpinfo *pi;
| 92{ 93 struct pnpinfo *pi;
|
| 94 struct pnpident *id;
|
82
| 95
|
83 while (pnp_devices != NULL) { 84 pi = pnp_devices; 85 pnp_devices = pnp_devices->pi_next; 86 if (pi->pi_ident) 87 free(pi->pi_ident);
| 96 while (*list != NULL) { 97 pi = *list; 98 *list = (*list)->pi_next; 99 while (pi->pi_ident) { 100 id = pi->pi_ident; 101 pi->pi_ident = pi->pi_ident->id_next; 102 free(id); 103 }
|
88 if (pi->pi_module) 89 free(pi->pi_module); 90 if (pi->pi_argv) 91 free(pi->pi_argv); 92 free(pi); 93 } 94} 95 96/* 97 * The PnP configuration database consists of a flat text file with 98 * entries one per line. Valid lines are: 99 * 100 * # <text> 101 * 102 * This line is a comment, and ignored. 103 * 104 * [<name>] 105 * 106 * Entries following this line are for devices connected to the 107 * bus <name>, At least one such entry must be encountered 108 * before identifiers are recognised. 109 * 110 * ident=<identifier> rev=<revision> module=<module> args=<arguments> 111 * 112 * This line describes an identifier:module mapping. The 'ident' 113 * and 'module' fields are required; the 'rev' field is currently 114 * ignored (but should be used), and the 'args' field must come 115 * last. 116 */
| 104 if (pi->pi_module) 105 free(pi->pi_module); 106 if (pi->pi_argv) 107 free(pi->pi_argv); 108 free(pi); 109 } 110} 111 112/* 113 * The PnP configuration database consists of a flat text file with 114 * entries one per line. Valid lines are: 115 * 116 * # <text> 117 * 118 * This line is a comment, and ignored. 119 * 120 * [<name>] 121 * 122 * Entries following this line are for devices connected to the 123 * bus <name>, At least one such entry must be encountered 124 * before identifiers are recognised. 125 * 126 * ident=<identifier> rev=<revision> module=<module> args=<arguments> 127 * 128 * This line describes an identifier:module mapping. The 'ident' 129 * and 'module' fields are required; the 'rev' field is currently 130 * ignored (but should be used), and the 'args' field must come 131 * last. 132 */
|
117static void
| 133static int
|
118pnp_readconf(char *path) 119{ 120 struct pnpinfo *pi;
| 134pnp_readconf(char *path) 135{ 136 struct pnpinfo *pi;
|
| 137 struct pnpident *id;
|
121 int fd, line; 122 char lbuf[128], *currbus, *ident, *revision, *module, *args; 123 char *cp, *ep, *tp, c; 124 125 /* try to open the file */ 126 if ((fd = open(path, O_RDONLY)) >= 0) { 127 line = 0; 128 currbus = NULL; 129 130 while (fgetstr(lbuf, sizeof(lbuf), fd) > 0) { 131 line++; 132 /* Find the first non-space character on the line */ 133 for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) 134 ; 135 136 /* keep/discard? */ 137 if ((*cp == 0) || (*cp == '#')) 138 continue; 139 140 /* bus declaration? */ 141 if (*cp == '[') { 142 if (((ep = strchr(cp, ']')) == NULL) || ((ep - cp) < 2)) { 143 printf("%s line %d: bad bus specification\n", path, line); 144 } else { 145 if (currbus != NULL) 146 free(currbus); 147 *ep = 0; 148 currbus = strdup(cp + 1); 149 } 150 continue; 151 } 152 153 /* XXX should we complain? */ 154 if (currbus == NULL) 155 continue; 156 157 /* mapping */
| 138 int fd, line; 139 char lbuf[128], *currbus, *ident, *revision, *module, *args; 140 char *cp, *ep, *tp, c; 141 142 /* try to open the file */ 143 if ((fd = open(path, O_RDONLY)) >= 0) { 144 line = 0; 145 currbus = NULL; 146 147 while (fgetstr(lbuf, sizeof(lbuf), fd) > 0) { 148 line++; 149 /* Find the first non-space character on the line */ 150 for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) 151 ; 152 153 /* keep/discard? */ 154 if ((*cp == 0) || (*cp == '#')) 155 continue; 156 157 /* bus declaration? */ 158 if (*cp == '[') { 159 if (((ep = strchr(cp, ']')) == NULL) || ((ep - cp) < 2)) { 160 printf("%s line %d: bad bus specification\n", path, line); 161 } else { 162 if (currbus != NULL) 163 free(currbus); 164 *ep = 0; 165 currbus = strdup(cp + 1); 166 } 167 continue; 168 } 169 170 /* XXX should we complain? */ 171 if (currbus == NULL) 172 continue; 173 174 /* mapping */
|
158 for (ident = module = args = NULL; *cp != 0;) {
| 175 for (ident = module = args = revision = NULL; *cp != 0;) {
|
159 160 /* discard leading whitespace */ 161 if (isspace(*cp)) { 162 cp++; 163 continue; 164 } 165 166 /* scan for terminator, separator */
| 176 177 /* discard leading whitespace */ 178 if (isspace(*cp)) { 179 cp++; 180 continue; 181 } 182 183 /* scan for terminator, separator */
|
167 for (ep = cp; (*ep != 0) && (*ep != '=') && !isspace(ep); ep++)
| 184 for (ep = cp; (*ep != 0) && (*ep != '=') && !isspace(*ep); ep++)
|
168 ; 169 170 if (*ep == '=') { 171 *ep = 0;
| 185 ; 186 187 if (*ep == '=') { 188 *ep = 0;
|
172 for (tp = ep + 1; (*tp != 0) && !isspace(tp); tp++)
| 189 for (tp = ep + 1; (*tp != 0) && !isspace(*tp); tp++)
|
173 ; 174 c = *tp; 175 *tp = 0; 176 if ((ident == NULL) && !strcmp(cp, "ident")) { 177 ident = ep + 1; 178 } else if ((revision == NULL) && !strcmp(cp, "revision")) { 179 revision = ep + 1; 180 } else if ((args == NULL) && !strcmp(cp, "args")) { 181 *tp = c; 182 while (*tp != 0) /* skip to end of string */ 183 tp++; 184 args = ep + 1; 185 } else { 186 /* XXX complain? */ 187 } 188 cp = tp; 189 continue; 190 } 191 192 /* it's garbage or a keyword - ignore it for now */ 193 cp = ep; 194 } 195 196 /* we must have at least ident and module set */ 197 if ((ident == NULL) || (module == NULL)) { 198 printf("%s line %d: bad mapping\n", path, line); 199 continue; 200 } 201 202 /*
| 190 ; 191 c = *tp; 192 *tp = 0; 193 if ((ident == NULL) && !strcmp(cp, "ident")) { 194 ident = ep + 1; 195 } else if ((revision == NULL) && !strcmp(cp, "revision")) { 196 revision = ep + 1; 197 } else if ((args == NULL) && !strcmp(cp, "args")) { 198 *tp = c; 199 while (*tp != 0) /* skip to end of string */ 200 tp++; 201 args = ep + 1; 202 } else { 203 /* XXX complain? */ 204 } 205 cp = tp; 206 continue; 207 } 208 209 /* it's garbage or a keyword - ignore it for now */ 210 cp = ep; 211 } 212 213 /* we must have at least ident and module set */ 214 if ((ident == NULL) || (module == NULL)) { 215 printf("%s line %d: bad mapping\n", path, line); 216 continue; 217 } 218 219 /*
|
203 * Loop looking for module/bus that might match this
| 220 * Loop looking for module/bus that might match this, but aren't already 221 * assigned.
|
204 * XXX no revision parse/test here yet. 205 */
| 222 * XXX no revision parse/test here yet. 223 */
|
206 for (pi = pnp_modules; pi != NULL; pi = pi->pi_next) { 207 if (!strcmp(pnphandlers[pi->pi_handler]->pp_name, currbus) && 208 !strcmp(pi->pi_indent, ident)) { 209 if (args != NULL) 210 if (parse(&pi->pi_argc, &pi->pi_argv, args)) { 211 printf("%s line %d: bad arguments\n", path, line);
| 224 for (pi = pnp_devices; pi != NULL; pi = pi->pi_next) { 225 226 /* no driver assigned, bus matches OK */ 227 if ((pi->pi_module == NULL) && 228 !strcmp(pi->pi_handler->pp_name, currbus)) { 229 230 /* scan idents, take first match */ 231 for (id = pi->pi_ident; id != NULL; id = id->id_next) 232 if (!strcmp(id->id_ident, ident))
|
212 break;
| 233 break;
|
213 } 214 pi->pi_module = strdup(module);
| 234 235 /* find a match? */ 236 if (id != NULL) { 237 if (args != NULL) 238 if (parse(&pi->pi_argc, &pi->pi_argv, args)) { 239 printf("%s line %d: bad arguments\n", path, line); 240 continue; 241 } 242 pi->pi_module = strdup(module); 243 printf("use module '%s' for %s:%s\n", module, pi->pi_handler->pp_name, id->id_ident); 244 }
|
215 } 216 } 217 } 218 close(fd); 219 }
| 245 } 246 } 247 } 248 close(fd); 249 }
|
| 250 return(CMD_OK);
|
220} 221
| 251} 252
|
| 253static int 254pnp_scankernel(void) 255{ 256 return(CMD_OK); 257} 258 259/* 260 * Add a unique identifier to (pi) 261 */ 262void 263pnp_addident(struct pnpinfo *pi, char *ident) 264{ 265 struct pnpident *id, **idp; 266 267 if (pi->pi_ident == NULL) { 268 idp = &(pi->pi_ident); 269 } else { 270 for (id = pi->pi_ident; id->id_next != NULL; id = id->id_next) 271 if (!strcmp(id->id_ident, ident)) 272 return; /* already have this one */ 273 ; 274 idp = &(id->id_next); 275 } 276 *idp = malloc(sizeof(struct pnpident)); 277 (*idp)->id_next = NULL; 278 (*idp)->id_ident = strdup(ident); 279} 280
|
| |