xserver: Branch 'master' - 14 commits

Keith Packard keithp at kemper.freedesktop.org
Thu Jun 10 18:43:03 PDT 2010


 Xi/exevents.c                        |    4 
 config/Makefile.am                   |    2 
 config/dbus.c                        |    1 
 config/fdi2iclass.py                 |  202 +++++++++++++++++++++++++++++++
 config/hal.c                         |   32 ++++-
 config/udev.c                        |   62 +++++++++
 configure.ac                         |    5 
 dix/inpututils.c                     |    6 
 hw/xfree86/common/xf86Xinput.c       |  222 +++++++++++++++++++++++------------
 hw/xfree86/doc/man/xorg.conf.man.pre |   71 +++++++++--
 hw/xfree86/parser/InputClass.c       |  191 +++++++++++++++++++++++-------
 hw/xfree86/parser/xf86Parser.h       |   20 ++-
 hw/xfree86/parser/xf86tokens.h       |    4 
 include/dix-config.h.in              |    3 
 include/input.h                      |    2 
 test/input.c                         |   24 +++
 16 files changed, 713 insertions(+), 138 deletions(-)

New commits:
commit 07a093add0b7e40c4d9b9b59273e3ff9e14a88a7
Merge: 84190d2... dc61448...
Author: Keith Packard <keithp at keithp.com>
Date:   Thu Jun 10 18:39:10 2010 -0700

    Merge remote branch 'whot/for-keith'

commit dc614484f93b67e8b62dbb1bb2fd247fe5a4c850
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Jun 10 12:21:36 2010 +1000

    Xi: don't copy the modifier key count when copying device classes (#25480)
    
    The modifier key count is maintained by the XKB layer and
    increased/decreased for all modifiers that set state.
    
    Test case, MD/SD modifier key count in comment:
    1. keyboard 1: press and hold Shift_L    # SD:1     MD:1
    2. keyboard 2: press and release Shift_L # SD:1,0   MD:1,0
    <class copy happens>                     # SD:1     MD:1
    3. keyboard 1: release Shift_L           # SD:0     MD:1
    4. keyboard 1: press and release Shift_L # SD:1,0   MD:2,1
    
    The modifier is now logically down on the MD but not on keyboard 1 or
    keyboard 2.
    
    XKB is layered in before the DIX, it increases/decreases the modifier key
    count accordingly. In the above example, during (2), the MD gets the key
    release and thus clears the modifier bit. (3) doesn't forward the release to
    the MD because it is already cleared. The copy of modifierKeysDown when the
    lastSlave changes however increases the counter for the held key. On (4),
    the press and release are both forwarded to the MD, causing a offset by 1
    and thus do not clear the logical modifier state.
    
    X.Org Bug 25480 <http://bugs.freedesktop.org/show_bug.cgi?id=25480>
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Acked-by: Daniel Stone <daniel at fooishbar.org>

diff --git a/Xi/exevents.c b/Xi/exevents.c
index 56d9bf7..22a1fa4 100644
--- a/Xi/exevents.c
+++ b/Xi/exevents.c
@@ -193,16 +193,12 @@ void
 CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
 {
     KeyClassPtr mk = master->key;
-    KeyClassPtr dk = device->key;
-    int i;
 
     if (device == master)
         return;
 
     mk->sourceid = device->id;
 
-    for (i = 0; i < 8; i++)
-        mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
 
     if (!XkbCopyDeviceKeymap(master, device))
         FatalError("Couldn't pivot keymap from device to core!\n");
commit 7805e45284264b4cd286eece02e85426896e9f7b
Author: Peter Hutterer <peter.hutterer at who-t.net>
Date:   Thu Jun 10 14:31:48 2010 +1000

    config: remove redundant DBUS API define, require dbus-1 >= 1.0
    
    It's still being pulled in by the HAL CFLAGS but the requirement to define
    this was dropped from DBus pre 1.0 (November 2006).
    This means we require dbus 1.0 now.
    
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
    Reviewed-by: Daniel Stone <daniel at fooishbar.org>
    Reviewed-by: Dan Nicholson <dbn.lists at gmail.com>

diff --git a/config/dbus.c b/config/dbus.c
index 4888f62..b67fddb 100644
--- a/config/dbus.c
+++ b/config/dbus.c
@@ -27,7 +27,6 @@
 #include <dix-config.h>
 #endif
 
-#define DBUS_API_SUBJECT_TO_CHANGE
 #include <dbus/dbus.h>
 #include <string.h>
 
diff --git a/configure.ac b/configure.ac
index 81b6e4c..02660a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -809,6 +809,7 @@ LIBPCIACCESS="pciaccess >= 0.8.0"
 LIBGLIB="glib-2.0 >= 2.16"
 LIBUDEV="libudev >= 143"
 LIBSELINUX="libselinux >= 2.0.86"
+LIBDBUS="dbus-1 >= 1.0"
 
 if test "x$CONFIG_UDEV" = xyes &&
  { test "x$CONFIG_DBUS_API" = xyes || test "x$CONFIG_HAL" = xyes; }; then
@@ -832,7 +833,7 @@ fi
 dnl HAVE_DBUS is true if we actually have the D-Bus library, whereas
 dnl CONFIG_DBUS_API is true if we want to enable the D-Bus config
 dnl API.
-PKG_CHECK_MODULES(DBUS, dbus-1, [HAVE_DBUS=yes], [HAVE_DBUS=no])
+PKG_CHECK_MODULES(DBUS, $LIBDBUS, [HAVE_DBUS=yes], [HAVE_DBUS=no])
 if test "x$HAVE_DBUS" = xyes; then
 	AC_DEFINE(HAVE_DBUS, 1, [Have D-Bus support])
 fi
commit 66b21b2f455a1dfbc92f7caa571dcff3f3765808
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:58 2010 -0700

    xfree86: Match devices based on current driver setting
    
    Often we want to apply a driver specific option to a set of devices and
    don't care how the driver was selected for that device. The MatchDriver
    entry can be used to match the current driver string:
    
    	MatchDriver "evdev|mouse"
    	Option "Emulate3Buttons" "yes"
    
    The driver string is a case sensitive match.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index fa0ed85..b2a1d1f 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -594,7 +594,7 @@ MatchAttrToken(const char *attr, struct list *patterns,
  * statements must match.
  */
 static Bool
-InputClassMatches(const XF86ConfInputClassPtr iclass,
+InputClassMatches(const XF86ConfInputClassPtr iclass, const IDevPtr idev,
                   const InputAttributes *attrs)
 {
     /* MatchProduct substring */
@@ -621,6 +621,10 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
     if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
         return FALSE;
 
+    /* MatchDriver string */
+    if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
+        return FALSE;
+
     /*
      * MatchTag string
      * See if any of the device's tags match any of the MatchTag tokens.
@@ -673,34 +677,33 @@ static int
 MergeInputClasses(const IDevPtr idev, const InputAttributes *attrs)
 {
     XF86ConfInputClassPtr cl;
-    XF86OptionPtr classopts, mergedopts = NULL;
-    char *classdriver = NULL;
+    XF86OptionPtr classopts;
 
     for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
-        if (!InputClassMatches(cl, attrs))
+        if (!InputClassMatches(cl, idev, attrs))
             continue;
 
-        /* Collect class options and merge over previous classes */
+        /* Collect class options and driver settings */
+        classopts = xf86optionListDup(cl->option_lst);
+        if (cl->driver) {
+            free(idev->driver);
+            idev->driver = xstrdup(cl->driver);
+            if (!idev->driver) {
+                xf86Msg(X_ERROR, "Failed to allocate memory while merging "
+                        "InputClass configuration");
+                return BadAlloc;
+            }
+            classopts = xf86ReplaceStrOption(classopts, "driver",
+                                             idev->driver);
+        }
+
+        /* Apply options to device with InputClass settings preferred. */
         xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
                 idev->identifier, cl->identifier);
-        if (cl->driver)
-            classdriver = cl->driver;
-        classopts = xf86optionListDup(cl->option_lst);
-        mergedopts = xf86optionListMerge(mergedopts, classopts);
+        idev->commonOptions = xf86optionListMerge(idev->commonOptions,
+                                                  classopts);
     }
 
-    /* Apply options to device with InputClass settings preferred. */
-    if (classdriver) {
-        free(idev->driver);
-        idev->driver = xstrdup(classdriver);
-        if (!idev->driver) {
-            xf86Msg(X_ERROR, "Failed to allocate memory while merging "
-                    "InputClass configuration");
-            return BadAlloc;
-        }
-        mergedopts = xf86ReplaceStrOption(mergedopts, "driver", idev->driver);
-    }
-    idev->commonOptions = xf86optionListMerge(idev->commonOptions, mergedopts);
     return Success;
 }
 
@@ -716,7 +719,7 @@ IgnoreInputClass(const IDevPtr idev, const InputAttributes *attrs)
     const char *ignore_class;
 
     for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
-        if (!InputClassMatches(cl, attrs))
+        if (!InputClassMatches(cl, idev, attrs))
             continue;
         if (xf86findOption(cl->option_lst, "Ignore")) {
             ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index f6b90be..6b3636f 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1123,6 +1123,15 @@ separated by a ':'. This is the same format as the
 .BR lsusb (8)
 program.
 .TP 7
+.BI "MatchDriver \*q" matchdriver \*q
+Check the case-sensitive string
+.RI \*q matchdriver \*q
+against the currently configured driver of the device. Ordering of sections
+using this entry is important since it will not match unless the driver has
+been set by the config backend or a previous
+.B InputClass
+section.
+.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 f2b46bb..ce611d9 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -50,6 +50,7 @@ xf86ConfigSymTabRec InputClassTab[] =
     {MATCH_OS, "matchos"},
     {MATCH_PNPID, "matchpnpid"},
     {MATCH_USBID, "matchusbid"},
+    {MATCH_DRIVER, "matchdriver"},
     {MATCH_TAG, "matchtag"},
     {MATCH_IS_KEYBOARD, "matchiskeyboard"},
     {MATCH_IS_POINTER, "matchispointer"},
@@ -91,6 +92,7 @@ xf86parseInputClassSection(void)
     list_init(&ptr->match_os);
     list_init(&ptr->match_pnpid);
     list_init(&ptr->match_usbid);
+    list_init(&ptr->match_driver);
     list_init(&ptr->match_tag);
 
     while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
@@ -153,6 +155,12 @@ xf86parseInputClassSection(void)
             add_group_entry(&ptr->match_usbid,
                             xstrtokenize(val.str, TOKEN_SEP));
             break;
+        case MATCH_DRIVER:
+            if (xf86getSubToken(&(ptr->comment)) != STRING)
+                Error(QUOTE_MSG, "MatchDriver");
+            add_group_entry(&ptr->match_driver,
+                            xstrtokenize(val.str, TOKEN_SEP));
+            break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
@@ -283,6 +291,13 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
                         *cur);
             fprintf(cf, "\"\n");
         }
