]>
Commit | Line | Data |
---|---|---|
727ce158 | 1 | /* |
727ce158 MM |
2 | * The PCI Library -- ID to Name Translation |
3 | * | |
6dbdb96c | 4 | * Copyright (c) 1997--2008 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 MM |
18 | char *name; |
19 | ||
752d4d9a | 20 | while (!(name = pci_id_lookup(a, flags, cat, id1, id2, id3, id4))) |
a3d33b94 | 21 | { |
103f074c MM |
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 | { | |
752d4d9a | 29 | if (name = pci_id_net_lookup(a, cat, id1, id2, id3, id4)) |
103f074c | 30 | { |
752d4d9a MM |
31 | pci_id_insert(a, cat, id1, id2, id3, id4, name, SRC_NET); |
32 | pci_mfree(name); | |
103f074c MM |
33 | pci_id_cache_dirty(a); |
34 | } | |
35 | else | |
752d4d9a | 36 | pci_id_insert(a, cat, id1, id2, id3, id4, "", SRC_NET); |
103f074c MM |
37 | /* We want to iterate the lookup to get the allocated ID entry from the hash */ |
38 | continue; | |
39 | } | |
40 | return NULL; | |
a3d33b94 | 41 | } |
103f074c | 42 | return (name[0] ? name : NULL); |
a3d33b94 MM |
43 | } |
44 | ||
afebde01 | 45 | static char * |
103f074c | 46 | id_lookup_subsys(struct pci_access *a, int flags, int iv, int id, int isv, int isd) |
aeaca5d3 | 47 | { |
afebde01 | 48 | char *d = NULL; |
aeaca5d3 | 49 | if (iv > 0 && id > 0) /* Per-device lookup */ |
103f074c | 50 | d = id_lookup(a, flags, ID_SUBSYSTEM, iv, id, isv, isd); |
aeaca5d3 | 51 | if (!d) /* Generic lookup */ |
103f074c | 52 | d = id_lookup(a, flags, ID_GEN_SUBSYSTEM, isv, isd, 0, 0); |
aeaca5d3 | 53 | if (!d && iv == isv && id == isd) /* Check for subsystem == device */ |
103f074c | 54 | d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0); |
aeaca5d3 | 55 | return d; |
727ce158 MM |
56 | } |
57 | ||
afebde01 MM |
58 | static char * |
59 | format_name(char *buf, int size, int flags, char *name, char *num, char *unknown) | |
bc2eed2d MM |
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); | |
e616394f MM |
72 | if (res >= size && size >= 4) |
73 | buf[size-2] = buf[size-3] = buf[size-4] = '.'; | |
74 | else if (res < 0 || res >= size) | |
bc2eed2d | 75 | return "<pci_lookup_name: buffer too small>"; |
e616394f | 76 | return buf; |
bc2eed2d MM |
77 | } |
78 | ||
afebde01 MM |
79 | static char * |
80 | format_name_pair(char *buf, int size, int flags, char *v, char *d, char *num) | |
bc2eed2d MM |
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) | |
5904157c | 92 | res = snprintf(buf, size, "Device [%s]", num); |
bc2eed2d | 93 | else /* v && !d */ |
5904157c | 94 | res = snprintf(buf, size, "%s Device [%s]", v, num); |
bc2eed2d MM |
95 | } |
96 | else | |
97 | { | |
98 | if (v && d) | |
99 | res = snprintf(buf, size, "%s %s", v, d); | |
100 | else if (!v) | |
5904157c | 101 | res = snprintf(buf, size, "Device %s", num); |
bc2eed2d | 102 | else /* v && !d */ |
5904157c | 103 | res = snprintf(buf, size, "%s Device %s", v, num+5); |
bc2eed2d | 104 | } |
e616394f MM |
105 | if (res >= size && size >= 4) |
106 | buf[size-2] = buf[size-3] = buf[size-4] = '.'; | |
107 | else if (res < 0 || res >= size) | |
bc2eed2d | 108 | return "<pci_lookup_name: buffer too small>"; |
e616394f | 109 | return buf; |
bc2eed2d MM |
110 | } |
111 | ||
727ce158 | 112 | char * |
aeaca5d3 | 113 | pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) |
727ce158 | 114 | { |
aeaca5d3 | 115 | va_list args; |
afebde01 | 116 | char *v, *d, *cls, *pif; |
aeaca5d3 | 117 | int iv, id, isv, isd, icls, ipif; |
afebde01 | 118 | char numbuf[16], pifbuf[32]; |
aeaca5d3 MM |
119 | |
120 | va_start(args, flags); | |
727ce158 | 121 | |
103f074c | 122 | flags |= a->id_lookup_mode; |
a42c0dad MM |
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 | } | |
bc2eed2d MM |
130 | if (flags & PCI_LOOKUP_MIXED) |
131 | flags &= ~PCI_LOOKUP_NUMERIC; | |
aeaca5d3 | 132 | |
103f074c | 133 | if (!a->id_hash && !(flags & (PCI_LOOKUP_NUMERIC | PCI_LOOKUP_SKIP_LOCAL)) && !a->id_load_failed) |
bc2eed2d | 134 | pci_load_name_list(a); |
aeaca5d3 | 135 | |
bc2eed2d | 136 | switch (flags & 0xffff) |
727ce158 MM |
137 | { |
138 | case PCI_LOOKUP_VENDOR: | |
aeaca5d3 | 139 | iv = va_arg(args, int); |
bc2eed2d | 140 | sprintf(numbuf, "%04x", iv); |
5904157c | 141 | return format_name(buf, size, flags, id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0), numbuf, "Vendor"); |
727ce158 | 142 | case PCI_LOOKUP_DEVICE: |
aeaca5d3 MM |
143 | iv = va_arg(args, int); |
144 | id = va_arg(args, int); | |
bc2eed2d | 145 | sprintf(numbuf, "%04x", id); |
5904157c | 146 | return format_name(buf, size, flags, id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0), numbuf, "Device"); |
727ce158 | 147 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE: |
aeaca5d3 MM |
148 | iv = va_arg(args, int); |
149 | id = va_arg(args, int); | |
bc2eed2d | 150 | sprintf(numbuf, "%04x:%04x", iv, id); |
103f074c MM |
151 | v = id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0); |
152 | d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0); | |
bc2eed2d | 153 | return format_name_pair(buf, size, flags, v, d, numbuf); |
aeaca5d3 MM |
154 | case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR: |
155 | isv = va_arg(args, int); | |
bc2eed2d | 156 | sprintf(numbuf, "%04x", isv); |
103f074c | 157 | v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0); |
bc2eed2d | 158 | return format_name(buf, size, flags, v, numbuf, "Unknown vendor"); |
aeaca5d3 MM |
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); | |
bc2eed2d | 164 | sprintf(numbuf, "%04x", isd); |
5904157c | 165 | return format_name(buf, size, flags, id_lookup_subsys(a, flags, iv, id, isv, isd), numbuf, "Device"); |
727ce158 | 166 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: |
aeaca5d3 MM |
167 | iv = va_arg(args, int); |
168 | id = va_arg(args, int); | |
169 | isv = va_arg(args, int); | |
170 | isd = va_arg(args, int); | |
103f074c MM |
171 | v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0); |
172 | d = id_lookup_subsys(a, flags, iv, id, isv, isd); | |
bc2eed2d MM |
173 | sprintf(numbuf, "%04x:%04x", isv, isd); |
174 | return format_name_pair(buf, size, flags, v, d, numbuf); | |
727ce158 | 175 | case PCI_LOOKUP_CLASS: |
aeaca5d3 | 176 | icls = va_arg(args, int); |
bc2eed2d | 177 | sprintf(numbuf, "%04x", icls); |
103f074c MM |
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))) | |
bc2eed2d MM |
180 | { |
181 | if (!(flags & PCI_LOOKUP_NUMERIC)) /* Include full class number */ | |
182 | flags |= PCI_LOOKUP_MIXED; | |
183 | } | |
5904157c | 184 | return format_name(buf, size, flags, cls, numbuf, "Class"); |
d4798a32 | 185 | case PCI_LOOKUP_PROGIF: |
aeaca5d3 MM |
186 | icls = va_arg(args, int); |
187 | ipif = va_arg(args, int); | |
bc2eed2d | 188 | sprintf(numbuf, "%02x", ipif); |
103f074c | 189 | pif = id_lookup(a, flags, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0); |
bc2eed2d | 190 | if (!pif && icls == 0x0101 && !(ipif & 0x70)) |
d4798a32 MM |
191 | { |
192 | /* IDE controllers have complex prog-if semantics */ | |
bc2eed2d | 193 | sprintf(pifbuf, "%s%s%s%s%s", |
a42c0dad MM |
194 | (ipif & 0x80) ? " Master" : "", |
195 | (ipif & 0x08) ? " SecP" : "", | |
196 | (ipif & 0x04) ? " SecO" : "", | |
197 | (ipif & 0x02) ? " PriP" : "", | |
198 | (ipif & 0x01) ? " PriO" : ""); | |
bc2eed2d | 199 | pif = pifbuf; |
a42c0dad MM |
200 | if (*pif) |
201 | pif++; | |
d4798a32 | 202 | } |
bc2eed2d | 203 | return format_name(buf, size, flags, pif, numbuf, "ProgIf"); |
727ce158 MM |
204 | default: |
205 | return "<pci_lookup_name: invalid request>"; | |
206 | } | |
727ce158 | 207 | } |