diff options
Diffstat (limited to 'sysfsutils/cmd/names.c')
-rw-r--r-- | sysfsutils/cmd/names.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/sysfsutils/cmd/names.c b/sysfsutils/cmd/names.c new file mode 100644 index 0000000..1e80d1b --- /dev/null +++ b/sysfsutils/cmd/names.c @@ -0,0 +1,358 @@ +/* + * $Id: names.c,v 1.2.2.1 2005/04/06 23:18:11 stekloff Exp $ + * + * The PCI Library -- ID to Name Translation + * + * Copyright (c) 1997--2002 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 <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include <errno.h> + +#include "names.h" + +struct nl_entry { + struct nl_entry *next; + unsigned short id1, id2, id3, id4; + int cat; + unsigned char *name; +}; + +#define NL_VENDOR 0 +#define NL_DEVICE 1 +#define NL_SUBSYSTEM 2 +#define NL_CLASS 3 +#define NL_SUBCLASS 4 +#define NL_PROGIF 5 + +#define HASH_SIZE 1024 + +static inline unsigned int nl_calc_hash(int cat, int id1, int id2, int id3, int id4) +{ + unsigned int h; + + h = id1 ^ id2 ^ id3 ^ id4 ^ (cat << 5); + h += (h >> 6); + return h & (HASH_SIZE-1); +} + +static struct nl_entry *nl_lookup(struct pci_access *a, int num, int cat, int id1, int id2, int id3, int id4) +{ + 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)) + n = n->next; + + return n; +} + +static int nl_add(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, unsigned char *text) +{ + unsigned int h = nl_calc_hash(cat, id1, id2, id3, id4); + struct nl_entry *n = a->nl_hash[h]; + + while (n && (n->id1 != id1 || n->id2 != id2 || n->id3 != id3 || n->id4 != id4 || n->cat != cat)) + n = n->next; + if (n) + return 1; + n = malloc(sizeof(struct nl_entry)); + bzero(n, sizeof(struct nl_entry)); + n->id1 = id1; + n->id2 = id2; + n->id3 = id3; + n->id4 = id4; + n->cat = cat; + n->name = text; + n->next = a->nl_hash[h]; + a->nl_hash[h] = n; + return 0; +} + +static void +err_name_list(struct pci_access *a, unsigned char *msg) +{ + fprintf(stderr, "%s: %s: %s\n", a->pci_id_file_name, msg, strerror(errno)); +} + +static void +parse_name_list(struct pci_access *a) +{ + unsigned char *p = a->nl_list; + unsigned char *q, *r; + int lino = 0; + unsigned int id1=0, id2=0, id3=0, id4=0; + int cat = -1; + + while (*p) + { + lino++; + q = p; + while (*p && *p != '\n') + p++; + if (*p == '\n') + *p++ = 0; + if (!*q || *q == '#') + continue; + r = p; + while (r > q && r[-1] == ' ') + *--r = 0; + r = q; + while (*q == '\t') + q++; + if (q == r) + { + if (q[0] == 'C' && q[1] == ' ') + { + if (strlen(q+2) < 3 || + q[4] != ' ' || + sscanf(q+2, "%x", &id1) != 1) + goto parserr; + cat = NL_CLASS; + } + else + { + if (strlen(q) < 5 || + q[4] != ' ' || + sscanf(q, "%x", &id1) != 1) + goto parserr; + cat = NL_VENDOR; + } + id2 = id3 = id4 = 0; + q += 4; + } + else if (q == r+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; + 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; + id3 = id4 = 0; + break; + default: + goto parserr; + } + else if (q == r+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; + 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; + id4 = 0; + break; + default: + goto parserr; + } + else + goto parserr; + while (*q == ' ') + q++; + if (!*q) + goto parserr; + if (nl_add(a, cat, id1, id2, id3, id4, q)) + fprintf(stderr, "%s, line %d: duplicate entry", a->pci_id_file_name, lino); + } + return; + +parserr: + fprintf(stderr, "%s, line %d: parse error", a->pci_id_file_name, lino); +} + +static void +load_name_list(struct pci_access *a) +{ + int fd; + struct stat st; + + fd = open(a->pci_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 = malloc(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 = malloc(sizeof(struct nl_entry *) * HASH_SIZE); + bzero(a->nl_hash, sizeof(struct nl_entry *) * HASH_SIZE); + parse_name_list(a); + close(fd); +} + +void +pci_free_name_list(struct pci_access *a) +{ + int i = 0; + struct nl_entry *n = NULL, *temp = NULL; + + free(a->nl_list); + a->nl_list = NULL; + if (a->nl_hash != NULL) { + for (i = 0; i < HASH_SIZE; i++) { + if (a->nl_hash[i] != NULL) { + n = a->nl_hash[i]; + do { + temp = n->next; + free (n); + n = temp; + } while (temp != NULL); + } + } + } + free(a->nl_hash); + a->nl_hash = NULL; +} + +unsigned char * +pci_lookup_name(struct pci_access *a, unsigned char *buf, int size, int flags, unsigned int arg1, unsigned int arg2, unsigned int arg3, unsigned int arg4) +{ + int num = a->numeric_ids; + int res; + struct nl_entry *n; + + if (flags & PCI_LOOKUP_NUMERIC) + { + flags &= PCI_LOOKUP_NUMERIC; + num = 1; + } + if (!a->nl_hash && !num) + { + load_name_list(a); + num = a->numeric_ids; + } + switch (flags) + { + case PCI_LOOKUP_VENDOR: + if ((n = nl_lookup(a, num, NL_VENDOR, arg1, 0, 0, 0))) + return n->name; + else + res = snprintf(buf, size, "%04x", arg1); + break; + case PCI_LOOKUP_DEVICE: + if ((n = nl_lookup(a, num, NL_DEVICE, arg1, arg2, 0, 0))) + return n->name; + else + res = snprintf(buf, size, "%04x", arg2); + break; + case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE: + if (!num) + { + 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); + } + 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; + else + res = snprintf(buf, size, "%04x", arg2); + 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; + else + res = snprintf(buf, size, "%04x", arg4); + break; + case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: + if (!num) + { + 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); + } + 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); + else + res = snprintf(buf, size, "Class %04x", arg1); + 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) + { + /* 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) + buf[--res] = 0; + break; + } + return NULL; + default: + return "<pci_lookup_name: invalid request>"; + } + if (res == size) + return "<too-large>"; + else + return buf; +} |