]> mj.ucw.cz Git - pciutils.git/blob - lib/names.c
Forgot to add...
[pciutils.git] / lib / names.c
1 /*
2  *      $Id: names.c,v 1.5 2000/04/21 11:58:48 mj Exp $
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;
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         {
102           if (*p == '#')
103             {
104               *p++ = 0;
105               while (*p && *p != '\n')
106                 p++;
107               break;
108             }
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;
119       while (*q == '\t')
120         q++;
121       if (q == r)
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;
129               cat = NL_CLASS;
130             }
131           else
132             {
133               if (strlen(q) < 5 ||
134                   q[4] != ' ' ||
135                   sscanf(q, "%x", &id1) != 1)
136                 goto parserr;
137               cat = NL_VENDOR;
138             }
139           id2 = id3 = id4 = 0;
140           q += 4;
141         }
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:
164             goto parserr;
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:
186             goto parserr;
187           }
188       else
189         goto parserr;
190       while (*q == ' ')
191         q++;
192       if (!*q)
193         goto parserr;
194       if (nl_add(a, cat, id1, id2, id3, id4, q))
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
236 char *
237 pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
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:
256       if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0))
257         return n->name;
258       else
259         res = snprintf(buf, size, "%04x", arg1);
260       break;
261     case PCI_LOOKUP_DEVICE:
262       if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0))
263         return n->name;
264       else
265         res = snprintf(buf, size, "%04x", arg2);
266       break;
267     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
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);
282       break;
283     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM:
284       if (n = nl_lookup(a, num, NL_VENDOR, arg3, 0, 0, 0))
285         return n->name;
286       else
287         res = snprintf(buf, size, "%04x", arg1);
288       break;
289     case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
290       if (n = nl_lookup(a, num, NL_SUBSYSTEM, arg1, arg2, arg3, arg4))
291         return n->name;
292       else if (arg1 == arg3 && arg2 == arg4 && (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0)))
293         return n->name;
294       else
295         res = snprintf(buf, size, "%04x", arg2);
296       break;
297     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
298       if (!num)
299         {
300           struct nl_entry *e, *e2;
301           e = nl_lookup(a, 0, NL_VENDOR, arg3, 0, 0, 0);
302           e2 = nl_lookup(a, 0, NL_SUBSYSTEM, arg1, arg2, arg3, arg4);
303           if (!e2 && arg1 == arg2 && arg3 == arg4)
304             /* Cheat for vendors blindly setting subsystem ID same as device ID */
305             e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0);
306           if (!e)
307             res = snprintf(buf, size, "Unknown device %04x:%04x", arg3, arg4);
308           else if (!e2)
309             res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg4);
310           else
311             res = snprintf(buf, size, "%s %s", e->name, e2->name);
312         }
313       else
314         res = snprintf(buf, size, "%04x:%04x", arg3, arg4);
315       break;
316     case PCI_LOOKUP_CLASS:
317       if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff, 0, 0))
318         return n->name;
319       else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0, 0, 0))
320         res = snprintf(buf, size, "%s [%04x]", n->name, arg1);
321       else
322         res = snprintf(buf, size, "Class %04x", arg1);
323       break;
324     case PCI_LOOKUP_PROGIF:
325       if (n = nl_lookup(a, num, NL_PROGIF, arg1 >> 8, arg1 & 0xff, arg2, 0))
326         return n->name;
327       if (arg1 == 0x0101)
328         {
329           /* IDE controllers have complex prog-if semantics */
330           if (arg2 & 0x70)
331             return NULL;
332           res = snprintf(buf, size, "%s%s%s%s%s",
333                          (arg2 & 0x80) ? "Master " : "",
334                          (arg2 & 0x08) ? "SecP " : "",
335                          (arg2 & 0x04) ? "SecO " : "",
336                          (arg2 & 0x02) ? "PriP " : "",
337                          (arg2 & 0x01) ? "PriO " : "");
338           if (res)
339             buf[--res] = 0;
340           break;
341         }
342       return NULL;
343     default:
344       return "<pci_lookup_name: invalid request>";
345     }
346   return (res == size) ? "<too-large>" : buf;
347 }