1 /* 2 * The PCI Library -- Device Filtering 3 * 4 * Copyright (c) 1998--2014 Martin Mares <[email protected]> 5 * 6 * Can be freely distributed and used under the terms of the GNU GPL. 7 */ 8 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include "internal.h" 13 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 19 void 20 pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) 21 { 22 f->domain = f->bus = f->slot = f->func = -1; 23 f->vendor = f->device = f->device_class = -1; 24 } 25 26 /* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */ 27 28 char * 29 pci_filter_parse_slot_v33(struct pci_filter *f, char *str) 30 { 31 char *colon = strrchr(str, ':'); 32 char *dot = strchr((colon ? colon + 1 : str), '.'); 33 char *mid = str; 34 char *e, *bus, *colon2; 35 36 if (colon) 37 { 38 *colon++ = 0; 39 mid = colon; 40 colon2 = strchr(str, ':'); 41 if (colon2) 42 { 43 *colon2++ = 0; 44 bus = colon2; 45 if (str[0] && strcmp(str, "*")) 46 { 47 long int x = strtol(str, &e, 16); 48 if ((e && *e) || (x < 0 || x > 0x7fffffff)) 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); 58 if ((e && *e) || (x < 0 || x > 0xff)) 59 return "Invalid bus number"; 60 f->bus = x; 61 } 62 } 63 if (dot) 64 *dot++ = 0; 65 if (mid[0] && strcmp(mid, "*")) 66 { 67 long int x = strtol(mid, &e, 16); 68 if ((e && *e) || (x < 0 || x > 0x1f)) 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); 75 if ((e && *e) || (x < 0 || x > 7)) 76 return "Invalid function number"; 77 f->func = x; 78 } 79 return NULL; 80 } 81 82 /* ID filter syntax: [vendor]:[device][:class] */ 83 84 char * 85 pci_filter_parse_id_v33(struct pci_filter *f, char *str) 86 { 87 char *s, *c, *e; 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); 98 if ((e && *e) || (x < 0 || x > 0xffff)) 99 return "Invalid vendor ID"; 100 f->vendor = x; 101 } 102 c = strchr(s, ':'); 103 if (c) 104 *c++ = 0; 105 if (s[0] && strcmp(s, "*")) 106 { 107 long int x = strtol(s, &e, 16); 108 if ((e && *e) || (x < 0 || x > 0xffff)) 109 return "Invalid device ID"; 110 f->device = x; 111 } 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"; 117 f->device_class = x; 118 } 119 return NULL; 120 } 121 122 int 123 pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) 124 { 125 if ((f->domain >= 0 && f->domain != d->domain) || 126 (f->bus >= 0 && f->bus != d->bus) || 127 (f->slot >= 0 && f->slot != d->dev) || 128 (f->func >= 0 && f->func != d->func)) 129 return 0; 130 if (f->device >= 0 || f->vendor >= 0) 131 { 132 pci_fill_info_v35(d, PCI_FILL_IDENT); 133 if ((f->device >= 0 && f->device != d->device_id) || 134 (f->vendor >= 0 && f->vendor != d->vendor_id)) 135 return 0; 136 } 137 if (f->device_class >= 0) 138 { 139 pci_fill_info(d, PCI_FILL_CLASS); 140 if (f->device_class != d->device_class) 141 return 0; 142 } 143 return 1; 144 } 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->slot; 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->slot; 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); 241