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