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 #ifdef BOOT_FORTH 21 #include "ficl.h" 22 #endif 23 24 static struct pnpinfo_stql pnp_devices; 25 static int pnp_devices_initted = 0; 26 27 static void pnp_discard(void); 28 29 /* 30 * Perform complete enumeration sweep 31 */ 32 33 COMMAND_SET(pnpscan, "pnpscan", "scan for PnP devices", pnp_scan); 34 35 static int 36 pnp_scan(int argc, char *argv[]) 37 { 38 struct pnpinfo *pi; 39 int hdlr; 40 int verbose; 41 int ch; 42 43 if (pnp_devices_initted == 0) { 44 STAILQ_INIT(&pnp_devices); 45 pnp_devices_initted = 1; 46 } 47 48 verbose = 0; 49 optind = 1; 50 optreset = 1; 51 while ((ch = getopt(argc, argv, "v")) != -1) { 52 switch(ch) { 53 case 'v': 54 verbose = 1; 55 break; 56 case '?': 57 default: 58 /* getopt has already reported an error */ 59 return(CMD_OK); 60 } 61 } 62 63 /* forget anything we think we knew */ 64 pnp_discard(); 65 66 /* iterate over all of the handlers */ 67 for (hdlr = 0; pnphandlers[hdlr] != NULL; hdlr++) { 68 if (verbose) 69 printf("Probing %s...\n", pnphandlers[hdlr]->pp_name); 70 pnphandlers[hdlr]->pp_enumerate(); 71 } 72 if (verbose) { 73 pager_open(); 74 if (pager_output("PNP scan summary:\n")) 75 goto out; 76 STAILQ_FOREACH(pi, &pnp_devices, pi_link) { 77 pager_output(STAILQ_FIRST(&pi->pi_ident)->id_ident); /* first ident should be canonical */ 78 if (pi->pi_desc != NULL) { 79 pager_output(" : "); 80 pager_output(pi->pi_desc); 81 } 82 if (pager_output("\n")) 83 break; 84 } 85 out: 86 pager_close(); 87 } 88 return(CMD_OK); 89 } 90 91 /* 92 * Throw away anything we think we know about PnP devices. 93 */ 94 static void 95 pnp_discard(void) 96 { 97 struct pnpinfo *pi; 98 99 while (STAILQ_FIRST(&pnp_devices) != NULL) { 100 pi = STAILQ_FIRST(&pnp_devices); 101 STAILQ_REMOVE_HEAD(&pnp_devices, pi_link); 102 pnp_freeinfo(pi); 103 } 104 } 105 106 /* 107 * Add a unique identifier to (pi) 108 */ 109 void 110 pnp_addident(struct pnpinfo *pi, char *ident) 111 { 112 struct pnpident *id; 113 114 STAILQ_FOREACH(id, &pi->pi_ident, id_link) 115 if (!strcmp(id->id_ident, ident)) 116 return; /* already have this one */ 117 118 id = malloc(sizeof(struct pnpident)); 119 id->id_ident = strdup(ident); 120 STAILQ_INSERT_TAIL(&pi->pi_ident, id, id_link); 121 } 122 123 /* 124 * Allocate a new pnpinfo struct 125 */ 126 struct pnpinfo * 127 pnp_allocinfo(void) 128 { 129 struct pnpinfo *pi; 130 131 pi = malloc(sizeof(struct pnpinfo)); 132 bzero(pi, sizeof(struct pnpinfo)); 133 STAILQ_INIT(&pi->pi_ident); 134 return(pi); 135 } 136 137 /* 138 * Release storage held by a pnpinfo struct 139 */ 140 void 141 pnp_freeinfo(struct pnpinfo *pi) 142 { 143 struct pnpident *id; 144 145 while (!STAILQ_EMPTY(&pi->pi_ident)) { 146 id = STAILQ_FIRST(&pi->pi_ident); 147 STAILQ_REMOVE_HEAD(&pi->pi_ident, id_link); 148 free(id->id_ident); 149 free(id); 150 } 151 if (pi->pi_desc) 152 free(pi->pi_desc); 153 if (pi->pi_module) 154 free(pi->pi_module); 155 if (pi->pi_argv) 156 free(pi->pi_argv); 157 free(pi); 158 } 159 160 /* 161 * Add a new pnpinfo struct to the list. 162 */ 163 void 164 pnp_addinfo(struct pnpinfo *pi) 165 { 166 STAILQ_INSERT_TAIL(&pnp_devices, pi, pi_link); 167 } 168 169 170 /* 171 * Format an EISA id as a string in standard ISA PnP format, AAAIIRR 172 * where 'AAA' is the EISA vendor ID, II is the product ID and RR the revision ID. 173 */ 174 char * 175 pnp_eisaformat(u_int8_t *data) 176 { 177 static char idbuf[8]; 178 const char hextoascii[] = "0123456789abcdef"; 179 180 idbuf[0] = '@' + ((data[0] & 0x7c) >> 2); 181 idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5)); 182 idbuf[2] = '@' + (data[1] & 0x1f); 183 idbuf[3] = hextoascii[(data[2] >> 4)]; 184 idbuf[4] = hextoascii[(data[2] & 0xf)]; 185 idbuf[5] = hextoascii[(data[3] >> 4)]; 186 idbuf[6] = hextoascii[(data[3] & 0xf)]; 187 idbuf[7] = 0; 188 return(idbuf); 189 } 190 191 #ifdef BOOT_FORTH 192 void 193 ficlPnpdevices(FICL_VM *pVM) 194 { 195 static int pnp_devices_initted = 0; 196 #if FICL_ROBUST > 1 197 vmCheckStack(pVM, 0, 1); 198 #endif 199 200 if(!pnp_devices_initted) { 201 STAILQ_INIT(&pnp_devices); 202 pnp_devices_initted = 1; 203 } 204 205 stackPushPtr(pVM->pStack, &pnp_devices); 206 207 return; 208 } 209 210 void 211 ficlPnphandlers(FICL_VM *pVM) 212 { 213 #if FICL_ROBUST > 1 214 vmCheckStack(pVM, 0, 1); 215 #endif 216 217 stackPushPtr(pVM->pStack, pnphandlers); 218 219 return; 220 } 221 222 /* 223 * Glue function to add the appropriate forth words to access pnp BIOS 224 * functionality. 225 */ 226 static void ficlCompilePnp(FICL_SYSTEM *pSys) 227 { 228 FICL_DICT *dp = pSys->dp; 229 assert (dp); 230 231 dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT); 232 dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT); 233 } 234 235 FICL_COMPILE_SET(ficlCompilePnp); 236 #endif 237