]>
git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/names.c
2 * The PCI Library -- ID to Name Translation
4 * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
18 struct id_entry
*next
;
36 struct id_bucket
*next
;
41 #define BUCKET_SIZE 8192
42 #define HASH_SIZE 4099
45 #define BUCKET_ALIGNMENT __alignof__(struct id_bucket)
48 struct id_bucket
*next
;
51 #define BUCKET_ALIGNMENT sizeof(union id_align)
53 #define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT)
55 static void *id_alloc(struct pci_access
*a
, unsigned int size
)
57 struct id_bucket
*buck
= a
->current_id_bucket
;
59 if (!buck
|| buck
->full
+ size
> BUCKET_SIZE
)
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
));
67 buck
->full
= BUCKET_ALIGN(buck
->full
+ size
);
68 return (byte
*)buck
+ pos
;
71 static inline u32
id_pair(unsigned int x
, unsigned int y
)
73 return ((x
<< 16) | y
);
76 static inline unsigned int id_hash(int cat
, u32 id12
, u32 id34
)
80 h
= id12
^ (id34
<< 3) ^ (cat
<< 5);
84 static char *id_lookup(struct pci_access
*a
, int cat
, int id1
, int id2
, int id3
, int id4
)
87 u32 id12
= id_pair(id1
, id2
);
88 u32 id34
= id_pair(id3
, id4
);
92 n
= a
->id_hash
[id_hash(cat
, id12
, id34
)];
93 while (n
&& (n
->id12
!= id12
|| n
->id34
!= id34
|| n
->cat
!= cat
))
95 return n
? n
->name
: NULL
;
98 static int id_insert(struct pci_access
*a
, int cat
, int id1
, int id2
, int id3
, int id4
, char *text
)
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
);
106 while (n
&& (n
->id12
!= id12
|| n
->id34
!= id34
|| n
->cat
!= cat
))
110 n
= id_alloc(a
, sizeof(struct id_entry
) + len
);
114 memcpy(n
->name
, text
, len
+1);
115 n
->next
= a
->id_hash
[h
];
120 static int id_hex(char *p
, int cnt
)
126 if (*p
>= '0' && *p
<= '9')
128 else if (*p
>= 'a' && *p
<= 'f')
129 x
+= (*p
- 'a' + 10);
130 else if (*p
>= 'A' && *p
<= 'F')
131 x
+= (*p
- 'A' + 10);
139 static inline int id_white_p(int c
)
141 return (c
== ' ') || (c
== '\t');
144 static const char *id_parse_list(struct pci_access
*a
, FILE *f
, int *lino
)
148 int id1
=0, id2
=0, id3
=0, id4
=0;
151 static const char parse_error
[] = "Parse error";
154 while (fgets(line
, sizeof(line
), f
))
158 while (*p
&& *p
!= '\n' && *p
!= '\r')
161 return "Line too long";
163 if (p
> line
&& (p
[-1] == ' ' || p
[-1] == '\t'))
167 while (id_white_p(*p
))
169 if (!*p
|| *p
== '#')
177 if (!nest
) /* Top-level entries */
179 if (p
[0] == 'C' && p
[1] == ' ') /* Class block */
181 if ((id1
= id_hex(p
+2, 2)) < 0 || !id_white_p(p
[4]))
186 else if (p
[0] == 'S' && p
[1] == ' ')
187 { /* Generic subsystem block */
188 if ((id1
= id_hex(p
+2, 4)) < 0 || p
[6])
190 if (!id_lookup(a
, ID_VENDOR
, id1
, 0, 0, 0))
191 return "Vendor does not exist";
192 cat
= ID_GEN_SUBSYSTEM
;
195 else if (p
[0] >= 'A' && p
[0] <= 'Z' && p
[1] == ' ')
196 { /* Unrecognized block (RFU) */
202 if ((id1
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
209 else if (cat
== ID_UNKNOWN
) /* Nested entries in RFU blocks are skipped */
211 else if (nest
== 1) /* Nesting level 1 */
217 if ((id2
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
223 case ID_GEN_SUBSYSTEM
:
224 if ((id2
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
232 if ((id2
= id_hex(p
, 2)) < 0 || !id_white_p(p
[2]))
241 else if (nest
== 2) /* Nesting level 2 */
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]))
254 if ((id3
= id_hex(p
, 2)) < 0 || !id_white_p(p
[2]))
263 else /* Nesting level 3 or more */
265 while (id_white_p(*p
))
269 if (id_insert(a
, cat
, id1
, id2
, id3
, id4
, p
))
270 return "Duplicate entry";
276 pci_load_name_list(struct pci_access
*a
)
282 pci_free_name_list(a
);
283 a
->hash_load_failed
= 1;
284 if (!(f
= fopen(a
->id_file_name
, "r")))
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
))
293 a
->error("%s at %s, line %d\n", err
, a
->id_file_name
, lino
);
294 a
->hash_load_failed
= 0;
299 pci_free_name_list(struct pci_access
*a
)
301 pci_mfree(a
->id_hash
);
303 while (a
->current_id_bucket
)
305 struct id_bucket
*buck
= a
->current_id_bucket
;
306 a
->current_id_bucket
= buck
->next
;
312 id_lookup_subsys(struct pci_access
*a
, int iv
, int id
, int isv
, int isd
)
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);
325 format_name(char *buf
, int size
, int flags
, char *name
, char *num
, char *unknown
)
328 if ((flags
& PCI_LOOKUP_NO_NUMBERS
) && !name
)
330 else if (flags
& PCI_LOOKUP_NUMERIC
)
331 res
= snprintf(buf
, size
, "%s", num
);
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
);
337 res
= snprintf(buf
, size
, "%s [%s]", name
, num
);
338 if (res
< 0 || res
>= size
)
339 return "<pci_lookup_name: buffer too small>";
345 format_name_pair(char *buf
, int size
, int flags
, char *v
, char *d
, char *num
)
348 if ((flags
& PCI_LOOKUP_NO_NUMBERS
) && (!v
|| !d
))
350 if (flags
& PCI_LOOKUP_NUMERIC
)
351 res
= snprintf(buf
, size
, "%s", num
);
352 else if (flags
& PCI_LOOKUP_MIXED
)
355 res
= snprintf(buf
, size
, "%s %s [%s]", v
, d
, num
);
357 res
= snprintf(buf
, size
, "Unknown device [%s]", num
);
359 res
= snprintf(buf
, size
, "%s Unknown device [%s]", v
, num
);
364 res
= snprintf(buf
, size
, "%s %s", v
, d
);
366 res
= snprintf(buf
, size
, "Unknown device %s", num
);
368 res
= snprintf(buf
, size
, "%s Unknown device %s", v
, num
+5);
370 if (res
< 0 || res
>= size
)
371 return "<pci_lookup_name: buffer too small>";
377 pci_lookup_name(struct pci_access
*a
, char *buf
, int size
, int flags
, ...)
380 char *v
, *d
, *cls
, *pif
;
381 int iv
, id
, isv
, isd
, icls
, ipif
;
382 char numbuf
[16], pifbuf
[32];
384 va_start(args
, flags
);
386 if (!(flags
& PCI_LOOKUP_NO_NUMBERS
))
388 if (a
->numeric_ids
> 1)
389 flags
|= PCI_LOOKUP_MIXED
;
390 else if (a
->numeric_ids
)
391 flags
|= PCI_LOOKUP_NUMERIC
;
393 if (flags
& PCI_LOOKUP_MIXED
)
394 flags
&= ~PCI_LOOKUP_NUMERIC
;
396 if (!a
->id_hash
&& !(flags
& PCI_LOOKUP_NUMERIC
) && !a
->hash_load_failed
)
397 pci_load_name_list(a
);
399 switch (flags
& 0xffff)
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)))
444 if (!(flags
& PCI_LOOKUP_NUMERIC
)) /* Include full class number */
445 flags
|= PCI_LOOKUP_MIXED
;
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))
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" : "");
466 return format_name(buf
, size
, flags
, pif
, numbuf
, "ProgIf");
468 return "<pci_lookup_name: invalid request>";