]>
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); | |
72 | if (res < 0 || res >= size) | |
73 | return "<pci_lookup_name: buffer too small>"; | |
74 | else | |
75 | return buf; | |
76 | } | |
77 | ||
afebde01 MM |
78 | static char * |
79 | format_name_pair(char *buf, int size, int flags, char *v, char *d, char *num) | |
bc2eed2d MM |
80 | { |
81 | int res; | |
82 | if ((flags & PCI_LOOKUP_NO_NUMBERS) && (!v || !d)) | |
83 | return NULL; | |
84 | if (flags & PCI_LOOKUP_NUMERIC) | |
85 | res = snprintf(buf, size, "%s", num); | |
86 | else if (flags & PCI_LOOKUP_MIXED) | |
87 | { | |
88 | if (v && d) | |
89 | res = snprintf(buf, size, "%s %s [%s]", v, d, num); | |
90 | else if (!v) | |
5904157c | 91 | res = snprintf(buf, size, "Device [%s]", num); |
bc2eed2d | 92 | else /* v && !d */ |
5904157c | 93 | res = snprintf(buf, size, "%s Device [%s]", v, num); |
bc2eed2d MM |
94 | } |
95 | else | |
96 | { | |
97 | if (v && d) | |
98 | res = snprintf(buf, size, "%s %s", v, d); | |
99 | else if (!v) | |
5904157c | 100 | res = snprintf(buf, size, "Device %s", num); |
bc2eed2d | 101 | else /* v && !d */ |
5904157c | 102 | res = snprintf(buf, size, "%s Device %s", v, num+5); |
bc2eed2d MM |
103 | } |
104 | if (res < 0 || res >= size) | |
105 | return "<pci_lookup_name: buffer too small>"; | |
106 | else | |
107 | return buf; | |
108 | } | |
109 | ||
727ce158 | 110 | char * |
aeaca5d3 | 111 | pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) |
727ce158 | 112 | { |
aeaca5d3 | 113 | va_list args; |
afebde01 | 114 | char *v, *d, *cls, *pif; |
aeaca5d3 | 115 | int iv, id, isv, isd, icls, ipif; |
afebde01 | 116 | char numbuf[16], pifbuf[32]; |
aeaca5d3 MM |
117 | |
118 | va_start(args, flags); | |
727ce158 | 119 | |
103f074c | 120 | flags |= a->id_lookup_mode; |
a42c0dad MM |
121 | if (!(flags & PCI_LOOKUP_NO_NUMBERS)) |
122 | { | |
123 | if (a->numeric_ids > 1) | |
124 | flags |= PCI_LOOKUP_MIXED; | |
125 | else if (a->numeric_ids) | |
126 | flags |= PCI_LOOKUP_NUMERIC; | |
127 | } | |
bc2eed2d MM |
128 | if (flags & PCI_LOOKUP_MIXED) |
129 | flags &= ~PCI_LOOKUP_NUMERIC; | |
aeaca5d3 | 130 | |
103f074c | 131 | if (!a->id_hash && !(flags & (PCI_LOOKUP_NUMERIC | PCI_LOOKUP_SKIP_LOCAL)) && !a->id_load_failed) |
bc2eed2d | 132 | pci_load_name_list(a); |
aeaca5d3 | 133 | |
bc2eed2d | 134 | switch (flags & 0xffff) |
727ce158 MM |
135 | { |
136 | case PCI_LOOKUP_VENDOR: | |
aeaca5d3 | 137 | iv = va_arg(args, int); |
bc2eed2d | 138 | sprintf(numbuf, "%04x", iv); |
5904157c | 139 | return format_name(buf, size, flags, id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0), numbuf, "Vendor"); |
727ce158 | 140 | case PCI_LOOKUP_DEVICE: |
aeaca5d3 MM |
141 | iv = va_arg(args, int); |
142 | id = va_arg(args, int); | |
bc2eed2d | 143 | sprintf(numbuf, "%04x", id); |
5904157c | 144 | return format_name(buf, size, flags, id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0), numbuf, "Device"); |
727ce158 | 145 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE: |
aeaca5d3 MM |
146 | iv = va_arg(args, int); |
147 | id = va_arg(args, int); | |
bc2eed2d | 148 | sprintf(numbuf, "%04x:%04x", iv, id); |
103f074c MM |
149 | v = id_lookup(a, flags, ID_VENDOR, iv, 0, 0, 0); |
150 | d = id_lookup(a, flags, ID_DEVICE, iv, id, 0, 0); | |
bc2eed2d | 151 | return format_name_pair(buf, size, flags, v, d, numbuf); |
aeaca5d3 MM |
152 | case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR: |
153 | isv = va_arg(args, int); | |
bc2eed2d | 154 | sprintf(numbuf, "%04x", isv); |
103f074c | 155 | v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0); |
bc2eed2d | 156 | return format_name(buf, size, flags, v, numbuf, "Unknown vendor"); |
aeaca5d3 MM |
157 | case PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE: |
158 | iv = va_arg(args, int); | |
159 | id = va_arg(args, int); | |
160 | isv = va_arg(args, int); | |
161 | isd = va_arg(args, int); | |
bc2eed2d | 162 | sprintf(numbuf, "%04x", isd); |
5904157c | 163 | return format_name(buf, size, flags, id_lookup_subsys(a, flags, iv, id, isv, isd), numbuf, "Device"); |
727ce158 | 164 | case PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE | PCI_LOOKUP_SUBSYSTEM: |
aeaca5d3 MM |
165 | iv = va_arg(args, int); |
166 | id = va_arg(args, int); | |
167 | isv = va_arg(args, int); | |
168 | isd = va_arg(args, int); | |
103f074c MM |
169 | v = id_lookup(a, flags, ID_VENDOR, isv, 0, 0, 0); |
170 | d = id_lookup_subsys(a, flags, iv, id, isv, isd); | |
bc2eed2d MM |
171 | sprintf(numbuf, "%04x:%04x", isv, isd); |
172 | return format_name_pair(buf, size, flags, v, d, numbuf); | |
727ce158 | 173 | case PCI_LOOKUP_CLASS: |
aeaca5d3 | 174 | icls = va_arg(args, int); |
bc2eed2d | 175 | sprintf(numbuf, "%04x", icls); |
103f074c MM |
176 | cls = id_lookup(a, flags, ID_SUBCLASS, icls >> 8, icls & 0xff, 0, 0); |
177 | if (!cls && (cls = id_lookup(a, flags, ID_CLASS, icls >> 8, 0, 0, 0))) | |
bc2eed2d MM |
178 | { |
179 | if (!(flags & PCI_LOOKUP_NUMERIC)) /* Include full class number */ | |
180 | flags |= PCI_LOOKUP_MIXED; | |
181 | } | |
5904157c | 182 | return format_name(buf, size, flags, cls, numbuf, "Class"); |
d4798a32 | 183 | case PCI_LOOKUP_PROGIF: |
aeaca5d3 MM |
184 | icls = va_arg(args, int); |
185 | ipif = va_arg(args, int); | |
bc2eed2d | 186 | sprintf(numbuf, "%02x", ipif); |
103f074c | 187 | pif = id_lookup(a, flags, ID_PROGIF, icls >> 8, icls & 0xff, ipif, 0); |
bc2eed2d | 188 | if (!pif && icls == 0x0101 && !(ipif & 0x70)) |
d4798a32 MM |
189 | { |
190 | /* IDE controllers have complex prog-if semantics */ | |
bc2eed2d | 191 | sprintf(pifbuf, "%s%s%s%s%s", |
a42c0dad MM |
192 | (ipif & 0x80) ? " Master" : "", |
193 | (ipif & 0x08) ? " SecP" : "", | |
194 | (ipif & 0x04) ? " SecO" : "", | |
195 | (ipif & 0x02) ? " PriP" : "", | |
196 | (ipif & 0x01) ? " PriO" : ""); | |
bc2eed2d | 197 | pif = pifbuf; |
a42c0dad MM |
198 | if (*pif) |
199 | pif++; | |
d4798a32 | 200 | } |
bc2eed2d | 201 | return format_name(buf, size, flags, pif, numbuf, "ProgIf"); |
727ce158 MM |
202 | default: |
203 | return "<pci_lookup_name: invalid request>"; | |
204 | } | |
727ce158 | 205 | } |