1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/boot/i386/libi386/biospci.c,v 1.4 2003/08/25 23:28:31 obrien Exp $ 27 */ 28 29 /* 30 * PnP enumerator using the PCI BIOS. 31 */ 32 33 #include <stand.h> 34 #include <machine/stdarg.h> 35 #include <machine/psl.h> 36 #include <bootstrap.h> 37 #include <isapnp.h> 38 #include <btxv86.h> 39 40 /* 41 * Stupid PCI BIOS interface doesn't let you simply enumerate everything 42 * that's there, instead you have to ask it if it has something. 43 * 44 * So we have to scan by class code, subclass code and sometimes programming 45 * interface. 46 */ 47 48 struct pci_progif 49 { 50 int pi_code; 51 const char *pi_name; 52 }; 53 54 static struct pci_progif progif_null[] = { 55 {0x0, NULL}, 56 {-1, NULL} 57 }; 58 59 static struct pci_progif progif_display[] = { 60 {0x0, "VGA"}, 61 {0x1, "8514"}, 62 {-1, NULL} 63 }; 64 65 static struct pci_progif progif_ide[] = { 66 {0x00, NULL}, 67 {0x01, NULL}, 68 {0x02, NULL}, 69 {0x03, NULL}, 70 {0x04, NULL}, 71 {0x05, NULL}, 72 {0x06, NULL}, 73 {0x07, NULL}, 74 {0x08, NULL}, 75 {0x09, NULL}, 76 {0x0a, NULL}, 77 {0x0b, NULL}, 78 {0x0c, NULL}, 79 {0x0d, NULL}, 80 {0x0e, NULL}, 81 {0x0f, NULL}, 82 {0x80, NULL}, 83 {0x81, NULL}, 84 {0x82, NULL}, 85 {0x83, NULL}, 86 {0x84, NULL}, 87 {0x85, NULL}, 88 {0x86, NULL}, 89 {0x87, NULL}, 90 {0x88, NULL}, 91 {0x89, NULL}, 92 {0x8a, NULL}, 93 {0x8b, NULL}, 94 {0x8c, NULL}, 95 {0x8d, NULL}, 96 {0x8e, NULL}, 97 {0x8f, NULL}, 98 {-1, NULL} 99 }; 100 101 static struct pci_progif progif_serial[] = { 102 {0x0, "8250"}, 103 {0x1, "16450"}, 104 {0x2, "16550"}, 105 {-1, NULL} 106 }; 107 108 static struct pci_progif progif_parallel[] = { 109 {0x0, "Standard"}, 110 {0x1, "Bidirectional"}, 111 {0x2, "ECP"}, 112 {-1, NULL} 113 }; 114 115 116 struct pci_subclass 117 { 118 int ps_subclass; 119 const char *ps_name; 120 struct pci_progif *ps_progif; /* if set, use for programming interface value(s) */ 121 }; 122 123 static struct pci_subclass subclass_old[] = { 124 {0x0, "Old non-VGA", progif_null}, 125 {0x1, "Old VGA", progif_null}, 126 {-1, NULL, NULL} 127 }; 128 129 static struct pci_subclass subclass_mass[] = { 130 {0x0, "SCSI", progif_null}, 131 {0x1, "IDE", progif_ide}, 132 {0x2, "Floppy disk", progif_null}, 133 {0x3, "IPI", progif_null}, 134 {0x4, "RAID", progif_null}, 135 {0x80, "mass storage", progif_null}, 136 {-1, NULL, NULL} 137 }; 138 139 static struct pci_subclass subclass_net[] = { 140 {0x0, "Ethernet", progif_null}, 141 {0x1, "Token ring", progif_null}, 142 {0x2, "FDDI", progif_null}, 143 {0x3, "ATM", progif_null}, 144 {0x80, "network", progif_null}, 145 {-1, NULL, NULL} 146 }; 147 148 static struct pci_subclass subclass_display[] = { 149 {0x0, NULL, progif_display}, 150 {0x1, "XGA", progif_null}, 151 {0x80, "other", progif_null}, 152 {-1, NULL, NULL} 153 }; 154 155 static struct pci_subclass subclass_comms[] = { 156 {0x0, "serial", progif_serial}, 157 {0x1, "parallel", progif_parallel}, 158 {0x80, "communications", progif_null}, 159 {-1, NULL, NULL} 160 }; 161 162 static struct pci_subclass subclass_serial[] = { 163 {0x0, "Firewire", progif_null}, 164 {0x1, "ACCESS.bus", progif_null}, 165 {0x2, "SSA", progif_null}, 166 {0x3, "USB", progif_null}, 167 {0x4, "Fibrechannel", progif_null}, 168 {-1, NULL, NULL} 169 }; 170 171 static struct pci_class 172 { 173 int pc_class; 174 const char *pc_name; 175 struct pci_subclass *pc_subclass; 176 } pci_classes[] = { 177 {0x0, "device", subclass_old}, 178 {0x1, "controller", subclass_mass}, 179 {0x2, "controller", subclass_net}, 180 {0x3, "display", subclass_display}, 181 {0x7, "controller", subclass_comms}, 182 {0xc, "controller", subclass_serial}, 183 {-1, NULL, NULL} 184 }; 185 186 187 static void biospci_enumerate(void); 188 static void biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi); 189 190 static int biospci_version; 191 static int biospci_hwcap; 192 193 struct pnphandler biospcihandler = 194 { 195 "PCI BIOS", 196 biospci_enumerate 197 }; 198 199 static void 200 biospci_enumerate(void) 201 { 202 int device_index, locator, devid; 203 struct pci_class *pc; 204 struct pci_subclass *psc; 205 struct pci_progif *ppi; 206 207 /* Find the PCI BIOS */ 208 v86.ctl = V86_FLAGS; 209 v86.addr = 0x1a; 210 v86.eax = 0xb101; 211 v86.edi = 0x0; 212 v86int(); 213 214 /* Check for OK response */ 215 if ((v86.efl & PSL_C) || ((v86.eax & 0xff00) != 0) || (v86.edx != 0x20494350)) 216 return; 217 218 biospci_version = v86.ebx & 0xffff; 219 biospci_hwcap = v86.eax & 0xff; 220 #if 0 221 printf("PCI BIOS %d.%d%s%s\n", 222 bcd2bin((biospci_version >> 8) & 0xf), bcd2bin(biospci_version & 0xf), 223 (biospci_hwcap & 1) ? " config1" : "", (biospci_hwcap & 2) ? " config2" : ""); 224 #endif 225 /* Iterate over known classes */ 226 for (pc = pci_classes; pc->pc_class >= 0; pc++) { 227 /* Iterate over subclasses */ 228 for (psc = pc->pc_subclass; psc->ps_subclass >= 0; psc++) { 229 /* Iterate over programming interfaces */ 230 for (ppi = psc->ps_progif; ppi->pi_code >= 0; ppi++) { 231 232 /* Scan for matches */ 233 for (device_index = 0; ; device_index++) { 234 235 /* Look for a match */ 236 v86.ctl = V86_FLAGS; 237 v86.addr = 0x1a; 238 v86.eax = 0xb103; 239 v86.ecx = (pc->pc_class << 16) + (psc->ps_subclass << 8) + ppi->pi_code; 240 v86.esi = device_index; 241 v86int(); 242 /* error/end of matches */ 243 if ((v86.efl & PSL_C) || (v86.eax & 0xff00)) 244 break; 245 246 /* Got something */ 247 locator = v86.ebx; 248 249 /* Read the device identifier from the nominated device */ 250 v86.ctl = V86_FLAGS; 251 v86.addr = 0x1a; 252 v86.eax = 0xb10a; 253 v86.ebx = locator; 254 v86.edi = 0x0; 255 v86int(); 256 /* error */ 257 if ((v86.efl & PSL_C) || (v86.eax & 0xff00)) 258 break; 259 260 /* We have the device ID, create a PnP object and save everything */ 261 devid = v86.ecx; 262 biospci_addinfo(devid, pc, psc, ppi); 263 } 264 } 265 } 266 } 267 } 268 269 static void 270 biospci_addinfo(int devid, struct pci_class *pc, struct pci_subclass *psc, struct pci_progif *ppi) 271 { 272 struct pnpinfo *pi; 273 char desc[80]; 274 275 276 /* build the description */ 277 desc[0] = 0; 278 if (ppi->pi_name != NULL) { 279 strcat(desc, ppi->pi_name); 280 strcat(desc, " "); 281 } 282 if (psc->ps_name != NULL) { 283 strcat(desc, psc->ps_name); 284 strcat(desc, " "); 285 } 286 if (pc->pc_name != NULL) 287 strcat(desc, pc->pc_name); 288 289 pi = pnp_allocinfo(); 290 pi->pi_desc = strdup(desc); 291 sprintf(desc,"0x%08x", devid); 292 pnp_addident(pi, desc); 293 pnp_addinfo(pi); 294 } 295