[PATCH v2 08/11] xfree86: Match devices based on USB ID

Dan Nicholson dbn.lists at gmail.com
Sat May 29 11:59:48 PDT 2010


Sometimes the vendor and product names aren't specific enough to target
a USB device, so expose the numeric codes in the ID. A MatchUSBID entry
has been added that supports shell pattern matching when fnmatch(3) is
available. For example:

	MatchUSBID "046d:*"

The IDs are stored in lowercase hex separated by a ':' like "lsusb" or
"lspci -n".

Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
---
 config/hal.c                         |   18 ++++++++++++++++++
 config/udev.c                        |   20 ++++++++++++++++++++
 dix/inpututils.c                     |    3 +++
 hw/xfree86/common/xf86Xinput.c       |    4 ++++
 hw/xfree86/doc/man/xorg.conf.man.pre |    9 +++++++++
 hw/xfree86/parser/InputClass.c       |   19 +++++++++++++++++++
 hw/xfree86/parser/xf86Parser.h       |    1 +
 hw/xfree86/parser/xf86tokens.h       |    1 +
 include/input.h                      |    1 +
 test/input.c                         |   12 ++++++++++++
 10 files changed, 88 insertions(+), 0 deletions(-)

diff --git a/config/hal.c b/config/hal.c
index 8061020..8f9aeb8 100644
--- a/config/hal.c
+++ b/config/hal.c
@@ -184,7 +184,24 @@ device_added(LibHalContext *hal_ctx, const char *udi)
 
     parent = get_prop_string(hal_ctx, udi, "info.parent");
     if (parent) {
+        int usb_vendor, usb_product;
+
         attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
+
+        /* construct USB ID in lowercase - "0000:ffff" */
+        usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
+                                                    "usb.vendor_id", NULL);
+        LogMessageVerb(X_INFO, 10,
+                       "config/hal: getting usb.vendor_id on %s "
+                       "returned %04x\n", parent, usb_vendor);
+        usb_product = libhal_device_get_property_int(hal_ctx, parent,
+                                                     "usb.product_id", NULL);
+        LogMessageVerb(X_INFO, 10,
+                       "config/hal: getting usb.product_id on %s "
+                       "returned %04x\n", parent, usb_product);
+        if (usb_vendor && usb_product)
+            attrs.usb_id = Xprintf("%04x:%04x", usb_vendor, usb_product);
+
         free(parent);
     }
 
@@ -391,6 +408,7 @@ unwind:
     free(attrs.vendor);
     free(attrs.device);
     free(attrs.pnp_id);
+    free(attrs.usb_id);
     if (attrs.tags) {
         char **tag = attrs.tags;
         while (*tag) {
diff --git a/config/udev.c b/config/udev.c
index f7ed4b2..16c4624 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -28,6 +28,7 @@
 #endif
 
 #include <libudev.h>
+#include <ctype.h>
 
 #include "input.h"
 #include "inputstr.h"
@@ -57,6 +58,7 @@ device_added(struct udev_device *udev_device)
     char *config_info = NULL;
     const char *syspath;
     const char *tags_prop;
+    const char *usb_vendor = NULL, *usb_model = NULL;
     const char *key, *value, *tmp;
     InputOption *options = NULL, *tmpo;
     InputAttributes attrs = {};
@@ -150,6 +152,12 @@ device_added(struct udev_device *udev_device)
         } else if (!strcmp(key, "ID_VENDOR")) {
             LOG_PROPERTY(path, key, value);
             attrs.vendor = value;
+        } else if (!strcmp(key, "ID_VENDOR_ID")) {
+            LOG_PROPERTY(path, key, value);
+            usb_vendor = value;
+        } else if (!strcmp(key, "ID_VENDOR_MODEL")) {
+            LOG_PROPERTY(path, key, value);
+            usb_model = value;
         } else if (!strcmp(key, "ID_INPUT_KEY")) {
             LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_KEYBOARD;
@@ -170,6 +178,17 @@ device_added(struct udev_device *udev_device)
             attrs.flags |= ATTR_TOUCHSCREEN;
         }
     }
+
+    /* construct USB ID in lowercase hex - "0000:ffff" */
+    if (usb_vendor && usb_model) {
+        attrs.usb_id = Xprintf("%s:%s", usb_vendor, usb_model);
+        if (attrs.usb_id) {
+            char *cur;
+            for (cur = attrs.usb_id; *cur; cur++)
+                *cur = tolower(*cur);
+        }
+    }
+
     LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
                name, path);
     rc = NewInputDeviceRequest(options, &attrs, &dev);
@@ -190,6 +209,7 @@ device_added(struct udev_device *udev_device)
         free(tmpo);
     }
 
+    free(attrs.usb_id);
     if (attrs.tags) {
         char **tag = attrs.tags;
         while (*tag) {
diff --git a/dix/inpututils.c b/dix/inpututils.c
index aa240dd..8ec80b5 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -359,6 +359,8 @@ DuplicateInputAttributes(InputAttributes *attrs)
         goto unwind;
     if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
         goto unwind;
+    if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
+        goto unwind;
 
     new_attr->flags = attrs->flags;
 
@@ -404,6 +406,7 @@ FreeInputAttributes(InputAttributes *attrs)
     free(attrs->vendor);
     free(attrs->device);
     free(attrs->pnp_id);
+    free(attrs->usb_id);
 
     if ((tags = attrs->tags))
         while(*tags)
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 5b0ec8f..4218039 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -604,6 +604,10 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
     if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, match_pattern))
         return FALSE;
 
