]>
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.
17 #ifdef PCI_COMPRESSED_IDS
19 typedef gzFile pci_file
;
20 #define pci_gets(f, l, s) gzgets(f, l, s)
21 #define pci_eof(f) gzeof(f)
23 static pci_file
pci_open(struct pci_access
*a
)
29 result
= gzopen(a
->id_file_name
, "r");
32 len
= strlen(a
->id_file_name
);
33 if (len
>= 3 && memcmp(a
->id_file_name
+ len
- 3, ".gz", 3) != 0)
35 new_name
= malloc(len
- 2);
36 memcpy(new_name
, a
->id_file_name
, len
- 3);
37 new_name
[len
- 3] = 0;
38 pci_set_name_list_path(a
, new_name
, 1);
39 return gzopen(a
->id_file_name
, "r");
42 #define pci_close(f) gzclose(f)
43 #define PCI_ERROR(f, err) \
46 err = gzerror(f, &errnum); \
47 if (errnum == Z_ERRNO) err = "I/O error"; \
48 else if (errnum >= 0) err = NULL; \
51 typedef FILE * pci_file
;
52 #define pci_gets(f, l, s) fgets(l, s, f)
53 #define pci_eof(f) feof(f)
54 #define pci_open(a) fopen(a->id_file_name, "r")
55 #define pci_close(f) fclose(f)
56 #define PCI_ERROR(f, err) if (!err && ferror(f)) err = "I/O error";
60 struct id_entry
*next
;
78 struct id_bucket
*next
;
83 #define BUCKET_SIZE 8192
84 #define HASH_SIZE 4099
87 #define BUCKET_ALIGNMENT __alignof__(struct id_bucket)
90 struct id_bucket
*next
;
93 #define BUCKET_ALIGNMENT sizeof(union id_align)
95 #define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT)
97 static void *id_alloc(struct pci_access
*a
, unsigned int size
)
99 struct id_bucket
*buck
= a
->current_id_bucket
;
101 if (!buck
|| buck
->full
+ size
> BUCKET_SIZE
)
103 buck
= pci_malloc(a
, BUCKET_SIZE
);
104 buck
->next
= a
->current_id_bucket
;
105 a
->current_id_bucket
= buck
;
106 buck
->full
= BUCKET_ALIGN(sizeof(struct id_bucket
));
109 buck
->full
= BUCKET_ALIGN(buck
->full
+ size
);
110 return (byte
*)buck
+ pos
;
113 static inline u32
id_pair(unsigned int x
, unsigned int y
)
115 return ((x
<< 16) | y
);
118 static inline unsigned int id_hash(int cat
, u32 id12
, u32 id34
)
122 h
= id12
^ (id34
<< 3) ^ (cat
<< 5);
123 return h
% HASH_SIZE
;
126 static char *id_lookup(struct pci_access
*a
, int cat
, int id1
, int id2
, int id3
, int id4
)
129 u32 id12
= id_pair(id1
, id2
);
130 u32 id34
= id_pair(id3
, id4
);
134 n
= a
->id_hash
[id_hash(cat
, id12
, id34
)];
135 while (n
&& (n
->id12
!= id12
|| n
->id34
!= id34
|| n
->cat
!= cat
))
137 return n
? n
->name
: NULL
;
140 static int id_insert(struct pci_access
*a
, int cat
, int id1
, int id2
, int id3
, int id4
, char *text
)
142 u32 id12
= id_pair(id1
, id2
);
143 u32 id34
= id_pair(id3
, id4
);
144 unsigned int h
= id_hash(cat
, id12
, id34
);
145 struct id_entry
*n
= a
->id_hash
[h
];
146 int len
= strlen(text
);
148 while (n
&& (n
->id12
!= id12
|| n
->id34
!= id34
|| n
->cat
!= cat
))
152 n
= id_alloc(a
, sizeof(struct id_entry
) + len
);
156 memcpy(n
->name
, text
, len
+1);
157 n
->next
= a
->id_hash
[h
];
162 static int id_hex(char *p
, int cnt
)
168 if (*p
>= '0' && *p
<= '9')
170 else if (*p
>= 'a' && *p
<= 'f')
171 x
+= (*p
- 'a' + 10);
172 else if (*p
>= 'A' && *p
<= 'F')
173 x
+= (*p
- 'A' + 10);
181 static inline int id_white_p(int c
)
183 return (c
== ' ') || (c
== '\t');
186 static const char *id_parse_list(struct pci_access
*a
, pci_file f
, int *lino
)
190 int id1
=0, id2
=0, id3
=0, id4
=0;
193 static const char parse_error
[] = "Parse error";
196 while (pci_gets(f
, line
, sizeof(line
)))
200 while (*p
&& *p
!= '\n' && *p
!= '\r')
202 if (!*p
&& !pci_eof(f
))
203 return "Line too long";
205 if (p
> line
&& (p
[-1] == ' ' || p
[-1] == '\t'))
209 while (id_white_p(*p
))
211 if (!*p
|| *p
== '#')
219 if (!nest
) /* Top-level entries */
221 if (p
[0] == 'C' && p
[1] == ' ') /* Class block */
223 if ((id1
= id_hex(p
+2, 2)) < 0 || !id_white_p(p
[4]))
228 else if (p
[0] == 'S' && p
[1] == ' ')
229 { /* Generic subsystem block */
230 if ((id1
= id_hex(p
+2, 4)) < 0 || p
[6])
232 if (!id_lookup(a
, ID_VENDOR
, id1
, 0, 0, 0))
233 return "Vendor does not exist";
234 cat
= ID_GEN_SUBSYSTEM
;
237 else if (p
[0] >= 'A' && p
[0] <= 'Z' && p
[1] == ' ')
238 { /* Unrecognized block (RFU) */
244 if ((id1
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
251 else if (cat
== ID_UNKNOWN
) /* Nested entries in RFU blocks are skipped */
253 else if (nest
== 1) /* Nesting level 1 */
259 if ((id2
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
265 case ID_GEN_SUBSYSTEM
:
266 if ((id2
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]))
274 if ((id2
= id_hex(p
, 2)) < 0 || !id_white_p(p
[2]))
283 else if (nest
== 2) /* Nesting level 2 */
288 if ((id3
= id_hex(p
, 4)) < 0 || !id_white_p(p
[4]) || (id4
= id_hex(p
+5, 4)) < 0 || !id_white_p(p
[9]))
296 if ((id3
= id_hex(p
, 2)) < 0 || !id_white_p(p
[2]))
305 else /* Nesting level 3 or more */
307 while (id_white_p(*p
))
311 if (id_insert(a
, cat
, id1
, id2
, id3
, id4
, p
))
312 return "Duplicate entry";
318 pci_load_name_list(struct pci_access
*a
)
324 pci_free_name_list(a
);
325 a
->hash_load_failed
= 1;
326 if (!(f
= pci_open(a
)))
328 a
->id_hash
= pci_malloc(a
, sizeof(struct id_entry
*) * HASH_SIZE
);
329 bzero(a
->id_hash
, sizeof(struct id_entry
*) * HASH_SIZE
);
330 err
= id_parse_list(a
, f
, &lino
);
334 a
->error("%s at %s, line %d\n", err
, a
->id_file_name
, lino
);
335 a
->hash_load_failed
= 0;
340 pci_free_name_list(struct pci_access
*a
)
342 pci_mfree(a
->id_hash
);
344 while (a
->current_id_bucket
)
346 struct id_bucket
*buck
= a
->current_id_bucket
;
347 a
->current_id_bucket
= buck
->next
;
353 id_lookup_subsys(struct pci_access
*a
, int iv
, int id
, int isv
, int isd
)
356 if (iv
> 0 && id
> 0) /* Per-device lookup */
357 d
= id_lookup(a
, ID_SUBSYSTEM
, iv
, id
, isv
, isd
);
358 if (!d
) /* Generic lookup */
359 d
= id_lookup(a
, ID_GEN_SUBSYSTEM
, isv
, isd
, 0, 0);
360 if (!d
&& iv
== isv
&& id
== isd
) /* Check for subsystem == device */
361 d
= id_lookup(a
, ID_DEVICE
, iv
, id
, 0, 0);
366 format_name(char *buf
, int size
, int flags
, char *name
, char *num
, char *unknown
)
369 if ((flags
& PCI_LOOKUP_NO_NUMBERS
) && !name
)
371 else if (flags
& PCI_LOOKUP_NUMERIC
)
372 res
= snprintf(buf
, size
, "%s", num
);
374 res
= snprintf(buf
, size
, ((flags
& PCI_LOOKUP_MIXED
) ? "%s [%s]" : "%s %s"), unknown
, num
);
375 else if (!(flags
& PCI_LOOKUP_MIXED
))
376 res
= snprintf(buf
, size
, "%s", name
);
378 res
= snprintf(buf
, size
, "%s [%s]", name
, num
);
379 if (res
< 0 || res
>= size
)
380 return "<pci_lookup_name: buffer too small>";
386 format_name_pair(char *buf
, int size
, int flags
, char *v
, char *d
, char *num
)
389 if ((flags
& PCI_LOOKUP_NO_NUMBERS
) && (!v
|| !d
))
391 if (flags
& PCI_LOOKUP_NUMERIC
)
392 res
= snprintf(buf
, size
, "%s", num
);
393 else if (flags
& PCI_LOOKUP_MIXED
)
396 res
= snprintf(buf
, size
, "%s %s [%s]", v
, d
, num
);
398 res
= snprintf(buf
, size
, "Unknown device [%s]", num
);
400 res
= snprintf(buf
, size
, "%s Unknown device [%s]", v
, num
);
405 res
= snprintf(buf
, size
, "%s %s", v
, d
);
407 res
= snprintf(buf
, size
, "Unknown device %s", num
);
409 res
= snprintf(buf
, size
, "%s Unknown device %s", v
, num
+5);
411 if (res
< 0 || res
>= size
)
412 return "<pci_lookup_name: buffer too small>";
418 pci_lookup_name(struct pci_access
*a
, char *buf
, int size
, int flags
, ...)
421 char *v
, *d
, *cls
, *pif
;
422 int iv
, id
, isv
, isd
, icls
, ipif
;
423 char numbuf
[16], pifbuf
[32];
425 va_start(args
, flags
);
427 if (!(flags
& PCI_LOOKUP_NO_NUMBERS
))
429 if (a
->numeric_ids
> 1)
430 flags
|= PCI_LOOKUP_MIXED
;
431 else if (a
->numeric_ids
)
432 flags
|= PCI_LOOKUP_NUMERIC
;
434 if (flags
& PCI_LOOKUP_MIXED
)
435 flags
&= ~PCI_LOOKUP_NUMERIC
;
437 if (!a
->id_hash
&& !(flags
& PCI_LOOKUP_NUMERIC
) && !a
->hash_load_failed
)
438 pci_load_name_list(a
);
440 switch (flags
& 0xffff)
442 case PCI_LOOKUP_VENDOR
:
443 iv
= va_arg(args
, int);
444 sprintf(numbuf
, "%04x", iv
);
445 return format_name(buf
, size
, flags
, id_lookup(a
, ID_VENDOR
, iv
, 0, 0, 0), numbuf
, "Unknown vendor");
446 case PCI_LOOKUP_DEVICE
:
447 iv
= va_arg(args
, int);
448 id
= va_arg(args
, int);
449 sprintf(numbuf
, "%04x", id
);
450 return format_name(buf
, size
, flags
, id_lookup(a
, ID_DEVICE
, iv
, id
, 0, 0), numbuf
, "Unknown device");
451 case PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
:
452 iv
= va_arg(args
, int);
453 id
= va_arg(args
, int);
454 sprintf(numbuf
, "%04x:%04x", iv
, id
);
455 v
= id_lookup(a
, ID_VENDOR
, iv
, 0, 0, 0);
456 d
= id_lookup(a
, ID_DEVICE
, iv
, id
, 0, 0);
457 return format_name_pair(buf
, size
, flags
, v
, d
, numbuf
);
458 case PCI_LOOKUP_SUBSYSTEM
| PCI_LOOKUP_VENDOR
:
459 isv
= va_arg(args
, int);
460 sprintf(numbuf
, "%04x", isv
);
461 v
= id_lookup(a
, ID_VENDOR
, isv
, 0, 0, 0);
462 return format_name(buf
, size
, flags
, v
, numbuf
, "Unknown vendor");
463 case PCI_LOOKUP_SUBSYSTEM
| PCI_LOOKUP_DEVICE
:
464 iv
= va_arg(args
, int);
465 id
= va_arg(args
, int);
466 isv
= va_arg(args
, int);
467 isd
= va_arg(args
, int);
468 sprintf(numbuf
, "%04x", isd
);
469 return format_name(buf
, size
, flags
, id_lookup_subsys(a
, iv
, id
, isv
, isd
), numbuf
, "Unknown device");
470 case PCI_LOOKUP_VENDOR
| PCI_LOOKUP_DEVICE
| PCI_LOOKUP_SUBSYSTEM
:
471 iv
= va_arg(args
, int);
472 id
= va_arg(args
, int);
473 isv
= va_arg(args
, int);
474 isd
= va_arg(args
, int);
475 v
= id_lookup(a
, ID_VENDOR
, isv
, 0, 0, 0);
476 d
= id_lookup_subsys(a
, iv
, id
, isv
, isd
);
477 sprintf(numbuf
, "%04x:%04x", isv
, isd
);
478 return format_name_pair(buf
, size
, flags
, v
, d
, numbuf
);
479 case PCI_LOOKUP_CLASS
:
480 icls
= va_arg(args
, int);
481 sprintf(numbuf
, "%04x", icls
);
482 cls
= id_lookup(a
, ID_SUBCLASS
, icls
>> 8, icls
& 0xff, 0, 0);
483 if (!cls
&& (cls
= id_lookup(a
, ID_CLASS
, icls
>> 8, 0, 0, 0)))
485 if (!(flags
& PCI_LOOKUP_NUMERIC
)) /* Include full class number */
486 flags
|= PCI_LOOKUP_MIXED
;
488 return format_name(buf
, size
, flags
, cls
, numbuf
, ((flags
& PCI_LOOKUP_MIXED
) ? "Unknown class" : "Class"));
489 case PCI_LOOKUP_PROGIF
:
490 icls
= va_arg(args
, int);
491 ipif
= va_arg(args
, int);
492 sprintf(numbuf
, "%02x", ipif
);
493 pif
= id_lookup(a
, ID_PROGIF
, icls
>> 8, icls
& 0xff, ipif
, 0);
494 if (!pif
&& icls
== 0x0101 && !(ipif
& 0x70))
496 /* IDE controllers have complex prog-if semantics */
497 sprintf(pifbuf
, "%s%s%s%s%s",
498 (ipif
& 0x80) ? " Master" : "",
499 (ipif
& 0x08) ? " SecP" : "",
500 (ipif
& 0x04) ? " SecO" : "",
501 (ipif
& 0x02) ? " PriP" : "",
502 (ipif
& 0x01) ? " PriO" : "");
507 return format_name(buf
, size
, flags
, pif
, numbuf
, "ProgIf");
509 return "<pci_lookup_name: invalid request>";
513 void pci_set_name_list_path(struct pci_access
*a
, char *name
, int to_be_freed
)
516 free(a
->id_file_name
);
517 a
->id_file_name
= name
;
518 a
->free_id_name
= to_be_freed
;