]> mj.ucw.cz Git - pciutils.git/blob - lib/names.c
Cleaned up usage of `char' and `byte'.
[pciutils.git] / lib / names.c
1 /*
2  *      The PCI Library -- ID to Name Translation
3  *
4  *      Copyright (c) 1997--2006 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 <stdarg.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #include "internal.h"
16
17 struct id_entry {
18   struct id_entry *next;
19   u32 id12, id34;
20   byte cat;
21   char name[1];
22 };
23
24 enum id_entry_type {
25   ID_UNKNOWN,
26   ID_VENDOR,
27   ID_DEVICE,
28   ID_SUBSYSTEM,
29   ID_GEN_SUBSYSTEM,
30   ID_CLASS,
31   ID_SUBCLASS,
32   ID_PROGIF
33 };
34
35 struct id_bucket {
36   struct id_bucket *next;
37   unsigned int full;
38 };
39
40 #define MAX_LINE 1024
41 #define BUCKET_SIZE 8192
42 #define HASH_SIZE 4099
43
44 #ifdef __GNUC__
45 #define BUCKET_ALIGNMENT __alignof__(struct id_bucket)
46 #else
47 union id_align {
48   struct id_bucket *next;
49   unsigned int full;
50 };
51 #define BUCKET_ALIGNMENT sizeof(union id_align)
52 #endif
53 #define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT)
54
55 static void *id_alloc(struct pci_access *a, unsigned int size)
56 {
57   struct id_bucket *buck = a->current_id_bucket;
58   unsigned int pos;
59   if (!buck || buck->full + size > BUCKET_SIZE)
60     {
61       buck = pci_malloc(a, BUCKET_SIZE);
62       buck->next = a->current_id_bucket;
63       a->current_id_bucket = buck;
64       buck->full = BUCKET_ALIGN(sizeof(struct id_bucket));
65     }
66   pos = buck->full;
67   buck->full = BUCKET_ALIGN(buck->full + size);
68   return (byte *)buck + pos;
69 }
70
71 static inline u32 id_pair(unsigned int x, unsigned int y)
72 {
73   return ((x << 16) | y);
74 }
75
76 static inline unsigned int id_hash(int cat, u32 id12, u32 id34)
77 {
78   unsigned int h;
79
80   h = id12 ^ (id34 << 3) ^ (cat << 5);
81   return h % HASH_SIZE;
82 }
83
84 static char *id_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
85 {
86   struct id_entry *n;
87   u32 id12 = id_pair(id1, id2);
88   u32 id34 = id_pair(id3, id4);
89
90   if (!a->id_hash)
91     return NULL;
92   n = a->id_hash[id_hash(cat, id12, id34)];
93   while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
94     n = n->next;
95   return n ? n->name : NULL;
96 }
97
98 static int id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, char *text)
99 {
100   u32 id12 = id_pair(id1, id2);
101   u32 id34 = id_pair(id3, id4);
102   unsigned int h = id_hash(cat, id12, id34);
103   struct id_entry *n = a->id_hash[h];
104   int len = strlen(text);
105
106   while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
107     n = n->next;
108   if (n)
109     return 1;
110   n = id_alloc(a, sizeof(struct id_entry) + len);
111   n->id12 = id12;
112   n->id34 = id34;
113   n->cat = cat;
114   memcpy(n->name, text, len+1);
115   n->next = a->id_hash[h];
116   a->id_hash[h] = n;
117   return 0;
118 }
119
120 static int id_hex(char *p, int cnt)
121 {
122   int x = 0;
123   while (cnt--)
124     {
125       x <<= 4;
126       if (*p >= '0' && *p <= '9')
127         x += (*p - '0');
128       else if (*p >= 'a' && *p <= 'f')
129         x += (*p - 'a' + 10);
130       else if (*p >= 'A' && *p <= 'F')
131         x += (*p - 'A' + 10);
132       else
133         return -1;
134       p++;
135     }
136   return x;
137 }
138
139 static inline int id_white_p(int c)
140 {
141   return (c == ' ') || (c == '\t');
142 }
143
144 static const char *id_parse_list(struct pci_access *a, FILE *f, int *lino)
145 {
146   char line[MAX_LINE];
147   char *p;
148   int id1=0, id2=0, id3=0, id4=0;
149   int cat = -1;
150   int nest;
151   static const char parse_error[] = "Parse error";
152
153   *lino = 0;
154   while (fgets(line, sizeof(line), f))
155     {
156       (*lino)++;
157       p = line;
158       while (*p && *p != '\n' && *p != '\r')
159         p++;
160       if (!*p && !feof(f))
161         return "Line too long";
162       *p = 0;
163       if (p > line && (p[-1] == ' ' || p[-1] == '\t'))
164         *--p = 0;
165
166       p = line;
167       while (id_white_p(*p))
168         p++;
169       if (!*p || *p == '#')
170         continue;
171
172       p = line;
173       while (*p == '\t')
174         p++;
175       nest = p - line;
176
177       if (!nest)                                        /* Top-level entries */
178         {
179           if (p[0] == 'C' && p[1] == ' ')               /* Class block */
180             {
181               if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4]))
182                 return parse_error;
183               cat = ID_CLASS;
184               p += 5;
185             }
186           else if (p[0] == 'S' && p[1] == ' ')
187             {                                           /* Generic subsystem block */
188               if ((id1 = id_hex(p+2, 4)) < 0 || p[6])
189                 return parse_error;
190               if (!id_lookup(a, ID_VENDOR, id1, 0, 0, 0))
191                 return "Vendor does not exist";
192               cat = ID_GEN_SUBSYSTEM;
193               continue;
194             }
195           else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ')
196             {                                           /* Unrecognized block (RFU) */
197               cat = ID_UNKNOWN;
198               continue;
199             }
200           else                                          /* Vendor ID */
201             {
202               if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
203                 return parse_error;
204               cat = ID_VENDOR;
205               p += 5;
206             }
207           id2 = id3 = id4 = 0;
208         }
209       else if (cat == ID_UNKNOWN)                       /* Nested entries in RFU blocks are skipped */
210         continue;
211       else if (nest == 1)                               /* Nesting level 1 */
212         switch (cat)
213           {
214           case ID_VENDOR:
215           case ID_DEVICE:
216           case ID_SUBSYSTEM:
217             if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
218               return parse_error;
219             p += 5;
220             cat = ID_DEVICE;
221             id3 = id4 = 0;
222             break;
223           case ID_GEN_SUBSYSTEM:
224             if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4]))
225               return parse_error;
226             p += 5;
227             id3 = id4 = 0;
228             break;
229           case ID_CLASS:
230           case ID_SUBCLASS:
231           case ID_PROGIF:
232             if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
233               return parse_error;
234             p += 3;
235             cat = ID_SUBCLASS;
236             id3 = id4 = 0;
237             break;
238           default:
239             return parse_error;
240           }
241       else if (nest == 2)                               /* Nesting level 2 */
242         switch (cat)
243           {
244           case ID_DEVICE:
245           case ID_SUBSYSTEM:
246             if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9]))
247               return parse_error;
248             p += 10;
249             cat = ID_SUBSYSTEM;
250             break;
251           case ID_CLASS:
252           case ID_SUBCLASS:
253           case ID_PROGIF:
254             if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2]))
255               return parse_error;
256             p += 3;
257             cat = ID_PROGIF;
258             id4 = 0;
259             break;
260           default:
261             return parse_error;
262           }
263       else                                              /* Nesting level 3 or more */
264         return parse_error;
265       while (id_white_p(*p))
266         p++;
267       if (!*p)
268         return parse_error;
269       if (id_insert(a, cat, id1, id2, id3, id4, p))
270         return "Duplicate entry";
271     }
272   return NULL;
273 }
274
275 int
276 pci_load_name_list(struct pci_access *a)
277 {
278   FILE *f;
279   int lino;
280   const char *err;
281
282   pci_free_name_list(a);
283   a->hash_load_failed = 1;
284   if (!(f = fopen(a->id_file_name, "r")))
285     return 0;
286   a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE);
287   bzero(a->id_hash, sizeof(struct id_entry *) * HASH_SIZE);
288   err = id_parse_list(a, f, &lino);
289   if (!err && ferror(f))
290     err = "I/O error";
291   fclose(f);
292   if (err)
293     a->error("%s at %s, line %d\n", err, a->id_file_name, lino);
294   a->hash_load_failed = 0;
295   return 1;
296 }
297
298 void
299 pci_free_name_list(struct pci_access *a)
300 {
301   pci_mfree(a->id_hash);
302   a->id_hash = NULL;
303   while (a->current_id_bucket)
304     {
305       struct id_bucket *buck = a->current_id_bucket;
306       a->current_id_bucket = buck->next;
307       pci_mfree(buck);
308     }
309 }
310
311 static char *
312 id_lookup_subsys(struct pci_access *a, int iv, int id, int isv, int isd)
313 {
314   char *d = NULL;
315   if (iv > 0 && id > 0)                                         /* Per-device lookup */
316     d = id_lookup(a, ID_SUBSYSTEM, iv, id, isv, isd);
317   if (!d)                                                       /* Generic lookup */
318     d = id_lookup(a, ID_GEN_SUBSYSTEM, isv, isd, 0, 0);
319   if (!d && iv == isv && id == isd)                             /* Check for subsystem == device */
320     d = id_lookup(a, ID_DEVICE, iv, id, 0, 0);
321   return d;
322 }
323
324 static char *
325 format_name(char *buf, int size, int flags, char *name, char *num, char *unknown)
326 {
327   int res;
328   if ((flags & PCI_LOOKUP_NO_NUMBERS) && !name)
329     return NULL;
330   else if (flags & PCI_LOOKUP_NUMERIC)
331     res = snprintf(buf, size, "%s", num);
332   else if (!name)
333     res = snprintf(buf, size, ((flags & PCI_LOOKUP_MIXED) ? "%s [%s]" : "%s %s"), unknown, num);
334   else if (!(flags & PCI_LOOKUP_MIXED))
335     res = snprintf(buf, size, "%s", name);
336   else
337     res = snprintf(buf, size, "%s [%s]", name, num);
338   if (res < 0 || res >= size)
339     return "<pci_lookup_name: buffer too small>";
340   else
341     return buf;
342 }
343
344 static char *
345 format_name_pair(char *buf, int size, int flags, char *v, char *d, char *num)
346 {
347   int res;
348   if ((flags & PCI_LOOKUP_NO_NUMBERS) && (!v || !d))
349     return NULL;
350   if (flags & PCI_LOOKUP_NUMERIC)
351     res = snprintf(buf, size, "%s", num);
352   else if (flags & PCI_LOOKUP_MIXED)
353     {
354       if (v && d)
355         res = snprintf(buf, size, "%s %s [%s]", v, d, num);
356       else if (!v)
357         res = snprintf(buf, size, "Unknown device [%s]", num);
358       else /* v && !d */
359         res = snprintf(buf, size, "%s Unknown device [%s]", v, num);
360     }
361   else
362     {
363       if (v && d)
364         res = snprintf(buf, size, "%s %s", v, d);
365       else if (!v)
366         res = snprintf(buf, size, "Unknown device %s", num);
367       else /* v && !d */
368         res = snprintf(buf, size, "%s Unknown device %s", v, num+5);
369     }
370   if (res < 0 || res >= size)
371     return "<pci_lookup_name: buffer too small>";
372   else
373     return buf;
374 }
375
376 char *
377 pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...)
378 {
379   va_list args;
380   char *v, *d, *cls, *pif;
381   int iv, id, isv, isd, icls, ipif;
382   char numbuf[16], pifbuf[32];
383
384   va_start(args, flags);
385
386   if (!(flags & PCI_LOOKUP_NO_NUMBERS))
387     {
388       if (a->numeric_ids > 1)
389         flags |= PCI_LOOKUP_MIXED;
390       else if (a->numeric_ids)
391         flags |= PCI_LOOKUP_NUMERIC;
392     }
393   if (flags & PCI_LOOKUP_MIXED)
394     flags &= ~PCI_LOOKUP_NUMERIC;
395
396   if (!a->id_hash && !(flags & PCI_LOOKUP_NUMERIC) && !a->hash_load_failed)
397     pci_load_name_list(a);
398
399   switch (flags & 0xffff)
400     {
401     case PCI_LOOKUP_VENDOR:
402       iv = va_arg(args, int);
403       sprintf(numbuf, "%04x", iv);
404       return format_name(buf, size, flags, id_lookup(a, ID_VENDOR, iv, 0, 0, 0), numbuf, "Unknown vendor");
405     case PCI_LOOKUP_DEVICE:
406       iv = va_arg(args, int);
407       id = va_arg(args, int);
408       sprintf(numbuf, "%04x", id);
409       return format_name(buf, size, flags, id_lookup(a, ID_DEVICE, iv, id, 0, 0), numbuf, "Unknown device");
410     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
411       iv = va_arg(args, int);
412       id = va_arg(args, int);
413       sprintf(numbuf, "%04x:%04x", iv, id);
414       v = id_lookup(a, ID_VENDOR, iv, 0, 0, 0);
415       d = id_lookup(a, ID_DEVICE, iv, id, 0, 0);
416       return format_name_pair(buf, size, flags, v, d, numbuf);
417     case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR:
418       isv = va_arg(args, int);
419       sprintf(numbuf, "%04x", isv);
420       v = id_lookup(a, ID_VENDOR, isv, 0, 0, 0);
421       return format_name(buf, size, flags, v, numbuf, "Unknown vendor");
422     case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE:
423       iv = va_arg(args, int);
424       id = va_arg(args, int);
425       isv = va_arg(args, int);
426       isd = va_arg(args, int);
427       sprintf(numbuf, "%04x", isd);
428       return format_name(buf, size, flags, id_lookup_subsys(a, iv, id, isv, isd), numbuf, "Unknown device");
429     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
430       iv = va_arg(args, int);
431       id = va_arg(args, int);
432       isv = va_arg(args, int);
433       isd = va_arg(args, int);
434       v = id_lookup(a, ID_VENDOR, isv, 0, 0, 0);
435       d = id_lookup_subsys(a, iv, id, isv, isd);
436       sprintf(numbuf, "%04x:%04x", isv, isd);
437       return format_name_pair(buf, size, flags, v, d, numbuf);
438     case PCI_LOOKUP_CLASS:
439       icls = va_arg(args, int);
440       sprintf(numbuf, "%04x", icls);
441       cls = id_lookup(a, ID_SUBCLASS, icls >> 8, icls & 0xff, 0, 0);
442       if (!cls && (cls = id_lookup(a, ID_CLASS, icls >> 8, 0, 0, 0)))
443         {
444           if (!(flags & PCI_LOOKUP_NUMERIC)) /* Include full class number */
445             flags |= PCI_LOOKUP_MIXED;
446         }
447       return format_name(buf, size, flags, cls, numbuf, ((flags & PCI_LOOKUP_MIXED) ? "Unknown class" : "Class"));
448     case PCI_LOOKUP_PROGIF:
449       icls = va_arg(args, int);
450       ipif = va_arg(args, int);
451       sprintf(numbuf, "%02x", ipif);
452       pif = id_lookup(a, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0);
453       if (!pif && icls == 0x0101 && !(ipif & 0x70))
454         {
455           /* IDE controllers have complex prog-if semantics */
456           sprintf(pifbuf, "%s%s%s%s%s",
457                   (ipif & 0x80) ? " Master" : "",
458                   (ipif & 0x08) ? " SecP" : "",
459                   (ipif & 0x04) ? " SecO" : "",
460                   (ipif & 0x02) ? " PriP" : "",
461                   (ipif & 0x01) ? " PriO" : "");
462           pif = pifbuf;
463           if (*pif)
464             pif++;
465         }
466       return format_name(buf, size, flags, pif, numbuf, "ProgIf");
467     default:
468       return "<pci_lookup_name: invalid request>";
469     }
470 }