On Thu, Jul 30, 2009 at 6:49 PM, Peter Hutterer<[email protected]> wrote:
> On Thu, Jul 30, 2009 at 08:21:52AM -0500, Dan Nicholson wrote:
>> On Wed, Jul 29, 2009 at 11:13 PM, Peter
>> Hutterer<[email protected]> wrote:
>> > I have poked at libudev a bit today in a weak effort to look what's 
>> > required
>> > to switch the X server over. I'd be happy if someone else takes over at
>> > this, but right now I don't see this happening for 1.7 anyway. Especially
>> > since the udev code I just wrote required me to put a big "i know this API
>> > will change" define in.
>>
>> Peter,
>>
>> I've been working on some patches to add an InputClass configuration
>> in the anticipation that when udev hotplugging shows up to the server
>> so we don't have to attempt to migrate people to a udev configuration.
>> Would you consider having a look at the patches before we add yet
>> another input device configuration system?
>
> sure, just send them my way. Are we talking about similar patches you did
> ages ago to get xorg.conf and HAL together?

Yes, but improved (IMO). I'm still not sure you'll like them, but this
adds an InputClass section where you can match on properties of the
device to apply settings. Basically, I think hal and udev should be
used for device notification and get out of the business of being our
configuration stores.

Have a look at these two patches. There are some of improvements I
have in mind, but this is the gist of it. Also, I just rebased them to
master, so I'm not sure they even build.

Let me know what you think.

--
Dan
From 43c0705549f5a52984efdbaf7067054201771e81 Mon Sep 17 00:00:00 2001
From: Dan Nicholson <[email protected]>
Date: Sun, 19 Jul 2009 10:50:16 -0700
Subject: [PATCH 1/2] xfree86: Introduce InputClass configuration

Currently Xorg uses hal's fdi files to decide what configuration options
are applied to automatically added input devices. This is sub-optimal
since it requires users to use a new and different configuration store
than xorg.conf.

The InputClass section attempts to provide a system similar to hal where
configuration can be applied to all devices with certain characteristics.
For now, devices can be matched either to a substring of the product name
via a NameMatch entry, or to a pathname pattern of the device file via a
DeviceMatch entry.

See the INPUTCLASS section in xorg.conf(5) for more details.

Signed-off-by: Dan Nicholson <[email protected]>
---
 configure.ac                         |    2 +-
 hw/xfree86/common/xf86Xinput.c       |   88 +++++++++++++++++
 hw/xfree86/doc/man/xorg.conf.man.pre |   73 ++++++++++++++
 hw/xfree86/parser/Configint.h        |    2 +
 hw/xfree86/parser/InputClass.c       |  171 ++++++++++++++++++++++++++++++++++
 hw/xfree86/parser/Makefile.am        |    1 +
 hw/xfree86/parser/configProcs.h      |    5 +
 hw/xfree86/parser/read.c             |    8 ++
 hw/xfree86/parser/write.c            |    2 +
 hw/xfree86/parser/xf86Parser.h       |   13 +++
 hw/xfree86/parser/xf86tokens.h       |    6 +-
 include/dix-config.h.in              |    3 +
 12 files changed, 372 insertions(+), 2 deletions(-)
 create mode 100644 hw/xfree86/parser/InputClass.c

diff --git a/configure.ac b/configure.ac
index 1e3438e..3287f9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,7 +113,7 @@ AM_CONDITIONAL(XSERVER_DTRACE, [test "x$WDTRACE" != "xno"])
 
 AC_HEADER_DIRENT
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h])
+AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h dlfcn.h stropts.h fnmatch.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 210f5bf..cb0f7b6 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -57,9 +57,11 @@
 #include <X11/Xatom.h>
 #include "xf86.h"
 #include "xf86Priv.h"
+#include "xf86Config.h"
 #include "xf86Xinput.h"
 #include "XIstubs.h"
 #include "xf86Optrec.h"
