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