From 52aecc758f87ef7e273bb1df88116e0bbed6bfbf Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 2 Nov 2014 12:11:05 +0100 Subject: Backward ABI compatibility for new filters and pci_fill_info This is tricky, because we have to translate between old and new format of struct pci_filter. At least, I added several RFU fields so this hopefully won't have to happen again soon. --- lib/access.c | 18 +++++---- lib/caps.c | 2 +- lib/filter.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- lib/internal.h | 19 ++++----- lib/libpci.ver | 9 +++++ lib/pci.h | 3 +- 6 files changed, 143 insertions(+), 29 deletions(-) diff --git a/lib/access.c b/lib/access.c index 61b3530..d292085 100644 --- a/lib/access.c +++ b/lib/access.c @@ -1,7 +1,7 @@ /* * The PCI Library -- User Access * - * Copyright (c) 1997--2013 Martin Mares + * Copyright (c) 1997--2014 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -153,8 +153,8 @@ pci_write_block(struct pci_dev *d, int pos, byte *buf, int len) return d->methods->write(d, pos, buf, len); } -int VERSIONED -pci_fill_info_v32(struct pci_dev *d, int flags) +int +pci_fill_info_v33(struct pci_dev *d, int flags) { if (flags & PCI_FILL_RESCAN) { @@ -168,13 +168,15 @@ pci_fill_info_v32(struct pci_dev *d, int flags) } /* In version 3.1, pci_fill_info got new flags => versioned alias */ -/* In version 3.2, the same has happened */ -STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v32(d, flags)); -DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v32); -DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v32); +/* In versions 3.2 and 3.3, the same has happened */ +STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v33(d, flags)); +DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v33); +DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v33); +DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v33); SYMBOL_VERSION(pci_fill_info_v30, pci_fill_info@LIBPCI_3.0); SYMBOL_VERSION(pci_fill_info_v31, pci_fill_info@LIBPCI_3.1); -SYMBOL_VERSION(pci_fill_info_v32, pci_fill_info@@LIBPCI_3.2); +SYMBOL_VERSION(pci_fill_info_v32, pci_fill_info@LIBPCI_3.2); +SYMBOL_VERSION(pci_fill_info_v33, pci_fill_info@@LIBPCI_3.3); void pci_setup_cache(struct pci_dev *d, byte *cache, int len) diff --git a/lib/caps.c b/lib/caps.c index 2378591..4cf9ad8 100644 --- a/lib/caps.c +++ b/lib/caps.c @@ -106,7 +106,7 @@ pci_find_cap(struct pci_dev *d, unsigned int id, unsigned int type) { struct pci_cap *c; - pci_fill_info_v32(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS)); + pci_fill_info_v33(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS)); for (c=d->first_cap; c; c=c->next) if (c->type == type && c->id == id) return c; diff --git a/lib/filter.c b/lib/filter.c index fab0025..55eb682 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -1,7 +1,7 @@ /* * The PCI Library -- Device Filtering * - * Copyright (c) 1998--2003 Martin Mares + * Copyright (c) 1998--2014 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -11,17 +11,22 @@ #include "internal.h" +void pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) VERSIONED_ABI; +char *pci_filter_parse_slot_v33(struct pci_filter *f, char *str) VERSIONED_ABI; +char *pci_filter_parse_id_v33(struct pci_filter *f, char *str) VERSIONED_ABI; +int pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) VERSIONED_ABI; + void -pci_filter_init(struct pci_access *a UNUSED, struct pci_filter *f) +pci_filter_init_v33(struct pci_access *a UNUSED, struct pci_filter *f) { f->domain = f->bus = f->slot = f->func = -1; - f->vendor = f->device = f->class = -1; + f->vendor = f->device = f->device_class = -1; } /* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */ char * -pci_filter_parse_slot(struct pci_filter *f, char *str) +pci_filter_parse_slot_v33(struct pci_filter *f, char *str) { char *colon = strrchr(str, ':'); char *dot = strchr((colon ? colon + 1 : str), '.'); @@ -77,7 +82,7 @@ pci_filter_parse_slot(struct pci_filter *f, char *str) /* ID filter syntax: [vendor]:[device][:class] */ char * -pci_filter_parse_id(struct pci_filter *f, char *str) +pci_filter_parse_id_v33(struct pci_filter *f, char *str) { char *s, *c, *e; @@ -109,13 +114,13 @@ pci_filter_parse_id(struct pci_filter *f, char *str) long int x = strtol(c, &e, 16); if ((e && *e) || (x < 0 || x > 0xffff)) return "Invalid class code"; - f->class = x; + f->device_class = x; } return NULL; } int -pci_filter_match(struct pci_filter *f, struct pci_dev *d) +pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) { if ((f->domain >= 0 && f->domain != d->domain) || (f->bus >= 0 && f->bus != d->bus) || @@ -124,16 +129,112 @@ pci_filter_match(struct pci_filter *f, struct pci_dev *d) return 0; if (f->device >= 0 || f->vendor >= 0) { - pci_fill_info_v32(d, PCI_FILL_IDENT); + pci_fill_info_v33(d, PCI_FILL_IDENT); if ((f->device >= 0 && f->device != d->device_id) || (f->vendor >= 0 && f->vendor != d->vendor_id)) return 0; } - if (f->class >= 0) + if (f->device_class >= 0) { pci_fill_info(d, PCI_FILL_CLASS); - if (f->class != d->device_class) + if (f->device_class != d->device_class) return 0; } return 1; } + +/* + * Before pciutils v3.3, struct pci_filter had fewer fields, + * so we have to provide compatibility wrappers. + */ + +struct pci_filter_v30 { + int domain, bus, slot, func; /* -1 = ANY */ + int vendor, device; +}; + +void pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f) VERSIONED_ABI; +char *pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI; +char *pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str) VERSIONED_ABI; +int pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d) VERSIONED_ABI; + +static void +pci_filter_import_v30(struct pci_filter_v30 *old, struct pci_filter *new) +{ + new->domain = old->domain; + new->bus = old->bus; + new->slot = old->bus; + new->func = old->func; + new->vendor = old->vendor; + new->device = old->device; + new->device_class = -1; +} + +static void +pci_filter_export_v30(struct pci_filter *new, struct pci_filter_v30 *old) +{ + old->domain = new->domain; + old->bus = new->bus; + old->slot = new->bus; + old->func = new->func; + old->vendor = new->vendor; + old->device = new->device; +} + +void +pci_filter_init_v30(struct pci_access *a, struct pci_filter_v30 *f) +{ + struct pci_filter new; + pci_filter_init_v33(a, &new); + pci_filter_export_v30(&new, f); +} + +char * +pci_filter_parse_slot_v30(struct pci_filter_v30 *f, char *str) +{ + struct pci_filter new; + char *err; + pci_filter_import_v30(f, &new); + if (err = pci_filter_parse_slot_v33(&new, str)) + return err; + pci_filter_export_v30(&new, f); + return NULL; +} + +char * +pci_filter_parse_id_v30(struct pci_filter_v30 *f, char *str) +{ + struct pci_filter new; + char *err; + pci_filter_import_v30(f, &new); + if (err = pci_filter_parse_id_v33(&new, str)) + return err; + if (new.device_class >= 0) + return "Filtering by class not supported in this program"; + pci_filter_export_v30(&new, f); + return NULL; +} + +int +pci_filter_match_v30(struct pci_filter_v30 *f, struct pci_dev *d) +{ + struct pci_filter new; + pci_filter_import_v30(f, &new); + return pci_filter_match_v33(&new, d); +} + +STATIC_ALIAS(void pci_filter_init(struct pci_access *a, struct pci_filter *f), pci_filter_init_v33(a, f)); +SYMBOL_VERSION(pci_filter_init_v30, pci_filter_init@LIBPCI_3.0); +SYMBOL_VERSION(pci_filter_init_v33, pci_filter_init@@LIBPCI_3.3); + +STATIC_ALIAS(char *pci_filter_parse_slot(struct pci_filter *f, char *str), pci_filter_parse_slot_v33(f, str)); +SYMBOL_VERSION(pci_filter_parse_slot_v30, pci_filter_parse_slot@LIBPCI_3.0); +SYMBOL_VERSION(pci_filter_parse_slot_v33, pci_filter_parse_slot@@LIBPCI_3.3); + +STATIC_ALIAS(char *pci_filter_parse_id(struct pci_filter *f, char *str), pci_filter_parse_id_v33(f, str)); +SYMBOL_VERSION(pci_filter_parse_id_v30, pci_filter_parse_id@LIBPCI_3.0); +SYMBOL_VERSION(pci_filter_parse_id_v33, pci_filter_parse_id@@LIBPCI_3.3); + +STATIC_ALIAS(int pci_filter_match(struct pci_filter *f, struct pci_dev *d), pci_filter_match_v33(f, d)); +SYMBOL_VERSION(pci_filter_match_v30, pci_filter_match@LIBPCI_3.0); +SYMBOL_VERSION(pci_filter_match_v33, pci_filter_match@@LIBPCI_3.3); diff --git a/lib/internal.h b/lib/internal.h index ea63738..a312385 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -13,18 +13,18 @@ // Functions, which are bound to externally visible symbols by the versioning // mechanism, have to be declared as VERSIONED. Otherwise, GCC with global // optimizations is happy to optimize them away, leading to linker failures. -#define VERSIONED __attribute__((used)) +#define VERSIONED_ABI __attribute__((used)) PCI_ABI #ifdef __APPLE__ #define STATIC_ALIAS(_decl, _for) _decl PCI_ABI { return _for; } -#define DEFINE_ALIAS(_decl, _for) extern _decl __attribute__((alias(#_for))) -#define SYMBOL_VERSION(_int, _ext) asm(".symver " #_int "," #_ext) -#else -#define STATIC_ALIAS(_decl, _for) #define DEFINE_ALIAS(_decl, _for) #define SYMBOL_VERSION(_int, _ext) +#else +#define STATIC_ALIAS(_decl, _for) +#define DEFINE_ALIAS(_decl, _for) extern _decl __attribute__((alias(#_for))) +#define SYMBOL_VERSION(_int, _ext) asm(".symver " #_int "," #_ext) #endif #else -#define VERSIONED +#define VERSIONED_ABI #define STATIC_ALIAS(_decl, _for) _decl { return _for; } #define DEFINE_ALIAS(_decl, _for) #define SYMBOL_VERSION(_int, _ext) @@ -65,9 +65,10 @@ char *pci_strdup(struct pci_access *a, const char *s); struct pci_dev *pci_alloc_dev(struct pci_access *); int pci_link_dev(struct pci_access *, struct pci_dev *); -int pci_fill_info_v30(struct pci_dev *, int flags) PCI_ABI; -int pci_fill_info_v31(struct pci_dev *, int flags) PCI_ABI; -int pci_fill_info_v32(struct pci_dev *, int flags) PCI_ABI; +int pci_fill_info_v30(struct pci_dev *, int flags) VERSIONED_ABI; +int pci_fill_info_v31(struct pci_dev *, int flags) VERSIONED_ABI; +int pci_fill_info_v32(struct pci_dev *, int flags) VERSIONED_ABI; +int pci_fill_info_v33(struct pci_dev *, int flags) VERSIONED_ABI; /* params.c */ void pci_define_param(struct pci_access *acc, char *param, char *val, char *help); diff --git a/lib/libpci.ver b/lib/libpci.ver index 3f73fca..31f89fd 100644 --- a/lib/libpci.ver +++ b/lib/libpci.ver @@ -52,3 +52,12 @@ LIBPCI_3.2 { global: pci_fill_info; }; + +LIBPCI_3.3 { + global: + pci_fill_info; + pci_filter_init; + pci_filter_match; + pci_filter_parse_id; + pci_filter_parse_slot; +}; diff --git a/lib/pci.h b/lib/pci.h index 0c57fdd..3933f3d 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -198,7 +198,8 @@ struct pci_cap *pci_find_cap(struct pci_dev *, unsigned int id, unsigned int typ struct pci_filter { int domain, bus, slot, func; /* -1 = ANY */ - int vendor, device, class; + int vendor, device, device_class; + int rfu[3]; }; void pci_filter_init(struct pci_access *, struct pci_filter *) PCI_ABI; -- cgit v1.2.1