~peter-pearse/ubuntu/natty/pciutils/prop001

« back to all changes in this revision

Viewing changes to lib/names.c

  • Committer: Bazaar Package Importer
  • Author(s): Remco van de Meent
  • Date: 2002-03-11 13:26:04 UTC
  • Revision ID: james.westby@ubuntu.com-20020311132604-7way9hqnt42hgmxd
Tags: upstream-2.1.9
ImportĀ upstreamĀ versionĀ 2.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      $Id: names.c,v 1.6 2000/04/29 12:56:23 mj Exp $
 
3
 *
 
4
 *      The PCI Library -- ID to Name Translation
 
5
 *
 
6
 *      Copyright (c) 1997--2000 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 == arg3 && arg2 == 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
}