+#include "xf86Parser.h"
 #include "mipointer.h"
 #include "xf86InPriv.h"
 #include "compiler.h"
@@ -74,6 +76,11 @@
 #include "exglobals.h"
 #include "eventstr.h"
 
+#include <string.h>     /* InputClassMatches */
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
 #include "extnsionst.h"
 
 #include "windowstr.h"	/* screenIsSaved */
@@ -471,6 +478,82 @@ AddOtherInputDevices(void)
 {
 }
 
+/* Get the device file from the options, preferring Device to Path. */
+static char *
+InputDevicePath(XF86OptionPtr options)
+{
+    char *device;
+
+    if (!options)
+        return NULL;
+    device = xf86findOptionValue(options, "device");
+    if (!device)
+        device = xf86findOptionValue(options, "path");
+    return device;
+}
+
+/*
+ * Classes without any Match statements match all devices. Otherwise, all
+ * statements must match.
+ */
+static Bool
+InputClassMatches(XF86ConfInputClassPtr iclass, const char *name,
+                  const char *device)
+{
+    if (iclass->inc_name_match &&
+        (!name || !strstr(name, iclass->inc_name_match)))
+        return False;
+    if (iclass->inc_device_match &&
+#ifdef HAVE_FNMATCH_H
+        (!device || fnmatch(iclass->inc_device_match, device, 0) != 0))
+#else
+        (!device || !strstr(device, iclass->inc_device_match)))
+#endif
+        return False;
+    return True;
+}
+
+/*
+ * Merge in any InputClass configurations. Each InputClass section can
+ * override the original device configuration as well as any previous
+ * InputClass sections.
+ */
+static int
+MergeInputClasses(IDevPtr idev)
+{
+    XF86ConfInputClassPtr cl;
+    XF86OptionPtr tmp;
+
+    for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
+        /* Assume that the device's product name is its identifier. */
+        if (!InputClassMatches(cl, idev->identifier,
+            InputDevicePath(idev->commonOptions)))
+            continue;
+        xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
+                idev->identifier, cl->inc_identifier);
+
+        if (cl->inc_driver) {
+            if (idev->driver)
+                free(idev->driver);
+            idev->driver = xstrdup(cl->inc_driver);
+            if (!idev->driver) {
+                xf86Msg(X_ERROR, "Could not allocate memory while merging "
+                        "InputClass configuration");
+                return BadAlloc;
+            }
+        }
+
+        tmp = xf86optionListDup(cl->inc_option_lst);
+        if (idev->commonOptions)
+            idev->commonOptions = xf86optionListMerge(idev->commonOptions,
+                                                      tmp);
+        else
+            idev->commonOptions = tmp;
+    }
+
+    return Success;
+}
+
 /**
  * Create a new input device, activate and enable it.
  *
@@ -640,6 +723,11 @@ NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev)
         option->value = NULL;
     }
 
+    /* Apply InputClass settings */
+    rval = MergeInputClasses(idev);
+    if (rval != Success)
+        goto unwind;
+
     rval = xf86NewInputDevice(idev, pdev,
                 (!is_auto || (is_auto && xf86Info.autoEnableDevices)));
     if (rval == Success)
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index 634805a..9a338b6 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -117,6 +117,7 @@ The section names are:
 .BR "Module         " "Dynamic module loading"
 .BR "Extensions     " "Extension enabling"
 .BR "InputDevice    " "Input device description"
+.BR "InputClass     " "Input class description"
 .BR "Device         " "Graphics device description"
 .BR "VideoAdaptor   " "Xv video adaptor description"
 .BR "Monitor        " "Monitor description"
@@ -903,6 +904,78 @@ Default: 0.
 .TP 7
 .BI "Option \*qSendDragEvents\*q  \*q" boolean \*q
 ???
