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