Add a new type WacomMatch that holds device matching information.
A WacomDevice in libwacom now has a bunch of possible matches that can be
queried. The first possible match is the default match unless the device was
updated otherwise (e.g. libwacom_device_new_from_path will set the correct
match).

Previous calls to get bustype, vendor_id, product_id now return the set
match's values.

Basic refcounting was added to the WacomDevice to allow for the device to be
stored multiple times in the device hashtable.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
Changes since v1:
- libwacom_get_matches is constified
- libwacom_get_matches returns NULL-terminated array, no nmatches
- libwacom_copy_match explicitly copies fields
- refcounting through g_atomic_int_*
- g_realloc_n instead of realloc
- g_strsplit handling improved

 data/generate-udev-rules.c   |   17 +++++--
 libwacom/libwacom-database.c |   66 ++++++++++++++++++-------
 libwacom/libwacom.c          |  110 +++++++++++++++++++++++++++++++++++-------
 libwacom/libwacom.h          |   19 +++++++-
 libwacom/libwacomint.h       |   18 +++++--
 5 files changed, 187 insertions(+), 43 deletions(-)

diff --git a/data/generate-udev-rules.c b/data/generate-udev-rules.c
index 4c70fce..17d234b 100644
--- a/data/generate-udev-rules.c
+++ b/data/generate-udev-rules.c
@@ -41,11 +41,11 @@ static void print_udev_header (void)
     printf ("\n");
 }
 
-static void print_udev_entry (WacomDevice *device)
+static void print_udev_entry_for_match (WacomDevice *device, const WacomMatch 
*match)
 {
-    WacomBusType type       = libwacom_get_bustype (device);
-    int          vendor     = libwacom_get_vendor_id (device);
-    int          product    = libwacom_get_product_id (device);
+    WacomBusType type       = libwacom_match_get_bustype (match);
+    int          vendor     = libwacom_match_get_vendor_id (match);
+    int          product    = libwacom_match_get_product_id (match);
     int          has_touch  = libwacom_has_touch (device);
     static char *touchpad;
 
@@ -67,6 +67,15 @@ static void print_udev_entry (WacomDevice *device)
     }
 }
 
+static void print_udev_entry (WacomDevice *device)
+{
+    const WacomMatch **matches, **match;
+
+    matches = libwacom_get_matches(device);
+    for (match = matches; *match; match++)
+        print_udev_entry_for_match(device, *match);
+}
+
 static void print_udev_trailer (void)
 {
     printf ("\n");
diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c
index 2a0ee19..308ba6d 100644
--- a/libwacom/libwacom-database.c
+++ b/libwacom/libwacom-database.c
@@ -122,21 +122,45 @@ make_match_string (WacomBusType bus, int vendor_id, int 
product_id)
 }
 
 static int
