xref: /openbsd-src/sys/dev/pci/pci_subr.c (revision a22bd23892e5059fac7719e8cabaa2631e413e53)
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