+.SH "INPUTCLASS SECTION"
+The config file may have multiple
+.B InputClass
+sections.
+These sections are optional and are used to provide configuration for a
+class of input devices as they are automatically added. An input device can
+match more than one
+.B InputClass
+section. Each class can add or update settings from a previous class.
+.PP
+.B InputClass
+sections have the following format:
+.PP
+.RS 4
+.nf
+.B  "Section \*qInputClass\*q"
+.BI "    Identifier  \*q" name \*q
+.BI "    NameMatch   \*q" namematch \*q
+.BI "    DeviceMatch \*q" devicematch \*q
+.BI "    Driver      \*q" inputdriver \*q
+.I  "    options"
+.I  "    ..."
+.B  "EndSection"
+.fi
+.RE
+.PP
+The
+.B Identifier
+and
+.B Driver
+entries are required in all
+.B InputClass
+sections.
+All other entries are optional.
+.PP
+The
+.B Identifier
+entry specifies the unique name for this input class.
+The
+.B Driver
+entry specifies the name of the driver to use for this input device.
+After all classes have been examined, the
+.RI \*q inputdriver \*q
+module from the final
+.B Driver
+entry will be enabled when using the loadable server.
+.PP
+When an input device is automatically added, its characteristics are
+checked against all
+.B InputClass
+sections. An optional
+.B NameMatch
+entry can be used to check if the substring
+.RI \*q namematch \*q
+occurs in the device's product name. An optional
+.B DeviceMatch
+entry can be used to check if the device file matches the pathname pattern
+.RI \*q devicematch \*q
+. If neither a
+.B NameMatch
+or a
+.B DeviceMatch
+entry appear, the
+.B InputClass
+section is generic and will match any input device. If both entries appear,
+both must match for the configuration to apply.
+.PP
+See the
+.B InputDevice
+section above for a description of the various
+.B Option
+entries.
 .SH "DEVICE SECTION"
 The config file may have multiple
 .B Device
diff --git a/hw/xfree86/parser/Configint.h b/hw/xfree86/parser/Configint.h
index cdc7be8..2359ebf 100644
--- a/hw/xfree86/parser/Configint.h
+++ b/hw/xfree86/parser/Configint.h
@@ -201,6 +201,8 @@ else\
 "This section must have only one of either %s line."
 #define UNDEFINED_INPUTDRIVER_MSG \
 "InputDevice section \"%s\" must have a Driver line."
