1 /* $OpenBSD: pci_subr.c,v 1.9 2001/01/16 23:35:31 d Exp $ */ 2 /* $NetBSD: pci_subr.c,v 1.19 1996/10/13 01:38:29 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved. 6 * Copyright (c) 1994 Charles Hannum. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles Hannum. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * PCI autoconfiguration support functions. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 #ifdef PCIVERBOSE 45 #include <dev/pci/pcidevs.h> 46 #endif 47 48 /* 49 * Descriptions of known PCI classes and subclasses. 50 * 51 * Subclasses are described in the same way as classes, but have a 52 * NULL subclass pointer. 53 */ 54 struct pci_class { 55 char *name; 56 int val; /* as wide as pci_{,sub}class_t */ 57 struct pci_class *subclasses; 58 }; 59 60 struct pci_class pci_subclass_prehistoric[] = { 61 { "miscellaneous", PCI_SUBCLASS_PREHISTORIC_MISC, }, 62 { "VGA", PCI_SUBCLASS_PREHISTORIC_VGA, }, 63 { 0 } 64 }; 65 66 struct pci_class pci_subclass_mass_storage[] = { 67 { "SCSI", PCI_SUBCLASS_MASS_STORAGE_SCSI, }, 68 { "IDE", PCI_SUBCLASS_MASS_STORAGE_IDE, }, 69 { "floppy", PCI_SUBCLASS_MASS_STORAGE_FLOPPY, }, 70 { "IPI", PCI_SUBCLASS_MASS_STORAGE_IPI, }, 71 { "RAID", PCI_SUBCLASS_MASS_STORAGE_RAID, }, 72 { "miscellaneous", PCI_SUBCLASS_MASS_STORAGE_MISC, }, 73 { 0 }, 74 }; 75 76 struct pci_class pci_subclass_network[] = { 77 { "ethernet", PCI_SUBCLASS_NETWORK_ETHERNET, }, 78 { "token ring", PCI_SUBCLASS_NETWORK_TOKENRING, }, 79 { "FDDI", PCI_SUBCLASS_NETWORK_FDDI, }, 80 { "ATM", PCI_SUBCLASS_NETWORK_ATM, }, 81 { "miscellaneous", PCI_SUBCLASS_NETWORK_MISC, }, 82 { 0 }, 83 }; 84 85 struct pci_class pci_subclass_display[] = { 86 { "VGA", PCI_SUBCLASS_DISPLAY_VGA, }, 87 { "XGA", PCI_SUBCLASS_DISPLAY_XGA, }, 88 { "miscellaneous", PCI_SUBCLASS_DISPLAY_MISC, }, 89 { 0 }, 90 }; 91 92 struct pci_class pci_subclass_multimedia[] = { 93 { "video", PCI_SUBCLASS_MULTIMEDIA_VIDEO, }, 94 { "audio", PCI_SUBCLASS_MULTIMEDIA_AUDIO, }, 95 { "miscellaneous", PCI_SUBCLASS_MULTIMEDIA_MISC, }, 96 { 0 }, 97 }; 98 99 struct pci_class pci_subclass_memory[] = { 100 { "RAM", PCI_SUBCLASS_MEMORY_RAM, }, 101 { "flash", PCI_SUBCLASS_MEMORY_FLASH, }, 102 { "miscellaneous", PCI_SUBCLASS_MEMORY_MISC, }, 103 { 0 }, 104 }; 105 106 struct pci_class pci_subclass_bridge[] = { 107 { "host", PCI_SUBCLASS_BRIDGE_HOST, }, 108 { "ISA", PCI_SUBCLASS_BRIDGE_ISA, }, 109 { "EISA", PCI_SUBCLASS_BRIDGE_EISA, }, 110 { "MicroChannel", PCI_SUBCLASS_BRIDGE_MC, }, 111 { "PCI", PCI_SUBCLASS_BRIDGE_PCI, }, 112 { "PCMCIA", PCI_SUBCLASS_BRIDGE_PCMCIA, }, 113 { "NuBus", PCI_SUBCLASS_BRIDGE_NUBUS, }, 114 { "CardBus", PCI_SUBCLASS_BRIDGE_CARDBUS, }, 115 { "miscellaneous", PCI_SUBCLASS_BRIDGE_MISC, }, 116 { 0 }, 117 }; 118 119 struct pci_class pci_subclass_communications[] = { 120 { "serial", PCI_SUBCLASS_COMMUNICATIONS_SERIAL, }, 121 { "parallel", PCI_SUBCLASS_COMMUNICATIONS_PARALLEL, }, 122 { "miscellaneous", PCI_SUBCLASS_COMMUNICATIONS_MISC, }, 123 { 0 }, 124 }; 125 126 struct pci_class pci_subclass_system[] = { 127 { "8259 PIC", PCI_SUBCLASS_SYSTEM_PIC, }, 128 { "8237 DMA", PCI_SUBCLASS_SYSTEM_DMA, }, 129 { "8254 timer", PCI_SUBCLASS_SYSTEM_TIMER, }, 130 { "RTC", PCI_SUBCLASS_SYSTEM_RTC, }, 131 { "miscellaneous", PCI_SUBCLASS_SYSTEM_MISC, }, 132 { 0 }, 133 }; 134 135 struct pci_class pci_subclass_input[] = { 136 { "keyboard", PCI_SUBCLASS_INPUT_KEYBOARD, }, 137 { "digitizer", PCI_SUBCLASS_INPUT_DIGITIZER, }, 138 { "mouse", PCI_SUBCLASS_INPUT_MOUSE, }, 139 { "miscellaneous", PCI_SUBCLASS_INPUT_MISC, }, 140 { 0 }, 141 }; 142 143 struct pci_class pci_subclass_dock[] = { 144 { "generic", PCI_SUBCLASS_DOCK_GENERIC, }, 145 { "miscellaneous", PCI_SUBCLASS_DOCK_MISC, }, 146 { 0 }, 147 }; 148 149 struct pci_class pci_subclass_processor[] = { 150 { "386", PCI_SUBCLASS_PROCESSOR_386, }, 151 { "486", PCI_SUBCLASS_PROCESSOR_486, }, 152 { "Pentium", PCI_SUBCLASS_PROCESSOR_PENTIUM, }, 153 { "Alpha", PCI_SUBCLASS_PROCESSOR_ALPHA, }, 154 { "PowerPC", PCI_SUBCLASS_PROCESSOR_POWERPC, }, 155 { "Co-processor", PCI_SUBCLASS_PROCESSOR_COPROC, }, 156 { 0 }, 157 }; 158 159 struct pci_class pci_subclass_serialbus[] = { 160 { "Firewire", PCI_SUBCLASS_SERIALBUS_FIREWIRE, }, 161 { "ACCESS.bus", PCI_SUBCLASS_SERIALBUS_ACCESS, }, 162 { "SSA", PCI_SUBCLASS_SERIALBUS_SSA, }, 163 { "USB", PCI_SUBCLASS_SERIALBUS_USB, }, 164 { "Fiber Channel", PCI_SUBCLASS_SERIALBUS_FIBER, }, 165 { 0 }, 166 }; 167 168 struct pci_class pci_class[] = { 169 { "prehistoric", PCI_CLASS_PREHISTORIC, 170 pci_subclass_prehistoric, }, 171 { "mass storage", PCI_CLASS_MASS_STORAGE, 172 pci_subclass_mass_storage, }, 173 { "network", PCI_CLASS_NETWORK, 174 pci_subclass_network, }, 175 { "display", PCI_CLASS_DISPLAY, 176 pci_subclass_display, }, 177 { "multimedia", PCI_CLASS_MULTIMEDIA, 178 pci_subclass_multimedia, }, 179 { "memory", PCI_CLASS_MEMORY, 180 pci_subclass_memory, }, 181 { "bridge", PCI_CLASS_BRIDGE, 182 pci_subclass_bridge, }, 183 { "communications", PCI_CLASS_COMMUNICATIONS, 184 pci_subclass_communications, }, 185 { "system", PCI_CLASS_SYSTEM, 186 pci_subclass_system, }, 187 { "input", PCI_CLASS_INPUT, 188 pci_subclass_input, }, 189 { "dock", PCI_CLASS_DOCK, 190 pci_subclass_dock, }, 191 { "processor", PCI_CLASS_PROCESSOR, 192 pci_subclass_processor, }, 193 { "serial bus", PCI_CLASS_SERIALBUS, 194 pci_subclass_serialbus, }, 195 { "undefined", PCI_CLASS_UNDEFINED, 196 0, }, 197 { 0 }, 198 }; 199 200 #ifdef PCIVERBOSE 201 /* 202 * Descriptions of of known vendors and devices ("products"). 203 */ 204 struct pci_knowndev { 205 pci_vendor_id_t vendor; 206 pci_product_id_t product; 207 int flags; 208 char *vendorname, *productname; 209 }; 210 #define PCI_KNOWNDEV_NOPROD 0x01 /* match on vendor only */ 211 212 #include <dev/pci/pcidevs_data.h> 213 #endif /* PCIVERBOSE */ 214 215 void 216 pci_devinfo(id_reg, class_reg, showclass, cp) 217 pcireg_t id_reg, class_reg; 218 int showclass; 219 char *cp; 220 { 221 pci_vendor_id_t vendor; 222 pci_product_id_t product; 223 pci_class_t class; 224 pci_subclass_t subclass; 225 pci_interface_t interface; 226 pci_revision_t revision; 227 char *vendor_namep, *product_namep; 228 struct pci_class *classp, *subclassp; 229 #ifdef PCIVERBOSE 230 struct pci_knowndev *kdp; 231 const char *unmatched = "unknown "; 232 #else 233 const char *unmatched = ""; 234 #endif 235 236 vendor = PCI_VENDOR(id_reg); 237 product = PCI_PRODUCT(id_reg); 238 239 class = PCI_CLASS(class_reg); 240 subclass = PCI_SUBCLASS(class_reg); 241 interface = PCI_INTERFACE(class_reg); 242 revision = PCI_REVISION(class_reg); 243 244 #ifdef PCIVERBOSE 245 kdp = pci_knowndevs; 246 while (kdp->vendorname != NULL) { /* all have vendor name */ 247 if (kdp->vendor == vendor && (kdp->product == product || 248 (kdp->flags & PCI_KNOWNDEV_NOPROD) != 0)) 249 break; 250 kdp++; 251 } 252 if (kdp->vendorname == NULL) 253 vendor_namep = product_namep = NULL; 254 else { 255 vendor_namep = kdp->vendorname; 256 product_namep = (kdp->flags & PCI_KNOWNDEV_NOPROD) == 0 ? 257 kdp->productname : NULL; 258 } 259 #else /* PCIVERBOSE */ 260 vendor_namep = product_namep = NULL; 261 #endif /* PCIVERBOSE */ 262 263 classp = pci_class; 264 while (classp->name != NULL) { 265 if (class == classp->val) 266 break; 267 classp++; 268 } 269 270 subclassp = (classp->name != NULL) ? classp->subclasses : NULL; 271 while (subclassp && subclassp->name != NULL) { 272 if (subclass == subclassp->val) 273 break; 274 subclassp++; 275 } 276 277 if (vendor_namep == NULL) 278 cp += sprintf(cp, "%svendor 0x%04x product 0x%04x", 279 unmatched, vendor, product); 280 else if (product_namep != NULL) 281 cp += sprintf(cp, "\"%s %s\"", vendor_namep, product_namep); 282 else 283 cp += sprintf(cp, "vendor \"%s\", unknown product 0x%x", 284 vendor_namep, product); 285 if (showclass && product_namep == NULL) { 286 cp += sprintf(cp, " ("); 287 if (classp->name == NULL) 288 cp += sprintf(cp, 289 "unknown class 0x%02x, subclass 0x%02x", 290 class, subclass); 291 else { 292 cp += sprintf(cp, "class %s, ", classp->name); 293 if (subclassp == NULL || subclassp->name == NULL) 294 cp += sprintf(cp, "unknown subclass 0x%02x", 295 subclass); 296 else 297 cp += sprintf(cp, "subclass %s", 298 subclassp->name); 299 } 300 #if 0 /* not very useful */ 301 cp += sprintf(cp, ", interface 0x%02x", interface); 302 #endif 303 cp += sprintf(cp, ", rev 0x%02x)", revision); 304 } else 305 cp += sprintf(cp, " rev 0x%02x", revision); 306 } 307