+        list_for_each_entry(group, &ptr->match_driver, entry) {
+            fprintf(cf, "\tMatchDriver     \"");
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
+            fprintf(cf, "\"\n");
+        }
         list_for_each_entry(group, &ptr->match_tag, entry) {
             fprintf(cf, "\tMatchTag        \"");
             for (cur = group->values; *cur; cur++)
@@ -363,6 +378,12 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
                 free(*list);
             free(group);
         }
+        list_for_each_entry_safe(group, next, &ptr->match_driver, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
+                free(*list);
+            free(group);
+        }
         list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
             list_del(&group->entry);
             for (list = group->values; *list; list++)
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 26d9a5b..337ad07 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -357,6 +357,7 @@ typedef struct
 	struct list match_os;
 	struct list match_pnpid;
 	struct list match_usbid;
+	struct list match_driver;
 	struct list match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index 23460dd..c16a8f5 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -282,6 +282,7 @@ typedef enum {
     MATCH_OS,
     MATCH_PNPID,
     MATCH_USBID,
+    MATCH_DRIVER,
     MATCH_TAG,
     MATCH_IS_KEYBOARD,
     MATCH_IS_POINTER,
commit a71bdff47d4cc80da6ceeb548db1dcc8e8b59702
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:57 2010 -0700

    xfree86: Allow multiple InputClass Match* entries for && matching
    
    Currently when there multiple InputClass entries of the same type, only
    the last entry is used and the previous ones are ignored. Instead,
    multiple entries are used to create multiple matching conditions.
    
    For instance, an InputClass with
    
    	MatchProduct "foo"
    	MatchProduct "bar"
    
    will require that the device's product name contain both foo and bar.
    This provides a complement to the || style matching when an entry is
    split using the "|" token.
    
    The xorg.conf man page has added an example to hopefully clarify the two
    types of compound matches.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 4218039..fa0ed85 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -551,29 +551,42 @@ match_path_pattern(const char *attr, const char *pattern)
 #endif
 
 /*
- * Match an attribute against a NULL terminated list of patterns. If any
- * pattern is matched, return TRUE.
+ * Match an attribute against a list of NULL terminated arrays of patterns.
+ * If a pattern in each list entry is matched, return TRUE.
  */
 static Bool
-MatchAttrToken(const char *attr, char **patterns,
+MatchAttrToken(const char *attr, struct list *patterns,
                int (*compare)(const char *attr, const char *pattern))
 {
-    char **cur;
+    const xf86MatchGroup *group;
 
     /* If there are no patterns, accept the match */
-    if (!patterns)
+    if (list_is_empty(patterns))
         return TRUE;
 
     /* If there are patterns but no attribute, reject the match */
     if (!attr)
         return FALSE;
 
-    /* Otherwise, iterate the patterns looking for a match */
-    for (cur = patterns; *cur; cur++)
-        if ((*compare)(attr, *cur) == 0)
-            return TRUE;
+    /*
+     * Otherwise, iterate the list of patterns ensuring each entry has a
+     * match. Each list entry is a separate Match line of the same type.
+     */
+    list_for_each_entry(group, patterns, entry) {
+        char * const *cur;
+        Bool match = FALSE;
+
+        for (cur = group->values; *cur; cur++)
+            if ((*compare)(attr, *cur) == 0) {
+                match = TRUE;
+                break;
+            }
+        if (!match)
+            return FALSE;
+    }
 
-    return FALSE;
+    /* All the entries in the list matched the attribute */
+    return TRUE;
 }
 
 /*
@@ -585,41 +598,41 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
                   const InputAttributes *attrs)
 {
     /* MatchProduct substring */
-    if (!MatchAttrToken(attrs->product, iclass->match_product, match_substring))
+    if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
         return FALSE;
 
     /* MatchVendor substring */
-    if (!MatchAttrToken(attrs->vendor, iclass->match_vendor, match_substring))
+    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
         return FALSE;
 
     /* MatchDevicePath pattern */
-    if (!MatchAttrToken(attrs->device, iclass->match_device, match_path_pattern))
+    if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
         return FALSE;
 
     /* MatchOS case-insensitive string */
-    if (!MatchAttrToken(HostOS(), iclass->match_os, strcasecmp))
+    if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
         return FALSE;
 
     /* MatchPnPID pattern */
-    if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, match_pattern))
+    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
         return FALSE;
 
     /* MatchUSBID pattern */
