]>
Commit | Line | Data |
---|---|---|
727ce158 | 1 | /* |
d4798a32 | 2 | * $Id: names.c,v 1.3 1999/10/09 13:26:12 mj Exp $ |
727ce158 MM |
3 | * |
4 | * The PCI Library -- ID to Name Translation | |
5 | * | |
6 | * Copyright (c) 1997--1999 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; | |
d4798a32 | 23 | word id1, id2, id3, id4; |
727ce158 MM |
24 | int cat; |
25 | byte *name; | |
26 | }; | |
27 | ||
28 | #define NL_VENDOR 0 | |
29 | #define NL_DEVICE 1 | |
d4798a32 MM |
30 | #define NL_SUBSYSTEM 2 |
31 | #define NL_CLASS 3 | |
32 | #define NL_SUBCLASS 4 | |
33 | #define NL_PROGIF 5 | |
727ce158 MM |
34 | |
35 | #define HASH_SIZE 1024 | |
36 | ||
d4798a32 | 37 | static inline unsigned int nl_calc_hash(int cat, int id1, int id2, int id3, int id4) |
727ce158 MM |
38 | { |
39 | unsigned int h; | |
40 | ||
d4798a32 | 41 | h = id1 ^ id2 ^ id3 ^ id4 ^ (cat << 5); |
727ce158 MM |
42 | h += (h >> 6); |
43 | return h & (HASH_SIZE-1); | |
44 | } | |
45 | ||
d4798a32 | 46 | static struct nl_entry *nl_lookup(struct pci_access *a, int num, int cat, int id1, int id2, int id3, int id4) |
727ce158 MM |
47 | { |
48 | unsigned int h; | |
49 | struct nl_entry *n; | |
50 | ||
51 | if (num) | |
52 | return NULL; | |
d4798a32 | 53 | h = nl_calc_hash(cat, id1, id2, id3, id4); |
727ce158 | 54 | n = a->nl_hash[h]; |
d4798a32 | 55 | while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat)) |
727ce158 MM |
56 | n = n->next; |
57 | return n; | |
58 | } | |
59 | ||
d4798a32 | 60 | static int nl_add(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, byte *text) |
727ce158 | 61 | { |
d4798a32 | 62 | unsigned int h = nl_calc_hash(cat, id1, id2, id3, id4); |
727ce158 MM |
63 | struct nl_entry *n = a->nl_hash[h]; |
64 | ||
d4798a32 | 65 | while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat)) |
727ce158 MM |
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; | |
d4798a32 MM |
72 | n->id3 = id3; |
73 | n->id4 = id4; | |
727ce158 MM |
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; | |
d4798a32 MM |
93 | unsigned int id1=0, id2=0, id3=0, id4=0; |
94 | int cat = -1; | |
727ce158 MM |
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 | } | |
727ce158 MM |
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; | |
d4798a32 | 119 | while (*q == '\t') |
727ce158 | 120 | q++; |
d4798a32 | 121 | if (q == r) |
727ce158 MM |
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; | |
d4798a32 | 129 | cat = NL_CLASS; |
727ce158 MM |
130 | } |
131 | else | |
132 | { | |
133 | if (strlen(q) < 5 || | |
134 | q[4] != ' ' || | |
135 | sscanf(q, "%x", &id1) != 1) | |
136 | goto parserr; | |
d4798a32 | 137 | cat = NL_VENDOR; |
727ce158 | 138 | } |
d4798a32 MM |
139 | id2 = id3 = id4 = 0; |
140 | q += 4; | |
727ce158 | 141 | } |
d4798a32 MM |
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: | |
727ce158 | 164 | goto parserr; |
d4798a32 MM |
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: | |
727ce158 | 186 | goto parserr; |
d4798a32 MM |
187 | } |
188 | else | |
189 | goto parserr; | |
727ce158 MM |
190 | while (*q == ' ') |
191 | q++; | |
192 | if (!*q) | |
193 | goto parserr; | |
d4798a32 | 194 | if (nl_add(a, cat, id1, id2, id3, id4, q)) |
727ce158 MM |
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 | ||
727ce158 | 236 | char * |
d4798a32 | 237 | pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4) |
727ce158 MM |
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: | |
d4798a32 | 256 | if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0)) |
727ce158 MM |
257 | return n->name; |
258 | else | |
259 | res = snprintf(buf, size, "%04x", arg1); | |
260 | break; | |
261 | case PCI_LOOKUP_DEVICE: | |
d4798a32 | 262 | if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0)) |
727ce158 MM |
263 | return n->name; |
264 | else | |
7bed2d83 | 265 | res = snprintf(buf, size, "%04x", arg2); |
727ce158 MM |
266 | break; |
267 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE: | |
d4798a32 MM |
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); | |
727ce158 MM |
282 | break; |
283 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM: | |
d4798a32 | 284 | if (n = nl_lookup(a, num, NL_VENDOR, arg3, 0, 0, 0)) |
727ce158 MM |
285 | return n->name; |
286 | else | |
287 | res = snprintf(buf, size, "%04x", arg1); | |
288 | break; | |
289 | case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: | |
d4798a32 | 290 | if (n = nl_lookup(a, num, NL_SUBSYSTEM, arg1, arg2, arg3, arg4)) |
727ce158 MM |
291 | return n->name; |
292 | else | |
7bed2d83 | 293 | res = snprintf(buf, size, "%04x", arg2); |
727ce158 MM |
294 | break; |
295 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: | |
d4798a32 MM |
296 | if (!num) |
297 | { | |
298 | struct nl_entry *e, *e2; | |
299 | e = nl_lookup(a, 0, NL_VENDOR, arg3, 0, 0, 0); | |
300 | e2 = nl_lookup(a, 0, NL_SUBSYSTEM, arg1, arg2, arg3, arg4); | |
301 | if (!e) | |
302 | res = snprintf(buf, size, "Unknown device %04x:%04x", arg1, arg2); | |
303 | else if (!e2) | |
304 | res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg2); | |
305 | else | |
306 | res = snprintf(buf, size, "%s %s", e->name, e2->name); | |
307 | } | |
308 | else | |
309 | res = snprintf(buf, size, "%04x:%04x", arg3, arg4); | |
727ce158 MM |
310 | break; |
311 | case PCI_LOOKUP_CLASS: | |
d4798a32 | 312 | if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff, 0, 0)) |
727ce158 | 313 | return n->name; |
d4798a32 | 314 | else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0, 0, 0)) |
727ce158 MM |
315 | res = snprintf(buf, size, "%s [%04x]", n->name, arg1); |
316 | else | |
317 | res = snprintf(buf, size, "Class %04x", arg1); | |
318 | break; | |
d4798a32 MM |
319 | case PCI_LOOKUP_PROGIF: |
320 | if (n = nl_lookup(a, num, NL_PROGIF, arg1 >> 8, arg1 & 0xff, arg2, 0)) | |
321 | return n->name; | |
322 | if (arg1 == 0x0101) | |
323 | { | |
324 | /* IDE controllers have complex prog-if semantics */ | |
325 | if (arg2 & 0x70) | |
326 | return NULL; | |
327 | res = snprintf(buf, size, "%s%s%s%s%s", | |
328 | (arg2 & 0x80) ? "Master " : "", | |
329 | (arg2 & 0x08) ? "SecP " : "", | |
330 | (arg2 & 0x04) ? "SecO " : "", | |
331 | (arg2 & 0x02) ? "PriP " : "", | |
332 | (arg2 & 0x01) ? "PriO " : ""); | |
333 | if (res) | |
334 | buf[--res] = 0; | |
335 | break; | |
336 | } | |
337 | return NULL; | |
727ce158 MM |
338 | default: |
339 | return "<pci_lookup_name: invalid request>"; | |
340 | } | |
341 | return (res == size) ? "<too-large>" : buf; | |
342 | } |