-libwacom_matchstr_to_ints(const char *match, uint32_t *vendor_id, uint32_t 
*product_id, WacomBusType *bus)
+libwacom_matchstr_to_matches(WacomDevice *device, const char *match)
 {
-       char busstr[64];
-       int rc;
+       int rc = 1;
+       char **strs;
+       int i, nmatches = 0;
+       WacomBusType first_bus;
+       int first_vendor_id, first_product_id;
 
        if (match == NULL)
                return 0;
 
-       rc = sscanf(match, "%63[^:]:%x:%x", busstr, vendor_id, product_id);
-       if (rc != 3)
-               return 0;
+       strs = g_strsplit(match, ";", 0);
+       for (i = 0; strs[i] != NULL; i++) {
+               char busstr[64];
+               int vendor_id, product_id;
+               WacomBusType bus;
+               rc = sscanf(strs[i], "%63[^:]:%x:%x", busstr, &vendor_id, 
&product_id);
+               if (rc != 3) {
+                       DBG("failed to match '%s' for product/vendor IDs. 
Skipping.\n", strs[i]);
+                       continue;
+               }
+               bus = bus_from_str (busstr);
+
+               libwacom_update_match(device, bus, vendor_id, product_id);
 
-       *bus = bus_from_str (busstr);
+               if (nmatches == 0) {
+                       first_bus = bus;
+                       first_vendor_id = vendor_id;
+                       first_product_id = product_id;
+               }
+               nmatches++;
+       }
 
-       return 1;
+       /* set default to first entry */
+       if (nmatches > 1)
+               libwacom_update_match(device, first_bus, first_vendor_id, 
first_product_id);
+
+       g_strfreev(strs);
+       return i;
 }
 
 static void
@@ -298,18 +322,17 @@ libwacom_parse_tablet_keyfile(const char *path)
 
        match = g_key_file_get_string(keyfile, DEVICE_GROUP, "DeviceMatch", 
NULL);
        if (g_strcmp0 (match, GENERIC_DEVICE_MATCH) == 0) {
-               device->match = match;
+               libwacom_update_match(device, WBUSTYPE_UNKNOWN, 0, 0);
        } else {
-               if (!libwacom_matchstr_to_ints(match, &device->vendor_id, 
&device->product_id, &device->bus)) {
+               if (libwacom_matchstr_to_matches(device, match) == 0) {
                        DBG("failed to match '%s' for product/vendor IDs in 
'%s'\n", match, path);
                        g_free (match);
                        g_free (device);
                        device = NULL;
                        goto out;
                }
-               device->match = make_match_string(device->bus, 
device->vendor_id, device->product_id);
-               g_free (match);
        }
+       g_free (match);
 
        device->name = g_key_file_get_string(keyfile, DEVICE_GROUP, "Name", 
NULL);
        device->width = g_key_file_get_integer(keyfile, DEVICE_GROUP, "Width", 
NULL);
@@ -358,17 +381,17 @@ libwacom_parse_tablet_keyfile(const char *path)
 
        if (device->features & FEATURE_BUILTIN &&
            device->features & FEATURE_REVERSIBLE)
-               g_warning ("Tablet '%s' is both reversible and builtin. This is 
impossible", device->match);
+               g_warning ("Tablet '%s' is both reversible and builtin. This is 
impossible", libwacom_get_match(device));
 
        if (!(device->features & FEATURE_RING) &&
            (device->features & FEATURE_RING2))
-               g_warning ("Table '%s' has Ring2 but no Ring. This is 
impossible", device->match);
+               g_warning ("Table '%s' has Ring2 but no Ring. This is 
impossible", libwacom_get_match(device));
 
        device->num_strips = g_key_file_get_integer(keyfile, FEATURES_GROUP, 
"NumStrips", NULL);
        device->num_buttons = g_key_file_get_integer(keyfile, FEATURES_GROUP, 
"Buttons", &error);
        if (device->num_buttons == 0 &&
            g_error_matches (error, G_KEY_FILE_ERROR, 
G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
-               g_warning ("Tablet '%s' has no buttons defined, do something!", 
device->match);
+               g_warning ("Tablet '%s' has no buttons defined, do something!", 
libwacom_get_match(device));
                g_clear_error (&error);
        }
        if (device->num_buttons > 0) {
@@ -445,13 +468,22 @@ libwacom_database_new_for_path (const char *datadir)
     nfiles = n;
     while(n--) {
            WacomDevice *d;
+           const WacomMatch **matches, **match;
 
            path = g_build_filename (datadir, files[n]->d_name, NULL);
            d = libwacom_parse_tablet_keyfile(path);
            g_free(path);
 
-           if (d)
-                   g_hash_table_insert (db->device_ht, g_strdup (d->match), d);
+           if (!d)
+                   continue;
+
+           matches = libwacom_get_matches(d);
+           for (match = matches; *match; match++) {
+                   const char *matchstr;
+                   matchstr = libwacom_match_get_match_string(*match);
+                   g_hash_table_insert (db->device_ht, g_strdup (matchstr), d);
+                   d->refcnt++;
+           }
     }
 
     while(nfiles--)
diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c
index c16e4b5..09739a4 100644
--- a/libwacom/libwacom.c
+++ b/libwacom/libwacom.c
@@ -172,20 +172,37 @@ bail:
        return retval;
 }
 
+static WacomMatch *libwacom_copy_match(const WacomMatch *src)
+{
+       WacomMatch *dst;
+
+       dst = g_new0(WacomMatch, 1);
+       dst->match = g_strdup(src->match);
+       dst->bus = src->bus;
+       dst->vendor_id = src->vendor_id;
+       dst->product_id = src->product_id;
+
+       return dst;
+}
+
 static WacomDevice *
 libwacom_copy(const WacomDevice *device)
 {
        WacomDevice *d;
+       int i;
 
        d = g_new0 (WacomDevice, 1);
+       g_atomic_int_inc(&d->refcnt);
        d->name = g_strdup (device->name);
        d->width = device->width;
        d->height = device->height;
-       d->match = g_strdup (device->match);
-       d->vendor_id = device->vendor_id;
-       d->product_id = device->product_id;
+       d->nmatches = device->nmatches;
+       d->matches = g_malloc((d->nmatches + 1) * sizeof(WacomMatch*));
+       for (i = 0; i < d->nmatches; i++)
+               d->matches[i] = libwacom_copy_match(device->matches[i]);
+       d->matches[d->nmatches] = NULL;
+       d->match = device->match;
        d->cls = device->cls;
-       d->bus = device->bus;
        d->num_strips = device->num_strips;
        d->features = device->features;
        d->strips_num_modes = device->strips_num_modes;
@@ -256,11 +273,13 @@ libwacom_new_from_path(WacomDeviceDatabase *db, const 
char *path, int fallback,
                    g_free (ret->name);
                    ret->name = name;
            }
-           libwacom_update_match(ret, bus, vendor_id, product_id);
     } else {
            g_free (name);
     }
 
+    /* for multiple-match devices, set to the one we requested */
+    libwacom_update_match(ret, bus, vendor_id, product_id);
+
     if (device) {
            if (builtin == IS_BUILTIN_TRUE)
                ret->features |= FEATURE_BUILTIN;
@@ -328,9 +347,18 @@ libwacom_new_from_name(WacomDeviceDatabase *db, const char 
*name, WacomError *er
 void
 libwacom_destroy(WacomDevice *device)
 {
+       int i;
+
+       if (!g_atomic_int_dec_and_test(&device->refcnt))
+               return;
+
        g_free (device->name);
 
-       g_free (device->match);
+       for (i = 0; i < device->nmatches; i++) {
+               g_free (device->matches[i]->match);
+               g_free (device->matches[i]);
+       }
+       g_free (device->matches);
        g_free (device->supported_styli);
        g_free (device->buttons);
        g_free (device);
@@ -339,16 +367,40 @@ libwacom_destroy(WacomDevice *device)
 void
 libwacom_update_match(WacomDevice *device, WacomBusType bus, int vendor_id, 
int product_id)
 {
-       device->vendor_id = vendor_id;
-       device->product_id = product_id;
-       device->bus = bus;
-       g_free(device->match);
-       device->match = make_match_string(device->bus, device->vendor_id, 
device->product_id);
+       char *newmatch;
+       int i;
+       WacomMatch match;
+
+       if (bus == WBUSTYPE_UNKNOWN && vendor_id == 0 && product_id == 0)
+               newmatch = g_strdup("generic");
+       else
+               newmatch = make_match_string(bus, vendor_id, product_id);
+
+       match.match = newmatch;
+       match.bus = bus;
+       match.vendor_id = vendor_id;
+       match.product_id = product_id;
+
+       for (i = 0; i < device->nmatches; i++) {
+               if 
(g_strcmp0(libwacom_match_get_match_string(device->matches[i]), newmatch) == 0) 
{
+                       device->match = i;
+                       g_free(newmatch);
+                       return;
+               }
+       }
+
+       device->nmatches++;
+
+       device->matches = g_realloc_n(device->matches, device->nmatches + 1, 
sizeof(WacomMatch));
+       device->matches[device->nmatches] = NULL;
+       device->matches[device->nmatches - 1] = libwacom_copy_match(&match);
+       device->match = device->nmatches - 1;
+       g_free(newmatch);
 }
 
 int libwacom_get_vendor_id(WacomDevice *device)
 {
-    return device->vendor_id;
+    return device->matches[device->match]->vendor_id;
 }
 
 const char* libwacom_get_name(WacomDevice *device)
@@ -358,14 +410,17 @@ const char* libwacom_get_name(WacomDevice *device)
 
 int libwacom_get_product_id(WacomDevice *device)
 {
-    return device->product_id;
+    return device->matches[device->match]->product_id;
 }
 
 const char* libwacom_get_match(WacomDevice *device)
 {
-    /* FIXME make sure this only returns the first match
-     * when we implement multiple matching */
-    return device->match;
+    return device->matches[device->match]->match;
+}
+
+const WacomMatch** libwacom_get_matches(WacomDevice *device)
+{
+    return (const WacomMatch**)device->matches;
 }
 
 int libwacom_get_width(WacomDevice *device)
@@ -447,7 +502,7 @@ int libwacom_is_reversible(WacomDevice *device)
 
 WacomBusType libwacom_get_bustype(WacomDevice *device)
 {
-    return device->bus;
+    return device->matches[device->match]->bus;
 }
 
 WacomButtonFlags
@@ -519,4 +574,25 @@ void libwacom_stylus_destroy(WacomStylus *stylus)
        g_free (stylus);
 }
 
+
+WacomBusType libwacom_match_get_bustype(const WacomMatch *match)
+{
+       return match->bus;
+}
+
+uint32_t libwacom_match_get_product_id(const WacomMatch *match)
+{
+       return match->product_id;
+}
+
+uint32_t libwacom_match_get_vendor_id(const WacomMatch *match)
+{
+       return match->vendor_id;
+}
+
+const char* libwacom_match_get_match_string(const WacomMatch *match)
+{
+       return match->match;
+}
+
 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h
index bdc12b0..26df3ab 100644
--- a/libwacom/libwacom.h
+++ b/libwacom/libwacom.h
@@ -34,6 +34,7 @@
 #define _LIBWACOM_H_
 /** @endcond */
 
+#include <stdint.h>
 /**
  @mainpage
 
@@ -79,6 +80,8 @@
 
 typedef struct _WacomDevice WacomDevice;
 
+typedef struct _WacomMatch WacomMatch;
+
 typedef struct _WacomStylus WacomStylus;
 
 typedef struct _WacomError WacomError;
@@ -291,12 +294,20 @@ int libwacom_get_vendor_id(WacomDevice *device);
 
 /**
  * @param device The tablet to query
- * @return The first match for the device in question
+ * @return The current match string used for this device (if set) or the first
+ * match string in the tablet definition.
  */
 const char* libwacom_get_match(WacomDevice *device);
 
 /**
  * @param device The tablet to query
+ * @return A pointer to the null-terminated list of possible matches for this 
device. Do not
+ * modify this pointer or any content!
+ */
+const WacomMatch** libwacom_get_matches(WacomDevice *device);
+
+/**
+ * @param device The tablet to query
  * @return The numeric product ID for this device
  */
 int libwacom_get_product_id(WacomDevice *device);
@@ -464,6 +475,12 @@ int         libwacom_stylus_has_lens (const WacomStylus 
*stylus);
  */
 WacomStylusType libwacom_stylus_get_type (const WacomStylus *stylus);
 
+
+WacomBusType libwacom_match_get_bustype(const WacomMatch *match);
+uint32_t libwacom_match_get_product_id(const WacomMatch *match);
+uint32_t libwacom_match_get_vendor_id(const WacomMatch *match);
+const char* libwacom_match_get_match_string(const WacomMatch *match);
+
 #endif /* _LIBWACOM_H_ */
 
 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h
index e759a0f..1ec0a39 100644
--- a/libwacom/libwacomint.h
+++ b/libwacom/libwacomint.h
@@ -56,18 +56,26 @@ enum WacomFeature {
 };
 
 /* WARNING: When adding new members to this struct
+ * make sure to update libwacom_copy_match() ! */
+struct _WacomMatch {
+       char *match;
+       WacomBusType bus;
+       uint32_t vendor_id;
+       uint32_t product_id;
+};
+
+/* WARNING: When adding new members to this struct
  * make sure to update libwacom_copy() ! */
 struct _WacomDevice {
        char *name;
        int width;
        int height;
 
-       char *match;
-       uint32_t vendor_id;
-       uint32_t product_id;
+       int match;      /* used match or first match by default */
+       WacomMatch **matches; /* NULL-terminated */
+       int nmatches; /* not counting NULL-terminated element */
 
        WacomClass cls;
-       WacomBusType bus;
        int num_strips;
        uint32_t features;
 
@@ -80,6 +88,8 @@ struct _WacomDevice {
 
        int num_buttons;
        WacomButtonFlags *buttons;
+
+       gint refcnt; /* for the db hashtable */
 };
 
 struct _WacomStylus {
-- 
1.7.10


------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to