-    if (!MatchAttrToken(attrs->usb_id, iclass->match_usbid, match_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.
      */
-    if (iclass->match_tag) {
+    if (!list_is_empty(&iclass->match_tag)) {
         char * const *tag;
         Bool match;
 
         if (!attrs->tags)
             return FALSE;
         for (tag = attrs->tags, match = FALSE; *tag; tag++) {
-            if (MatchAttrToken(*tag, iclass->match_tag, strcmp)) {
+            if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
                 match = TRUE;
                 break;
             }
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index 63dbb68..f6b90be 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1065,26 +1065,42 @@ of the class. If none of the optional entries appear, the
 .B InputClass
 section is generic and will match any input device. If more than one of
 these entries appear, they all must match for the configuration to apply.
-The allowed matching entries are shown below.
 .PP
+There are two types of match entries used in
+.B InputClass
+sections. The first allows various tokens to be matched against attributes
+of the device. An entry can be constructed to match attributes from different
+devices by separating arguments with a '|' character. Multiple entries of the
+same type may be supplied to add multiple matching conditions on the same
+attribute. For example:
+.PP
+.RS 4
+.nf
+.B  "Section \*qInputClass\*q"
+.B  "    Identifier   \*qMy Class\*q"
+.B  "    # product string must contain example and
+.B  "    # either gizmo or gadget
+.B  "    MatchProduct \*qexample\*q
+.B  "    MatchProduct \*qgizmo|gadget\*q
+.I  "    ..."
+.B  "EndSection"
+.fi
+.RE
 .TP 7
 .BI "MatchProduct  \*q" matchproduct \*q
 This entry can be used to check if the substring
 .RI \*q matchproduct \*q
-occurs in the device's product name. Multiple substrings can be matched by
-separating arguments with a '|' character.
+occurs in the device's product name.
 .TP 7
 .BI "MatchVendor  \*q" matchvendor \*q
 This entry can be used to check if the substring
 .RI \*q matchvendor \*q
-occurs in the device's vendor name. Multiple substrings can be matched by
-separating arguments with a '|' character.
+occurs in the device's vendor name.
 .TP 7
 .BI "MatchDevicePath \*q" matchdevice \*q
 This entry can be used to check if the device file matches the
 .RI \*q matchdevice \*q
-pathname pattern. Multiple patterns can be matched by separating arguments
-with a '|' character.
+pathname pattern.
 .TP 7
 .BI "MatchOS \*q" matchos \*q
 This entry can be used to check if the operating system matches the
@@ -1092,14 +1108,12 @@ case-insensitive
 .RI \*q matchos \*q
 string. This entry is only supported on platforms providing the
 .BR uname (2)
-system call. Multiple operating systems can be matched by separating arguments
-with a '|' character.
+system call.
 .TP 7
 .BI "MatchPnPID \*q" matchpnp \*q
 The device's Plug and Play (PnP) ID can be checked against the
 .RI \*q matchpnp \*q
-shell wildcard pattern. Multiple IDs can be matched by separating arguments
-with a '|' character.
+shell wildcard pattern.
 .TP 7
 .BI "MatchUSBID \*q" matchusb \*q
 The device's USB ID can be checked against the
@@ -1107,17 +1121,20 @@ The device's USB ID can be checked against the
 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.
+program.
 .TP 7
 .BI "MatchTag \*q" matchtag \*q
 This entry can be used to check if tags assigned by the config backend
 matches the
 .RI \*q matchtag \*q
-pattern.  Multiple patterns can be matched by separating arguments
-with a '|' character. A match is found if at least one of the tags given in
+pattern. A match is found if at least one of the tags given in
 .RI \*q matchtag \*q
 matches at least one of the tags assigned by the backend.
+.PP
+The second type of entry is used to match device types. These entries take a
+boolean argument similar to
+.B Option
+entries.
 .TP 7
 .BI "MatchIsKeyboard     \*q" bool \*q
 .TP 7
@@ -1130,9 +1147,6 @@ matches at least one of the tags assigned by the backend.
 .BI "MatchIsTouchpad     \*q" bool \*q
 .TP 7
 .BI "MatchIsTouchscreen  \*q" bool \*q
-Match device types. These entries take a boolean argument similar to
-.B Option
-entries.
 .PP
 When an input device has been matched to the
 .B InputClass
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index bdcfba4..f2b46bb 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -64,6 +64,18 @@ xf86ConfigSymTabRec InputClassTab[] =
 
 #define TOKEN_SEP "|"
 
+static void
+add_group_entry(struct list *head, char **values)
+{
+    xf86MatchGroup *group;
+
+    group = malloc(sizeof(*group));
+    if (group) {
+        group->values = values;
+        list_add(&group->entry, head);
+    }
+}
+
 XF86ConfInputClassPtr
 xf86parseInputClassSection(void)
 {
@@ -72,6 +84,15 @@ xf86parseInputClassSection(void)
 
     parsePrologue(XF86ConfInputClassPtr, XF86ConfInputClassRec)
 
+    /* Initialize MatchGroup lists */
+    list_init(&ptr->match_product);
+    list_init(&ptr->match_vendor);
+    list_init(&ptr->match_device);
+    list_init(&ptr->match_os);
+    list_init(&ptr->match_pnpid);
+    list_init(&ptr->match_usbid);
+    list_init(&ptr->match_tag);
+
     while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
         switch (token) {
         case COMMENT:
@@ -99,37 +120,44 @@ xf86parseInputClassSection(void)
         case MATCH_PRODUCT:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchProduct");
-            ptr->match_product = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_product,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_VENDOR:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchVendor");
-            ptr->match_vendor = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_vendor,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_DEVICE_PATH:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchDevicePath");
-            ptr->match_device = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_device,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_OS:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchOS");
-            ptr->match_os = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_os,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_PNPID:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchPnPID");
-            ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&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);
+            add_group_entry(&ptr->match_usbid,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
-            ptr->match_tag = xstrtokenize(val.str, TOKEN_SEP);
+            add_group_entry(&ptr->match_tag,
+                            xstrtokenize(val.str, TOKEN_SEP));
             break;
         case MATCH_IS_KEYBOARD:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
@@ -201,7 +229,8 @@ xf86parseInputClassSection(void)
 void
 xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
 {
-    char **list;
+    const xf86MatchGroup *group;
+    char * const *cur;
 
     while (ptr) {
         fprintf(cf, "Section \"InputClass\"\n");
@@ -211,62 +240,57 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
             fprintf(cf, "\tIdentifier      \"%s\"\n", ptr->identifier);
         if (ptr->driver)
             fprintf(cf, "\tDriver          \"%s\"\n", ptr->driver);
-        if (ptr->match_product) {
+
+        list_for_each_entry(group, &ptr->match_product, entry) {
             fprintf(cf, "\tMatchProduct    \"");
-            for (list = ptr->match_product; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_product ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_vendor) {
+        list_for_each_entry(group, &ptr->match_vendor, entry) {
             fprintf(cf, "\tMatchVendor     \"");
-            for (list = ptr->match_vendor; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_vendor ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_device) {
+        list_for_each_entry(group, &ptr->match_device, entry) {
             fprintf(cf, "\tMatchDevicePath \"");
-            for (list = ptr->match_device; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_device ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_os) {
+        list_for_each_entry(group, &ptr->match_os, entry) {
             fprintf(cf, "\tMatchOS         \"");
-            for (list = ptr->match_os; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_os ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_pnpid) {
+        list_for_each_entry(group, &ptr->match_pnpid, entry) {
             fprintf(cf, "\tMatchPnPID      \"");
-            for (list = ptr->match_pnpid; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_pnpid ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_usbid) {
+        list_for_each_entry(group, &ptr->match_usbid, entry) {
             fprintf(cf, "\tMatchUSBID      \"");
-            for (list = ptr->match_usbid; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_usbid ? "" : TOKEN_SEP,
-                        *list);
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
-        if (ptr->match_tag) {
-            fprintf(cf, "\tMatchTag \"");
-            for (list = ptr->match_tag; *list; list++)
-                fprintf(cf, "%s%s",
-                        list == ptr->match_tag ? "" : TOKEN_SEP,
-                        *list);
+        list_for_each_entry(group, &ptr->match_tag, entry) {
+            fprintf(cf, "\tMatchTag        \"");
+            for (cur = group->values; *cur; cur++)
+                fprintf(cf, "%s%s", cur == group->values ? "" : TOKEN_SEP,
+                        *cur);
             fprintf(cf, "\"\n");
         }
+
         if (ptr->is_keyboard.set)
             fprintf(cf, "\tIsKeyboard      \"%s\"\n",
                     ptr->is_keyboard.val ? "yes" : "no");
@@ -295,46 +319,57 @@ void
 xf86freeInputClassList (XF86ConfInputClassPtr ptr)
 {
     XF86ConfInputClassPtr prev;
-    char **list;
 
     while (ptr) {
+        xf86MatchGroup *group, *next;
+        char **list;
+
         TestFree(ptr->identifier);
         TestFree(ptr->driver);
-        if (ptr->match_product) {
-            for (list = ptr->match_product; *list; list++)
+
+        list_for_each_entry_safe(group, next, &ptr->match_product, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_product);
+            free(group);
         }
-        if (ptr->match_vendor) {
-            for (list = ptr->match_vendor; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_vendor, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_vendor);
+            free(group);
         }
-        if (ptr->match_device) {
-            for (list = ptr->match_device; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_device, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_device);
+            free(group);
         }
-        if (ptr->match_os) {
-            for (list = ptr->match_os; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_os, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_os);
+            free(group);
         }
-        if (ptr->match_pnpid) {
-            for (list = ptr->match_pnpid; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_pnpid);
+            free(group);
         }
-        if (ptr->match_usbid) {
-            for (list = ptr->match_usbid; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_usbid);
+            free(group);
         }
-        if (ptr->match_tag) {
-            for (list = ptr->match_tag; *list; list++)
+        list_for_each_entry_safe(group, next, &ptr->match_tag, entry) {
+            list_del(&group->entry);
+            for (list = group->values; *list; list++)
                 free(*list);
-            free(ptr->match_tag);
+            free(group);
         }
+
         TestFree(ptr->comment);
         xf86optionListFree(ptr->option_lst);
 
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index a86462f..26d9a5b 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -66,6 +66,7 @@
 
 #include <X11/Xdefs.h>
 #include "xf86Optrec.h"
+#include "list.h"
 
 #define HAVE_PARSER_DECLS
 
@@ -340,16 +341,23 @@ xf86TriState;
 
 typedef struct
 {
+	struct list entry;
+	char **values;
+}
+xf86MatchGroup;
+
+typedef struct
+{
 	GenericListRec list;
 	char *identifier;
 	char *driver;
-	char **match_product;
-	char **match_vendor;
-	char **match_device;
-	char **match_os;
-	char **match_pnpid;
-	char **match_usbid;
-	char **match_tag;
+	struct list match_product;
+	struct list match_vendor;
+	struct list match_device;
+	struct list match_os;
+	struct list match_pnpid;
+	struct list match_usbid;
+	struct list match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
 	xf86TriState is_joystick;
commit 842625928632ae767b0689fcdb5103c1779a4c91
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:56 2010 -0700

    config: Script to convert HAL fdi settings to InputClass sections
    
    In the new world of udev and InputClass, x11_* settings from HAL fdi
    files will not be honored. This script converts those settings into
    valid InputClass sections that can be dropped into xorg.conf.d.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/config/Makefile.am b/config/Makefile.am
index 675a3b2..e1f1c4e 100644
--- a/config/Makefile.am
+++ b/config/Makefile.am
@@ -36,4 +36,4 @@ endif # CONFIG_NEED_DBUS
 
 endif # !CONFIG_UDEV
 
-EXTRA_DIST = xorg-server.conf x11-input.fdi 10-evdev.conf
+EXTRA_DIST = xorg-server.conf x11-input.fdi 10-evdev.conf fdi2iclass.py
diff --git a/config/fdi2iclass.py b/config/fdi2iclass.py
new file mode 100755
index 0000000..8974440
--- /dev/null
+++ b/config/fdi2iclass.py
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+#
+# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
+# Modified from Martin Pitt's original fdi2mpi.py script:
+# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
+#
+# (C) 2010 Dan Nicholson
+# (C) 2009 Canonical Ltd.
+# Author: Dan Nicholson <dbn.lists at gmail.com>
+# Author: Martin Pitt <martin.pitt at ubuntu.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# fur- nished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+#  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+#  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+#  NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import sys, xml.dom.minidom
+
+# dict converting <match> tags to Match* entries
+match_table = {
+    'info.product': 'MatchProduct',
+    'input.product': 'MatchProduct',
+    'info.vendor': 'MatchVendor',
+    'input.vendor': 'MatchVendor',
+    'info.device': 'MatchDevicePath',
+    'linux.device_file': 'MatchDevicePath',
+    '/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
+    '@info.parent:pnp.id': 'MatchPnPID',
+}
+
+# dict converting info.capabilities list to Match* entries
+cap_match_table = {
+    'input.keys': 'MatchIsKeyboard',
+    'input.keyboard': 'MatchIsKeyboard',
+    'input.keypad': 'MatchIsKeyboard',
+    'input.mouse': 'MatchIsPointer',
+    'input.joystick': 'MatchIsJoystick',
+    'input.tablet': 'MatchIsTablet',
+    'input.touchpad': 'MatchIsTouchpad',
+    'input.touchscreen': 'MatchIsTouchscreen',
+}
+
+def device_glob(path):
+    '''Convert a contains device path to a glob entry'''
+    if path[0] != '/':
+        path = '*' + path
+    return path + '*'
+
+def parse_match(node):
+    '''Parse a <match> tag to a tuple with InputClass values'''
+    match = None
+    value = None
+    booltype = False
+
+    # see what type of key we have
+    if node.attributes.has_key('key'):
+        key = node.attributes['key'].nodeValue
+        if key in match_table:
+            match = match_table[key]
+        elif key == 'info.capabilities':
+            booltype = True
+
+    # bail out now if it's unrecognized
+    if not match and not booltype:
+        return (match, value)
+
+    if node.attributes.has_key('string'):
+        value = node.attributes['string'].nodeValue
+    elif node.attributes.has_key('contains'):
+        value = node.attributes['contains'].nodeValue
+        if match == 'MatchDevicePath':
+            value = device_glob(value)
+        elif booltype and value in cap_match_table:
+            match = cap_match_table[value]
+            value = 'yes'
+    elif node.attributes.has_key('string_outof'):
+        value = node.attributes['string_outof'].nodeValue.replace(';','|')
+    elif node.attributes.has_key('contains_outof'):
+        all_values = node.attributes['contains_outof'].nodeValue.split(';')
+        for v in all_values:
+            if match == 'MatchDevicePath':
+                v = device_glob(v)
+            elif match == 'MatchPnPID' and len(v) < 7:
+                v += '*'
+            if value:
+                value += '|' + v
+            else:
+                value = v
+
+    return (match, value)
+
+def parse_options(node):
+    '''Parse the x11_* options and return InputClass entries'''
+    driver = ''
+    ignore = False
+    options = []
+    for n in node.childNodes:
+        if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
+            continue
+
+        tag = n.tagName
+        key = n.attributes['key'].nodeValue
+        value = ''
+
+        if n.hasChildNodes():
+            content_node = n.childNodes[0]
+            assert content_node.nodeType == xml.dom.Node.TEXT_NODE
+            value = content_node.nodeValue
+
+        if tag == 'match':
+            continue
+        assert tag in ('addset', 'merge', 'append', 'remove')
+
+        if tag == 'remove' and key == 'input.x11_driver':
+            ignore = True
+        elif key == 'input.x11_driver':
+            driver = value
+        elif key.startswith('input.x11_options.'):
+            option = key.split('.', 2)[2]
+            options.append((option, value))
+
+    return (driver, ignore, options)
+
+def is_match_node(node):
+    '''Check if a node is a <match> element'''
+    return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
+        node.tagName == 'match'
+
+def parse_all_matches(node):
+    '''Parse a x11 match tag and any parents that don't supply their
+    own options'''
+    matches = []
+
+    while True:
+        (key, value) = parse_match(node)
+        if key and value:
+            matches.append((key, value))
+
+        # walk up to a parent match node
+        node = node.parentNode
+        if node == None or not is_match_node(node):
+            break
+
+        # leave if there other options at this level
+        children = set([n.tagName for n in node.childNodes
+                        if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
+        if children & set(['addset', 'merge', 'append']):
+            break
+
+    return matches
+
+# stupid counter to give "unique" rule names
+num_sections = 1
+def print_section(matches, driver, ignore, options):
+    '''Print a valid InputClass section to stdout'''
+    global num_sections
+    print 'Section "InputClass"'
+    print '\tIdentifier "Converted Class %d"' % num_sections
+    num_sections += 1
+    for m, v in matches:
+        print '\t%s "%s"' % (m, v)
+    if driver:
+        print '\tDriver "%s"' % driver
+    if ignore:
+        print '\tOption "Ignore" "yes"'
+    for o, v in options:
+        print '\tOption "%s" "%s"' % (o, v)
+    print 'EndSection'
+
+def parse_fdi(fdi):
+    '''Parse x11 matches from fdi'''
+    # find all <match> leaf nodes
+    num = 0
+    for match_node in fdi.getElementsByTagName('match'):
+        children = set([n.tagName for n in match_node.childNodes
+                if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
+
+        # see if there are any options at this level
+        (driver, ignore, options) = parse_options(match_node)
+        if not driver and not ignore and not options:
+            continue
+
+        matches = parse_all_matches(match_node)
+        if num > 0:
+            print
+        print_section(matches, driver, ignore, options)
+        num += 1
+
+for f in sys.argv[1:]:
+    parse_fdi(xml.dom.minidom.parse(f))
commit 87a1507da7e7788232d74285ef377b67b70e0fa4
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Thu Jun 10 06:15:41 2010 -0700

    xfree86: Match devices based on USB ID
    
    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>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

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);
commit 645679c1523eee7028f3244cee57936b93326a2a
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Thu Jun 10 06:11:10 2010 -0700

    xfree86: Match devices based on PnP ID
    
    Serial input devices lack properties such as product or vendor name. This
    makes matching InputClass sections difficult. Add a MatchPnPID entry to
    test against the PnP ID of the device. The entry supports a shell pattern
    match on platforms that support fnmatch(3). For example:
    
    	MatchPnPID "WACf*"
    
    A match type for non-path pattern matching, match_pattern, has been added.
    The difference between this and match_path_pattern is the FNM_PATHNAME
    flag in fnmatch(3).
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/config/hal.c b/config/hal.c
index e0ff842..8061020 100644
--- a/config/hal.c
+++ b/config/hal.c
@@ -129,7 +129,7 @@ static void
 device_added(LibHalContext *hal_ctx, const char *udi)
 {
     char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
-    char *hal_tags;
+    char *hal_tags, *parent;
     InputOption *options = NULL, *tmpo = NULL;
     InputAttributes attrs = {0};
     DeviceIntPtr dev = NULL;
@@ -182,6 +182,12 @@ device_added(LibHalContext *hal_ctx, const char *udi)
     if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
         attrs.flags |= ATTR_TOUCHSCREEN;
 
+    parent = get_prop_string(hal_ctx, udi, "info.parent");
+    if (parent) {
+        attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
+        free(parent);
+    }
+
     options = calloc(sizeof(*options), 1);
     if (!options){
         LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n");
@@ -384,6 +390,7 @@ unwind:
     free(attrs.product);
     free(attrs.vendor);
     free(attrs.device);
+    free(attrs.pnp_id);
     if (attrs.tags) {
         char **tag = attrs.tags;
         while (*tag) {
diff --git a/config/udev.c b/config/udev.c
index 5d001de..f7ed4b2 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -99,6 +99,9 @@ device_added(struct udev_device *udev_device)
             name = udev_device_get_property_value(parent, "NAME");
             LOG_PROPERTY(ppath, "NAME", name);
         }
+
+        attrs.pnp_id = udev_device_get_sysattr_value(parent, "id");
+        LOG_SYSATTR(ppath, "id", attrs.pnp_id);
     }
     if (!name)
         name = "(unnamed)";
diff --git a/dix/inpututils.c b/dix/inpututils.c
index df2ace0..aa240dd 100644
--- a/dix/inpututils.c
+++ b/dix/inpututils.c
@@ -357,6 +357,8 @@ DuplicateInputAttributes(InputAttributes *attrs)
         goto unwind;
     if (attrs->device && !(new_attr->device = strdup(attrs->device)))
         goto unwind;
+    if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
+        goto unwind;
 
     new_attr->flags = attrs->flags;
 
@@ -401,6 +403,7 @@ FreeInputAttributes(InputAttributes *attrs)
     free(attrs->product);
     free(attrs->vendor);
     free(attrs->device);
+    free(attrs->pnp_id);
 
     if ((tags = attrs->tags))
         while(*tags)
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 0f6ccc1..5b0ec8f 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -532,6 +532,16 @@ match_substring(const char *attr, const char *pattern)
 
 #ifdef HAVE_FNMATCH_H
 static int
+match_pattern(const char *attr, const char *pattern)
+{
+    return fnmatch(pattern, attr, 0);
+}
+#else
+#define match_pattern match_substring
+#endif
+
+#ifdef HAVE_FNMATCH_H
+static int
 match_path_pattern(const char *attr, const char *pattern)
 {
     return fnmatch(pattern, attr, FNM_PATHNAME);
@@ -590,6 +600,10 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
     if (!MatchAttrToken(HostOS(), iclass->match_os, strcasecmp))
         return FALSE;
 
+    /* MatchPnPID pattern */
+    if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, 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 50d4f36..c17ecb9 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1095,6 +1095,12 @@ string. This entry is only supported on platforms providing the
 system call. Multiple operating systems can be matched by separating arguments
 with a '|' character.
 .TP 7
+.BI "MatchPnPID \*q" matchpnp \*q
+The device's Plug and Play (PnP) ID can be checked against the
+.RI \*q matchpnp \*q
+shell wildcard pattern. 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 20ebfb5..e5ef96c 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -48,6 +48,7 @@ xf86ConfigSymTabRec InputClassTab[] =
     {MATCH_VENDOR, "matchvendor"},
     {MATCH_DEVICE_PATH, "matchdevicepath"},
     {MATCH_OS, "matchos"},
+    {MATCH_PNPID, "matchpnpid"},
     {MATCH_TAG, "matchtag"},
     {MATCH_IS_KEYBOARD, "matchiskeyboard"},
     {MATCH_IS_POINTER, "matchispointer"},
@@ -114,6 +115,11 @@ xf86parseInputClassSection(void)
                 Error(QUOTE_MSG, "MatchOS");
             ptr->match_os = xstrtokenize(val.str, TOKEN_SEP);
             break;
+        case MATCH_PNPID:
+            if (xf86getSubToken(&(ptr->comment)) != STRING)
+                Error(QUOTE_MSG, "MatchPnPID");
+            ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP);
+            break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
@@ -231,6 +237,14 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
                         *list);
             fprintf(cf, "\"\n");
         }
+        if (ptr->match_pnpid) {
+            fprintf(cf, "\tMatchPnPID      \"");
+            for (list = ptr->match_pnpid; *list; list++)
+                fprintf(cf, "%s%s",
+                        list == ptr->match_pnpid ? "" : TOKEN_SEP,
+                        *list);
+            fprintf(cf, "\"\n");
+        }
         if (ptr->match_tag) {
             fprintf(cf, "\tMatchTag \"");
             for (list = ptr->match_tag; *list; list++)
@@ -292,6 +306,11 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
                 free(*list);
             free(ptr->match_os);
         }
+        if (ptr->match_pnpid) {
+            for (list = ptr->match_pnpid; *list; list++)
+                free(*list);
+            free(ptr->match_pnpid);
+        }
         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 3623ca1..87fc31c 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -347,6 +347,7 @@ typedef struct
 	char **match_vendor;
 	char **match_device;
 	char **match_os;
+	char **match_pnpid;
 	char **match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index fd13d6d..aa33935 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -280,6 +280,7 @@ typedef enum {
     MATCH_VENDOR,
     MATCH_DEVICE_PATH,
     MATCH_OS,
+    MATCH_PNPID,
     MATCH_TAG,
     MATCH_IS_KEYBOARD,
     MATCH_IS_POINTER,
diff --git a/include/input.h b/include/input.h
index c68a284..5969693 100644
--- a/include/input.h
+++ b/include/input.h
@@ -215,6 +215,7 @@ typedef struct _InputAttributes {
     char                *product;
     char                *vendor;
     char                *device;
+    char                *pnp_id;
     char                **tags; /* null-terminated */
     uint32_t            flags;
 } InputAttributes;
diff --git a/test/input.c b/test/input.c
index 12771c5..dd197dd 100644
--- a/test/input.c
+++ b/test/input.c
@@ -801,6 +801,13 @@ static void cmp_attr_fields(InputAttributes *attr1,
     } else
         g_assert(attr2->device == NULL);
 
+    if (attr1->pnp_id != NULL)
+    {
+        g_assert(attr1->pnp_id != attr2->pnp_id);
+        g_assert(strcmp(attr1->pnp_id, attr2->pnp_id) == 0);
+    } else
+        g_assert(attr2->pnp_id == NULL);
+
     tags1 = attr1->tags;
     tags2 = attr2->tags;
 
@@ -866,6 +873,11 @@ static void dix_input_attributes(void)
     cmp_attr_fields(&orig, new);
     FreeInputAttributes(new);
 
+    orig.pnp_id = "PnPID";
+    new = DuplicateInputAttributes(&orig);
+    cmp_attr_fields(&orig, new);
+    FreeInputAttributes(new);
+
     orig.flags = 0xF0;
     new = DuplicateInputAttributes(&orig);
     cmp_attr_fields(&orig, new);
commit d1b4beecbc16448282dcc825dd5c354e96e48eca
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:53 2010 -0700

    xfree86: Add MatchOS InputClass entry for operating system matching
    
    Allow InputClass sections to match against the running operating system
    to narrow the application of rules. An example where this could be used
    is to specify that the default input driver on Linux is evdev while it's
    mouse/kbd everywhere else.
    
    The operating system name is the same as `uname -s`, and matching is
    case-insensitive.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/configure.ac b/configure.ac
index c8b49de..81b6e4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -123,7 +123,7 @@ AM_CONDITIONAL(SPECIAL_DTRACE_OBJECTS, [test "x$SPECIAL_DTRACE_OBJECTS" = "xyes"
 
 AC_HEADER_DIRENT
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.h])
+AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.h sys/utsname.h])
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 58e09cc..0f6ccc1 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -80,6 +80,9 @@
 #ifdef HAVE_FNMATCH_H
 #include <fnmatch.h>
 #endif
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
 
 #include "extnsionst.h"
 
@@ -496,6 +499,31 @@ AddOtherInputDevices(void)
 {
 }
 
+/*
+ * Get the operating system name from uname and store it statically to avoid
+ * repeating the system call each time MatchOS is checked.
+ */
+static const char *
+HostOS(void)
+{
+#ifdef HAVE_SYS_UTSNAME_H
+    struct utsname name;
+    static char host_os[sizeof(name.sysname)] = "";
+
+    if (*host_os == '\0') {
+        if (uname(&name) >= 0)
+            strcpy(host_os, name.sysname);
+        else {
+            strncpy(host_os, "unknown", sizeof(host_os));
+            host_os[sizeof(host_os)-1] = '\0';
+        }
+    }
+    return host_os;
+#else
+    return "";
+#endif
+}
+
 static int
 match_substring(const char *attr, const char *pattern)
 {
@@ -558,6 +586,10 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
     if (!MatchAttrToken(attrs->device, iclass->match_device, match_path_pattern))
         return FALSE;
 
+    /* MatchOS case-insensitive string */
+    if (!MatchAttrToken(HostOS(), iclass->match_os, strcasecmp))
+        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 9075db6..50d4f36 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1086,6 +1086,15 @@ This entry can be used to check if the device file matches the
 pathname pattern. Multiple patterns can be matched by separating arguments
 with a '|' character.
 .TP 7
+.BI "MatchOS \*q" matchos \*q
+This entry can be used to check if the operating system matches the
+case-insensitive
+.RI \*q matchos \*q
+string. This entry is only supported on platforms providing the
+.BR uname (2)
+system call. Multiple operating systems 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 7fb2866..20ebfb5 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -47,6 +47,7 @@ xf86ConfigSymTabRec InputClassTab[] =
     {MATCH_PRODUCT, "matchproduct"},
     {MATCH_VENDOR, "matchvendor"},
     {MATCH_DEVICE_PATH, "matchdevicepath"},
+    {MATCH_OS, "matchos"},
     {MATCH_TAG, "matchtag"},
     {MATCH_IS_KEYBOARD, "matchiskeyboard"},
     {MATCH_IS_POINTER, "matchispointer"},
@@ -108,6 +109,11 @@ xf86parseInputClassSection(void)
                 Error(QUOTE_MSG, "MatchDevicePath");
             ptr->match_device = xstrtokenize(val.str, TOKEN_SEP);
             break;
+        case MATCH_OS:
+            if (xf86getSubToken(&(ptr->comment)) != STRING)
+                Error(QUOTE_MSG, "MatchOS");
+            ptr->match_os = xstrtokenize(val.str, TOKEN_SEP);
+            break;
         case MATCH_TAG:
             if (xf86getSubToken(&(ptr->comment)) != STRING)
                 Error(QUOTE_MSG, "MatchTag");
@@ -217,6 +223,14 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
                         *list);
             fprintf(cf, "\"\n");
         }
+        if (ptr->match_os) {
+            fprintf(cf, "\tMatchOS         \"");
+            for (list = ptr->match_os; *list; list++)
+                fprintf(cf, "%s%s",
+                        list == ptr->match_os ? "" : TOKEN_SEP,
+                        *list);
+            fprintf(cf, "\"\n");
+        }
         if (ptr->match_tag) {
             fprintf(cf, "\tMatchTag \"");
             for (list = ptr->match_tag; *list; list++)
@@ -273,6 +287,11 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
                 free(*list);
             free(ptr->match_device);
         }
+        if (ptr->match_os) {
+            for (list = ptr->match_os; *list; list++)
+                free(*list);
+            free(ptr->match_os);
+        }
         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 d79544a..3623ca1 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -346,6 +346,7 @@ typedef struct
 	char **match_product;
 	char **match_vendor;
 	char **match_device;
+	char **match_os;
 	char **match_tag;
 	xf86TriState is_keyboard;
 	xf86TriState is_pointer;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index cb60070..fd13d6d 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -279,6 +279,7 @@ typedef enum {
     MATCH_PRODUCT,
     MATCH_VENDOR,
     MATCH_DEVICE_PATH,
+    MATCH_OS,
     MATCH_TAG,
     MATCH_IS_KEYBOARD,
     MATCH_IS_POINTER,
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 7759aac..6a33264 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -222,6 +222,9 @@
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
 /* Define to 1 if you have the <sys/vm86.h> header file. */
 #undef HAVE_SYS_VM86_H
 
commit 9b30fa9f8fedb7ddb5672f93ed1a154d13578c47
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:52 2010 -0700

    xfree86: Refactor InputClass matching code
    
    InputClassMatches was starting to get a little hairy with all the loops
    over the tokenized match strings. This adds code, but makes it easier to
    read and add new matches.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Jamey Sharp <jamey at minilop.net>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index 6e5132c..58e09cc 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -496,6 +496,48 @@ AddOtherInputDevices(void)
 {
 }
 
+static int
+match_substring(const char *attr, const char *pattern)
+{
+    return (strstr(attr, pattern)) ? 0 : -1;
+}
+
+#ifdef HAVE_FNMATCH_H
+static int
+match_path_pattern(const char *attr, const char *pattern)
+{
+    return fnmatch(pattern, attr, FNM_PATHNAME);
+}
+#else
+#define match_path_pattern match_substring
+#endif
+
+/*
+ * Match an attribute against a NULL terminated list of patterns. If any
+ * pattern is matched, return TRUE.
+ */
+static Bool
+MatchAttrToken(const char *attr, char **patterns,
+               int (*compare)(const char *attr, const char *pattern))
+{
+    char **cur;
+
+    /* If there are no patterns, accept the match */
+    if (!patterns)
+        return TRUE;
+
+    /* If there are patterns but no attribute, reject the match */
+    if (!attr)
+        return FALSE;
+
+    /* Otherwise, iterate the patterns looking for a match */
+    for (cur = patterns; *cur; cur++)
+        if ((*compare)(attr, *cur) == 0)
+            return TRUE;
+
+    return FALSE;
+}
+
 /*
  * Classes without any Match statements match all devices. Otherwise, all
  * statements must match.
@@ -504,67 +546,39 @@ static Bool
 InputClassMatches(const XF86ConfInputClassPtr iclass,
                   const InputAttributes *attrs)
 {
-    char **cur;
-    Bool match;
+    /* MatchProduct substring */
+    if (!MatchAttrToken(attrs->product, iclass->match_product, match_substring))
+        return FALSE;
 
-    if (iclass->match_product) {
-        if (!attrs->product)
-            return FALSE;
-        /* see if any of the values match */
-        for (cur = iclass->match_product, match = FALSE; *cur; cur++)
-            if (strstr(attrs->product, *cur)) {
-                match = TRUE;
-                break;
-            }
-        if (!match)
-            return FALSE;
-    }
-    if (iclass->match_vendor) {
-        if (!attrs->vendor)
-            return FALSE;
-        /* see if any of the values match */
-        for (cur = iclass->match_vendor, match = FALSE; *cur; cur++)
-            if (strstr(attrs->vendor, *cur)) {
-                match = TRUE;
-                break;
-            }
-        if (!match)
-            return FALSE;
-    }
-    if (iclass->match_device) {
-        if (!attrs->device)
-            return FALSE;
-        /* see if any of the values match */
-        for (cur = iclass->match_device, match = FALSE; *cur; cur++)
-#ifdef HAVE_FNMATCH_H
-            if (fnmatch(*cur, attrs->device, FNM_PATHNAME) == 0) {
-#else
-            if (strstr(attrs->device, *cur)) {
-#endif
-                match = TRUE;
-                break;
-            }
-        if (!match)
-            return FALSE;
-    }
+    /* MatchVendor substring */
+    if (!MatchAttrToken(attrs->vendor, iclass->match_vendor, match_substring))
+        return FALSE;
+
+    /* MatchDevicePath pattern */
+    if (!MatchAttrToken(attrs->device, iclass->match_device, match_path_pattern))
+        return FALSE;
+
+    /*
+     * MatchTag string
+     * See if any of the device's tags match any of the MatchTag tokens.
+     */
     if (iclass->match_tag) {
+        char * const *tag;
+        Bool match;
+
         if (!attrs->tags)
             return FALSE;
-
-        for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) {
-            char * const *tag;
-            for(tag = attrs->tags; *tag; tag++) {
-                if (!strcmp(*tag, *cur)) {
-                    match = TRUE;
-                    break;
-                }
+        for (tag = attrs->tags, match = FALSE; *tag; tag++) {
+            if (MatchAttrToken(*tag, iclass->match_tag, strcmp)) {
+                match = TRUE;
+                break;
             }
         }
-
         if (!match)
             return FALSE;
     }
 
+    /* MatchIs* booleans */
     if (iclass->is_keyboard.set &&
         iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
         return FALSE;
@@ -583,6 +597,7 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
     if (iclass->is_touchscreen.set &&
         iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
         return FALSE;
+
     return TRUE;
 }
 
commit d09bc8f8e5bb92899f7c90eab6b0907920c7d643
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:51 2010 -0700

    xfree86: Constify InputClass functions
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index c3a1ddd..6e5132c 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -501,7 +501,8 @@ AddOtherInputDevices(void)
  * statements must match.
  */
 static Bool
-InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
+InputClassMatches(const XF86ConfInputClassPtr iclass,
+                  const InputAttributes *attrs)
 {
     char **cur;
     Bool match;
@@ -591,7 +592,7 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
  * well as any previous InputClass sections.
  */
 static int
-MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
+MergeInputClasses(const IDevPtr idev, const InputAttributes *attrs)
 {
     XF86ConfInputClassPtr cl;
     XF86OptionPtr classopts, mergedopts = NULL;
@@ -630,7 +631,7 @@ MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
  * value of the last matching class and holler when returning TRUE.
  */
 static Bool
-IgnoreInputClass(IDevPtr idev, InputAttributes *attrs)
+IgnoreInputClass(const IDevPtr idev, const InputAttributes *attrs)
 {
     XF86ConfInputClassPtr cl;
     Bool ignore = FALSE;
commit 61c35d8ac4b6423caf2dcecb4ff25baaaaa14b1c
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:50 2010 -0700

    config/hal: Missing newline in log message
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/config/hal.c b/config/hal.c
index b5a350f..e0ff842 100644
--- a/config/hal.c
+++ b/config/hal.c
@@ -622,7 +622,7 @@ config_hal_init(void)
     }
 
     /* verbose message */
-    LogMessageVerb(X_INFO,7,"config/hal: initialized");
+    LogMessageVerb(X_INFO,7,"config/hal: initialized\n");
 
     return 1;
 }
commit 697c5b010d7f6df0ec9cae6352b125c4cbdbaad3
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:49 2010 -0700

    config/udev: Add verbose info when fetching udev properties
    
    Give the user a chance to see why their input devices are being ignored,
    even if they have to start the server with -logverbose.
    
    Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/config/udev.c b/config/udev.c
index 5e8d8da..5d001de 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -37,6 +37,17 @@
 
 #define UDEV_XKB_PROP_KEY "xkb"
 
+#define LOG_PROPERTY(path, prop, val)                                   \
+    LogMessageVerb(X_INFO, 10,                                          \
+                   "config/udev: getting property %s on %s "            \
+                   "returned \"%s\"\n",                                 \
+                   (prop), (path), (val) ? (val) : "(null)")
+#define LOG_SYSATTR(path, attr, val)                                    \
+    LogMessageVerb(X_INFO, 10,                                          \
+                   "config/udev: getting attribute %s on %s "           \
+                   "returned \"%s\"\n",                                 \
+                   (attr), (path), (val) ? (val) : "(null)")
+
 static struct udev_monitor *udev_monitor;
 
 static void
@@ -45,6 +56,7 @@ device_added(struct udev_device *udev_device)
     const char *path, *name = NULL;
     char *config_info = NULL;
     const char *syspath;
+    const char *tags_prop;
     const char *key, *value, *tmp;
     InputOption *options = NULL, *tmpo;
     InputAttributes attrs = {};
@@ -60,8 +72,13 @@ device_added(struct udev_device *udev_device)
     if (!path || !syspath)
         return;
 
-    if (!udev_device_get_property_value(udev_device, "ID_INPUT"))
+    if (!udev_device_get_property_value(udev_device, "ID_INPUT")) {
+        LogMessageVerb(X_INFO, 10,
+                       "config/udev: ignoring device %s without "
+                       "property ID_INPUT set\n",
+                       path);
         return;
+    }
 
     options = calloc(sizeof(*options), 1);
     if (!options)
@@ -74,9 +91,14 @@ device_added(struct udev_device *udev_device)
 
     parent = udev_device_get_parent(udev_device);
     if (parent) {
+        const char *ppath = udev_device_get_devnode(parent);
+
         name = udev_device_get_sysattr_value(parent, "name");
-        if (!name)
+        LOG_SYSATTR(ppath, "name", name);
+        if (!name) {
             name = udev_device_get_property_value(parent, "NAME");
+            LOG_PROPERTY(ppath, "NAME", name);
+        }
     }
     if (!name)
         name = "(unnamed)";
@@ -87,7 +109,10 @@ device_added(struct udev_device *udev_device)
     add_option(&options, "path", path);
     add_option(&options, "device", path);
     attrs.device = path;
-    attrs.tags = xstrtokenize(udev_device_get_property_value(udev_device, "ID_INPUT.tags"), ",");
+
+    tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
+    LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
+    attrs.tags = xstrtokenize(tags_prop, ",");
 
     config_info = Xprintf("udev:%s", syspath);
     if (!config_info)
@@ -107,6 +132,7 @@ device_added(struct udev_device *udev_device)
         value = udev_list_entry_get_value(entry);
         if (!strncasecmp(key, UDEV_XKB_PROP_KEY,
                                 sizeof(UDEV_XKB_PROP_KEY) - 1)) {
+            LOG_PROPERTY(path, key, value);
             tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
             if (!strcasecmp(tmp, "rules"))
                 add_option(&options, "xkb_rules", value);
@@ -119,18 +145,25 @@ device_added(struct udev_device *udev_device)
             else if (!strcasecmp(tmp, "options"))
                 add_option(&options, "xkb_options", value);
         } else if (!strcmp(key, "ID_VENDOR")) {
+            LOG_PROPERTY(path, key, value);
             attrs.vendor = value;
         } else if (!strcmp(key, "ID_INPUT_KEY")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_KEYBOARD;
         } else if (!strcmp(key, "ID_INPUT_MOUSE")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_POINTER;
         } else if (!strcmp(key, "ID_INPUT_JOYSTICK")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_JOYSTICK;
         } else if (!strcmp(key, "ID_INPUT_TABLET")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_TABLET;
         } else if (!strcmp(key, "ID_INPUT_TOUCHPAD")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_TOUCHPAD;
         } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
+            LOG_PROPERTY(path, key, value);
             attrs.flags |= ATTR_TOUCHSCREEN;
         }
     }
commit 94547b2d1448232ae316c228d65482cc0b646ac2
Author: Dan Nicholson <dbn.lists at gmail.com>
Date:   Mon Jun 7 20:39:48 2010 -0700

    config/hal: don't leak the input.tags property
    
    Signed-off-by: Julien Cristau <jcristau at debian.org>
    Reviewed-by: Dan Nicholson <dbn.lists at gmail.com>
    Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

diff --git a/config/hal.c b/config/hal.c
index 5938d4e..b5a350f 100644
--- a/config/hal.c
+++ b/config/hal.c
@@ -129,6 +129,7 @@ static void
 device_added(LibHalContext *hal_ctx, const char *udi)
 {
     char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
+    char *hal_tags;
     InputOption *options = NULL, *tmpo = NULL;
     InputAttributes attrs = {0};
     DeviceIntPtr dev = NULL;
@@ -164,7 +165,9 @@ device_added(LibHalContext *hal_ctx, const char *udi)
         attrs.product = xstrdup(name);
 
     attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
-    attrs.tags = xstrtokenize(get_prop_string(hal_ctx, udi, "input.tags"), ",");
+    hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
+    attrs.tags = xstrtokenize(hal_tags, ",");
+    free(hal_tags);
 
     if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
         attrs.flags |= ATTR_KEYBOARD;


More information about the xorg-commit mailing list