/*
* The PCI Library -- ID to Name Translation
*
- * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2007 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdarg.h>
#include <string.h>
#include <errno.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
#include "internal.h"
{
struct id_bucket *buck = a->current_id_bucket;
unsigned int pos;
+
+ if (!a->id_hash)
+ {
+ a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE);
+ memset(a->id_hash, 0, sizeof(struct id_entry *) * HASH_SIZE);
+ }
+
if (!buck || buck->full + size > BUCKET_SIZE)
{
buck = pci_malloc(a, BUCKET_SIZE);
return h % HASH_SIZE;
}
-static char *id_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
+static char *id_net_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);
+ byte name[256], dnsname[256], answer[4096], txt[256];
+ const byte *data;
+ int res, i, j, dlen;
+ ns_msg m;
+ ns_rr rr;
- if (!a->id_hash)
- return NULL;
- 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 ? n->name : NULL;
+ switch (cat)
+ {
+ case ID_VENDOR:
+ sprintf(name, "%04x", id1);
+ break;
+ case ID_DEVICE:
+ sprintf(name, "%04x.%04x", id2, id1);
+ break;
+ case ID_SUBSYSTEM:
+ sprintf(name, "%04x.%04x.%04x.%04x", id4, id3, id2, id1);
+ break;
+ case ID_GEN_SUBSYSTEM:
+ sprintf(name, "%04x.%04x.s", id2, id1);
+ break;
+ case ID_CLASS:
+ sprintf(name, "%02x.c", id1);
+ break;
+ case ID_SUBCLASS:
+ sprintf(name, "%02x.%02x.c", id2, id1);
+ break;
+ case ID_PROGIF:
+ sprintf(name, "%02x.%02x.%02x.c", id3, id2, id1);
+ break;
+ default:
+ return NULL;
+ }
+ sprintf(dnsname, "%s.%s", name, a->id_domain);
+
+ a->debug("Resolving %s\n", dnsname);
+ res_init();
+ res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer));
+ if (res < 0)
+ {
+ a->debug("\tfailed, h_errno=%d\n", _res.res_h_errno);
+ return NULL;
+ }
+ if (ns_initparse(answer, res, &m) < 0)
+ {
+ a->debug("\tinitparse failed\n");
+ return NULL;
+ }
+ for (i=0; ns_parserr(&m, ns_s_an, i, &rr) >= 0; i++)
+ {
+ a->debug("\tanswer %d (class %d, type %d)\n", i, ns_rr_class(rr), ns_rr_type(rr));
+ if (ns_rr_class(rr) != ns_c_in || ns_rr_type(rr) != ns_t_txt)
+ continue;
+ data = ns_rr_rdata(rr);
+ dlen = ns_rr_rdlen(rr);
+ j = 0;
+ while (j < dlen && j+1+data[j] <= dlen)
+ {
+ memcpy(txt, &data[j+1], data[j]);
+ txt[data[j]] = 0;
+ j += 1+data[j];
+ a->debug("\t\t%s\n", txt);
+ if (txt[0] == 'i' && txt[1] == '=')
+ return strdup(txt+2); /* FIXME */
+ }
+ }
+
+ return NULL;
}
static int id_insert(struct pci_access *a, int cat, int id1, int id2, int id3, int id4, char *text)
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];
+ struct id_entry *n = a->id_hash ? a->id_hash[h] : NULL;
int len = strlen(text);
while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
return 0;
}
+static char *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);
+ char *name;
+
+ if (a->id_hash)
+ {
+ n = a->id_hash[id_hash(cat, id12, id34)];
+ while (n && (n->id12 != id12 || n->id34 != id34 || n->cat != cat))
+ n = n->next;
+ if (n)
+ return n->name;
+ }
+ if (name = id_net_lookup(a, cat, id1, id2, id3, id4))
+ {
+ id_insert(a, cat, id1, id2, id3, id4, name);
+ return name;
+ }
+ return NULL;
+}
+
static int id_hex(char *p, int cnt)
{
int x = 0;
a->hash_load_failed = 1;
if (!(f = pci_open(a)))
return 0;
- a->id_hash = pci_malloc(a, sizeof(struct id_entry *) * HASH_SIZE);
- memset(a->id_hash, 0, sizeof(struct id_entry *) * HASH_SIZE);
err = id_parse_list(a, f, &lino);
PCI_ERROR(f, err);
pci_close(f);