From d09bc8f8e5bb92899f7c90eab6b0907920c7d643 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 7 Jun 2010 20:39:51 -0700 Subject: xfree86: Constify InputClass functions Signed-off-by: Dan Nicholson Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- hw/xfree86/common/xf86Xinput.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index c3a1dddc4..6e5132c0e 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; -- cgit v1.2.3 From 9b30fa9f8fedb7ddb5672f93ed1a154d13578c47 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 7 Jun 2010 20:39:52 -0700 Subject: 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 Reviewed-by: Jamey Sharp Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- hw/xfree86/common/xf86Xinput.c | 117 +++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 51 deletions(-) (limited to 'hw') diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index 6e5132c0e..58e09cc83 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; } -- cgit v1.2.3 From d1b4beecbc16448282dcc825dd5c354e96e48eca Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 7 Jun 2010 20:39:53 -0700 Subject: 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- configure.ac | 2 +- hw/xfree86/common/xf86Xinput.c | 32 ++++++++++++++++++++++++++++++++ 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/dix-config.h.in | 3 +++ 7 files changed, 66 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/configure.ac b/configure.ac index c8b49debb..81b6e4c1c 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 58e09cc83..0f6ccc1ab 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -80,6 +80,9 @@ #ifdef HAVE_FNMATCH_H #include #endif +#ifdef HAVE_SYS_UTSNAME_H +#include +#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 9075db64f..50d4f3624 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 7fb2866cd..20ebfb503 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 d79544a20..3623ca16d 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 cb600704b..fd13d6d95 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 7759aac6a..6a332642b 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -222,6 +222,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UTSNAME_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VM86_H -- cgit v1.2.3 From 645679c1523eee7028f3244cee57936b93326a2a Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Thu, 10 Jun 2010 06:11:10 -0700 Subject: 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- config/hal.c | 9 ++++++++- config/udev.c | 3 +++ dix/inpututils.c | 3 +++ hw/xfree86/common/xf86Xinput.c | 14 ++++++++++++++ hw/xfree86/doc/man/xorg.conf.man.pre | 6 ++++++ 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, 68 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/config/hal.c b/config/hal.c index e0ff842ad..806102041 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 5d001de5e..f7ed4b2de 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 df2ace0bb..aa240dd74 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 0f6ccc1ab..5b0ec8f26 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -530,6 +530,16 @@ match_substring(const char *attr, const char *pattern) return (strstr(attr, pattern)) ? 0 : -1; } +#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) @@ -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 50d4f3624..c17ecb941 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 20ebfb503..e5ef96cde 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 3623ca16d..87fc31c5f 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 fd13d6d95..aa33935d1 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 c68a28441..5969693e1 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 12771c59a..dd197dd64 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); -- cgit v1.2.3 From 87a1507da7e7788232d74285ef377b67b70e0fa4 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Thu, 10 Jun 2010 06:15:41 -0700 Subject: 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- 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(+) (limited to 'hw') diff --git a/config/hal.c b/config/hal.c index 806102041..8f9aeb8d3 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 f7ed4b2de..16c462455 100644 --- a/config/udev.c +++ b/config/udev.c @@ -28,6 +28,7 @@ #endif #include +#include #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 aa240dd74..8ec80b5e8 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 5b0ec8f26..421803962 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 c17ecb941..63dbb68b1 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 e5ef96cde..bdcfba486 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 87fc31c5f..a86462f93 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 aa33935d1..23460dd73 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 5969693e1..0a08ea425 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 dd197dd64..b90d3b4fd 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); -- cgit v1.2.3 From a71bdff47d4cc80da6ceeb548db1dcc8e8b59702 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 7 Jun 2010 20:39:57 -0700 Subject: 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- hw/xfree86/common/xf86Xinput.c | 49 ++++++---- hw/xfree86/doc/man/xorg.conf.man.pre | 50 +++++++---- hw/xfree86/parser/InputClass.c | 167 +++++++++++++++++++++-------------- hw/xfree86/parser/xf86Parser.h | 22 +++-- 4 files changed, 179 insertions(+), 109 deletions(-) (limited to 'hw') diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index 421803962..fa0ed8592 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 63dbb68b1..f6b90be2c 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 bdcfba486..f2b46bb1c 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 a86462f93..26d9a5b33 100644 --- a/hw/xfree86/parser/xf86Parser.h +++ b/hw/xfree86/parser/xf86Parser.h @@ -66,6 +66,7 @@ #include #include "xf86Optrec.h" +#include "list.h" #define HAVE_PARSER_DECLS @@ -338,18 +339,25 @@ typedef struct } 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; -- cgit v1.2.3 From 66b21b2f455a1dfbc92f7caa571dcff3f3765808 Mon Sep 17 00:00:00 2001 From: Dan Nicholson Date: Mon, 7 Jun 2010 20:39:58 -0700 Subject: 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 Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- hw/xfree86/common/xf86Xinput.c | 47 +++++++++++++++++++----------------- hw/xfree86/doc/man/xorg.conf.man.pre | 9 +++++++ hw/xfree86/parser/InputClass.c | 21 ++++++++++++++++ hw/xfree86/parser/xf86Parser.h | 1 + hw/xfree86/parser/xf86tokens.h | 1 + 5 files changed, 57 insertions(+), 22 deletions(-) (limited to 'hw') diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index fa0ed8592..b2a1d1ffc 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 f6b90be2c..6b3636fff 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 f2b46bb1c..ce611d990 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 26d9a5b33..337ad0718 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 23460dd73..c16a8f551 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, -- cgit v1.2.3