]> mj.ucw.cz Git - pciutils.git/blob - lib/names.c
Don't forget to initialize hdrtype.
[pciutils.git] / lib / names.c
1 /*
2  *      $Id: names.c,v 1.9 2002/03/30 15:39:25 mj Exp $
3  *
4  *      The PCI Library -- ID to Name Translation
5  *
6  *      Copyright (c) 1997--2002 Martin Mares <mj@ucw.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 }