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