summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2014-11-02 12:11:05 +0100
committerMartin Mares <mj@ucw.cz>2014-11-02 12:11:05 +0100
commit52aecc758f87ef7e273bb1df88116e0bbed6bfbf (patch)
tree3befb7c5bb555998cf16450e01206e949acbdef6
parent4d1c95253f900ccb62b2b960f9ae34d82ac26f29 (diff)
downloadpciutils-52aecc758f87ef7e273bb1df88116e0bbed6bfbf.tar.gz
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.
-rw-r--r--lib/access.c18
-rw-r--r--lib/caps.c2
-rw-r--r--lib/filter.c121
-rw-r--r--lib/internal.h19
-rw-r--r--lib/libpci.ver9
-rw-r--r--lib/pci.h3
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 <mj@ucw.cz>
+ * Copyright (c) 1997--2014 Martin Mares <mj@ucw.cz>
*
* 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 <mj@ucw.cz>
+ * Copyright (c) 1998--2014 Martin Mares <mj@ucw.cz>
*
* 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;