+#define UNDEFINED_INPUTCLASSDRIVER_MSG \
+"InputClass section \"%s\" must have a Driver line."
 #define INVALID_GAMMA_MSG \
 "gamma correction value(s) expected\n either one value or three r/g/b values."
 #define GROUP_MSG \
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
new file mode 100644
index 0000000..6e915bc
--- /dev/null
+++ b/hw/xfree86/parser/InputClass.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2009 Dan Nicholson
+ *
+ * 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 furnished 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, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* View/edit this file with tab stops set to 4 */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "xf86Parser.h"
+#include "xf86tokens.h"
+#include "Configint.h"
+
+extern LexRec val;
+
+static
+xf86ConfigSymTabRec InputClassTab[] =
+{
+	{ENDSECTION, "endsection"},
+	{IDENTIFIER, "identifier"},
+	{OPTION, "option"},
+	{DRIVER, "driver"},
+	{NAME_MATCH, "namematch"},
+	{DEVICE_MATCH, "devicematch"},
+	{-1, ""},
+};
+
+#define CLEANUP xf86freeInputClassList
+
+XF86ConfInputClassPtr
+xf86parseInputClassSection(void)
+{
+	int has_ident = FALSE;
+	int token;
+	parsePrologue (XF86ConfInputClassPtr, XF86ConfInputClassRec)
+
+	while ((token = xf86getToken (InputClassTab)) != ENDSECTION)
+	{
+		switch (token)
+		{
+		case COMMENT:
+			ptr->inc_comment = xf86addComment(ptr->inc_comment,
+								val.str);
+			break;
+		case IDENTIFIER:
+			if (xf86getSubToken (&(ptr->inc_comment)) != STRING)
+				Error (QUOTE_MSG, "Identifier");
+			if (has_ident == TRUE)
+				Error (MULTIPLE_MSG, "Identifier");
+			ptr->inc_identifier = val.str;
+			has_ident = TRUE;
+			break;
+		case DRIVER:
+			if (xf86getSubToken (&(ptr->inc_comment)) != STRING)
+				Error (QUOTE_MSG, "Driver");
+                        if (strcmp(val.str, "keyboard") == 0)
+                            ptr->inc_driver = "kbd";
+                        else
+			    ptr->inc_driver = val.str;
+			break;
+		case OPTION:
+			ptr->inc_option_lst = xf86parseOption(ptr->inc_option_lst);
+			break;
+		case NAME_MATCH:
+			if (xf86getSubToken(&(ptr->inc_comment)) != STRING)
+				Error (QUOTE_MSG, "NameMatch");
+			ptr->inc_name_match = val.str;
+			break;
+		case DEVICE_MATCH:
+			if (xf86getSubToken(&(ptr->inc_comment)) != STRING)
+				Error (QUOTE_MSG, "DeviceMatch");
+			ptr->inc_device_match = val.str;
+			break;
+		case EOF_TOKEN:
+			Error (UNEXPECTED_EOF_MSG, NULL);
+			break;
+		default:
+			Error (INVALID_KEYWORD_MSG, xf86tokenString ());
+			break;
+		}
+	}
+
+	if (!has_ident)
+		Error (NO_IDENT_MSG, NULL);
+
+#ifdef DEBUG
+	printf ("InputClass section parsed\n");
+#endif
+
+	return ptr;
+}
+
+void
+xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
+{
+	while (ptr)
+	{
+		fprintf (cf, "Section \"InputClass\"\n");
+		if (ptr->inc_comment)
+			fprintf (cf, "%s", ptr->inc_comment);
+		if (ptr->inc_identifier)
+			fprintf (cf, "\tIdentifier  \"%s\"\n", ptr->inc_identifier);
+		if (ptr->inc_driver)
+			fprintf (cf, "\tDriver      \"%s\"\n", ptr->inc_driver);
+		if (ptr->inc_name_match)
+			fprintf (cf, "\tNameMatch   \"%s\"\n", ptr->inc_name_match);
+		if (ptr->inc_device_match)
+			fprintf (cf, "\tDeviceMatch \"%s\"\n", ptr->inc_device_match);
+		xf86printOptionList(cf, ptr->inc_option_lst, 1);
+		fprintf (cf, "EndSection\n\n");
+		ptr = ptr->list.next;
+	}
+}
+
+void
+xf86freeInputClassList (XF86ConfInputClassPtr ptr)
+{
+	XF86ConfInputClassPtr prev;
+
+	while (ptr)
+	{
+		TestFree (ptr->inc_identifier);
+		TestFree (ptr->inc_driver);
+		TestFree (ptr->inc_name_match);
+		TestFree (ptr->inc_device_match);
+		TestFree (ptr->inc_comment);
+		xf86optionListFree (ptr->inc_option_lst);
+
+		prev = ptr;
+		ptr = ptr->list.next;
+		free (prev);
+	}
+}
+
+int
+xf86validateInputClass (XF86ConfigPtr p)
+{
+	XF86ConfInputClassPtr input = p->conf_inputclass_lst;
+
+	while (input) {
+		if (!input->inc_driver) {
+			xf86validationError (UNDEFINED_INPUTCLASSDRIVER_MSG,
+						input->inc_identifier);
+			return (FALSE);
+		}
+		input = input->list.next;
+	}
+	return (TRUE);
+}
diff --git a/hw/xfree86/parser/Makefile.am b/hw/xfree86/parser/Makefile.am
index c062209..af781c4 100644
--- a/hw/xfree86/parser/Makefile.am
+++ b/hw/xfree86/parser/Makefile.am
@@ -12,6 +12,7 @@ libxf86config_la_SOURCES = \
 	Files.c \
 	Flags.c \
 	Input.c \
