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