Merge remote branch 'whot/for-keith'

This commit is contained in:
Keith Packard 2010-06-10 18:39:10 -07:00
commit 07a093add0
16 changed files with 719 additions and 144 deletions

View File

@ -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");

View File

@ -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

View File

@ -27,7 +27,6 @@
#include <dix-config.h>
#endif
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <string.h>

202
config/fdi2iclass.py Executable file
View File

@ -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@gmail.com>
# Author: Martin Pitt <martin.pitt@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))

View File

@ -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, *parent;
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;
@ -179,6 +182,29 @@ 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) {
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);
}
options = calloc(sizeof(*options), 1);
if (!options){
LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n");
@ -381,6 +407,8 @@ unwind:
free(attrs.product);
free(attrs.vendor);
free(attrs.device);
free(attrs.pnp_id);
free(attrs.usb_id);
if (attrs.tags) {
char **tag = attrs.tags;
while (*tag) {
@ -619,7 +647,7 @@ config_hal_init(void)
}
/* verbose message */
LogMessageVerb(X_INFO,7,"config/hal: initialized");
LogMessageVerb(X_INFO,7,"config/hal: initialized\n");
return 1;
}

View File

@ -28,6 +28,7 @@
#endif
#include <libudev.h>
#include <ctype.h>
#include "input.h"
#include "inputstr.h"
@ -37,6 +38,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 +57,8 @@ 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 *usb_vendor = NULL, *usb_model = NULL;
const char *key, *value, *tmp;
InputOption *options = NULL, *tmpo;
InputAttributes attrs = {};
@ -60,8 +74,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 +93,17 @@ 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);
}
attrs.pnp_id = udev_device_get_sysattr_value(parent, "id");
LOG_SYSATTR(ppath, "id", attrs.pnp_id);
}
if (!name)
name = "(unnamed)";
@ -87,7 +114,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 +137,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,21 +150,45 @@ 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_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;
} 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;
}
}
/* 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);
@ -154,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) {

View File

@ -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
@ -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

View File

@ -357,6 +357,10 @@ 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;
if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
goto unwind;
new_attr->flags = attrs->flags;
@ -401,6 +405,8 @@ FreeInputAttributes(InputAttributes *attrs)
free(attrs->product);
free(attrs->vendor);
free(attrs->device);
free(attrs->pnp_id);
free(attrs->usb_id);
if ((tags = attrs->tags))
while(*tags)

View File

@ -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,74 +499,153 @@ 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)
{
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)
{
return fnmatch(pattern, attr, FNM_PATHNAME);
}
#else
#define match_path_pattern match_substring
#endif
/*
* 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, struct list *patterns,
int (*compare)(const char *attr, const char *pattern))
{
const xf86MatchGroup *group;
/* If there are no patterns, accept the match */
if (list_is_empty(patterns))
return TRUE;
/* If there are patterns but no attribute, reject the match */
if (!attr)
return FALSE;
/*
* 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;
}
/* All the entries in the list matched the attribute */
return TRUE;
}
/*
* Classes without any Match statements match all devices. Otherwise, all
* statements must match.
*/
static Bool
InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
InputClassMatches(const XF86ConfInputClassPtr iclass, const IDevPtr idev,
const InputAttributes *attrs)
{
char **cur;
Bool match;
/* MatchProduct substring */
if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
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;
/* MatchOS case-insensitive string */
if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
return FALSE;
/* MatchPnPID 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))
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.
*/
if (!list_is_empty(&iclass->match_tag)) {
char * const *tag;
Bool match;
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;
}
if (iclass->match_tag) {
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;
@ -582,6 +664,7 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
if (iclass->is_touchscreen.set &&
iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
return FALSE;
return TRUE;
}
@ -591,37 +674,36 @@ 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;
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;
}
@ -630,14 +712,14 @@ 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;
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);

View File