+	InputClass.c \
 	Layout.c \
 	Module.c \
 	Video.c \
diff --git a/hw/xfree86/parser/configProcs.h b/hw/xfree86/parser/configProcs.h
index 26ba40e..9c50ea0 100644
--- a/hw/xfree86/parser/configProcs.h
+++ b/hw/xfree86/parser/configProcs.h
@@ -48,6 +48,11 @@ XF86ConfInputPtr xf86parseInputSection(void);
 void xf86printInputSection(FILE *f, XF86ConfInputPtr ptr);
 void xf86freeInputList(XF86ConfInputPtr ptr);
 int xf86validateInput (XF86ConfigPtr p);
+/* InputClass.c */
+XF86ConfInputClassPtr xf86parseInputClassSection(void);
+void xf86printInputClassSection(FILE *f, XF86ConfInputClassPtr ptr);
+void xf86freeInputClassList(XF86ConfInputClassPtr ptr);
+int xf86validateInputClass(XF86ConfigPtr p);
 /* Layout.c */
 XF86ConfLayoutPtr xf86parseLayoutSection(void);
 void xf86printLayoutSection(FILE *cf, XF86ConfLayoutPtr ptr);
diff --git a/hw/xfree86/parser/read.c b/hw/xfree86/parser/read.c
index e965d20..1091be5 100644
--- a/hw/xfree86/parser/read.c
+++ b/hw/xfree86/parser/read.c
@@ -177,6 +177,14 @@ xf86readConfigFile (void)
 				HANDLE_LIST (conf_input_lst, xf86parseInputSection,
 							 XF86ConfInputPtr);
 			}
+			else if (xf86nameCompare(val.str, "inputclass") == 0)
+			{
+				free(val.str);
+				val.str = NULL;
+				HANDLE_LIST (conf_inputclass_lst,
+						xf86parseInputClassSection,
+						XF86ConfInputClassPtr);
+			}
 			else if (xf86nameCompare (val.str, "module") == 0)
 			{
 				free(val.str);
diff --git a/hw/xfree86/parser/write.c b/hw/xfree86/parser/write.c
index 3b77b93..083203c 100644
--- a/hw/xfree86/parser/write.c
+++ b/hw/xfree86/parser/write.c
@@ -117,6 +117,8 @@ doWriteConfigFile (const char *filename, XF86ConfigPtr cptr)
 
 	xf86printInputSection (cf, cptr->conf_input_lst);
 
+	xf86printInputClassSection (cf, cptr->conf_inputclass_lst);
+
 	xf86printVideoAdaptorSection (cf, cptr->conf_videoadaptor_lst);
 
 	xf86printModesSection (cf, cptr->conf_modes_lst);
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 6030800..a369598 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -330,6 +330,18 @@ typedef struct
 }
 XF86ConfInputrefRec, *XF86ConfInputrefPtr;
 
+typedef struct
+{
+	GenericListRec list;
+	char *inc_identifier;
+	char *inc_driver;
+	char *inc_name_match;
+	char *inc_device_match;
+	XF86OptionPtr inc_option_lst;
+	char *inc_comment;
+}
+XF86ConfInputClassRec, *XF86ConfInputClassPtr;
+
 /* Values for adj_where */
 #define CONF_ADJ_OBSOLETE	-1
 #define CONF_ADJ_ABSOLUTE	0
@@ -438,6 +450,7 @@ typedef struct
 	XF86ConfDevicePtr conf_device_lst;
 	XF86ConfScreenPtr conf_screen_lst;
 	XF86ConfInputPtr conf_input_lst;
