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