+    /* MatchUSBID pattern */
+    if (!MatchAttrToken(attrs->usb_id, iclass->match_usbid, match_pattern))
+        return FALSE;
+
     /*
      * MatchTag string
      * See if any of the device's tags match any of the MatchTag tokens.
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index c17ecb9..63dbb68 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1101,6 +1101,15 @@ The device's Plug and Play (PnP) ID can be checked against the
 shell wildcard pattern. Multiple IDs can be matched by separating arguments
 with a '|' character.
 .TP 7
+.BI "MatchUSBID \*q" matchusb \*q
+The device's USB ID can be checked against the
+.RI \*q matchusb \*q
+shell wildcard pattern. The ID is constructed as lowercase hexadecimal numbers
+separated by a ':'. This is the same format as the
+.BR lsusb (8)
+program. Multiple IDs can be matched by separating arguments with a '|'
+character.
+.TP 7
 .BI "MatchTag \*q" matchtag \*q
 This entry can be used to check if tags assigned by the config backend
 matches the
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index e5ef96c..bdcfba4 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -49,6 +49,7 @@ xf86ConfigSymTabRec InputClassTab[] =
     {MATCH_DEVICE_PATH, "matchdevicepath"},
     {MATCH_OS, "matchos"},
     {MATCH_PNPID, "matchpnpid"},
+    {MATCH_USBID, "matchusbid"},
     {MATCH_TAG, "matchtag"},
     {MATCH_IS_KEYBOARD, "matchiskeyboard"},
     {MATCH_IS_POINTER, "matchispointer"},
@@ -120,6 +121,11 @@ xf86parseInputClassSection(void)
                 Error(QUOTE_MSG, "MatchPnPID");
             ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP);
             break;
+        case MATCH_USBID:
+            if (xf86getSubToken(&(ptr->comment)) != STRING)
+                Error(QUOTE_MSG, "MatchUSBID");
+            ptr->match_usbid = xstrtokenize(val.str, TOKEN_SEP);
+            break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
@@ -245,6 +251,14 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
                         *list);
             fprintf(cf, "\"\n");
         }
+        if (ptr->match_usbid) {
+            fprintf(cf, "\tMatchUSBID      \"");
+            for (list = ptr->match_usbid; *list; list++)
+                fprintf(cf, "%s%s",
+                        list == ptr->match_usbid ? "" : TOKEN_SEP,
+                        *list);
+            fprintf(cf, "\"\n");
+        }
         if (ptr->match_tag) {
             fprintf(cf, "\tMatchTag \"");
             for (list = ptr->match_tag; *list; list++)
@@ -311,6 +325,11 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
                 free(*list);
             free(ptr->match_pnpid);
         }
+        if (ptr->match_usbid) {
+            for (list = ptr->match_usbid; *list; list++)
+                free(*list);
+            free(ptr->match_usbid);
+        }
         if (ptr->match_tag) {
             for (list = ptr->match_tag; *list; list++)
                 free(*list);
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 87fc31c..a86462f 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -348,6 +348,7 @@ typedef struct
 	char **match_device;
 	char **match_os;
 	char **match_pnpid;
+	char **match_usbid;
 	char **match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index aa33935..23460dd 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -281,6 +281,7 @@ typedef enum {
     MATCH_DEVICE_PATH,
     MATCH_OS,
     MATCH_PNPID,
+    MATCH_USBID,
     MATCH_TAG,
     MATCH_IS_KEYBOARD,
     MATCH_IS_POINTER,
diff --git a/include/input.h b/include/input.h
index 5969693..0a08ea4 100644
--- a/include/input.h
+++ b/include/input.h
@@ -216,6 +216,7 @@ typedef struct _InputAttributes {
     char                *vendor;
     char                *device;
     char                *pnp_id;
+    char                *usb_id;
     char                **tags; /* null-terminated */
     uint32_t            flags;
 } InputAttributes;
diff --git a/test/input.c b/test/input.c
index dd197dd..b90d3b4 100644
--- a/test/input.c
+++ b/test/input.c
@@ -808,6 +808,13 @@ static void cmp_attr_fields(InputAttributes *attr1,
     } else
         g_assert(attr2->pnp_id == NULL);
 
+    if (attr1->usb_id != NULL)
+    {
+        g_assert(attr1->usb_id != attr2->usb_id);
+        g_assert(strcmp(attr1->usb_id, attr2->usb_id) == 0);
+    } else
+        g_assert(attr2->usb_id == NULL);
+
     tags1 = attr1->tags;
     tags2 = attr2->tags;
 
@@ -878,6 +885,11 @@ static void dix_input_attributes(void)
     cmp_attr_fields(&orig, new);
     FreeInputAttributes(new);
 
+    orig.usb_id = "USBID";
+    new = DuplicateInputAttributes(&orig);
+    cmp_attr_fields(&orig, new);
+    FreeInputAttributes(new);
+
     orig.flags = 0xF0;
     new = DuplicateInputAttributes(&orig);
     cmp_attr_fields(&orig, new);
-- 
1.6.6.1


More information about the xorg-devel mailing list