+	XF86ConfInputClassPtr conf_inputclass_lst;
 	XF86ConfLayoutPtr conf_layout_lst;
 	XF86ConfVendorPtr conf_vendor_lst;
 	XF86ConfDRIPtr conf_dri;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index 4c1d38c..fd3a84e 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -273,7 +273,11 @@ typedef enum {
 
     /* DRI Tokens */
     GROUP,
-    BUFFERS
+    BUFFERS,
+
+    /* InputClass Tokens */
+    NAME_MATCH,
+    DEVICE_MATCH
 } ParserTokens;
 
 #endif /* _xf86_tokens_h */
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index fcb582f..6fe5325 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -216,6 +216,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
 /* Have /dev/urandom */
 #undef HAVE_URANDOM
 
-- 
1.6.2.5

From b187182377c4fdec1b59ff4289792d347175e14a Mon Sep 17 00:00:00 2001
From: Dan Nicholson <[email protected]>
Date: Mon, 20 Jul 2009 22:41:25 -0700
Subject: [PATCH 2/2] xfree86: Use InputDevice configuration for automatic devices

When an automatically added device is requested, we trawl the list of
InputDevices from xorg.conf to see if any have a matching device file.
If so, the InputDevice configuration is used to setup the device.

A "xfree86:<identifier>" cookie is added when creating static xorg.conf
devices so that duplicates will not be automatically generated. This
allows static and automatic input device configuration to be mixed.

Signed-off-by: Dan Nicholson <[email protected]>
---
 hw/xfree86/common/xf86Init.c   |   25 +++++++++
 hw/xfree86/common/xf86Xinput.c |  111 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 130 insertions(+), 6 deletions(-)

diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index 44eed4d..afd6d90 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -1097,6 +1097,9 @@ InitInput(int argc, char **argv)
 
     /* Call the PreInit function for each input device instance. */
     for (pDev = xf86ConfigLayout.inputs; pDev && *pDev; pDev++) {
+        const char *identifier;
+        char *config_info;
+
         /* Replace obsolete keyboard driver with kbd */
         if (!xf86NameCmp((*pDev)->driver, "keyboard")) {
             strcpy((*pDev)->driver, "kbd");
@@ -1105,6 +1108,28 @@ InitInput(int argc, char **argv)
         /* If one fails, the others will too */
         if (xf86NewInputDevice(*pDev, &dev, TRUE) == BadAlloc)
             break;
+
+        /* Setup config_info of "xfree86:" + identifier + '\0' */
+        identifier = (*pDev)->identifier;
+        config_info = xalloc(strlen(identifier) + 9);
+        if (!config_info) {
+            xf86Msg(X_ERROR, "%s: Could not allocate configuration name\n",
+                    identifier);
+            continue;
+        }
+        sprintf(config_info, "xfree86:%s", identifier);
+
+        for (; dev; dev = dev->next) {
+            if (dev->config_info)
+                xfree(dev->config_info);
+            dev->config_info = xstrdup(config_info);
+            if (!dev->config_info) {
+                xf86Msg(X_ERROR, "%s: Could not duplicate configuration name\n",
+                        identifier);
+                break;
+            }
+        }
+        xfree(config_info);
     }
 }
 
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index cb0f7b6..09a35fb 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -76,9 +76,14 @@
 #include "exglobals.h"
 #include "eventstr.h"
 
-#include <string.h>     /* InputClassMatches */
+#include <string.h>     /* FindInputByDevice */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #ifdef HAVE_FNMATCH_H
-#include <fnmatch.h>
+#include <fnmatch.h>    /* InputClassMatches */
 #endif
 
 #include "extnsionst.h"
@@ -492,6 +497,71 @@ InputDevicePath(XF86OptionPtr options)
     return device;
 }
 
