]> git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/names.c
Fixed a couple of bugs in the AIX port and added several new ID's.
[thirdparty/pciutils.git] / lib / names.c
1 /*
2 * $Id: names.c,v 1.6 2000/04/29 12:56:23 mj Exp $
3 *
4 * The PCI Library -- ID to Name Translation
5 *
6 * Copyright (c) 1997--2000 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <errno.h>
18
19 #include "internal.h"
20
21 struct nl_entry {
22 struct nl_entry *next;
23 word id1, id2, id3, id4;
24 int cat;
25 byte *name;
26 };
27
28 #define NL_VENDOR 0
29 #define NL_DEVICE 1
30 #define NL_SUBSYSTEM 2
31 #define NL_CLASS 3
32 #define NL_SUBCLASS 4
33 #define NL_PROGIF 5
34
35 #define HASH_SIZE 1024
36
37 static inline unsigned int nl_calc_hash(int cat, int id1, int id2, int id3, int id4)
38 {
39 unsigned int h;
40
41 h = id1 ^ id2 ^ id3 ^ id4 ^ (cat << 5);
42 h += (h >> 6);
43 return h & (HASH_SIZE-1);
44 }
45
46 static struct nl_entry *nl_lookup(struct pci_access *a, int num, int cat, int id1, int id2, int id3, int id4)
47 {
48 unsigned int h;
49 struct nl_entry *n;
50
51 if (num)
52 return NULL;
53 h = nl_calc_hash(cat, id1, id2, id3, id4);
54 n = a->nl_hash[h];
55 while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat))
56 n = n->next;
57 return n;
58 }
59
60 static int nl_add(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, byte *text)
61 {
62 unsigned int h = nl_calc_hash(cat, id1, id2, id3, id4);
63 struct nl_entry *n = a->nl_hash[h];
64
65 while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat))
66 n = n->next;
67 if (n)
68 return 1;
69 n = pci_malloc(a, sizeof(struct nl_entry));
70 n->id1 = id1;
71 n->id2 = id2;
72 n->id3 = id3;
73 n->id4 = id4;
74 n->cat = cat;
75 n->name = text;
76 n->next = a->nl_hash[h];
77 a->nl_hash[h] = n;
78 return 0;
79 }
80
81 static void
82 err_name_list(struct pci_access *a, char *msg)
83 {
84 a->error("%s: %s: %s\n", a->id_file_name, msg, strerror(errno));
85 }
86
87 static void
88 parse_name_list(struct pci_access *a)
89 {
90 byte *p = a->nl_list;
91 byte *q, *r;
92 int lino = 0;
93 unsigned int id1=0, id2=0, id3=0, id4=0;
94 int cat = -1;
95
96 while (*p)
97 {
98 lino++;
99 q = p;
100 while (*p && *p != '\n')
101 {
102 if (*p == '#')
103 {
104 *p++ = 0;
105 while (*p && *p != '\n')
106 p++;
107 break;
108 }
109 p++;
110 }
111 if (*p == '\n')
112 *p++ = 0;
113 if (!*q)
114 continue;
115 r = p;
116 while (r > q && r[-1] == ' ')
117 *--r = 0;
118 r = q;
119 while (*q == '\t')
120 q++;
121 if (q == r)
122 {
123 if (q[0] == 'C' && q[1] == ' ')
124 {
125 if (strlen(q+2) < 3 ||
126 q[4] != ' ' ||
127 sscanf(q+2, "%x", &id1) != 1)
128 goto parserr;
129 cat = NL_CLASS;
130 }
131 else
132 {
133 if (strlen(q) < 5 ||
134 q[4] != ' ' ||
135 sscanf(q, "%x", &id1) != 1)
136 goto parserr;
137 cat = NL_VENDOR;
138 }
139 id2 = id3 = id4 = 0;
140 q += 4;
141 }
142 else if (q == r+1)
143 switch (cat)
144 {
145 case NL_VENDOR:
146 case NL_DEVICE:
147 case NL_SUBSYSTEM:
148 if (sscanf(q, "%x", &id2) != 1 || q[4] != ' ')
149 goto parserr;
150 q += 5;
151 cat = NL_DEVICE;
152 id3 = id4 = 0;
153 break;
154 case NL_CLASS:
155 case NL_SUBCLASS:
156 case NL_PROGIF:
157 if (sscanf(q, "%x", &id2) != 1 || q[2] != ' ')
158 goto parserr;
159 q += 3;
160 cat = NL_SUBCLASS;
161 id3 = id4 = 0;
162 break;
163 default:
164 goto parserr;
165 }
166 else if (q == r+2)
167 switch (cat)
168 {
169 case NL_DEVICE:
170 case NL_SUBSYSTEM:
171 if (sscanf(q, "%x%x", &id3, &id4) != 2 || q[9] != ' ')
172 goto parserr;
173 q += 10;
174 cat = NL_SUBSYSTEM;
175 break;
176 case NL_CLASS:
177 case NL_SUBCLASS:
178 case NL_PROGIF:
179 if (sscanf(q, "%x", &id3) != 1 || q[2] != ' ')
180 goto parserr;
181 q += 3;
182 cat = NL_PROGIF;
183 id4 = 0;
184 break;
185 default:
186 goto parserr;
187 }
188 else
189 goto parserr;
190 while (*q == ' ')
191 q++;
192 if (!*q)
193 goto parserr;
194 if (nl_add(a, cat, id1, id2, id3, id4, q))
195 a->error("%s, line %d: duplicate entry", a->id_file_name, lino);
196 }
197 return;
198
199 parserr:
200 a->error("%s, line %d: parse error", a->id_file_name, lino);
201 }
202
203 static void
204 load_name_list(struct pci_access *a)
205 {
206 int fd;
207 struct stat st;
208
209 fd = open(a->id_file_name, O_RDONLY);
210 if (fd < 0)
211 {
212 a->numeric_ids = 1;
213 return;
214 }
215 if (fstat(fd, &st) < 0)
216 err_name_list(a, "stat");
217 a->nl_list = pci_malloc(a, st.st_size + 1);
218 if (read(fd, a->nl_list, st.st_size) != st.st_size)
219 err_name_list(a, "read");
220 a->nl_list[st.st_size] = 0;
221 a->nl_hash = pci_malloc(a, sizeof(struct nl_entry *) * HASH_SIZE);
222 bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE);
223 parse_name_list(a);
224 close(fd);
225 }
226
227 void
228 pci_free_name_list(struct pci_access *a)
229 {
230 pci_mfree(a->nl_list);
231 a->nl_list = NULL;
232 pci_mfree(a->nl_hash);
233 a->nl_hash = NULL;
234 }
235
236 char *
237 pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
238 {
239 int num = a->numeric_ids;
240 int res;
241 struct nl_entry *n;
242
243 if (flags & PCI_LOOKUP_NUMERIC)
244 {
245 flags &= PCI_LOOKUP_NUMERIC;
246 num = 1;
247 }
248 if (!a->nl_hash && !num)
249 {
250 load_name_list(a);
251 num = a->numeric_ids;
252 }
253 switch (flags)
254 {
255 case PCI_LOOKUP_VENDOR:
256 if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0))
257 return n->name;
258 else
259 res = snprintf(buf, size, "%04x", arg1);
260 break;
261 case PCI_LOOKUP_DEVICE:
262 if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0))
263 return n->name;
264 else
265 res = snprintf(buf, size, "%04x", arg2);
266 break;
267 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
268 if (!num)
269 {
270 struct nl_entry *e, *e2;
271 e = nl_lookup(a, 0, NL_VENDOR, arg1, 0, 0, 0);
272 e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0);
273 if (!e)
274 res = snprintf(buf, size, "Unknown device %04x:%04x", arg1, arg2);
275 else if (!e2)
276 res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg2);
277 else
278 res = snprintf(buf, size, "%s %s", e->name, e2->name);
279 }
280 else
281 res = snprintf(buf, size, "%04x:%04x", arg1, arg2);
282 break;
283 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM:
284 if (n = nl_lookup(a, num, NL_VENDOR, arg3, 0, 0, 0))
285 return n->name;
286 else
287 res = snprintf(buf, size, "%04x", arg1);
288 break;
289 case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
290 if (n = nl_lookup(a, num, NL_SUBSYSTEM, arg1, arg2, arg3, arg4))
291 return n->name;
292 else if (arg1 == arg3 && arg2 == arg4 && (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0)))
293 return n->name;
294 else
295 res = snprintf(buf, size, "%04x", arg2);
296 break;
297 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
298 if (!num)
299 {
300 struct nl_entry *e, *e2;
301 e = nl_lookup(a, 0, NL_VENDOR, arg3, 0, 0, 0);
302 e2 = nl_lookup(a, 0, NL_SUBSYSTEM, arg1, arg2, arg3, arg4);
303 if (!e2 && arg1 == arg3 && arg2 == arg4)
304 /* Cheat for vendors blindly setting subsystem ID same as device ID */
305 e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0);
306 if (!e)
307 res = snprintf(buf, size, "Unknown device %04x:%04x", arg3, arg4);
308 else if (!e2)
309 res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg4);
310 else
311 res = snprintf(buf, size, "%s %s", e->name, e2->name);
312 }
313 else
314 res = snprintf(buf, size, "%04x:%04x", arg3, arg4);
315 break;
316 case PCI_LOOKUP_CLASS:
317 if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff, 0, 0))
318 return n->name;
319 else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0, 0, 0))
320 res = snprintf(buf, size, "%s [%04x]", n->name, arg1);
321 else
322 res = snprintf(buf, size, "Class %04x", arg1);
323 break;
324 case PCI_LOOKUP_PROGIF:
325 if (n = nl_lookup(a, num, NL_PROGIF, arg1 >> 8, arg1 & 0xff, arg2, 0))
326 return n->name;
327 if (arg1 == 0x0101)
328 {
329 /* IDE controllers have complex prog-if semantics */
330 if (arg2 & 0x70)
331 return NULL;
332 res = snprintf(buf, size, "%s%s%s%s%s",
333 (arg2 & 0x80) ? "Master " : "",
334 (arg2 & 0x08) ? "SecP " : "",
335 (arg2 & 0x04) ? "SecO " : "",
336 (arg2 & 0x02) ? "PriP " : "",
337 (arg2 & 0x01) ? "PriO " : "");
338 if (res)
339 buf[--res] = 0;
340 break;
341 }
342 return NULL;
343 default:
344 return "<pci_lookup_name: invalid request>";
345 }
346 return (res == size) ? "<too-large>" : buf;
347 }