From: Martin Mares Date: Sat, 10 Sep 2005 12:09:51 +0000 (+0000) Subject: New names.c X-Git-Tag: v3.0.0~86 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=aeaca5d34d484d6d0916d6ca56701dbdd5f00979;p=pciutils.git New names.c git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-79 --- diff --git a/ChangeLog b/ChangeLog index 970fc77..6eb55c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-09-10 Martin Mares + + * lib/names.c: Rewritten the name database module almost from scratch. + Everything is much cleaner and there are hopefully no more memory leaks; + pci_lookup_name() now uses varargs in a backward compatible fashion. + Introduced PCI_LOOKUP_NO_NUMBERS. + + The new code supports subsystem entries not tied to a specific device. + I had to extend the format of pci.ids in order to support it, so I have + extended the idea of the "C" (class) blocks and introduced "S" blocks + for subsystems. To avoid doing more incompatible changes in the future, + the parser skips unknown single-letter blocks without reporting errors. + 2005-08-23 Martin Mares * Released as 2.1.99-test9. diff --git a/TODO b/TODO index 9c2e89f..b92f6c8 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,14 @@ -- names.c: remove memory leaks -- names.c: reading of separate subsystem entries - - update the web page +- kill "word" + - some extended capabilities are currently only partially decoded - finish PCI-X 2.0 capabilities - finish PCI Express support - reading of VPD - change machine-readable output? - "Class %04x" -> "%04x" -- merge pcimodules? +- class 0805? PCIIDS: - another mirror at Atrey? diff --git a/lib/names.c b/lib/names.c index 01f1417..0a88d62 100644 --- a/lib/names.c +++ b/lib/names.c @@ -1,336 +1,483 @@ /* * The PCI Library -- ID to Name Translation * - * Copyright (c) 1997--2002 Martin Mares + * Copyright (c) 1997--2005 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ #include #include +#include #include -#include -#include -#include #include #include "internal.h" -struct nl_entry { - struct nl_entry *next; - word id1, id2, id3, id4; - int cat; - byte *name; +struct id_entry { + struct id_entry *next; + u32 id12, id34; + byte cat; + byte name[1]; }; -#define NL_VENDOR 0 -#define NL_DEVICE 1 -#define NL_SUBSYSTEM 2 -#define NL_CLASS 3 -#define NL_SUBCLASS 4 -#define NL_PROGIF 5 +enum id_entry_type { + ID_UNKNOWN, + ID_VENDOR, + ID_DEVICE, + ID_SUBSYSTEM, + ID_GEN_SUBSYSTEM, + ID_CLASS, + ID_SUBCLASS, + ID_PROGIF +}; + +struct id_bucket { + struct id_bucket *next; + unsigned int full; +}; -#define HASH_SIZE 1024 +#define MAX_LINE 1024 +#define BUCKET_SIZE 8192 +#define HASH_SIZE 4099 -static inline unsigned int nl_calc_hash(int cat, int id1, int id2, int id3, int id4) +#ifdef __GNUC__FIXME +#define BUCKET_ALIGNMENT __alignof__(struct id_bucket) +#else +union id_align { + struct id_bucket *next; + unsigned int full; +}; +#define BUCKET_ALIGNMENT sizeof(union id_align) +#endif +#define BUCKET_ALIGN(n) ((n)+BUCKET_ALIGNMENT-(n)%BUCKET_ALIGNMENT) + +static void *id_alloc(struct pci_access *a, unsigned int size) { - unsigned int h; + struct id_bucket *buck = a->current_id_bucket; + unsigned int pos; + if (!buck || buck->full + size > BUCKET_SIZE) + { + buck = pci_malloc(a, BUCKET_SIZE); + buck->next = a->current_id_bucket; + a->current_id_bucket = buck; + buck->full = BUCKET_ALIGN(sizeof(struct id_bucket)); + } + pos = buck->full; + buck->full = BUCKET_ALIGN(buck->full + size); + return (byte *)buck + pos; +} - h = id1 ^ id2 ^ id3 ^ id4 ^ (cat << 5); - h += (h >> 6); - return h & (HASH_SIZE-1); +static inline u32 id_pair(unsigned int x, unsigned int y) +{ + return ((x << 16) | y); } -static struct nl_entry *nl_lookup(struct pci_access *a, int num, int cat, int id1, int id2, int id3, int id4) +static inline unsigned int id_hash(int cat, u32 id12, u32 id34) { unsigned int h; - struct nl_entry *n; - if (num) - return NULL; - h = nl_calc_hash(cat, id1, id2, id3, id4); - n = a->nl_hash[h]; - while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat)) + h = id12 ^ (id34 << 3) ^ (cat << 5); + return h % HASH_SIZE; +} + +static struct id_entry *id_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4) +{ + struct id_entry *n; + u32 id12 = id_pair(id1, id2); + u32 id34 = id_pair(id3, id4); + + n = a->id_hash[id_hash(cat, id12, id34)]; + while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat)) n = n->next; return n; } -static int nl_add(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, byte *text) +static int id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, byte *text) { - unsigned int h = nl_calc_hash(cat, id1, id2, id3, id4); - struct nl_entry *n = a->nl_hash[h]; + u32 id12 = id_pair(id1, id2); + u32 id34 = id_pair(id3, id4); + unsigned int h = id_hash(cat, id12, id34); + struct id_entry *n = a->id_hash[h]; + int len = strlen(text); - while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat)) + while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat)) n = n->next; if (n) return 1; - n = pci_malloc(a, sizeof(struct nl_entry)); - n->id1 = id1; - n->id2 = id2; - n->id3 = id3; - n->id4 = id4; + n = id_alloc(a, sizeof(struct id_entry) + len); + n->id12 = id12; + n->id34 = id34; n->cat = cat; - n->name = text; - n->next = a->nl_hash[h]; - a->nl_hash[h] = n; + memcpy(n->name, text, len+1); + n->next = a->id_hash[h]; + a->id_hash[h] = n; return 0; } -static void -err_name_list(struct pci_access *a, char *msg) +static int id_hex(byte *p, int cnt) { - a->error("%s: %s: %s\n", a->id_file_name, msg, strerror(errno)); + int x = 0; + while (cnt--) + { + x <<= 4; + if (*p >= '0' && *p <= '9') + x += (*p - '0'); + else if (*p >= 'a' && *p <= 'f') + x += (*p - 'a' + 10); + else if (*p >= 'A' && *p <= 'F') + x += (*p - 'A' + 10); + else + return -1; + p++; + } + return x; } -static void -parse_name_list(struct pci_access *a) +static inline int id_white_p(int c) { - byte *p = a->nl_list; - byte *q, *r; - int lino = 0; - unsigned int id1=0, id2=0, id3=0, id4=0; + return (c == ' ') || (c == '\t'); +} + +static const char *id_parse_list(struct pci_access *a, FILE *f, int *lino) +{ + byte line[MAX_LINE]; + byte *p; + int id1=0, id2=0, id3=0, id4=0; int cat = -1; + int nest; + static const char parse_error[] = "Parse error"; - while (*p) + *lino = 0; + while (fgets(line, sizeof(line), f)) { - lino++; - q = p; - while (*p && *p != '\n') + (*lino)++; + p = line; + while (*p && *p != '\n' && *p != '\r') p++; - if (*p == '\n') - *p++ = 0; - if (!*q || *q == '#') + if (!*p && !feof(f)) + return "Line too long"; + *p = 0; + if (p > line && (p[-1] == ' ' || p[-1] == '\t')) + *--p = 0; + + p = line; + while (id_white_p(*p)) + p++; + if (!*p || *p == '#') continue; - r = p; - while (r > q && r[-1] == ' ') - *--r = 0; - r = q; - while (*q == '\t') - q++; - if (q == r) + + p = line; + while (*p == '\t') + p++; + nest = p - line; + + if (!nest) /* Top-level entries */ { - if (q[0] == 'C' && q[1] == ' ') + if (p[0] == 'C' && p[1] == ' ') /* Class block */ { - if (strlen(q+2) < 3 || - q[4] != ' ' || - sscanf(q+2, "%x", &id1) != 1) - goto parserr; - cat = NL_CLASS; + if ((id1 = id_hex(p+2, 2)) < 0 || !id_white_p(p[4])) + return parse_error; + cat = ID_CLASS; + p += 5; + } + else if (p[0] == 'S' && p[1] == ' ') + { /* Generic subsystem block */ + if ((id1 = id_hex(p+2, 4)) < 0 || p[6]) + return parse_error; + if (!id_lookup(a, ID_VENDOR, id1, 0, 0, 0)) + return "Vendor does not exist"; + cat = ID_GEN_SUBSYSTEM; + continue; + } + else if (p[0] >= 'A' && p[0] <= 'Z' && p[1] == ' ') + { /* Unrecognized block (RFU) */ + cat = ID_UNKNOWN; + continue; } - else + else /* Vendor ID */ { - if (strlen(q) < 5 || - q[4] != ' ' || - sscanf(q, "%x", &id1) != 1) - goto parserr; - cat = NL_VENDOR; + if ((id1 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) + return parse_error; + cat = ID_VENDOR; + p += 5; } id2 = id3 = id4 = 0; - q += 4; } - else if (q == r+1) + else if (cat == ID_UNKNOWN) /* Nested entries in RFU blocks are skipped */ + continue; + else if (nest == 1) /* Nesting level 1 */ switch (cat) { - case NL_VENDOR: - case NL_DEVICE: - case NL_SUBSYSTEM: - if (sscanf(q, "%x", &id2) != 1 || q[4] != ' ') - goto parserr; - q += 5; - cat = NL_DEVICE; + case ID_VENDOR: + case ID_DEVICE: + case ID_SUBSYSTEM: + if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) + return parse_error; + p += 5; + cat = ID_DEVICE; + id3 = id4 = 0; + break; + case ID_GEN_SUBSYSTEM: + if ((id2 = id_hex(p, 4)) < 0 || !id_white_p(p[4])) + return parse_error; + p += 5; id3 = id4 = 0; break; - case NL_CLASS: - case NL_SUBCLASS: - case NL_PROGIF: - if (sscanf(q, "%x", &id2) != 1 || q[2] != ' ') - goto parserr; - q += 3; - cat = NL_SUBCLASS; + case ID_CLASS: + case ID_SUBCLASS: + case ID_PROGIF: + if ((id2 = id_hex(p, 2)) < 0 || !id_white_p(p[2])) + return parse_error; + p += 3; + cat = ID_SUBCLASS; id3 = id4 = 0; break; default: - goto parserr; + return parse_error; } - else if (q == r+2) + else if (nest == 2) /* Nesting level 2 */ switch (cat) { - case NL_DEVICE: - case NL_SUBSYSTEM: - if (sscanf(q, "%x%x", &id3, &id4) != 2 || q[9] != ' ') - goto parserr; - q += 10; - cat = NL_SUBSYSTEM; + case ID_DEVICE: + case ID_SUBSYSTEM: + if ((id3 = id_hex(p, 4)) < 0 || !id_white_p(p[4]) || (id4 = id_hex(p+5, 4)) < 0 || !id_white_p(p[9])) + return parse_error; + p += 10; + cat = ID_SUBSYSTEM; break; - case NL_CLASS: - case NL_SUBCLASS: - case NL_PROGIF: - if (sscanf(q, "%x", &id3) != 1 || q[2] != ' ') - goto parserr; - q += 3; - cat = NL_PROGIF; + case ID_CLASS: + case ID_SUBCLASS: + case ID_PROGIF: + if ((id3 = id_hex(p, 2)) < 0 || !id_white_p(p[2])) + return parse_error; + p += 3; + cat = ID_PROGIF; id4 = 0; break; default: - goto parserr; + return parse_error; } - else - goto parserr; - while (*q == ' ') - q++; - if (!*q) - goto parserr; - if (nl_add(a, cat, id1, id2, id3, id4, q)) - a->error("%s, line %d: duplicate entry", a->id_file_name, lino); + else /* Nesting level 3 or more */ + return parse_error; + while (id_white_p(*p)) + p++; + if (!*p) + return parse_error; + if (id_insert(a, cat, id1, id2, id3, id4, p)) + return "Duplicate entry"; } - return; - -parserr: - a->error("%s, line %d: parse error", a->id_file_name, lino); + return NULL; } -static void -load_name_list(struct pci_access *a) +int +pci_load_name_list(struct pci_access *a) { - int fd; - struct stat st; + FILE *f; + int lino; + const char *err; - fd = open(a->id_file_name, O_RDONLY); - if (fd < 0) - { - a->numeric_ids = 1; - return; - } - if (fstat(fd, &st) < 0) - err_name_list(a, "stat"); - a->nl_list = pci_malloc(a, st.st_size + 1); - if (read(fd, a->nl_list, st.st_size) != st.st_size) - err_name_list(a, "read"); - a->nl_list[st.st_size] = 0; - a->nl_hash = pci_malloc(a, sizeof(struct nl_entry *) * HASH_SIZE); - bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE); - parse_name_list(a); - close(fd); + pci_free_name_list(a); + if (!(f = fopen(a->id_file_name, "r"))) + return 0; + a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE); + bzero(a->id_hash, sizeof(struct id_entry *) * HASH_SIZE); + err = id_parse_list(a, f, &lino); + if (!err && ferror(f)) + err = "I/O error"; + fclose(f); + if (err) + a->error("%s at %s, line %d\n", err, a->id_file_name, lino); + return 1; } void pci_free_name_list(struct pci_access *a) { - pci_mfree(a->nl_list); - a->nl_list = NULL; - pci_mfree(a->nl_hash); - a->nl_hash = NULL; + pci_mfree(a->id_hash); + a->id_hash = NULL; + while (a->current_id_bucket) + { + struct id_bucket *buck = a->current_id_bucket; + a->current_id_bucket = buck->next; + pci_mfree(buck); + } +} + +static struct id_entry *id_lookup_subsys(struct pci_access *a, int iv, int id, int isv, int isd) +{ + struct id_entry *d = NULL; + if (iv > 0 && id > 0) /* Per-device lookup */ + d = id_lookup(a, ID_SUBSYSTEM, iv, id, isv, isd); + if (!d) /* Generic lookup */ + d = id_lookup(a, ID_GEN_SUBSYSTEM, isv, isd, 0, 0); + if (!d && iv == isv && id == isd) /* Check for subsystem == device */ + d = id_lookup(a, ID_DEVICE, iv, id, 0, 0); + return d; } char * -pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4) +pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) { - int num = a->numeric_ids; - int res; - struct nl_entry *n; + va_list args; + int num, res, synth; + struct id_entry *v, *d, *cls, *pif; + int iv, id, isv, isd, icls, ipif; + + va_start(args, flags); - if (flags & PCI_LOOKUP_NUMERIC) + num = 0; + if ((flags & PCI_LOOKUP_NUMERIC) || a->numeric_ids) { - flags &= PCI_LOOKUP_NUMERIC; + flags &= ~PCI_LOOKUP_NUMERIC; num = 1; } - if (!a->nl_hash && !num) + else if (!a->id_hash) { - load_name_list(a); - num = a->numeric_ids; + if (!pci_load_name_list(a)) + num = a->numeric_ids = 1; } + + if (flags & PCI_LOOKUP_NO_NUMBERS) + { + flags &= ~PCI_LOOKUP_NO_NUMBERS; + synth = 0; + if (num) + return NULL; + } + else + synth = 1; + switch (flags) { case PCI_LOOKUP_VENDOR: - if (n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0)) - return n->name; + iv = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x", iv); + else if (v = id_lookup(a, ID_VENDOR, iv, 0, 0, 0)) + return v->name; else - res = snprintf(buf, size, "%04x", arg1); + res = snprintf(buf, size, "Unknown vendor %04x", iv); break; case PCI_LOOKUP_DEVICE: - if (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0)) - return n->name; + iv = va_arg(args, int); + id = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x", id); + else if (d = id_lookup(a, ID_DEVICE, iv, id, 0, 0)) + return d->name; + else if (synth) + res = snprintf(buf, size, "Unknown device %04x", id); else - res = snprintf(buf, size, "%04x", arg2); + return NULL; break; case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE: - if (!num) + iv = va_arg(args, int); + id = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x:%04x", iv, id); + else { - struct nl_entry *e, *e2; - e = nl_lookup(a, 0, NL_VENDOR, arg1, 0, 0, 0); - e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0); - if (!e) - res = snprintf(buf, size, "Unknown device %04x:%04x", arg1, arg2); - else if (!e2) - res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg2); - else - res = snprintf(buf, size, "%s %s", e->name, e2->name); + v = id_lookup(a, ID_VENDOR, iv, 0, 0, 0); + d = id_lookup(a, ID_DEVICE, iv, id, 0, 0); + if (v && d) + res = snprintf(buf, size, "%s %s", v->name, d->name); + else if (!synth) + return NULL; + else if (!v) + res = snprintf(buf, size, "Unknown device %04x:%04x", iv, id); + else /* !d */ + res = snprintf(buf, size, "%s Unknown device %04x", v->name, id); } - else - res = snprintf(buf, size, "%04x:%04x", arg1, arg2); break; - case PCI_LOOKUP_VENDOR | PCI_LOOKUP_SUBSYSTEM: - if (n = nl_lookup(a, num, NL_VENDOR, arg3, 0, 0, 0)) - return n->name; + case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR: + isv = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x", isv); + else if (v = id_lookup(a, ID_VENDOR, isv, 0, 0, 0)) + return v->name; + else if (synth) + res = snprintf(buf, size, "Unknown vendor %04x", isv); else - res = snprintf(buf, size, "%04x", arg3); + return NULL; break; - case PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: - if (n = nl_lookup(a, num, NL_SUBSYSTEM, arg1, arg2, arg3, arg4)) - return n->name; - else if (arg1 == arg3 && arg2 == arg4 && (n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0))) - return n->name; + case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE: + iv = va_arg(args, int); + id = va_arg(args, int); + isv = va_arg(args, int); + isd = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x", isd); + else if (d = id_lookup_subsys(a, iv, id, isv, isd)) + return d->name; + else if (synth) + res = snprintf(buf, size, "Unknown device %04x", isd); else - res = snprintf(buf, size, "%04x", arg4); + return NULL; break; case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: - if (!num) + iv = va_arg(args, int); + id = va_arg(args, int); + isv = va_arg(args, int); + isd = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x:%04x", isv, isd); + else { - struct nl_entry *e, *e2; - e = nl_lookup(a, 0, NL_VENDOR, arg3, 0, 0, 0); - e2 = nl_lookup(a, 0, NL_SUBSYSTEM, arg1, arg2, arg3, arg4); - if (!e2 && arg1 == arg3 && arg2 == arg4) - /* Cheat for vendors blindly setting subsystem ID same as device ID */ - e2 = nl_lookup(a, 0, NL_DEVICE, arg1, arg2, 0, 0); - if (!e) - res = snprintf(buf, size, "Unknown device %04x:%04x", arg3, arg4); - else if (!e2) - res = snprintf(buf, size, "%s: Unknown device %04x", e->name, arg4); - else - res = snprintf(buf, size, "%s %s", e->name, e2->name); + v = id_lookup(a, ID_VENDOR, isv, 0, 0, 0); + d = id_lookup_subsys(a, iv, id, isv, isd); + if (v && d) + res = snprintf(buf, size, "%s %s", v->name, d->name); + else if (!synth) + return NULL; + else if (!v) + res = snprintf(buf, size, "Unknown device %04x:%04x", isv, isd); + else /* !d */ + res = snprintf(buf, size, "%s Unknown device %04x", v->name, isd); } - else - res = snprintf(buf, size, "%04x:%04x", arg3, arg4); break; case PCI_LOOKUP_CLASS: - if (n = nl_lookup(a, num, NL_SUBCLASS, arg1 >> 8, arg1 & 0xff, 0, 0)) - return n->name; - else if (n = nl_lookup(a, num, NL_CLASS, arg1, 0, 0, 0)) - res = snprintf(buf, size, "%s [%04x]", n->name, arg1); + icls = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%04x", icls); + else if (cls = id_lookup(a, ID_SUBCLASS, icls >> 8, icls & 0xff, 0, 0)) + return cls->name; + else if (cls = id_lookup(a, ID_CLASS, icls, 0, 0, 0)) + res = snprintf(buf, size, "%s [%04x]", cls->name, icls); + else if (synth) + res = snprintf(buf, size, "Class %04x", icls); else - res = snprintf(buf, size, "Class %04x", arg1); + return NULL; break; case PCI_LOOKUP_PROGIF: - if (n = nl_lookup(a, num, NL_PROGIF, arg1 >> 8, arg1 & 0xff, arg2, 0)) - return n->name; - if (arg1 == 0x0101) + icls = va_arg(args, int); + ipif = va_arg(args, int); + if (num) + res = snprintf(buf, size, "%02x", ipif); + else if (pif = id_lookup(a, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0)) + return pif->name; + else if (icls == 0x0101 && !(ipif & 0x70)) { /* IDE controllers have complex prog-if semantics */ - if (arg2 & 0x70) - return NULL; res = snprintf(buf, size, "%s%s%s%s%s", - (arg2 & 0x80) ? "Master " : "", - (arg2 & 0x08) ? "SecP " : "", - (arg2 & 0x04) ? "SecO " : "", - (arg2 & 0x02) ? "PriP " : "", - (arg2 & 0x01) ? "PriO " : ""); - if (res) + (ipif & 0x80) ? "Master " : "", + (ipif & 0x08) ? "SecP " : "", + (ipif & 0x04) ? "SecO " : "", + (ipif & 0x02) ? "PriP " : "", + (ipif & 0x01) ? "PriO " : ""); + if (res > 0 && res < size) buf[--res] = 0; - break; } - return NULL; + else if (synth) + res = snprintf(buf, size, "ProgIf %02x", ipif); + else + return NULL; + break; default: return ""; } - return (res == size) ? "" : buf; + if (res < 0 || res >= size) + return ""; + else + return buf; } diff --git a/lib/pci.h b/lib/pci.h index 3d8f865..c92df14 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -1,7 +1,7 @@ /* * The PCI Library * - * Copyright (c) 1997--2004 Martin Mares + * Copyright (c) 1997--2005 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -18,7 +18,6 @@ */ struct pci_methods; -struct nl_entry; enum pci_access_type { /* Known access methods, remember to update access.c as well */ @@ -53,8 +52,8 @@ struct pci_access { /* Fields used internally: */ struct pci_methods *methods; - char *nl_list; /* Name list cache */ - struct nl_entry **nl_hash; + struct id_entry **id_hash; /* names.c */ + struct id_bucket *current_id_bucket; int fd; /* proc: fd */ int fd_rw; /* proc: fd opened read-write */ struct pci_dev *cached_dev; /* proc: device the fd is for */ @@ -136,17 +135,34 @@ char *pci_filter_parse_id(struct pci_filter *, char *); int pci_filter_match(struct pci_filter *, struct pci_dev *); /* - * Device names + * Conversion of PCI ID's to names (according to the pci.ids file) + * + * Call pci_lookup_name() to identify different types of ID's: + * + * VENDOR (vendorID) -> vendor + * DEVICE (vendorID, deviceID) -> device + * VENDOR | DEVICE (vendorID, deviceID) -> combined vendor and device + * SUBSYSTEM | VENDOR (subvendorID) -> subsystem vendor + * SUBSYSTEM | DEVICE (vendorID, deviceID, subvendorID, subdevID) -> subsystem device + * SUBSYSTEM | VENDOR | DEVICE (vendorID, deviceID, subvendorID, subdevID) -> combined subsystem v+d + * SUBSYSTEM | ... (-1, -1, subvendorID, subdevID) -> generic subsystem + * CLASS (classID) -> class + * PROGIF (classID, progif) -> programming interface */ -char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, u32 arg1, u32 arg2, u32 arg3, u32 arg4); -void pci_free_name_list(struct pci_access *a); +char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...); -#define PCI_LOOKUP_VENDOR 1 -#define PCI_LOOKUP_DEVICE 2 -#define PCI_LOOKUP_CLASS 4 -#define PCI_LOOKUP_SUBSYSTEM 8 -#define PCI_LOOKUP_PROGIF 16 -#define PCI_LOOKUP_NUMERIC 0x10000 +int pci_load_name_list(struct pci_access *a); /* Called automatically by pci_lookup_*() when needed; returns success */ +void pci_free_name_list(struct pci_access *a); /* Called automatically by pci_cleanup() */ + +enum pci_lookup_mode { + PCI_LOOKUP_VENDOR = 1, /* Vendor name (args: vendorID) */ + PCI_LOOKUP_DEVICE = 2, /* Device name (args: vendorID, deviceID) */ + PCI_LOOKUP_CLASS = 4, /* Device class (args: classID) */ + PCI_LOOKUP_SUBSYSTEM = 8, + PCI_LOOKUP_PROGIF = 16, /* Programming interface (args: classID, prog_if) */ + PCI_LOOKUP_NUMERIC = 0x10000, /* Want only formatted numbers; default if access->numeric_ids is set */ + PCI_LOOKUP_NO_NUMBERS = 0x20000 /* Return NULL if not found in the database; default is to print numerically */ +}; #endif diff --git a/lspci.c b/lspci.c index b00ea48..7295bdd 100644 --- a/lspci.c +++ b/lspci.c @@ -266,7 +266,7 @@ show_terse(struct device *d) char *x; c = get_conf_byte(d, PCI_CLASS_PROG); x = pci_lookup_name(pacc, devbuf, sizeof(devbuf), - PCI_LOOKUP_PROGIF, + PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS, get_conf_word(d, PCI_CLASS_DEVICE), c, 0, 0); if (c || x) {