xref: /netbsd-src/sys/dev/pci/pci_subr.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: pci_subr.c,v 1.17 1996/03/02 02:28:48 cgd Exp $	*/
2 
3 /*
4  * Copyright (c) 1995, 1996 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 /*
48  * Descriptions of known PCI classes and subclasses.
49  *
50  * Subclasses are described in the same way as classes, but have a
51  * NULL subclass pointer.
52  */
53 struct pci_class {
54 	char		*name;
55 	int		val;		/* as wide as pci_{,sub}class_t */
56 	struct pci_class *subclasses;
57 };
58 
59 struct pci_class pci_subclass_prehistoric[] = {
60 	{ "miscellaneous",	PCI_SUBCLASS_PREHISTORIC_MISC,		},
61 	{ "VGA",		PCI_SUBCLASS_PREHISTORIC_VGA,		},
62 	{ 0 }
63 };
64 
65 struct pci_class pci_subclass_mass_storage[] = {
66 	{ "SCSI",		PCI_SUBCLASS_MASS_STORAGE_SCSI,		},
67 	{ "IDE",		PCI_SUBCLASS_MASS_STORAGE_IDE,		},
68 	{ "floppy",		PCI_SUBCLASS_MASS_STORAGE_FLOPPY,	},
69 	{ "IPI",		PCI_SUBCLASS_MASS_STORAGE_IPI,		},
70 	{ "miscellaneous",	PCI_SUBCLASS_MASS_STORAGE_MISC,		},
71 	{ 0 },
72 };
73 
74 struct pci_class pci_subclass_network[] = {
75 	{ "ethernet",		PCI_SUBCLASS_NETWORK_ETHERNET,		},
76 	{ "token ring",		PCI_SUBCLASS_NETWORK_TOKENRING,		},
77 	{ "FDDI",		PCI_SUBCLASS_NETWORK_FDDI,		},
78 	{ "miscellaneous",	PCI_SUBCLASS_NETWORK_MISC,		},
79 	{ 0 },
80 };
81 
82 struct pci_class pci_subclass_display[] = {
83 	{ "VGA",		PCI_SUBCLASS_DISPLAY_VGA,		},
84 	{ "XGA",		PCI_SUBCLASS_DISPLAY_XGA,		},
85 	{ "miscellaneous",	PCI_SUBCLASS_DISPLAY_MISC,		},
86 	{ 0 },
87 };
88 
89 struct pci_class pci_subclass_multimedia[] = {
90 	{ "video",		PCI_SUBCLASS_MULTIMEDIA_VIDEO,		},
91 	{ "audio",		PCI_SUBCLASS_MULTIMEDIA_AUDIO,		},
92 	{ "miscellaneous",	PCI_SUBCLASS_MULTIMEDIA_MISC,		},
93 	{ 0 },
94 };
95 
96 struct pci_class pci_subclass_memory[] = {
97 	{ "RAM",		PCI_SUBCLASS_MEMORY_RAM,		},
98 	{ "flash",		PCI_SUBCLASS_MEMORY_FLASH,		},
99 	{ "miscellaneous",	PCI_SUBCLASS_MEMORY_MISC,		},
100 	{ 0 },
101 };
102 
103 struct pci_class pci_subclass_bridge[] = {
104 	{ "host",		PCI_SUBCLASS_BRIDGE_HOST,		},
105 	{ "ISA",		PCI_SUBCLASS_BRIDGE_ISA,		},
106 	{ "EISA",		PCI_SUBCLASS_BRIDGE_EISA,		},
107 	{ "MicroChannel",	PCI_SUBCLASS_BRIDGE_MC,			},
108 	{ "PCI",		PCI_SUBCLASS_BRIDGE_PCI,		},
109 	{ "PCMCIA",		PCI_SUBCLASS_BRIDGE_PCMCIA,		},
110 	{ "miscellaneous",	PCI_SUBCLASS_BRIDGE_MISC,		},
111 	{ 0 },
112 };
113 
114 struct pci_class pci_class[] = {
115 	{ "prehistoric",	PCI_CLASS_PREHISTORIC,
116 	    pci_subclass_prehistoric,				},
117 	{ "mass storage",	PCI_CLASS_MASS_STORAGE,
118 	    pci_subclass_mass_storage,				},
119 	{ "network",		PCI_CLASS_NETWORK,
120 	    pci_subclass_network,				},
121 	{ "display",		PCI_CLASS_DISPLAY,
122 	    pci_subclass_display,				},
123 	{ "multimedia",		PCI_CLASS_MULTIMEDIA,
124 	    pci_subclass_multimedia,				},
125 	{ "memory",		PCI_CLASS_MEMORY,
126 	    pci_subclass_memory,				},
127 	{ "bridge",		PCI_CLASS_BRIDGE,
128 	    pci_subclass_bridge,				},
129 	{ "undefined",		PCI_CLASS_UNDEFINED,
130 	    0,							},
131 	{ 0 },
132 };
133 
134 #ifdef PCIVERBOSE
135 /*
136  * Descriptions of of known vendors and devices ("products").
137  */
138 struct pci_knowndev {
139 	pci_vendor_id_t		vendor;
140 	pci_product_id_t	product;
141 	int			flags;
142 	char			*vendorname, *productname;
143 };
144 #define	PCI_KNOWNDEV_NOPROD	0x01		/* match on vendor only */
145 
146 #include <dev/pci/pcidevs_data.h>
147 #endif /* PCIVERBOSE */
148 
149 void
150 pci_devinfo(id_reg, class_reg, showclass, cp)
151 	pcireg_t id_reg, class_reg;
152 	int showclass;
153 	char *cp;
154 {
155 	pci_vendor_id_t vendor;
156 	pci_product_id_t product;
157 	pci_class_t class;
158 	pci_subclass_t subclass;
159 	pci_interface_t interface;
160 	pci_revision_t revision;
161 	char *vendor_namep, *product_namep;
162 	struct pci_class *classp, *subclassp;
163 #ifdef PCIVERBOSE
164 	struct pci_knowndev *kdp;
165 	const char *unmatched = "unknown ";
166 #else
167 	const char *unmatched = "";
168 #endif
169 
170 	vendor = PCI_VENDOR(id_reg);
171 	product = PCI_PRODUCT(id_reg);
172 
173 	class = PCI_CLASS(class_reg);
174 	subclass = PCI_SUBCLASS(class_reg);
175 	interface = PCI_INTERFACE(class_reg);
176 	revision = PCI_REVISION(class_reg);
177 
178 #ifdef PCIVERBOSE
179 	kdp = pci_knowndevs;
180         while (kdp->vendorname != NULL) {	/* all have vendor name */
181                 if (kdp->vendor == vendor && (kdp->product == product ||
182 		    (kdp->flags & PCI_KNOWNDEV_NOPROD) != 0))
183                         break;
184 		kdp++;
185 	}
186         if (kdp->vendorname == NULL)
187 		vendor_namep = product_namep = NULL;
188 	else {
189 		vendor_namep = kdp->vendorname;
190 		product_namep = (kdp->flags & PCI_KNOWNDEV_NOPROD) == 0 ?
191 		    kdp->productname : NULL;
192         }
193 #else /* PCIVERBOSE */
194 	vendor_namep = product_namep = NULL;
195 #endif /* PCIVERBOSE */
196 
197 	classp = pci_class;
198 	while (classp->name != NULL) {
199 		if (class == classp->val)
200 			break;
201 		classp++;
202 	}
203 
204 	subclassp = (classp->name != NULL) ? classp->subclasses : NULL;
205 	while (subclassp && subclassp->name != NULL) {
206 		if (subclass == subclassp->val)
207 			break;
208 		subclassp++;
209 	}
210 
211 	if (vendor_namep == NULL)
212 		cp += sprintf(cp, "%svendor 0x%04x product 0x%04x",
213 		    unmatched, vendor, product);
214 	else if (product_namep != NULL)
215 		cp += sprintf(cp, "%s %s", vendor_namep, product_namep);
216 	else
217 		cp += sprintf(cp, "vendor %s, unknown product 0x%x",
218 		    vendor_namep, product);
219 	if (showclass) {
220 		cp += sprintf(cp, " (");
221 		if (classp->name == NULL)
222 			cp += sprintf(cp,
223 			    "unknown class 0x%2x, subclass 0x%02x",
224 			    class, subclass);
225 		else {
226 			cp += sprintf(cp, "class %s, ", classp->name);
227 			if (subclassp == NULL || subclassp->name == NULL)
228 				cp += sprintf(cp, "unknown subclass 0x%02x",
229 				    subclass);
230 			else
231 				cp += sprintf(cp, "subclass %s",
232 				    subclassp->name);
233 		}
234 #if 0 /* not very useful */
235 		cp += sprintf(cp, ", interface 0x%02x", interface);
236 #endif
237 		cp += sprintf(cp, ", revision 0x%02x)", revision);
238 	}
239 }
240