1: /*
2: * The PCI Library -- ID to Name Translation
3: *
4: * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
5: *
6: * Can be freely distributed and used under the terms of the GNU GPL.
7: */
8:
9: #include <stdio.h>
10: #include <stdarg.h>
11: #include <string.h>
12:
13: #include "internal.h"
14: #include "names.h"
15:
16: static char *id_lookup(struct pci_access *a, int flags, int cat, int id1, int id2, int id3, int id4)
17: {
18: char *name;
19:
20: while (!(name = pci_id_lookup(a, flags, cat, id1, id2, id3, id4)))
21: {
22: if ((flags & PCI_LOOKUP_CACHE) && !a->id_cache_status)
23: {
24: if (pci_id_cache_load(a, flags))
25: continue;
26: }
27: if (flags & PCI_LOOKUP_NETWORK)
28: {
29: if (name = pci_id_net_lookup(a, cat, id1, id2, id3, id4))
30: {
31: pci_id_insert(a, cat, id1, id2, id3, id4, name, SRC_NET);
32: pci_mfree(name);
33: pci_id_cache_dirty(a);
34: }
35: else
36: pci_id_insert(a, cat, id1, id2, id3, id4, "", SRC_NET);
37: /* We want to iterate the lookup to get the allocated ID entry from the hash */
38: continue;
39: }
40: return NULL;
41: }
42: return (name[0] ? name : NULL);
43: }
44:
45: static char *
46: id_lookup_subsys(struct pci_access *a, int flags, int iv, int id, int isv, int isd)
47: {
48: char *d = NULL;
49: if (iv > 0 && id > 0) /* Per-device lookup */
50: d = id_lookup(a, flags, ID_SUBSYSTEM, iv, id, isv, isd);
51: if (!d) /* Generic lookup */
52: d = id_lookup(a, flags, ID_GEN_SUBSYSTEM, isv, isd, 0, 0);
53: if (!d && iv == isv && id == isd) /* Check for subsystem == device */
54: d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0);
55: return d;
56: }
57:
58: static char *
59: format_name(char *buf, int size, int flags, char *name, char *num, char *unknown)
60: {
61: int res;
62: if ((flags & PCI_LOOKUP_NO_NUMBERS) && !name)
63: return NULL;
64: else if (flags & PCI_LOOKUP_NUMERIC)
65: res = snprintf(buf, size, "%s", num);
66: else if (!name)
67: res = snprintf(buf, size, ((flags & PCI_LOOKUP_MIXED) ? "%s [%s]" : "%s %s"), unknown, num);
68: else if (!(flags & PCI_LOOKUP_MIXED))
69: res = snprintf(buf, size, "%s", name);
70: else
71: res = snprintf(buf, size, "%s [%s]", name, num);
72: if (res >= size && size >= 4)
73: buf[size-2] = buf[size-3] = buf[size-4] = '.';
74: else if (res < 0 || res >= size)
75: return "<pci_lookup_name: buffer too small>";
76: return buf;
77: }
78:
79: static char *
80: format_name_pair(char *buf, int size, int flags, char *v, char *d, char *num)
81: {
82: int res;
83: if ((flags & PCI_LOOKUP_NO_NUMBERS) && (!v || !d))
84: return NULL;
85: if (flags & PCI_LOOKUP_NUMERIC)
86: res = snprintf(buf, size, "%s", num);
87: else if (flags & PCI_LOOKUP_MIXED)
88: {
89: if (v && d)
90: res = snprintf(buf, size, "%s %s [%s]", v, d, num);
91: else if (!v)
92: res = snprintf(buf, size, "Device [%s]", num);
93: else /* v && !d */
94: res = snprintf(buf, size, "%s Device [%s]", v, num);
95: }
96: else
97: {
98: if (v && d)
99: res = snprintf(buf, size, "%s %s", v, d);
100: else if (!v)
101: res = snprintf(buf, size, "Device %s", num);
102: else /* v && !d */
103: res = snprintf(buf, size, "%s Device %s", v, num+5);
104: }
105: if (res >= size && size >= 4)
106: buf[size-2] = buf[size-3] = buf[size-4] = '.';
107: else if (res < 0 || res >= size)
108: return "<pci_lookup_name: buffer too small>";
109: return buf;
110: }
111:
112: char *
113: pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...)
114: {
115: va_list args;
116: char *v, *d, *cls, *pif;
117: int iv, id, isv, isd, icls, ipif;
118: char numbuf[16], pifbuf[32];
119:
120: va_start(args, flags);
121:
122: flags |= a->id_lookup_mode;
123: if (!(flags & PCI_LOOKUP_NO_NUMBERS))
124: {
125: if (a->numeric_ids > 1)
126: flags |= PCI_LOOKUP_MIXED;
127: else if (a->numeric_ids)
128: flags |= PCI_LOOKUP_NUMERIC;
129: }
130: if (flags & PCI_LOOKUP_MIXED)
131: flags &= ~PCI_LOOKUP_NUMERIC;
132:
133: if (!a->id_hash && !(flags & (PCI_LOOKUP_NUMERIC | PCI_LOOKUP_SKIP_LOCAL)) && !a->id_load_failed)
134: pci_load_name_list(a);
135:
136: switch (flags & 0xffff)
137: {
138: case PCI_LOOKUP_VENDOR:
139: iv = va_arg(args, int);
140: sprintf(numbuf, "%04x", iv);
141: return format_name(buf, size, flags, id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0), numbuf, "Vendor");
142: case PCI_LOOKUP_DEVICE:
143: iv = va_arg(args, int);
144: id = va_arg(args, int);
145: sprintf(numbuf, "%04x", id);
146: return format_name(buf, size, flags, id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0), numbuf, "Device");
147: case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE:
148: iv = va_arg(args, int);
149: id = va_arg(args, int);
150: sprintf(numbuf, "%04x:%04x", iv, id);
151: v = id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0);
152: d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0);
153: return format_name_pair(buf, size, flags, v, d, numbuf);
154: case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR:
155: isv = va_arg(args, int);
156: sprintf(numbuf, "%04x", isv);
157: v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0);
158: return format_name(buf, size, flags, v, numbuf, "Unknown vendor");
159: case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE:
160: iv = va_arg(args, int);
161: id = va_arg(args, int);
162: isv = va_arg(args, int);
163: isd = va_arg(args, int);
164: sprintf(numbuf, "%04x", isd);
165: return format_name(buf, size, flags, id_lookup_subsys(a, flags, iv, id, isv, isd), numbuf, "Device");
166: case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM:
167: iv = va_arg(args, int);
168: id = va_arg(args, int);
169: isv = va_arg(args, int);
170: isd = va_arg(args, int);
171: v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0);
172: d = id_lookup_subsys(a, flags, iv, id, isv, isd);
173: sprintf(numbuf, "%04x:%04x", isv, isd);
174: return format_name_pair(buf, size, flags, v, d, numbuf);
175: case PCI_LOOKUP_CLASS:
176: icls = va_arg(args, int);
177: sprintf(numbuf, "%04x", icls);
178: cls = id_lookup(a, flags, ID_SUBCLASS, icls >> 8, icls & 0xff, 0, 0);
179: if (!cls && (cls = id_lookup(a, flags, ID_CLASS, icls >> 8, 0, 0, 0)))
180: {
181: if (!(flags & PCI_LOOKUP_NUMERIC)) /* Include full class number */
182: flags |= PCI_LOOKUP_MIXED;
183: }
184: return format_name(buf, size, flags, cls, numbuf, "Class");
185: case PCI_LOOKUP_PROGIF:
186: icls = va_arg(args, int);
187: ipif = va_arg(args, int);
188: sprintf(numbuf, "%02x", ipif);
189: pif = id_lookup(a, flags, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0);
190: if (!pif && icls == 0x0101 && !(ipif & 0x70))
191: {
192: /* IDE controllers have complex prog-if semantics */
193: sprintf(pifbuf, "%s%s%s%s%s",
194: (ipif & 0x80) ? " Master" : "",
195: (ipif & 0x08) ? " SecP" : "",
196: (ipif & 0x04) ? " SecO" : "",
197: (ipif & 0x02) ? " PriP" : "",
198: (ipif & 0x01) ? " PriO" : "");
199: pif = pifbuf;
200: if (*pif)
201: pif++;
202: }
203: return format_name(buf, size, flags, pif, numbuf, "ProgIf");
204: default:
205: return "<pci_lookup_name: invalid request>";
206: }
207: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>