]> mj.ucw.cz Git - pciutils.git/blob - lib/names.c
When device ID lookup fails, return hexadecimal device ID instead of vendor ID.
[pciutils.git] / lib / names.c
1 /*
2  *      $Id: names.c,v 1.2 1999/06/21 20:17:19 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;
24   int cat;
25   byte *name;
26 };
27
28 #define NL_VENDOR 0
29 #define NL_DEVICE 1
30 #define NL_CLASS 2
31 #define NL_SUBCLASS 3
32 #define NL_SUBSYSTEM_VENDOR 4
33 #define NL_SUBSYSTEM_DEVICE 5
34
35 #define HASH_SIZE 1024
36
37 static inline unsigned int nl_calc_hash(int cat, int id1, int id2)
38 {
39   unsigned int h;
40
41   h = id1 ^ id2 ^ (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)
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);
54   n = a->nl_hash[h];
55   while (n && (n->id1 != id1 || n->id2 != id2 || 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, byte *text)
61 {
62   unsigned int h = nl_calc_hash(cat, id1, id2);
63   struct nl_entry *n = a->nl_hash[h];
64
65   while (n && (n->id1 != id1 || n->id2 != id2 || 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->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;
92   int cat, last_cat = -1;
93
94   while (*p)
95     {
96       lino++;
97       q = p;
98       while (*p && *p != '\n')
99         {
100           if (*p == '#')
101             {
102               *p++ = 0;
103               while (*p && *p != '\n')
104                 p++;
105               break;
106             }
107           if (*p == '\t')
108             *p = ' ';
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 == ' ')
120         q++;
121       if (r == q)
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 = last_cat = NL_CLASS;
130             }
131           else if (q[0] == 'S' && q[1] == ' ')
132             {
133               if (strlen(q+2) < 5 ||
134                   q[6] != ' ' ||
135                   sscanf(q+2, "%x", &id1) != 1)
136                 goto parserr;
137               cat = last_cat = NL_SUBSYSTEM_VENDOR;
138               q += 2;
139             }
140           else
141             {
142               if (strlen(q) < 5 ||
143                   q[4] != ' ' ||
144                   sscanf(q, "%x", &id1) != 1)
145                 goto parserr;
146               cat = last_cat = NL_VENDOR;
147             }
148           id2 = 0;
149         }
150       else
151         {
152           if (sscanf(q, "%x", &id2) != 1)
153             goto parserr;
154           if (last_cat < 0)
155             goto parserr;
156           if (last_cat == NL_CLASS)
157             cat = NL_SUBCLASS;
158           else
159             cat = last_cat+1;
160         }
161       q += 4;
162       while (*q == ' ')
163         q++;
164       if (!*q)
165         goto parserr;
166       if (nl_add(a, cat, id1, id2, q))
167         a->error("%s, line %d: duplicate entry", a->id_file_name, lino);
168     }
169   return;
170
171 parserr:
172   a->error("%s, line %d: parse error", a->id_file_name, lino);
173 }
174
175 static void
176 load_name_list(struct pci_access *a)
177 {
178   int fd;
179   struct stat st;
180
181   fd = open(a->id_file_name, O_RDONLY);
182   if (fd < 0)
183     {
184       a->numeric_ids = 1;
185       return;
186     }
187   if (fstat(fd, &st) < 0)
188     err_name_list(a, "stat");
189   a->nl_list = pci_malloc(a, st.st_size + 1);
190   if (read(fd, a->nl_list, st.st_size) != st.st_size)
191     err_name_list(a, "read");
192   a->nl_list[st.st_size] = 0;
193   a->nl_hash = pci_malloc(a, sizeof(struct nl_entry *) * HASH_SIZE);
194   bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE);
195   parse_name_list(a);
196   close(fd);
197 }
198
199 void
200 pci_free_name_list(struct pci_access *a)
201 {
202   pci_mfree(a->nl_list);
203   a->nl_list = NULL;
204   pci_mfree(a->nl_hash);
205   a->nl_hash = NULL;
206 }
207
208 static int
209 compound_name(struct pci_access *a, int num, char *buf, int size, int cat, int v, int i)
210 {
211   if (!num)
212     {
213       struct nl_entry *e, *e2;
214
215       e = nl_lookup(a, 0, cat, v, 0);
216       e2 = nl_lookup(a, 0, cat+1, v, i);
217       if (!e)
218         return snprintf(buf, size, "Unknown device %04x:%04x", v, i);
219       else if (!e2)
220         return snprintf(buf, size, "%s: Unknown device %04x", e->name, i);
221       else
222         return snprintf(buf, size, "%s %s", e->name, e2->name);
223     }
224   else
225     return snprintf(buf, size, "%04x:%04x", v, i);
226 }
227
228 char *
229 pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2)
230 {
231   int num = a->numeric_ids;
232   int res;
233   struct nl_entry *n;
234
235   if (flags & PCI_LOOKUP_NUMERIC)
236     {
237       flags &= PCI_LOOKUP_NUMERIC;
238       num = 1;
239     }
240   if (!a->nl_hash && !num)
241     {
242       load_name_list(a);
243       num = a->numeric_ids;
244     }
245   switch (flags)
246     {
247     case PCI_LOOKUP_VENDOR:
248       if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0))
249         return n->name;
250       else
251         res = snprintf(buf, size, "%04x", arg1);
252       break;
253     case PCI_LOOKUP_DEVICE:
254       if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2))
255         return n->name;
256       else
257         res = snprintf(buf, size, "%04x", arg2);
258       break;
259     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
260       res = compound_name(a, num, buf, size, NL_VENDOR, arg1, arg2);
261       break;
262     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM:
263       if (n = nl_lookup(a, num, NL_SUBSYSTEM_VENDOR, arg1, 0))
264         return n->name;
265       else
266         res = snprintf(buf, size, "%04x", arg1);
267       break;
268     case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
269       if (n = nl_lookup(a, num, NL_SUBSYSTEM_DEVICE, arg1, arg2))
270         return n->name;
271       else
272         res = snprintf(buf, size, "%04x", arg2);
273       break;
274     case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
275       res = compound_name(a, num, buf, size, NL_SUBSYSTEM_VENDOR, arg1, arg2);
276       break;
277     case PCI_LOOKUP_CLASS:
278       if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff))
279         return n->name;
280       else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0))
281         res = snprintf(buf, size, "%s [%04x]", n->name, arg1);
282       else
283         res = snprintf(buf, size, "Class %04x", arg1);
284       break;
285     default:
286       return "<pci_lookup_name: invalid request>";
287     }
288   return (res == size) ? "<too-large>" : buf;
289 }