/*
* The PCI Library -- ID to Name Translation
*
- * Copyright (c) 1997--2002 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2005 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
#include <errno.h>
#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 "<pci_lookup_name: invalid request>";
}
- return (res == size) ? "<too-large>" : buf;
+ if (res < 0 || res >= size)
+ return "<pci_lookup_name: buffer too small>";
+ else
+ return buf;
}