Subversion Repositories HelenOS

Rev

Rev 1302 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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