+/* Find an InputDevice configuration which uses the given device file. */
+static XF86ConfInputPtr
+FindInputByDevice(const char *device, XF86ConfInputPtr conf)
+{
+    struct stat device_stat;
+
+    if (!device)
+        return NULL;
+    if (stat(device, &device_stat) < 0) {
+        xf86Msg(X_ERROR, "Could not stat input device \"%s\": %s\n",
+                device, strerror(errno));
+        return NULL;
+    }
+
+    while (conf) {
+        const char *conf_device;
+        struct stat conf_stat;
+
+        conf_device = InputDevicePath(conf->inp_option_lst);
+        if (conf_device) {
+            /* If the names match, we're good. */
+            if (strcmp(device, conf_device) == 0)
+                return conf;
+
+            /* Otherwise, we stat the name to resolve symlinks. If both
+             * paths have the same mode with equal device numbers, then
+             * we have a match. Don't warn about devices that don't
+             * exist, though. */
+            if ((stat(conf_device, &conf_stat) == 0) &&
+                (device_stat.st_mode == conf_stat.st_mode) &&
+                (device_stat.st_rdev == conf_stat.st_rdev))
+                return conf;
+        }
+
+        conf = conf->list.next;
+    }
+
+    return NULL;
+}
+
+/* See whether this device has already been added through xorg.conf. */
+static Bool
+DeviceIsDuplicate(XF86ConfInputPtr conf)
+{
+    DeviceIntPtr dev;
+
+    for (dev = inputInfo.devices; dev; dev = dev->next) {
+        if (!dev->config_info)
+            continue;
+        if ((strncmp(dev->config_info, "xfree86:", 8) == 0) &&
+            (strcmp(&dev->config_info[8], conf->inp_identifier) == 0))
+            return True;
+    }
+
+    for (dev = inputInfo.off_devices; dev; dev = dev->next) {
+        if (!dev->config_info)
+            continue;
+        if ((strncmp(dev->config_info, "xfree86:", 8) == 0) &&
+            (strcmp(&dev->config_info[8], conf->inp_identifier) == 0))
+            return True;
+    }
+
+    return False;
+}
+
 /*
  * Classes without any Match statements match all devices. Otherwise, all
  * statements must match.
@@ -660,6 +730,7 @@ NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev)
 {
     IDevRec *idev = NULL;
     InputOption *option = NULL;
+    XF86ConfInputPtr conf;
     int rval = Success;
     int is_auto = 0;
 
@@ -723,10 +794,38 @@ NewInputDeviceRequest (InputOption *options, DeviceIntPtr *pdev)
         option->value = NULL;
     }
 
-    /* Apply InputClass settings */
-    rval = MergeInputClasses(idev);
-    if (rval != Success)
-        goto unwind;
+    /* See if there's a matching InputDevice section. */
+    conf = FindInputByDevice(InputDevicePath(idev->commonOptions),
+                             xf86configptr->conf_input_lst);
+    if (conf) {
+        /* If the InputDevice was already added, clean up and return
+         * successfully. */
+        if (DeviceIsDuplicate(conf)) {
+            xf86Msg(X_WARNING, "Device \"%s\" is already added. Ignoring.\n",
+                    conf->inp_identifier);
+            rval = Success;
+            goto unwind;
+        }
+
+        /* Otherwise, replace configuration with InputDevice settings.
+         * The identifier is left as for identification on removal. */
+        xf86Msg(X_CONFIG, "%s: Applying InputDevice \"%s\"\n",
+                idev->identifier, conf->inp_identifier);
+        free(idev->driver);
+        idev->driver = xstrdup(conf->inp_driver);
+        if (!idev->driver) {
+                rval = BadAlloc;
+                goto unwind;
+        }
+        xf86optionListFree(idev->commonOptions);
+        idev->commonOptions = xf86optionListDup(conf->inp_option_lst);
+    }
+    else {
+        /* Apply InputClass settings if no matching InputDevice found. */
+        rval = MergeInputClasses(idev);
+        if (rval != Success)
+            goto unwind;
+    }
 
     rval = xf86NewInputDevice(idev, pdev,
                 (!is_auto || (is_auto && xf86Info.autoEnableDevices)));
-- 
1.6.2.5

_______________________________________________
devkit-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/devkit-devel

Reply via email to