]>
Commit | Line | Data |
---|---|---|
e4842ff3 | 1 | /* |
4284af58 | 2 | * The PCI Library -- Device Filtering |
e4842ff3 | 3 | * |
52aecc75 | 4 | * Copyright (c) 1998--2014 Martin Mares <mj@ucw.cz> |
e4842ff3 MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
e4842ff3 MM |
9 | #include <stdlib.h> |
10 | #include <string.h> | |
e4842ff3 | 11 | |
727ce158 | 12 | #include "internal.h" |
e4842ff3 | 13 | |
52aecc75 MM |
14 | void pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) VERSIONED_ABI; |
15 | char *pci_filter_parse_slot_v33(struct pci_filter *f, char *str) VERSIONED_ABI; | |
16 | char *pci_filter_parse_id_v33(struct pci_filter *f, char *str) VERSIONED_ABI; | |
17 | int pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) VERSIONED_ABI; | |
18 | ||
e4842ff3 | 19 | void |
52aecc75 | 20 | pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) |
e4842ff3 | 21 | { |
84c8d1bb | 22 | f->domain = f->bus = f->slot = f->func = -1; |
52aecc75 | 23 | f->vendor = f->device = f->device_class = -1; |
e4842ff3 MM |
24 | } |
25 | ||
84c8d1bb | 26 | /* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */ |
e4842ff3 MM |
27 | |
28 | char * | |
52aecc75 | 29 | pci_filter_parse_slot_v33(struct pci_filter *f, char *str) |
e4842ff3 | 30 | { |
84c8d1bb | 31 | char *colon = strrchr(str, ':'); |
e4842ff3 MM |
32 | char *dot = strchr((colon ? colon + 1 : str), '.'); |
33 | char *mid = str; | |
84c8d1bb | 34 | char *e, *bus, *colon2; |
e4842ff3 MM |
35 | |
36 | if (colon) | |
37 | { | |
38 | *colon++ = 0; | |
39 | mid = colon; | |
84c8d1bb MM |
40 | colon2 = strchr(str, ':'); |
41 | if (colon2) | |
e4842ff3 | 42 | { |
84c8d1bb MM |
43 | *colon2++ = 0; |
44 | bus = colon2; | |
45 | if (str[0] && strcmp(str, "*")) | |
46 | { | |
b9ca9147 | 47 | long int x = strtol(str, &e, 16); |
84c8d1bb MM |
48 | if ((e && *e) || (x < 0 || x > 0xffff)) |
49 | return "Invalid domain number"; | |
50 | f->domain = x; | |
51 | } | |
52 | } | |
53 | else | |
54 | bus = str; | |
55 | if (bus[0] && strcmp(bus, "*")) | |
56 | { | |
57 | long int x = strtol(bus, &e, 16); | |
cba7c00f | 58 | if ((e && *e) || (x < 0 || x > 0xff)) |
e4842ff3 MM |
59 | return "Invalid bus number"; |
60 | f->bus = x; | |
61 | } | |
62 | } | |
63 | if (dot) | |
64 | *dot++ = 0; | |
65 | if (mid[0] && strcmp(mid, "*")) | |
66 | { | |
71e8f0ae | 67 | long int x = strtol(mid, &e, 16); |
cba7c00f | 68 | if ((e && *e) || (x < 0 || x > 0x1f)) |
e4842ff3 MM |
69 | return "Invalid slot number"; |
70 | f->slot = x; | |
71 | } | |
72 | if (dot && dot[0] && strcmp(dot, "*")) | |
73 | { | |
74 | long int x = strtol(dot, &e, 16); | |
cba7c00f | 75 | if ((e && *e) || (x < 0 || x > 7)) |
e4842ff3 MM |
76 | return "Invalid function number"; |
77 | f->func = x; | |
78 | } | |
79 | return NULL; | |
80 | } | |
81 | ||
4d1c9525 | 82 | /* ID filter syntax: [vendor]:[device][:class] */ |
e4842ff3 MM |
83 | |
84 | char * | |
52aecc75 | 85 | pci_filter_parse_id_v33(struct pci_filter *f, char *str) |
e4842ff3 | 86 | { |
4d1c9525 | 87 | char *s, *c, *e; |
e4842ff3 MM |
88 | |
89 | if (!*str) | |
90 | return NULL; | |
91 | s = strchr(str, ':'); | |
92 | if (!s) | |
93 | return "':' expected"; | |
94 | *s++ = 0; | |
95 | if (str[0] && strcmp(str, "*")) | |
96 | { | |
97 | long int x = strtol(str, &e, 16); | |
f2505ce4 | 98 | if ((e && *e) || (x < 0 || x > 0xffff)) |
e4842ff3 MM |
99 | return "Invalid vendor ID"; |
100 | f->vendor = x; | |
101 | } | |
4d1c9525 MW |
102 | c = strchr(s, ':'); |
103 | if (c) | |
104 | *c++ = 0; | |
e4842ff3 MM |
105 | if (s[0] && strcmp(s, "*")) |
106 | { | |
107 | long int x = strtol(s, &e, 16); | |
f2505ce4 | 108 | if ((e && *e) || (x < 0 || x > 0xffff)) |
e4842ff3 MM |
109 | return "Invalid device ID"; |
110 | f->device = x; | |
111 | } | |
4d1c9525 MW |
112 | if (c && c[0] && strcmp(s, "*")) |
113 | { | |
114 | long int x = strtol(c, &e, 16); | |
115 | if ((e && *e) || (x < 0 || x > 0xffff)) | |
116 | return "Invalid class code"; | |
52aecc75 | 117 | f->device_class = x; |
4d1c9525 | 118 | } |
e4842ff3 MM |
119 | return NULL; |
120 | } | |
121 | ||
122 | int | |
52aecc75 | 123 | pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) |
e4842ff3 | 124 | { |
84c8d1bb MM |
125 | if ((f->domain >= 0 && f->domain != d->domain) || |
126 | (f->bus >= 0 && f->bus != d->bus) || | |
727ce158 MM |
127 | (f->slot >= 0 && f->slot != d->dev) || |
128 | (f->func >= 0 && f->func != d->func)) | |
e4842ff3 | 129 | return 0; |
727ce158 MM |
130 | if (f->device >= 0 || f->vendor >= 0) |
131 | { | |
52aecc75 | 132 | pci_fill_info_v33(d, PCI_FILL_IDENT); |
727ce158 MM |
133 | if ((f->device >= 0 && f->device != d->device_id) || |
134 | (f->vendor >= 0 && f->vendor != d->vendor_id)) | |
135 | return 0; | |
136 | } | |
52aecc75 | 137 | if (f->device_class >= 0) |
4d1c9525 MW |
138 | { |
139 | pci_fill_info(d, PCI_FILL_CLASS); | |
52aecc75 | 140 | if (f->device_class != d->device_class) |
4d1c9525 MW |
141 | return 0; |
142 | } | |
e4842ff3 MM |
143 | return 1; |
144 | } | |
52aecc75 MM |
145 | |
146 | /* | |
147 | * Before pciutils v3.3, struct pci_filter had fewer fields, | |
148 | * so we have to provide compatibility wrappers. | |
149 | */ | |
150 | ||
151 | struct pci_filter_v30 { | |
152 | int domain, bus, slot, func; /* -1 = ANY */ | |
153 | int vendor, device; | |
154 | }; | |
155 | ||
156 | void pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f) VERSIONED_ABI; | |
157 | char *pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI; | |
158 | char *pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI; | |
159 | int pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d) VERSIONED_ABI; | |
160 | ||
161 | static void | |
162 | pci_filter_import_v30(struct pci_filter_v30 *old, struct pci_filter *new) | |
163 | { | |
164 | new->domain = old->domain; | |
165 | new->bus = old->bus; | |
166 | new->slot = old->bus; | |
167 | new->func = old->func; | |
168 | new->vendor = old->vendor; | |
169 | new->device = old->device; | |
170 | new->device_class = -1; | |
171 | } | |
172 | ||
173 | static void | |
174 | pci_filter_export_v30(struct pci_filter *new, struct pci_filter_v30 *old) | |
175 | { | |
176 | old->domain = new->domain; | |
177 | old->bus = new->bus; | |
178 | old->slot = new->bus; | |
179 | old->func = new->func; | |
180 | old->vendor = new->vendor; | |
181 | old->device = new->device; | |
182 | } | |
183 | ||
184 | void | |
185 | pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f) | |
186 | { | |
187 | struct pci_filter new; | |
188 | pci_filter_init_v33(a, &new); | |
189 | pci_filter_export_v30(&new, f); | |
190 | } | |
191 | ||
192 | char * | |
193 | pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str) | |
194 | { | |
195 | struct pci_filter new; | |
196 | char *err; | |
197 | pci_filter_import_v30(f, &new); | |
198 | if (err = pci_filter_parse_slot_v33(&new, str)) | |
199 | return err; | |
200 | pci_filter_export_v30(&new, f); | |
201 | return NULL; | |
202 | } | |
203 | ||
204 | char * | |
205 | pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str) | |
206 | { | |
207 | struct pci_filter new; | |
208 | char *err; | |
209 | pci_filter_import_v30(f, &new); | |
210 | if (err = pci_filter_parse_id_v33(&new, str)) | |
211 | return err; | |
212 | if (new.device_class >= 0) | |
213 | return "Filtering by class not supported in this program"; | |
214 | pci_filter_export_v30(&new, f); | |
215 | return NULL; | |
216 | } | |
217 | ||
218 | int | |
219 | pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d) | |
220 | { | |
221 | struct pci_filter new; | |
222 | pci_filter_import_v30(f, &new); | |
223 | return pci_filter_match_v33(&new, d); | |
224 | } | |
225 | ||
226 | STATIC_ALIAS(void pci_filter_init(struct pci_access *a, struct pci_filter *f), pci_filter_init_v33(a, f)); | |
227 | SYMBOL_VERSION(pci_filter_init_v30, pci_filter_init@LIBPCI_3.0); | |
228 | SYMBOL_VERSION(pci_filter_init_v33, pci_filter_init@@LIBPCI_3.3); | |
229 | ||
230 | STATIC_ALIAS(char *pci_filter_parse_slot(struct pci_filter *f, char *str), pci_filter_parse_slot_v33(f, str)); | |
231 | SYMBOL_VERSION(pci_filter_parse_slot_v30, pci_filter_parse_slot@LIBPCI_3.0); | |
232 | SYMBOL_VERSION(pci_filter_parse_slot_v33, pci_filter_parse_slot@@LIBPCI_3.3); | |
233 | ||
234 | STATIC_ALIAS(char *pci_filter_parse_id(struct pci_filter *f, char *str), pci_filter_parse_id_v33(f, str)); | |
235 | SYMBOL_VERSION(pci_filter_parse_id_v30, pci_filter_parse_id@LIBPCI_3.0); | |
236 | SYMBOL_VERSION(pci_filter_parse_id_v33, pci_filter_parse_id@@LIBPCI_3.3); | |
237 | ||
238 | STATIC_ALIAS(int pci_filter_match(struct pci_filter *f, struct pci_dev *d), pci_filter_match_v33(f, d)); | |
239 | SYMBOL_VERSION(pci_filter_match_v30, pci_filter_match@LIBPCI_3.0); | |
240 | SYMBOL_VERSION(pci_filter_match_v33, pci_filter_match@@LIBPCI_3.3); |