@ -1065,35 +1065,85 @@ 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
case-insensitive
.RI \*q matchos \*q
string. This entry is only supported on platforms providing the
.BR uname (2)
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.
.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.
.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
.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
@ -1106,9 +1156,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

View File

@ -47,6 +47,10 @@ xf86ConfigSymTabRec InputClassTab[] =
{MATCH_PRODUCT, "matchproduct"},
{MATCH_VENDOR, "matchvendor"},
{MATCH_DEVICE_PATH, "matchdevicepath"},
{MATCH_OS, "matchos"},
{MATCH_PNPID, "matchpnpid"},
{MATCH_USBID, "matchusbid"},
{MATCH_DRIVER, "matchdriver"},
{MATCH_TAG, "matchtag"},
{MATCH_IS_KEYBOARD, "matchiskeyboard"},
{MATCH_IS_POINTER, "matchispointer"},
@ -61,6 +65,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)
{
@ -69,6 +85,16 @@ 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_driver);
list_init(&ptr->match_tag);
while ((token = xf86getToken(InputClassTab)) != ENDSECTION) {
switch (token) {
case COMMENT:
@ -96,22 +122,50 @@ 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");
add_group_entry(&ptr->match_os,
xstrtokenize(val.str, TOKEN_SEP));
break;
case MATCH_PNPID:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchPnPID");
add_group_entry(&ptr->match_pnpid,
xstrtokenize(val.str, TOKEN_SEP));
break;
case MATCH_USBID:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchUSBID");
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");
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)
@ -183,7 +237,8 @@ xf86parseInputClassSection(void)
void
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
{
char **list;
const xf86MatchGroup *group;
char * const *cur;
while (ptr) {
fprintf(cf, "Section \"InputClass\"\n");
@ -193,38 +248,64 @@ 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_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_os, entry) {
fprintf(cf, "\tMatchOS \"");
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_pnpid, entry) {
fprintf(cf, "\tMatchPnPID \"");
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_usbid, entry) {
fprintf(cf, "\tMatchUSBID \"");
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_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++)
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");
@ -253,31 +334,63 @@ 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_tag) {
for (list = ptr->match_tag; *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_tag);
free(group);
}
list_for_each_entry_safe(group, next, &ptr->match_pnpid, entry) {
list_del(&group->entry);
for (list = group->values; *list; list++)
free(*list);
free(group);
}
list_for_each_entry_safe(group, next, &ptr->match_usbid, entry) {
list_del(&group->entry);
for (list = group->values; *list; list++)
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++)
free(*list);
free(group);
}
TestFree(ptr->comment);
xf86optionListFree(ptr->option_lst);

View File

@ -66,6 +66,7 @@
#include <X11/Xdefs.h>
#include "xf86Optrec.h"
#include "list.h"
#define HAVE_PARSER_DECLS
@ -338,15 +339,26 @@ 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_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_driver;
struct list match_tag;
xf86TriState is_keyboard;
xf86TriState is_pointer;
xf86TriState is_joystick;

View File

@ -279,6 +279,10 @@ typedef enum {
MATCH_PRODUCT,
MATCH_VENDOR,
MATCH_DEVICE_PATH,
MATCH_OS,
MATCH_PNPID,
MATCH_USBID,
MATCH_DRIVER,
MATCH_TAG,
MATCH_IS_KEYBOARD,
MATCH_IS_POINTER,

View File

@ -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

View File

@ -215,6 +215,8 @@ typedef struct _InputAttributes {
char *product;
char *vendor;
char *device;
char *pnp_id;
char *usb_id;
char **tags; /* null-terminated */
uint32_t flags;
} InputAttributes;

View File

@ -801,6 +801,20 @@ 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);
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;
@ -866,6 +880,16 @@ 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.usb_id = "USBID";
new = DuplicateInputAttributes(&orig);
cmp_attr_fields(&orig, new);
FreeInputAttributes(new);
orig.flags = 0xF0;
new = DuplicateInputAttributes(&orig);
cmp_attr_fields(&orig, new);