]> git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/names.c
End-of-line comments are no longer supported. Hashes are now perfectly valid in
[thirdparty/pciutils.git] / lib / names.c
1 /*
2 * $Id: names.c,v 1.8 2002/03/30 15:13:06 mj Exp $
3 *
4 * The PCI Library -- ID to Name Translation
5 *
6 * Copyright (c) 1997--2002 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 p++;
102 if (*p == '\n')
103 *p++ = 0;
104 if (!*q || *q == '#')
105 continue;
106 r = p;
107 while (r > q && r[-1] == ' ')
108 *--r = 0;
109 r = q;
110 while (*q == '\t')
111 q++;
112 if (q == r)
113 {
114 if (q[0] == 'C' && q[1] == ' ')
115 {
116 if (strlen(q+2) < 3 ||
117 q[4] != ' ' ||
118 sscanf(q+2, "%x", &id1) != 1)
119 goto parserr;
120 cat = NL_CLASS;
121 }
122 else
123 {
124 if (strlen(q) < 5 ||
125 q[4] != ' ' ||
126 sscanf(q, "%x", &id1) != 1)
127 goto parserr;
128 cat = NL_VENDOR;
129 }
130 id2 = id3 = id4 = 0;
131 q += 4;
132 }
133 else if (q == r+1)
134 switch (cat)
135 {
136 case NL_VENDOR:
137 case NL_DEVICE:
138 case NL_SUBSYSTEM:
139 if (sscanf(q, "%x", &id2) != 1 || q[4] != ' ')
140 goto parserr;
141 q += 5;
142 cat = NL_DEVICE;
143 id3 = id4 = 0;
144 break;
145 case NL_CLASS:
146 case NL_SUBCLASS:
147 case NL_PROGIF:
148 if (sscanf(q, "%x", &id2) != 1 || q[2] != ' ')
149 goto parserr;
150 q += 3;
151 cat = NL_SUBCLASS;
152 id3 = id4 = 0;
153 break;
154 default:
155 goto parserr;
156 }
157 else if (q == r+2)
158 switch (cat)
159 {
160 case NL_DEVICE:
161 case NL_SUBSYSTEM:
162 if (sscanf(q, "%x%x", &id3, &id4) != 2 || q[9] != ' ')
163 goto parserr;
164 q += 10;
165 cat = NL_SUBSYSTEM;
166 break;
167 case NL_CLASS:
168 case NL_SUBCLASS:
169 case NL_PROGIF:
170 if (sscanf(q, "%x", &id3) != 1 || q[2] != ' ')
171 goto parserr;
172 q += 3;
173 cat = NL_PROGIF;
174 id4 = 0;
175 break;
176 default:
177 goto parserr;
178 }
179 else
180 goto parserr;
181 while (*q == ' ')
182 q++;
183 if (!*q)
184 goto parserr;
185 if (nl_add(a, cat, id1, id2, id3, id4, q))
186 a->error("%s, line %d: duplicate entry", a->id_file_name, lino);
187 }
188 return;
189
190 parserr:
191 a->error("%s, line %d: parse error", a->id_file_name, lino);
192 }
193
194 static void
195 load_name_list(struct pci_access *a)
196 {
197 int fd;
198 struct stat st;
199
200 fd = open(a->id_file_name, O_RDONLY);
201 if (fd < 0)
202 {
203 a->numeric_ids = 1;
204 return;
205 }
206 if (fstat(fd, &st) < 0)
207 err_name_list(a, "stat");
208 a->nl_list = pci_malloc(a, st.st_size + 1);
209 if (read(fd, a->nl_list, st.st_size) != st.st_size)
210 err_name_list(a, "read");
211 a->nl_list[st.st_size] = 0;
212 a->nl_hash = pci_malloc(a, sizeof(struct nl_entry *) * HASH_SIZE);
213 bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE);
214 parse_name_list(a);
215 close(fd);
216 }
217
218 void
219 pci_free_name_list(struct pci_access *a)
220 {
221 pci_mfree(a->nl_list);
222 a->nl_list = NULL;
223 pci_mfree(a->nl_hash);
224 a->nl_hash = NULL;
225 }
226
227 char *
228 pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
229 {
230 int num = a->numeric_ids;
231 int res;
232 struct nl_entry *n;
233
234 if (flags & PCI_LOOKUP_NUMERIC)
235 {
236 flags &= PCI_LOOKUP_NUMERIC;
237 num = 1;
238 }
239 if (!a->nl_hash && !num)
240 {
241 load_name_list(a);
242 num = a->numeric_ids;
243 }
244 switch (flags)
245 {
246 case PCI_LOOKUP_VENDOR:
247 if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0))
248 return n->name;
249 else
250 res = snprintf(buf, size, "%04x", arg1);
251 break;
252 case PCI_LOOKUP_DEVICE:
253 if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0))
254 return n->name;
255 else
256 res = snprintf(buf, size, "%04x", arg2);
257 break;
258 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
259 if (!num)
260 {
261 struct nl_entry *e, *e2;
262 e = nl_lookup(a, 0, NL_VENDOR, arg1, 0, 0, 0);
263 e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0);
264 if (!e)
265 res = snprintf(buf, size, "Unknown device %04x:%04x", arg1, arg2);
266 else if (!e2)
267 res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg2);
268 else
269 res = snprintf(buf, size, "%s %s", e->name, e2->name);
270 }
271 else
272 res = snprintf(buf, size, "%04x:%04x", arg1, arg2);
273 break;
274 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM:
275 if (n = nl_lookup(a, num, NL_VENDOR, arg3, 0, 0, 0))
276 return n->name;
277 else
278 res = snprintf(buf, size, "%04x", arg2);
279 break;
280 case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
281 if (n = nl_lookup(a, num, NL_SUBSYSTEM, arg1, arg2, arg3, arg4))
282 return n->name;
283 else if (arg1 == arg3 && arg2 == arg4 && (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0)))
284 return n->name;
285 else
286 res = snprintf(buf, size, "%04x", arg4);
287 break;
288 case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
289 if (!num)
290 {
291 struct nl_entry *e, *e2;
292 e = nl_lookup(a, 0, NL_VENDOR, arg3, 0, 0, 0);
293 e2 = nl_lookup(a, 0, NL_SUBSYSTEM, arg1, arg2, arg3, arg4);
294 if (!e2 && arg1 == arg3 && arg2 == arg4)
295 /* Cheat for vendors blindly setting subsystem ID same as device ID */
296 e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0);
297 if (!e)
298 res = snprintf(buf, size, "Unknown device %04x:%04x", arg3, arg4);
299 else if (!e2)
300 res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg4);
301 else
302 res = snprintf(buf, size, "%s %s", e->name, e2->name);
303 }
304 else
305 res = snprintf(buf, size, "%04x:%04x", arg3, arg4);
306 break;
307 case PCI_LOOKUP_CLASS:
308 if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff, 0, 0))
309 return n->name;
310 else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0, 0, 0))
311 res = snprintf(buf, size, "%s [%04x]", n->name, arg1);
312 else
313 res = snprintf(buf, size, "Class %04x", arg1);
314 break;
315 case PCI_LOOKUP_PROGIF:
316 if (n = nl_lookup(a, num, NL_PROGIF, arg1 >> 8, arg1 & 0xff, arg2, 0))
317 return n->name;
318 if (arg1 == 0x0101)
319 {
320 /* IDE controllers have complex prog-if semantics */
321 if (arg2 & 0x70)
322 return NULL;
323 res = snprintf(buf, size, "%s%s%s%s%s",
324 (arg2 & 0x80) ? "Master " : "",
325 (arg2 & 0x08) ? "SecP " : "",
326 (arg2 & 0x04) ? "SecO " : "",
327 (arg2 & 0x02) ? "PriP " : "",
328 (arg2 & 0x01) ? "PriO " : "");
329 if (res)
330 buf[--res] = 0;
331 break;
332 }
333 return NULL;
334 default:
335 return "<pci_lookup_name: invalid request>";
336 }
337 return (res == size) ? "<too-large>" : buf;
338 }