summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING95
-rw-r--r--Makefile.am40
-rw-r--r--README20
-rwxr-xr-xautogen.sh12
-rw-r--r--configure.ac77
-rw-r--r--debian/README.source73
-rwxr-xr-xdebian/changelog127
-rw-r--r--debian/compat1
-rw-r--r--debian/control35
-rw-r--r--debian/copyright100
-rw-r--r--debian/local/10-x11-evdev.fdi18
-rwxr-xr-xdebian/rules108
-rw-r--r--debian/watch2
-rw-r--r--debian/xserver-xorg-input-evdev.install2
-rw-r--r--debian/xserver-xorg-input-evdev.links1
-rw-r--r--debian/xserver-xorg-input-evdev.manpages1
-rw-r--r--debian/xsfbs/repack.sh32
-rw-r--r--debian/xsfbs/xsfbs.mk293
-rw-r--r--debian/xsfbs/xsfbs.sh853
-rw-r--r--include/Makefile.am2
-rwxr-xr-xinclude/evdev-properties.h69
-rw-r--r--man/Makefile.am57
-rw-r--r--man/evdev.man231
-rw-r--r--packaging/xorg-x11-drv-evdev.spec54
-rw-r--r--src/Makefile.am40
-rw-r--r--src/draglock.c321
-rw-r--r--src/emuMB.c421
-rw-r--r--src/emuWheel.c478
-rwxr-xr-xsrc/evdev.c2699
-rw-r--r--src/evdev.h225
-rw-r--r--xorg-evdev.pc.in6
31 files changed, 6493 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5fad136
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,95 @@
+Various copyright notices found in this driver:
+
+Copyright © 2004-2008 Red Hat, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without
+fee, provided that the above copyright notice appear in all copies
+and that both that copyright notice and this permission notice
+appear in supporting documentation, and that the name of Red Hat
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission. Red
+Hat makes no representations about the suitability of this software
+for any purpose. It is provided "as is" without express or implied
+warranty.
+
+THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+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 OPEN GROUP 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.
+
+Except as contained in this notice, the name of the copyright holders shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the copyright holders.
+
+Copyright © 2008 University of South Australia
+copyrights taken from xf86-input-mouse, partly valid for this driver.
+Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+Copyright 1993 by David Dawes <dawes@xfree86.org>
+Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+Copyright 1994-2002 by The XFree86 Project, Inc.
+Copyright 2002 by Paul Elliott
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without
+fee, provided that the above copyright notice appear in all copies
+and that both that copyright notice and this permission notice
+appear in supporting documentation, and that the name of the authors
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. The authors make no
+representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied
+warranty.
+
+THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+Copyright 2005 Adam Jackson.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ADAM JACKSON 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.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e8e6ec1
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,40 @@
+# Copyright 2005 Adam Jackson.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 (including the next
+# paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON 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.
+
+AUTOMAKE_OPTIONS = foreign
+
+# Ensure headers are installed below $(prefix) for distcheck
+DISTCHECK_CONFIGURE_FLAGS = --with-sdkdir='$${includedir}/xorg'
+
+SUBDIRS = src man include
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = xorg-evdev.pc
+
+EXTRA_DIST = ChangeLog
+
+MAINTAINERCLEANFILES=ChangeLog
+
+.PHONY: ChangeLog
+
+ChangeLog:
+ $(CHANGELOG_CMD)
+
+dist-hook: ChangeLog
diff --git a/README b/README
new file mode 100644
index 0000000..95873ba
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+xf86-input-evdev - Generic Linux input driver for the Xorg X server
+
+Please submit bugs & patches to the Xorg bugzilla:
+
+ https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
+
+All questions regarding this software should be directed at the
+Xorg mailing list:
+
+ http://lists.freedesktop.org/mailman/listinfo/xorg
+
+The master development code repository can be found at:
+
+ git://anongit.freedesktop.org/git/xorg/driver/xf86-input-evdev
+
+ http://cgit.freedesktop.org/xorg/driver/xf86-input-evdev
+
+For more information on the git code manager, see:
+
+ http://wiki.x.org/wiki/GitPage
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..218197d
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+#$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..d2a3bc1
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,77 @@
+# Copyright 2005 Adam Jackson.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 (including the next
+# paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON 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.
+#
+# Process this file with autoconf to produce a configure script
+
+AC_PREREQ(2.57)
+AC_INIT([xf86-input-evdev],
+ 2.3.2,
+ [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+ xf86-input-evdev)
+
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_AUX_DIR(.)
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AM_MAINTAINER_MODE
+
+# Require xorg-macros: XORG_DEFAULT_OPTIONS
+m4_ifndef([XORG_MACROS_VERSION], [AC_FATAL([must install xorg-macros 1.3 or later before running autoconf/autogen])])
+XORG_MACROS_VERSION(1.3)
+AM_CONFIG_HEADER([config.h])
+
+# Checks for programs.
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_PROG_CC
+XORG_DEFAULT_OPTIONS
+
+AH_TOP([#include "xorg-server.h"])
+
+AC_ARG_WITH(xorg-module-dir,
+ AC_HELP_STRING([--with-xorg-module-dir=DIR],
+ [Default xorg module directory [[default=$libdir/xorg/modules]]]),
+ [moduledir="$withval"],
+ [moduledir="$libdir/xorg/modules"])
+inputdir=${moduledir}/input
+AC_SUBST(inputdir)
+
+# Checks for pkg-config packages. We need to be able to override sdkdir
+# to satisfy silly distcheck requirements.
+PKG_CHECK_MODULES(XORG, xorg-server xproto $REQUIRED_MODULES)
+XORG_CFLAGS="$CWARNFLAGS $XORG_CFLAGS"
+AC_ARG_WITH([sdkdir], [],
+ [sdkdir="$withval"],
+ [sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server`])
+AC_SUBST([sdkdir])
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+
+DRIVER_NAME=evdev
+AC_SUBST([DRIVER_NAME])
+
+AC_OUTPUT([Makefile
+ src/Makefile
+ man/Makefile
+ include/Makefile
+ xorg-evdev.pc])
diff --git a/debian/README.source b/debian/README.source
new file mode 100644
index 0000000..34ab4bf
--- /dev/null
+++ b/debian/README.source
@@ -0,0 +1,73 @@
+------------------------------------------------------
+Quick Guide To Patching This Package For The Impatient
+------------------------------------------------------
+
+1. Make sure you have quilt installed
+2. Unpack the package as usual with "dpkg-source -x"
+3. Run the "patch" target in debian/rules
+4. Create a new patch with "quilt new" (see quilt(1))
+5. Edit all the files you want to include in the patch with "quilt edit"
+ (see quilt(1)).
+6. Write the patch with "quilt refresh" (see quilt(1))
+7. Run the "clean" target in debian/rules
+
+Alternatively, instead of using quilt directly, you can drop the patch in to
+debian/patches and add the name of the patch to debian/patches/series.
+
+------------------------------------
+Guide To The X Strike Force Packages
+------------------------------------
+
+The X Strike Force team maintains X packages in git repositories on
+git.debian.org in the pkg-xorg subdirectory. Most upstream packages
+are actually maintained in git repositories as well, so they often
+just need to be pulled into git.debian.org in a "upstream-*" branch.
+Otherwise, the upstream sources are manually installed in the Debian
+git repository.
+
+The .orig.tar.gz upstream source file could be generated this
+"upstream-*" branch in the Debian git repository but it is actually
+copied from upstream tarballs directly.
+
+Due to X.org being highly modular, packaging all X.org applications
+as their own independent packages would have created too many Debian
+packages. For this reason, some X.org applications have been grouped
+into larger packages: xutils, xutils-dev, x11-apps, x11-session-utils,
+x11-utils, x11-xfs-utils, x11-xkb-utils, x11-xserver-utils.
+Most packages, including the X.org server itself and all libraries
+and drivers are, however maintained independently.
+
+The Debian packaging is added by creating the "debian-*" git branch
+which contains the aforementioned "upstream-*" branch plus the debian/
+repository files.
+When a patch has to be applied to the Debian package, two solutions
+are involved:
+* If the patch is available in one of the upstream branches, it
+ may be git'cherry-picked into the Debian repository. In this
+ case, it appears directly in the .diff.gz.
+* Otherwise, the patch is added to debian/patches/ which is managed
+ with quilt as documented in /usr/share/doc/quilt/README.source.
+
+quilt is actually invoked by the Debian X packaging through a larger
+set of scripts called XSFBS. XSFBS brings some other X specific
+features such as managing dependencies and conflicts due to the video
+and input driver ABIs.
+XSFBS itself is maintained in a separate repository at
+ git://git.debian.org/pkg-xorg/xsfbs.git
+and it is pulled inside the other Debian X repositories when needed.
+
+The XSFBS patching system requires a build dependency on quilt. Also
+a dependency on $(STAMP_DIR)/patch has to be added to debian/rules
+so that the XSFBS patching occurs before the actual build. So the
+very first target of the build (likely the one running autoreconf)
+should depend on $(STAMP_DIR)/patch. It should also not depend on
+anything so that parallel builds are correctly supported (nothing
+should probably run while patching is being done). And finally, the
+clean target should depend on the xsfclean target so that patches
+are unapplied on clean.
+
+When the upstream sources contain some DFSG-nonfree files, they are
+listed in text files in debian/prune/ in the "debian-*" branch of
+the Debian repository. XSFBS' scripts then take care of removing
+these listed files during the build so as to generate a modified
+DFSG-free .orig.tar.gz tarball.
diff --git a/debian/changelog b/debian/changelog
new file mode 100755
index 0000000..fbe620d
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,127 @@
+xserver-xorg-input-evdev (2.3.2-4slp2+13) unstable; urgency=low
+
+ * Remove log messages applied in previous version
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+13
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Thu, 17 Nov 2011 13:07:31 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+12) unstable; urgency=low
+
+ * Leave log messages when a key is pressed or released.
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+12
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Fri, 04 Nov 2011 17:42:48 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+11) unstable; urgency=low
+
+ * oal rollback
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+11
+
+ -- SooChan Lim <sc1.lim@samsung.com> Fri, 08 Apr 2011 13:52:53 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+10) unstable; urgency=low
+
+ * Work for oal
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+10
+
+ -- SooChan Lim <sc1.lim@samsung.com> Tue, 05 Apr 2011 10:29:41 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+9) unstable; urgency=low
+
+ * [X11R7.6] upgrade package
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+9
+
+ -- SooChan Lim <sc1.lim@samsung.com> Thu, 03 Mar 2011 19:34:31 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+8) unstable; urgency=low
+
+ * Remove properties and functions related to set/unset the existence of
+ mouse and external keyboard devices
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+8
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Tue, 01 Feb 2011 13:48:06 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+7) unstable; urgency=low
+
+ * Add functions setting external keyboard existence
+ * Increase/decrease mouse existence when a mouse is connected/disconnected
+ * Remove a macro _F_X_MOUSE_EXIST_
+ * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+7
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Mon, 03 Jan 2011 19:31:10 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+6) unstable; urgency=low
+
+ * Add xserver-xorg-input-evdev-dbg package into debian/control file
+ * Modify debian/rules to strip binary except xserver-xorg-input-evdev-dbg
+ * Git: 165.213.180.234:/git/slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+6
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Mon, 22 Nov 2010 13:55:15 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+5) unstable; urgency=low
+
+ * Apply --as-needed option
+ * Git: 165.213.180.234:/git/slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+5
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Sat, 20 Nov 2010 17:06:01 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+4) unstable; urgency=low
+
+ * Change macro name (from _EVDEV_INIT_ABS_ONLY_FOR_POINTER_ to
+ _F_INIT_ABS_ONLY_FOR_POINTER_)
+ * Add a property for setting mouse existence (_F_X_MOUSE_EXIST_ macro)
+ * Git: 165.213.180.234:/git/slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+4
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Fri, 19 Nov 2010 15:17:25 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+3) unstable; urgency=low
+
+ * Modify evdev.c not to initialize abs class for keyboard device
+ * Git: 165.213.180.234:/git/slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+3
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Thu, 18 Nov 2010 13:37:22 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+2) unstable; urgency=low
+
+ * Reupload for fixing the problem (ABI not matching with xorg-server)
+ * Git: 165.213.180.234:/git/slp/pkgs/xorg/driver/xserver-xorg-input-evdev
+ * Tag: xserver-xorg-input-evdev_2.3.2-4slp2+2
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Wed, 10 Nov 2010 20:08:54 +0900
+
+xserver-xorg-input-evdev (2.3.2-4slp2+1) unstable; urgency=low
+
+ * Change revision
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Thu, 25 Mar 2010 18:08:01 +0900
+
+xserver-xorg-input-evdev (2.3.2-3) unstable; urgency=low
+
+ * Add EvdevSwapAxes() function for adjusting touch screen size properly
+ when screen is rotated with xrandr extension
+ (Adjust absinfo of max_x, min_x, max_y, min_y)
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Fri, 19 Mar 2010 17:51:14 +0900
+
+xserver-xorg-input-evdev (2.3.2-2) unstable; urgency=low
+
+ * Change not to strip binary
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Thu, 04 Feb 2010 17:00:32 +0900
+
+xserver-xorg-input-evdev (2.3.2-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Sung-Jin Park <sj76.park@samsung.com> Tue, 29 Sep 2009 21:04:26 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..637d384
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,35 @@
+Source: xserver-xorg-input-evdev
+Section: x11
+Priority: optional
+Maintainer: Sung-Jin Park <sj76.park@samsung.com>
+#Maintainer: Debian X Strike Force <debian-x@lists.debian.org>
+Uploaders: SooChan Lim <sc1.lim@samsung.com>, Sung-Jin Park <sj76.park@samsung.com>
+#Uploaders: David Nusinow <dnusinow@debian.org>, Drew Parsons <dparsons@debian.org>, Julien Cristau <jcristau@debian.org>, Brice Goglin <bgoglin@debian.org>
+Build-Depends: debhelper (>= 5.0.0), pkg-config, quilt, xserver-xorg-dev (>= 1.6.99.900), x11proto-core-dev, x11proto-randr-dev, x11proto-input-dev, x11proto-kb-dev, libxkbfile-dev, dpkg-dev (>= 1.14.17), automake, libtool, xutils-dev (>= 1:7.3~1)
+Standards-Version: 3.8.3
+Vcs-Git: git://git.debian.org/git/pkg-xorg/driver/xserver-xorg-input-evdev
+Vcs-Browser: http://git.debian.org/?p=pkg-xorg/driver/xserver-xorg-input-evdev.git
+
+Package: xserver-xorg-input-evdev
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${xserver}
+Provides: ${xinpdriver:Provides}
+Replaces: xserver-xorg (<< 6.8.2-35)
+Description: X.Org X server -- evdev input driver
+ This package provides the driver for input devices using evdev, the Linux
+ kernel's event delivery mechanism. This driver allows for multiple keyboards
+ and mice to be treated as separate input devices.
+ .
+ More information about X.Org can be found at:
+ <URL:http://www.X.org>
+ <URL:http://xorg.freedesktop.org>
+ <URL:http://lists.freedesktop.org/mailman/listinfo/xorg>
+ .
+ This package is built from the X.org xf86-input-evdev driver module.
+
+Package: xserver-xorg-input-evdev-dbg
+Section: debug
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${xserver}, xserver-xorg-input-evdev (=${Source-Version})
+Description: Debug package of xserver-xorg-input-evdev driver
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..4cf9803
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,100 @@
+This package was downloaded from
+git://anongit.freedesktop.org/git/xorg/driver/xf86-input-evdev.
+Release tarballs are available at
+http://xorg.freedesktop.org/releases/individual/driver/
+
+Various copyright notices found in this driver:
+
+Copyright © 2004-2008 Red Hat, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without
+fee, provided that the above copyright notice appear in all copies
+and that both that copyright notice and this permission notice
+appear in supporting documentation, and that the name of Red Hat
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission. Red
+Hat makes no representations about the suitability of this software
+for any purpose. It is provided "as is" without express or implied
+warranty.
+
+THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+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 OPEN GROUP 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.
+
+Except as contained in this notice, the name of the copyright holders shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the copyright holders.
+
+Copyright © 2008 University of South Australia
+copyrights taken from xf86-input-mouse, partly valid for this driver.
+Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+Copyright 1993 by David Dawes <dawes@xfree86.org>
+Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+Copyright 1994-2002 by The XFree86 Project, Inc.
+Copyright 2002 by Paul Elliott
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without
+fee, provided that the above copyright notice appear in all copies
+and that both that copyright notice and this permission notice
+appear in supporting documentation, and that the name of the authors
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. The authors make no
+representations about the suitability of this software for any
+purpose. It is provided "as is" without express or implied
+warranty.
+
+THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+Copyright 2005 Adam Jackson.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ADAM JACKSON 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.
+
diff --git a/debian/local/10-x11-evdev.fdi b/debian/local/10-x11-evdev.fdi
new file mode 100644
index 0000000..a7fe8cc
--- /dev/null
+++ b/debian/local/10-x11-evdev.fdi
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<deviceinfo version="0.2">
+ <device>
+ <match key="info.capabilities" contains="input.mouse">
+ <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
+ string="Linux">
+ <merge key="input.x11_driver" type="string">evdev</merge>
+ </match>
+ </match>
+
+ <match key="info.capabilities" contains="input.keys">
+ <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
+ string="Linux">
+ <merge key="input.x11_driver" type="string">evdev</merge>
+ </match>
+ </match>
+ </device>
+</deviceinfo>
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..360a704
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,108 @@
+#!/usr/bin/make -f
+# debian/rules for the Debian xserver-xorg-input-evdev package.
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>
+# Copyright © 2005 Daniel Stone <daniel@fooishbar.org>
+# Copyright © 2005 David Nusinow <dnusinow@debian.org>
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+include debian/xsfbs/xsfbs.mk
+
+CFLAGS = -Wall -g -D_F_INIT_ABS_ONLY_FOR_POINTER_
+LDFLAGS += -Wl,--hash-style=both -Wl,--as-needed
+ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+ NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+ MAKEFLAGS += -j$(NUMJOBS)
+endif
+
+DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
+ confflags += --build=$(DEB_HOST_GNU_TYPE)
+else
+ confflags += --build=$(DEB_HOST_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE)
+# confflags += --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE)
+endif
+
+# kbd_drv.a isn't phenomenally useful; kbd_drv.so more so
+confflags += --disable-static
+
+#configure: $(STAMP_DIR)/patch
+configure:
+ autoreconf -vfi
+ #./autogen.sh
+
+obj-$(DEB_BUILD_GNU_TYPE)/config.status: configure
+ mkdir -p obj-$(DEB_BUILD_GNU_TYPE)
+ cd obj-$(DEB_BUILD_GNU_TYPE) && \
+ ../configure --prefix=/usr --mandir=\$${prefix}/share/man \
+ --infodir=\$${prefix}/share/info $(confflags) \
+ CFLAGS="$(CFLAGS)"
+
+build: build-stamp
+build-stamp: obj-$(DEB_BUILD_GNU_TYPE)/config.status
+ dh_testdir
+ cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE)
+ >$@
+
+clean: xsfclean
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+
+ rm -f config.cache config.log config.status
+ rm -f */config.cache */config.log */config.status
+ rm -f conftest* */conftest*
+ rm -rf autom4te.cache */autom4te.cache
+ rm -rf obj-*
+ rm -f $$(find -name Makefile.in)
+ rm -f compile config.guess config.sub configure depcomp install-sh
+ rm -f ltmain.sh missing INSTALL aclocal.m4 ylwrap mkinstalldirs config.h.in
+
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install
+
+# Build architecture-dependent files here.
+binary-arch: build install serverabi
+ dh_testdir
+ dh_testroot
+
+ dh_installdocs
+# dh_installchangelogs ChangeLog
+ dh_installchangelogs
+ dh_install --sourcedir=debian/tmp --list-missing --exclude=usr/share/man/man4
+ #dh_install --sourcedir=debian/tmp --list-missing --exclude=evdev_drv.la --exclude=usr/share/man/man4
+# install -d debian/xserver-xorg-input-evdev/usr/share/hal/fdi/policy/20thirdparty
+# install -m 644 debian/local/10-x11-evdev.fdi debian/xserver-xorg-input-evdev/usr/share/hal/fdi/policy/20thirdparty/
+ dh_installman
+ dh_link
+ dh_strip --dbg-package=xserver-xorg-input-evdev-dbg
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+# dh_shlibdeps -- --warnings=6
+ dh_shlibdeps --
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+# Build architecture-independent files here.
+binary-indep: build install
+# Nothing to do
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..16cd015
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://xorg.freedesktop.org/releases/individual/driver/ xf86-input-evdev-(.*)\.tar\.gz
diff --git a/debian/xserver-xorg-input-evdev.install b/debian/xserver-xorg-input-evdev.install
new file mode 100644
index 0000000..1002d70
--- /dev/null
+++ b/debian/xserver-xorg-input-evdev.install
@@ -0,0 +1,2 @@
+usr/lib/xorg/modules/input/*.so
+usr/lib/xorg/modules/input/*.la
diff --git a/debian/xserver-xorg-input-evdev.links b/debian/xserver-xorg-input-evdev.links
new file mode 100644
index 0000000..c3758c4
--- /dev/null
+++ b/debian/xserver-xorg-input-evdev.links
@@ -0,0 +1 @@
+usr/share/bug/xserver-xorg-core/script usr/share/bug/xserver-xorg-input-evdev/script
diff --git a/debian/xserver-xorg-input-evdev.manpages b/debian/xserver-xorg-input-evdev.manpages
new file mode 100644
index 0000000..603f9bd
--- /dev/null
+++ b/debian/xserver-xorg-input-evdev.manpages
@@ -0,0 +1 @@
+debian/tmp/usr/share/man/man4/*
diff --git a/debian/xsfbs/repack.sh b/debian/xsfbs/repack.sh
new file mode 100644
index 0000000..5935cc9
--- /dev/null
+++ b/debian/xsfbs/repack.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+if ! [ -d debian/prune ]; then
+ exit 0
+fi
+
+if [ "x$1" != x--upstream-version ]; then
+ exit 1
+fi
+
+version="$2"
+filename="$3"
+
+if [ -z "$version" ] || ! [ -f "$filename" ]; then
+ exit 1
+fi
+
+dir="$(pwd)"
+tempdir="$(mktemp -d)"
+
+cd "$tempdir"
+tar xf "$dir/$filename"
+cat "$dir"/debian/prune/* | while read file; do rm -f */$file; done
+
+tar czf "$dir/$filename" *
+cd "$dir"
+rm -rf "$tempdir"
+echo "Done pruning upstream tarball"
+
+exit 0
diff --git a/debian/xsfbs/xsfbs.mk b/debian/xsfbs/xsfbs.mk
new file mode 100644
index 0000000..f0f8953
--- /dev/null
+++ b/debian/xsfbs/xsfbs.mk
@@ -0,0 +1,293 @@
+#!/usr/bin/make -f
+
+# Debian X Strike Force Build System (XSFBS): Make portion
+
+# Copyright 1996 Stephen Early
+# Copyright 1997 Mark Eichin
+# Copyright 1998-2005, 2007 Branden Robinson
+# Copyright 2005 David Nusinow
+#
+# Licensed under the GNU General Public License, version 2. See the file
+# /usr/share/common-licenses/GPL or <http://www.gnu.org/copyleft/gpl.txt>.
+
+# Originally by Stephen Early <sde1000@debian.org>
+# Modified by Mark W. Eichin <eichin@kitten.gen.ma.us>
+# Modified by Adam Heath <doogie@debian.org>
+# Modified by Branden Robinson <branden@debian.org>
+# Modified by Fabio Massimo Di Nitto <fabbione@fabbione.net>
+# Modified by David Nusinow <dnusinow@debian.org>
+# Acknowledgements to Manoj Srivastava.
+
+# Pass $(DH_OPTIONS) into the environment for debhelper's benefit.
+export DH_OPTIONS
+
+# force quilt to not use ~/.quiltrc and to use debian/patches
+QUILT = QUILT_PATCHES=debian/patches quilt --quiltrc /dev/null
+
+# Set up parameters for the upstream build environment.
+
+# Determine (source) package name from Debian changelog.
+SOURCE_NAME:=$(shell dpkg-parsechangelog -ldebian/changelog \
+ | grep '^Source:' | awk '{print $$2}')
+
+# Determine package version from Debian changelog.
+SOURCE_VERSION:=$(shell dpkg-parsechangelog -ldebian/changelog \
+ | grep '^Version:' | awk '{print $$2}')
+
+# Determine upstream version number.
+UPSTREAM_VERSION:=$(shell echo $(SOURCE_VERSION) | sed 's/-.*//')
+
+# Determine the source version without the epoch for make-orig-tar-gz
+NO_EPOCH_VER:=$(shell echo $(UPSTREAM_VERSION) | sed 's/^.://')
+
+# Figure out who's building this package.
+BUILDER:=$(shell echo $${DEBEMAIL:-$${EMAIL:-$$(echo $$LOGNAME@$$(cat /etc/mailname 2>/dev/null))}})
+
+# Find out if this is an official build; an official build has nothing but
+# digits, dots, and/or the codename of a release in the Debian part of the
+# version number. Anything else indicates an unofficial build.
+OFFICIAL_BUILD:=$(shell VERSION=$(SOURCE_VERSION); if ! expr "$$(echo $${VERSION\#\#*-} | sed 's/\(woody\|sarge\|etch\|lenny\)//g')" : ".*[^0-9.].*" >/dev/null 2>&1; then echo yes; fi)
+
+# Set up parameters for the Debian build environment.
+
+# Determine our architecture.
+BUILD_ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH)
+# Work around some old-time dpkg braindamage.
+BUILD_ARCH:=$(subst i486,i386,$(BUILD_ARCH))
+# The DEB_HOST_ARCH variable may be set per the Debian cross-compilation policy.
+ifdef DEB_HOST_ARCH
+ ARCH:=$(DEB_HOST_ARCH)
+else
+ # dpkg-cross sets the ARCH environment variable; if set, use it.
+ ifdef ARCH
+ ARCH:=$(ARCH)
+ else
+ ARCH:=$(BUILD_ARCH)
+ endif
+endif
+
+# $(STAMP_DIR) houses stamp files for complex targets.
+STAMP_DIR:=stampdir
+
+# $(DEBTREEDIR) is where all install rules are told (via $(DESTDIR)) to place
+# their files.
+DEBTREEDIR:=$(CURDIR)/debian/tmp
+
+# All "important" targets have four lines:
+# 1) A target name that is invoked by a package-building tool or the user.
+# This consists of a dependency on a "$(STAMP_DIR)/"-prefixed counterpart.
+# 2) A line delcaring 1) as a phony target (".PHONY:").
+# 3) A "$(STAMP_DIR)/"-prefixed target which does the actual work, and may
+# depend on other targets.
+# 4) A line declaring 3) as a member of the $(stampdir_targets) variable; the
+# "$(STAMP_DIR)/" prefix is omitted.
+#
+# This indirection is needed so that the "stamp" files that signify when a rule
+# is done can be located in a separate "stampdir". Recall that make has no way
+# to know when a goal has been met for a phony target (like "build" or
+# "install").
+#
+# At the end of each "$(STAMP_DIR)/" target, be sure to run the command ">$@"
+# so that the target will not be run again. Removing the file will make Make
+# run the target over.
+
+# All phony targets should be declared as dependencies of .PHONY, even if they
+# do not have "($STAMP_DIR)/"-prefixed counterparts.
+
+# Define a harmless default rule to keep things from going nuts by accident.
+.PHONY: default
+default:
+
+# Set up the $(STAMP_DIR) directory.
+.PHONY: stampdir
+stampdir_targets+=stampdir
+stampdir: $(STAMP_DIR)/stampdir
+$(STAMP_DIR)/stampdir:
+ mkdir $(STAMP_DIR)
+ >$@
+
+# Set up the package build directory as quilt expects to find it.
+.PHONY: prepare
+stampdir_targets+=prepare
+prepare: $(STAMP_DIR)/prepare
+$(STAMP_DIR)/prepare: $(STAMP_DIR)/log $(STAMP_DIR)/genscripts
+ >$@
+
+.PHONY: log
+stampdir_targets+=log
+log: $(STAMP_DIR)/log
+$(STAMP_DIR)/log: $(STAMP_DIR)/stampdir
+ mkdir -p $(STAMP_DIR)/log
+
+# Apply all patches to the upstream source.
+.PHONY: patch
+stampdir_targets+=patch
+patch: $(STAMP_DIR)/patch
+$(STAMP_DIR)/patch: $(STAMP_DIR)/prepare
+ if ! [ `which quilt` ]; then \
+ echo "Couldn't find quilt. Please install it or add it to the build-depends for this package."; \
+ exit 1; \
+ fi; \
+ if $(QUILT) next >/dev/null 2>&1; then \
+ echo -n "Applying patches..."; \
+ if $(QUILT) push -a -v >$(STAMP_DIR)/log/patch 2>&1; then \
+ cat $(STAMP_DIR)/log/patch; \
+ echo "successful."; \
+ else \
+ cat $(STAMP_DIR)/log/patch; \
+ echo "failed! (check $(STAMP_DIR)/log/patch for details)"; \
+ exit 1; \
+ fi; \
+ else \
+ echo "No patches to apply"; \
+ fi; \
+ >$@
+
+# Revert all patches to the upstream source.
+.PHONY: unpatch
+unpatch: $(STAMP_DIR)/log
+ rm -f $(STAMP_DIR)/patch
+ @echo -n "Unapplying patches..."; \
+ if $(QUILT) applied >/dev/null 2>/dev/null; then \
+ if $(QUILT) pop -a -v >$(STAMP_DIR)/log/unpatch 2>&1; then \
+ cat $(STAMP_DIR)/log/unpatch; \
+ echo "successful."; \
+ else \
+ cat $(STAMP_DIR)/log/unpatch; \
+ echo "failed! (check $(STAMP_DIR)/log/unpatch for details)"; \
+ exit 1; \
+ fi; \
+ else \
+ echo "nothing to do."; \
+ fi
+
+# Clean the generated maintainer scripts.
+.PHONY: cleanscripts
+cleanscripts:
+ rm -f $(STAMP_DIR)/genscripts
+ rm -f debian/*.config \
+ debian/*.postinst \
+ debian/*.postrm \
+ debian/*.preinst \
+ debian/*.prerm
+
+# Clean the package build tree.
+.PHONY: xsfclean
+xsfclean: cleanscripts unpatch
+ dh_testdir
+ rm -rf .pc
+ rm -rf $(STAMP_DIR) $(SOURCE_DIR)
+ rm -rf imports
+ dh_clean debian/shlibs.local \
+ debian/po/pothead
+
+# Generate the debconf templates POT file header.
+debian/po/pothead: debian/po/pothead.in
+ sed -e 's/SOURCE_VERSION/$(SOURCE_VERSION)/' \
+ -e 's/DATE/$(shell date "+%F %X%z"/)' <$< >$@
+
+# Update POT and PO files.
+.PHONY: updatepo
+updatepo: debian/po/pothead
+ debian/scripts/debconf-updatepo --pot-header=pothead --verbose
+
+# Remove files from the upstream source tree that we don't need, or which have
+# licensing problems. It must be run before creating the .orig.tar.gz.
+#
+# Note: This rule is for Debian package maintainers' convenience, and is not
+# needed for conventional build scenarios.
+.PHONY: prune-upstream-tree
+prune-upstream-tree:
+ # Ensure we're in the correct directory.
+ dh_testdir
+ grep -rvh '^#' debian/prune/ | xargs --no-run-if-empty rm -rf
+
+# Verify that there are no offsets or fuzz in the patches we apply.
+#
+# Note: This rule is for Debian package maintainers' convenience, and is not
+# needed for conventional build scenarios.
+.PHONY: patch-audit
+patch-audit: prepare unpatch
+ @echo -n "Auditing patches..."; \
+ >$(STAMP_DIR)/log/patch; \
+ FUZZY=; \
+ while [ -n "$$($(QUILT) next)" ]; do \
+ RESULT=$$($(QUILT) push -v | tee -a $(STAMP_DIR)/log/patch | grep ^Hunk | sed 's/^Hunk.*\(succeeded\|FAILED\).*/\1/');\
+ case "$$RESULT" in \
+ succeeded) \
+ echo "fuzzy patch: $$($(QUILT) top)" \
+ | tee -a $(STAMP_DIR)/log/$$($(QUILT) top); \
+ FUZZY=yes; \
+ ;; \
+ FAILED) \
+ echo "broken patch: $$($(QUILT) next)" \
+ | tee -a $(STAMP_DIR)/log/$$($(QUILT) next); \
+ exit 1; \
+ ;; \
+ esac; \
+ done; \
+ if [ -n "$$FUZZY" ]; then \
+ echo "there were fuzzy patches; please fix."; \
+ exit 1; \
+ else \
+ echo "done."; \
+ fi
+
+# Generate the maintainer scripts.
+.PHONY: genscripts
+stampdir_targets+=genscripts
+genscripts: $(STAMP_DIR)/genscripts
+$(STAMP_DIR)/genscripts: $(STAMP_DIR)/stampdir
+ for FILE in debian/*.config.in \
+ debian/*.postinst.in \
+ debian/*.postrm.in \
+ debian/*.preinst.in \
+ debian/*.prerm.in; do \
+ if [ -e "$$FILE" ]; then \
+ MAINTSCRIPT=$$(echo $$FILE | sed 's/.in$$//'); \
+ sed -n '1,/^#INCLUDE_SHELL_LIB#$$/p' <$$FILE \
+ | sed -e '/^#INCLUDE_SHELL_LIB#$$/d' >$$MAINTSCRIPT.tmp; \
+ cat debian/xsfbs/xsfbs.sh >>$$MAINTSCRIPT.tmp; \
+ sed -n '/^#INCLUDE_SHELL_LIB#$$/,$$p' <$$FILE \
+ | sed -e '/^#INCLUDE_SHELL_LIB#$$/d' >>$$MAINTSCRIPT.tmp; \
+ sed -e 's/@SOURCE_VERSION@/$(SOURCE_VERSION)/' \
+ -e 's/@OFFICIAL_BUILD@/$(OFFICIAL_BUILD)/' \
+ -e 's/@DEFAULT_DCRESOLUTIONS@/$(DEFAULT_DCRESOLUTIONS)/' \
+ <$$MAINTSCRIPT.tmp >$$MAINTSCRIPT; \
+ rm $$MAINTSCRIPT.tmp; \
+ fi; \
+ done
+ # Validate syntax of generated shell scripts.
+ #sh debian/scripts/validate-posix-sh debian/*.config \
+ # debian/*.postinst \
+ # debian/*.postrm \
+ # debian/*.preinst \
+ # debian/*.prerm
+ >$@
+
+# Generate the shlibs.local file.
+debian/shlibs.local:
+ cat debian/*.shlibs >$@
+
+SERVERMINVERS = $(shell cat /usr/share/xserver-xorg/serverminver 2>/dev/null)
+VIDEOABI = $(shell cat /usr/share/xserver-xorg/videoabiver 2>/dev/null)
+INPUTABI = $(shell cat /usr/share/xserver-xorg/inputabiver 2>/dev/null)
+SERVER_DEPENDS = xserver-xorg-core (>= $(SERVERMINVERS))
+VIDDRIVER_PROVIDES = xserver-xorg-video-$(VIDEOABI)
+INPDRIVER_PROVIDES = xserver-xorg-input-$(INPUTABI)
+ifeq ($(PACKAGE),)
+PACKAGE=$(shell awk '/^Package:/ { print $$2; exit }' < debian/control)
+endif
+
+.PHONY: serverabi
+serverabi: install
+ifeq ($(SERVERMINVERS),)
+ @echo error: xserver-xorg-dev needs to be installed
+ @exit 1
+else
+ echo "xserver:Depends=$(SERVER_DEPENDS)" >> debian/$(PACKAGE).substvars
+ echo "xviddriver:Provides=$(VIDDRIVER_PROVIDES)" >> debian/$(PACKAGE).substvars
+ echo "xinpdriver:Provides=$(INPDRIVER_PROVIDES)" >> debian/$(PACKAGE).substvars
+endif
+
+# vim:set noet ai sts=8 sw=8 tw=0:
diff --git a/debian/xsfbs/xsfbs.sh b/debian/xsfbs/xsfbs.sh
new file mode 100644
index 0000000..781826f
--- /dev/null
+++ b/debian/xsfbs/xsfbs.sh
@@ -0,0 +1,853 @@
+# $Id$
+
+# This is the X Strike Force shell library for X Window System package
+# maintainer scripts. It serves to define shell functions commonly used by
+# such packages, and performs some error checking necessary for proper operation
+# of those functions. By itself, it does not "do" much; the maintainer scripts
+# invoke the functions defined here to accomplish package installation and
+# removal tasks.
+
+# If you are reading this within a Debian package maintainer script (e.g.,
+# /var/lib/dpkg)info/PACKAGE.{config,preinst,postinst,prerm,postrm}), you can
+# skip past this library by scanning forward in this file to the string
+# "GOBSTOPPER".
+
+SOURCE_VERSION=@SOURCE_VERSION@
+OFFICIAL_BUILD=@OFFICIAL_BUILD@
+
+# Use special abnormal exit codes so that problems with this library are more
+# easily tracked down.
+SHELL_LIB_INTERNAL_ERROR=86
+SHELL_LIB_THROWN_ERROR=74
+SHELL_LIB_USAGE_ERROR=99
+
+# old -> new variable names
+if [ -z "$DEBUG_XORG_PACKAGE" ] && [ -n "$DEBUG_XFREE86_PACKAGE" ]; then
+ DEBUG_XORG_PACKAGE="$DEBUG_XFREE86_PACKAGE"
+fi
+if [ -z "$DEBUG_XORG_DEBCONF" ] && [ -n "$DEBUG_XFREE86_DEBCONF" ]; then
+ DEBUG_XORG_DEBCONF="$DEBUG_XFREE86_DEBCONF"
+fi
+
+# initial sanity checks
+if [ -z "$THIS_PACKAGE" ]; then
+ cat >&2 <<EOF
+Error: package maintainer script attempted to use shell library without
+definining \$THIS_PACKAGE shell variable. Please report the package name,
+version, and the text of this error message to the Debian Bug Tracking System.
+Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
+instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
+"doc-debian" package, or install the "reportbug" package and use the command of
+the same name to file a report against version $SOURCE_VERSION of this package.
+EOF
+ exit $SHELL_LIB_USAGE_ERROR
+fi
+
+if [ -z "$THIS_SCRIPT" ]; then
+ cat >&2 <<EOF
+Error: package maintainer script attempted to use shell library without
+definining \$THIS_SCRIPT shell variable. Please report the package name,
+version, and the text of this error message to the Debian Bug Tracking System.
+Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
+instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
+"doc-debian" package, or install the "reportbug" package and use the command of
+the same name to file a report against version $SOURCE_VERSION of the
+"$THIS_PACKAGE" package.
+EOF
+ exit $SHELL_LIB_USAGE_ERROR
+fi
+
+if [ "$1" = "reconfigure" ] || [ -n "$DEBCONF_RECONFIGURE" ]; then
+ RECONFIGURE="true"
+else
+ RECONFIGURE=
+fi
+
+if ([ "$1" = "install" ] || [ "$1" = "configure" ]) && [ -z "$2" ]; then
+ FIRSTINST="yes"
+fi
+
+if [ -z "$RECONFIGURE" ] && [ -z "$FIRSTINST" ]; then
+ UPGRADE="yes"
+fi
+
+trap "message;\
+ message \"Received signal. Aborting $THIS_PACKAGE package $THIS_SCRIPT script.\";\
+ message;\
+ exit 1" HUP INT QUIT TERM
+
+reject_nondigits () {
+ # syntax: reject_nondigits [ operand ... ]
+ #
+ # scan operands (typically shell variables whose values cannot be trusted) for
+ # characters other than decimal digits and barf if any are found
+ while [ -n "$1" ]; do
+ # does the operand contain anything but digits?
+ if ! expr "$1" : "[[:digit:]]\+$" > /dev/null 2>&1; then
+ # can't use die(), because it wraps message() which wraps this function
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_nondigits() encountered" \
+ "possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ shift
+ done
+}
+
+reject_whitespace () {
+ # syntax: reject_whitespace [ operand ]
+ #
+ # scan operand (typically a shell variable whose value cannot be trusted) for
+ # whitespace characters and barf if any are found
+ if [ -n "$1" ]; then
+ # does the operand contain any whitespace?
+ if expr "$1" : "[[:space:]]" > /dev/null 2>&1; then
+ # can't use die(), because I want to avoid forward references
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_whitespace() encountered" \
+ "possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ fi
+}
+
+reject_unlikely_path_chars () {
+ # syntax: reject_unlikely_path_chars [ operand ... ]
+ #
+ # scan operands (typically shell variables whose values cannot be trusted) for
+ # characters unlikely to be seen in a path and which the shell might
+ # interpret and barf if any are found
+ while [ -n "$1" ]; do
+ # does the operand contain any funny characters?
+ if expr "$1" : '.*[!$&()*;<>?|].*' > /dev/null 2>&1; then
+ # can't use die(), because I want to avoid forward references
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_unlikely_path_chars()" \
+ "encountered possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ shift
+ done
+}
+
+# Query the terminal to establish a default number of columns to use for
+# displaying messages to the user. This is used only as a fallback in the
+# event the COLUMNS variable is not set. ($COLUMNS can react to SIGWINCH while
+# the script is running, and this cannot, only being calculated once.)
+DEFCOLUMNS=$(stty size 2> /dev/null | awk '{print $2}') || true
+if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" > /dev/null 2>&1; then
+ DEFCOLUMNS=80
+fi
+
+message () {
+ # pretty-print messages of arbitrary length
+ reject_nondigits "$COLUMNS"
+ echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2
+}
+
+observe () {
+ # syntax: observe message ...
+ #
+ # issue observational message suitable for logging someday when support for
+ # it exists in dpkg
+ if [ -n "$DEBUG_XORG_PACKAGE" ]; then
+ message "$THIS_PACKAGE $THIS_SCRIPT note: $*"
+ fi
+}
+
+warn () {
+ # syntax: warn message ...
+ #
+ # issue warning message suitable for logging someday when support for
+ # it exists in dpkg; also send to standard error
+ message "$THIS_PACKAGE $THIS_SCRIPT warning: $*"
+}
+
+die () {
+ # syntax: die message ...
+ #
+ # exit script with error message
+ message "$THIS_PACKAGE $THIS_SCRIPT error: $*"
+ exit $SHELL_LIB_THROWN_ERROR
+}
+
+internal_error () {
+ # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message
+ message "internal error: $*"
+ if [ -n "$OFFICIAL_BUILD" ]; then
+ message "Please report a bug in the $THIS_SCRIPT script of the" \
+ "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
+ "Tracking System. Include all messages above that mention the" \
+ "$THIS_PACKAGE package. Visit " \
+ "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
+ "instructions, read the file" \
+ "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
+ "package, or install the reportbug package and use the command of" \
+ "the same name to file a report."
+ fi
+ exit $SHELL_LIB_INTERNAL_ERROR
+}
+
+usage_error () {
+ message "usage error: $*"
+ message "Please report a bug in the $THIS_SCRIPT script of the" \
+ "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
+ "Tracking System. Include all messages above that mention the" \
+ "$THIS_PACKAGE package. Visit " \
+ "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
+ "instructions, read the file" \
+ "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
+ "package, or install the reportbug package and use the command of" \
+ "the same name to file a report."
+ exit $SHELL_LIB_USAGE_ERROR
+}
+
+
+maplink () {
+ # returns what symlink should point to; i.e., what the "sane" answer is
+ # Keep this in sync with the debian/*.links files.
+ # This is only needed for symlinks to directories.
+ #
+ # XXX: Most of these look wrong in the X11R7 world and need to be fixed.
+ # If we've stopped using this function, fixing it might enable us to re-enable
+ # it again and catch more errors.
+ case "$1" in
+ /etc/X11/xkb/compiled) echo /var/lib/xkb ;;
+ /etc/X11/xkb/xkbcomp) echo /usr/X11R6/bin/xkbcomp ;;
+ /usr/X11R6/lib/X11/app-defaults) echo /etc/X11/app-defaults ;;
+ /usr/X11R6/lib/X11/fs) echo /etc/X11/fs ;;
+ /usr/X11R6/lib/X11/lbxproxy) echo /etc/X11/lbxproxy ;;
+ /usr/X11R6/lib/X11/proxymngr) echo /etc/X11/proxymngr ;;
+ /usr/X11R6/lib/X11/rstart) echo /etc/X11/rstart ;;
+ /usr/X11R6/lib/X11/twm) echo /etc/X11/twm ;;
+ /usr/X11R6/lib/X11/xdm) echo /etc/X11/xdm ;;
+ /usr/X11R6/lib/X11/xinit) echo /etc/X11/xinit ;;
+ /usr/X11R6/lib/X11/xkb) echo /etc/X11/xkb ;;
+ /usr/X11R6/lib/X11/xserver) echo /etc/X11/xserver ;;
+ /usr/X11R6/lib/X11/xsm) echo /etc/X11/xsm ;;
+ /usr/bin/X11) echo ../X11R6/bin ;;
+ /usr/bin/rstartd) echo ../X11R6/bin/rstartd ;;
+ /usr/include/X11) echo ../X11R6/include/X11 ;;
+ /usr/lib/X11) echo ../X11R6/lib/X11 ;;
+ *) internal_error "maplink() called with unknown path \"$1\"" ;;
+ esac
+}
+
+analyze_path () {
+ # given a supplied set of pathnames, break each one up by directory and do an
+ # ls -dl on each component, cumulatively; i.e.
+ # analyze_path /usr/X11R6/bin -> ls -dl /usr /usr/X11R6 /usr/X11R6/bin
+ # Thanks to Randolph Chung for this clever hack.
+
+ local f g
+
+ while [ -n "$1" ]; do
+ reject_whitespace "$1"
+ g=
+ message "Analyzing $1:"
+ for f in $(echo "$1" | tr / \ ); do
+ if [ -e /$g$f ]; then
+ ls -dl /$g$f /$g$f.dpkg-* 2> /dev/null || true
+ g=$g$f/
+ else
+ message "/$g$f: nonexistent; directory contents of /$g:"
+ ls -l /$g
+ break
+ fi
+ done
+ shift
+ done
+}
+
+find_culprits () {
+ local f p dpkg_info_dir possible_culprits smoking_guns bad_packages package \
+ msg
+
+ reject_whitespace "$1"
+ message "Searching for overlapping packages..."
+ dpkg_info_dir=/var/lib/dpkg/info
+ if [ -d $dpkg_info_dir ]; then
+ if [ "$(echo $dpkg_info_dir/*.list)" != "$dpkg_info_dir/*.list" ]; then
+ possible_culprits=$(ls -1 $dpkg_info_dir/*.list | egrep -v \
+ "(xbase-clients|x11-common|xfs|xlibs)")
+ if [ -n "$possible_culprits" ]; then
+ smoking_guns=$(grep -l "$1" $possible_culprits || true)
+ if [ -n "$smoking_guns" ]; then
+ bad_packages=$(printf "\\n")
+ for f in $smoking_guns; do
+ # too bad you can't nest parameter expansion voodoo
+ p=${f%*.list} # strip off the trailing ".list"
+ package=${p##*/} # strip off the directories
+ bad_packages=$(printf "%s\n%s" "$bad_packages" "$package")
+ done
+ msg=$(cat <<EOF
+The following packages appear to have file overlaps with the X.Org packages;
+these packages are either very old, or in violation of Debian Policy. Try
+upgrading each of these packages to the latest available version if possible:
+for example, with the command "apt-get install". If no newer version of a
+package is available, you will have to remove it; for example, with the command
+"apt-get remove". If even the latest available version of the package has
+this file overlap, please file a bug against that package with the Debian Bug
+Tracking System. You may want to refer the package maintainer to section 12.8
+of the Debian Policy manual.
+EOF
+)
+ message "$msg"
+ message "The overlapping packages are: $bad_packages"
+ else
+ message "no overlaps found."
+ fi
+ fi
+ else
+ message "cannot search; no matches for $dpkg_info_dir/*.list."
+ fi
+ else
+ message "cannot search; $dpkg_info_dir does not exist."
+ fi
+}
+
+check_symlink () {
+ # syntax: check_symlink symlink
+ #
+ # See if specified symlink points where it is supposed to. Return 0 if it
+ # does, and 1 if it does not.
+ #
+ # Primarily used by check_symlinks_and_warn() and check_symlinks_and_bomb().
+
+ local symlink
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "check_symlink() called with wrong number of arguments;" \
+ "expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ symlink="$1"
+
+ if [ "$(maplink "$symlink")" = "$(readlink "$symlink")" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+check_symlinks_and_warn () {
+ # syntax: check_symlinks_and_warn symlink ...
+ #
+ # For each argument, check for symlink sanity, and warn if it isn't sane.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install".
+
+ local errmsg symlink
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "check_symlinks_and_warn() called with wrong number of" \
+ "arguments; expected at least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ while [ -n "$1" ]; do
+ symlink="$1"
+ if [ -L "$symlink" ]; then
+ if ! check_symlink "$symlink"; then
+ observe "$symlink symbolic link points to wrong location" \
+ "$(readlink "$symlink"); removing"
+ rm "$symlink"
+ fi
+ elif [ -e "$symlink" ]; then
+ errmsg="$symlink exists and is not a symbolic link; this package cannot"
+ errmsg="$errmsg be installed until this"
+ if [ -f "$symlink" ]; then
+ errmsg="$errmsg file"
+ elif [ -d "$symlink" ]; then
+ errmsg="$errmsg directory"
+ else
+ errmsg="$errmsg thing"
+ fi
+ errmsg="$errmsg is removed"
+ die "$errmsg"
+ fi
+ shift
+ done
+}
+
+check_symlinks_and_bomb () {
+ # syntax: check_symlinks_and_bomb symlink ...
+ #
+ # For each argument, check for symlink sanity, and bomb if it isn't sane.
+ #
+ # Call this function from a postinst script.
+
+ local problem symlink
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "check_symlinks_and_bomb() called with wrong number of"
+ "arguments; expected at least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ while [ -n "$1" ]; do
+ problem=
+ symlink="$1"
+ if [ -L "$symlink" ]; then
+ if ! check_symlink "$symlink"; then
+ problem=yes
+ warn "$symlink symbolic link points to wrong location" \
+ "$(readlink "$symlink")"
+ fi
+ elif [ -e "$symlink" ]; then
+ problem=yes
+ warn "$symlink is not a symbolic link"
+ else
+ problem=yes
+ warn "$symlink symbolic link does not exist"
+ fi
+ if [ -n "$problem" ]; then
+ analyze_path "$symlink" "$(readlink "$symlink")"
+ find_culprits "$symlink"
+ die "bad symbolic links on system"
+ fi
+ shift
+ done
+}
+
+font_update () {
+ # run $UPDATECMDS in $FONTDIRS
+
+ local dir cmd shortcmd x_font_dir_prefix
+
+ x_font_dir_prefix="/usr/share/fonts/X11"
+
+ if [ -z "$UPDATECMDS" ]; then
+ usage_error "font_update() called but \$UPDATECMDS not set"
+ fi
+ if [ -z "$FONTDIRS" ]; then
+ usage_error "font_update() called but \$FONTDIRS not set"
+ fi
+
+ reject_unlikely_path_chars "$UPDATECMDS"
+ reject_unlikely_path_chars "$FONTDIRS"
+
+ for dir in $FONTDIRS; do
+ if [ -d "$x_font_dir_prefix/$dir" ]; then
+ for cmd in $UPDATECMDS; do
+ if which "$cmd" > /dev/null 2>&1; then
+ shortcmd=${cmd##*/}
+ observe "running $shortcmd in $dir font directory"
+ cmd_opts=
+ if [ "$shortcmd" = "update-fonts-alias" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ if [ "$shortcmd" = "update-fonts-dir" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ if [ "$shortcmd" = "update-fonts-scale" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \
+ "failed; font directory data may not" \
+ "be up to date"
+ else
+ warn "$cmd not found; not updating corresponding $dir font" \
+ "directory data"
+ fi
+ done
+ else
+ warn "$dir is not a directory; not updating font directory data"
+ fi
+ done
+}
+
+remove_conffile_prepare () {
+ # syntax: remove_conffile_prepare filename official_md5sum ...
+ #
+ # Check a conffile "filename" against a list of canonical MD5 checksums.
+ # If the file's current MD5 checksum matches one of the "official_md5sum"
+ # operands provided, then prepare the conffile for removal from the system.
+ # We defer actual deletion until the package is configured so that we can
+ # roll this operation back if package installation fails.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install" and verify $2 to ensure the package is being upgraded from a
+ # version (or installed over a version removed-but-not-purged) prior to the
+ # one in which the conffile was obsoleted.
+
+ local conffile current_checksum
+
+ # validate arguments
+ if [ $# -lt 2 ]; then
+ usage_error "remove_conffile_prepare() called with wrong number of" \
+ "arguments; expected at least 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+ shift
+
+ # does the conffile even exist?
+ if [ -e "$conffile" ]; then
+ # calculate its checksum
+ current_checksum=$(md5sum < "$conffile" | sed 's/[[:space:]].*//')
+ # compare it to each supplied checksum
+ while [ -n "$1" ]; do
+ if [ "$current_checksum" = "$1" ]; then
+ # we found a match; move the confffile and stop looking
+ observe "preparing obsolete conffile $conffile for removal"
+ mv "$conffile" "$conffile.$THIS_PACKAGE-tmp"
+ break
+ fi
+ shift
+ done
+ fi
+}
+
+remove_conffile_lookup () {
+ # syntax: remove_conffile_lookup package filename
+ #
+ # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal
+ # if it matches the actual file's md5sum.
+ #
+ # Call this function when you would call remove_conffile_prepare but only
+ # want to check against dpkg's status database instead of known checksums.
+
+ local package conffile old_md5sum
+
+ # validate arguments
+ if [ $# -ne 2 ]; then
+ usage_error "remove_conffile_lookup() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ package="$1"
+ conffile="$2"
+
+ if ! [ -e "$conffile" ]; then
+ return
+ fi
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$package" | \
+ awk '{ if (match($0, "^ '"$conffile"' ")) print $2}')"
+ if [ -n "$old_md5sum" ]; then
+ remove_conffile_prepare "$conffile" "$old_md5sum"
+ fi
+}
+
+remove_conffile_commit () {
+ # syntax: remove_conffile_commit filename
+ #
+ # Complete the removal of a conffile "filename" that has become obsolete.
+ #
+ # Call this function from a postinst script after having used
+ # remove_conffile_prepare() in the preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "remove_conffile_commit() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ # if the temporary file created by remove_conffile_prepare() exists, remove it
+ if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
+ observe "committing removal of obsolete conffile $conffile"
+ rm "$conffile.$THIS_PACKAGE-tmp"
+ fi
+}
+
+remove_conffile_rollback () {
+ # syntax: remove_conffile_rollback filename
+ #
+ # Roll back the removal of a conffile "filename".
+ #
+ # Call this function from a postrm script in the event $1 is "abort-upgrade"
+ # or "abort-install" is after having used remove_conffile_prepare() in the
+ # preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "remove_conffile_rollback() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ # if the temporary file created by remove_conffile_prepare() exists, move it
+ # back
+ if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
+ observe "rolling back removal of obsolete conffile $conffile"
+ mv "$conffile.$THIS_PACKAGE-tmp" "$conffile"
+ fi
+}
+
+replace_conffile_with_symlink_prepare () {
+ # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \
+ # official_md5sum ...
+ #
+ # Check a conffile "oldfilename" against a list of canonical MD5 checksums.
+ # If the file's current MD5 checksum matches one of the "official_md5sum"
+ # operands provided, then prepare the conffile for removal from the system.
+ # We defer actual deletion until the package is configured so that we can
+ # roll this operation back if package installation fails. Otherwise copy it
+ # to newfilename and let dpkg handle it through conffiles mechanism.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install" and verify $2 to ensure the package is being upgraded from a
+ # version (or installed over a version removed-but-not-purged) prior to the
+ # one in which the conffile was obsoleted.
+
+ local conffile current_checksum
+
+ # validate arguments
+ if [ $# -lt 3 ]; then
+ usage_error "replace_conffile_with_symlink_prepare() called with wrong" \
+ " number of arguments; expected at least 3, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ oldconffile="$1"
+ shift
+ newconffile="$1"
+ shift
+
+ remove_conffile_prepare "$_oldconffile" "$@"
+ # If $oldconffile still exists, then md5sums didn't match.
+ # Copy it to new one.
+ if [ -f "$oldconffile" ]; then
+ cp "$oldconffile" "$newconffile"
+ fi
+
+}
+
+replace_conffile_with_symlink_commit () {
+ # syntax: replace_conffile_with_symlink_commit oldfilename
+ #
+ # Complete the removal of a conffile "oldfilename" that has been
+ # replaced by a symlink.
+ #
+ # Call this function from a postinst script after having used
+ # replace_conffile_with_symlink_prepare() in the preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "replace_conffile_with_symlink_commit() called with wrong" \
+ "number of arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ remove_conffile_commit "$conffile"
+}
+
+replace_conffile_with_symlink_rollback () {
+ # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename
+ #
+ # Roll back the replacing of a conffile "oldfilename" with symlink to
+ # "newfilename".
+ #
+ # Call this function from a postrm script in the event $1 is "abort-upgrade"
+ # or "abort-install" and verify $2 to ensure the package failed to upgrade
+ # from a version (or install over a version removed-but-not-purged) prior
+ # to the one in which the conffile was obsoleted.
+ # You should have used replace_conffile_with_symlink_prepare() in the
+ # preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 2 ]; then
+ usage_error "replace_conffile_with_symlink_rollback() called with wrong" \
+ "number of arguments; expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ oldconffile="$1"
+ newconffile="$2"
+
+ remove_conffile_rollback "$_oldconffile"
+ if [ -f "$newconffile" ]; then
+ rm "$newconffile"
+ fi
+}
+
+run () {
+ # syntax: run command [ argument ... ]
+ #
+ # Run specified command with optional arguments and report its exit status.
+ # Useful for commands whose exit status may be nonzero, but still acceptable,
+ # or commands whose failure is not fatal to us.
+ #
+ # NOTE: Do *not* use this function with db_get or db_metaget commands; in
+ # those cases the return value of the debconf command *must* be checked
+ # before the string returned by debconf is used for anything.
+
+ local retval
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "run() called with wrong number of arguments; expected at" \
+ "least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ "$@" || retval=$?
+
+ if [ ${retval:-0} -ne 0 ]; then
+ observe "command \"$*\" exited with status $retval"
+ fi
+}
+
+make_symlink_sane () {
+ # syntax: make_symlink_sane symlink target
+ #
+ # Ensure that the symbolic link symlink exists, and points to target.
+ #
+ # If symlink does not exist, create it and point it at target.
+ #
+ # If symlink exists but is not a symbolic link, back it up.
+ #
+ # If symlink exists, is a symbolic link, but points to the wrong location, fix
+ # it.
+ #
+ # If symlink exists, is a symbolic link, and already points to target, do
+ # nothing.
+ #
+ # This function wouldn't be needed if ln had an -I, --idempotent option.
+
+ # Validate arguments.
+ if [ $# -ne 2 ]; then
+ usage_error "make_symlink_sane() called with wrong number of arguments;" \
+ "expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ # We could just use the positional parameters as-is, but that makes things
+ # harder to follow.
+ local symlink target
+
+ symlink="$1"
+ target="$2"
+
+ if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then
+ observe "link from $symlink to $target already exists"
+ else
+ observe "creating symbolic link from $symlink to $target"
+ mkdir -p "${target%/*}" "${symlink%/*}"
+ ln -s -b -S ".dpkg-old" "$target" "$symlink"
+ fi
+}
+
+migrate_dir_to_symlink () {
+ # syntax: migrate_dir_to_symlink old_location new_location
+ #
+ # Per Debian Policy section 6.5.4, "A directory will never be replaced by a
+ # symbolic link to a directory or vice versa; instead, the existing state
+ # (symlink or not) will be left alone and dpkg will follow the symlink if
+ # there is one."
+ #
+ # We have to do it ourselves.
+ #
+ # This function moves the contents of old_location, a directory, into
+ # new_location, a directory, then makes old_location a symbolic link to
+ # new_location.
+ #
+ # old_location need not exist, but if it does, it must be a directory (or a
+ # symlink to a directory). If it is not, it is backed up. If new_location
+ # exists already and is not a directory, it is backed up.
+ #
+ # This function should be called from a package's preinst so that other
+ # packages unpacked after this one --- but before this package's postinst runs
+ # --- are unpacked into new_location even if their payloads contain
+ # old_location filespecs.
+
+ # Validate arguments.
+ if [ $# -ne 2 ]; then
+ usage_error "migrate_dir_to_symlink() called with wrong number of"
+ "arguments; expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ # We could just use the positional parameters as-is, but that makes things
+ # harder to follow.
+ local new old
+
+ old="$1"
+ new="$2"
+
+ # Is old location a symlink?
+ if [ -L "$old" ]; then
+ # Does it already point to new location?
+ if [ "$(readlink "$old")" = "$new" ]; then
+ # Nothing to do; migration has already been done.
+ observe "migration of $old to $new already done"
+ return 0
+ else
+ # Back it up.
+ warn "backing up symbolic link $old as $old.dpkg-old"
+ mv -b "$old" "$old.dpkg-old"
+ fi
+ fi
+
+ # Does old location exist, but is not a directory?
+ if [ -e "$old" ] && ! [ -d "$old" ]; then
+ # Back it up.
+ warn "backing up non-directory $old as $old.dpkg-old"
+ mv -b "$old" "$old.dpkg-old"
+ fi
+
+ observe "migrating $old to $new"
+
+ # Is new location a symlink?
+ if [ -L "$new" ]; then
+ # Does it point the wrong way, i.e., back to where we're migrating from?
+ if [ "$(readlink "$new")" = "$old" ]; then
+ # Get rid of it.
+ observe "removing symbolic link $new which points to $old"
+ rm "$new"
+ else
+ # Back it up.
+ warn "backing up symbolic link $new as $new.dpkg-old"
+ mv -b "$new" "$new.dpkg-old"
+ fi
+ fi
+
+ # Does new location exist, but is not a directory?
+ if [ -e "$new" ] && ! [ -d "$new" ]; then
+ warn "backing up non-directory $new as $new.dpkg-old"
+ mv -b "$new" "$new.dpkg-old"
+ fi
+
+ # Create new directory if it does not yet exist.
+ if ! [ -e "$new" ]; then
+ observe "creating $new"
+ mkdir -p "$new"
+ fi
+
+ # Copy files in old location to new location. Back up any filenames that
+ # already exist in the new location with the extension ".dpkg-old".
+ observe "copying files from $old to $new"
+ if ! (cd "$old" && cp -a -b -S ".dpkg-old" . "$new"); then
+ die "error(s) encountered while copying files from $old to $new"
+ fi
+
+ # Remove files at old location.
+ observe "removing $old"
+ rm -r "$old"
+
+ # Create symlink from old location to new location.
+ make_symlink_sane "$old" "$new"
+}
+
+# vim:set ai et sw=2 ts=2 tw=80:
+
+# GOBSTOPPER: The X Strike Force shell library ends here.
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..58d7c39
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = evdev-properties.h
+sdk_HEADERS = evdev-properties.h
diff --git a/include/evdev-properties.h b/include/evdev-properties.h
new file mode 100755
index 0000000..3e3c194
--- /dev/null
+++ b/include/evdev-properties.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Peter Hutterer (peter.hutterer@redhat.com)
+ */
+
+
+#ifndef _EVDEV_PROPERTIES_H_
+#define _EVDEV_PROPERTIES_H_
+
+/* Middle mouse button emulation */
+/* BOOL */
+#define EVDEV_PROP_MIDBUTTON "Evdev Middle Button Emulation"
+/* CARD32 */
+#define EVDEV_PROP_MIDBUTTON_TIMEOUT "Evdev Middle Button Timeout"
+
+/* Wheel emulation */
+/* BOOL */
+#define EVDEV_PROP_WHEEL "Evdev Wheel Emulation"
+/* CARD8, 4 values [x up, x down, y up, y down], 0 to disable a value*/
+#define EVDEV_PROP_WHEEL_AXES "Evdev Wheel Emulation Axes"
+/* CARD16 */
+#define EVDEV_PROP_WHEEL_INERTIA "Evdev Wheel Emulation Inertia"
+/* CARD16 */
+#define EVDEV_PROP_WHEEL_TIMEOUT "Evdev Wheel Emulation Timeout"
+/* CARD8, value range 0-32, 0 to always scroll */
+#define EVDEV_PROP_WHEEL_BUTTON "Evdev Wheel Emulation Button"
+
+/* Drag lock */
+/* CARD8, either 1 value or pairs, value range 0-32, 0 to disable a value*/
+#define EVDEV_PROP_DRAGLOCK "Evdev Drag Lock Buttons"
+
+/* Axis inversion */
+/* BOOL, 2 values [x, y], 1 inverts axis */
+#define EVDEV_PROP_INVERT_AXES "Evdev Axis Inversion"
+
+/* Reopen attempts. */
+/* CARD8 */
+#define EVDEV_PROP_REOPEN "Evdev Reopen Attempts"
+
+/* Run-time calibration */
+/* CARD32, 4 values [minx, maxx, miny, maxy], or no values for unset */
+#define EVDEV_PROP_CALIBRATION "Evdev Axis Calibration"
+
+/* Swap x and y axis. */
+/* BOOL */
+#define EVDEV_PROP_SWAP_AXES "Evdev Axes Swap"
+
+#endif
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..276f2f0
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,57 @@
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation.
+#
+# 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 OPEN GROUP 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.
+#
+# Except as contained in this notice, the name of the copyright holders shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from the copyright holders.
+#
+
+drivermandir = $(DRIVER_MAN_DIR)
+
+driverman_PRE = @DRIVER_NAME@.man
+
+driverman_DATA = $(driverman_PRE:man=@DRIVER_MAN_SUFFIX@)
+
+EXTRA_DIST = @DRIVER_NAME@.man
+
+CLEANFILES = $(driverman_DATA)
+
+SED = sed
+
+# Strings to replace in man pages
+XORGRELSTRING = @PACKAGE_STRING@
+ XORGMANNAME = X Version 11
+
+MAN_SUBSTS = \
+ -e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xservername__|Xorg|g' \
+ -e 's|__xconfigfile__|xorg.conf|g' \
+ -e 's|__projectroot__|$(prefix)|g' \
+ -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \
+ -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
+ -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
+ -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
+ -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+
+SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
+
+.man.$(DRIVER_MAN_SUFFIX):
+ sed $(MAN_SUBSTS) < $< > $@
diff --git a/man/evdev.man b/man/evdev.man
new file mode 100644
index 0000000..9dd7a77
--- /dev/null
+++ b/man/evdev.man
@@ -0,0 +1,231 @@
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH EVDEV __drivermansuffix__ __vendorversion__
+.SH NAME
+evdev \- Generic Linux input driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qInputDevice\*q"
+.BI " Identifier \*q" devname \*q
+.B " Driver \*qevdev\*q"
+.BI " Option \*qDevice\*q \*q" devpath \*q
+.BI " Option \*qEmulate3Buttons\*q \*q" True \*q
+.BI " Option \*qEmulate3Timeout\*q \*q" 50 \*q
+.BI " Option \*qGrabDevice\*q \*q" False \*q
+\ \ ...
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B evdev
+is an __xservername__ input driver for Linux\'s generic event devices. It
+therefore supports all input devices that the kernel knows about, including
+most mice and keyboards.
+.PP
+The
+.B evdev
+driver can serve as both a pointer and a keyboard input device, and may be
+used as both the core keyboard and the core pointer. Multiple input devices
+are supported by multiple instances of this driver, with one Load
+directive for evdev in the Module section of your __xconfigfile__ for each
+input device that will use this driver.
+.PP
+.SH SUPPORTED HARDWARE
+In general, any input device that the kernel has a driver for can be accessed
+through the
+.B evdev
+driver. See the Linux kernel documentation for a complete list.
+.PP
+.SH CONFIGURATION DETAILS
+Please refer to __xconfigfile__(__filemansuffix__) for general configuration
+details and for options that can be used with all input drivers. This
+section only covers configuration details specific to this driver.
+.PP
+The following driver
+.B Options
+are supported:
+.TP 7
+.BI "Option \*qButtonMapping\*q \*q" string \*q
+Sets the button mapping for this device. The mapping is a space-separated list
+of button mappings that correspond in order to the physical buttons on the
+device (i.e. the first number is the mapping for button 1, etc.). The default
+mapping is "1 2 3 ... 32". A mapping of 0 deactivates the button. Multiple
+buttons can have the same mapping.
+For example, a left-handed mouse with deactivated scroll-wheel would use a
+mapping of "3 2 1 0 0". Invalid mappings are ignored and the default mapping
+is used. Buttons not specified in the user's mapping use the default mapping.
+.TP 7
+.BI "Option \*qDevice\*q \*q" string \*q
+Specifies the device through which the device can be accessed. This will
+generally be of the form \*q/dev/input/eventX\*q, where X is some integer.
+The mapping from device node to hardware is system-dependent.
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "L1 B2 L3 B4" \*q
+Sets \*qdrag lock buttons\*q that simulate holding a button down, so
+that low dexterity people do not have to hold a button down at the
+same time they move a mouse cursor. Button numbers occur in pairs,
+with the lock button number occurring first, followed by the button
+number that is the target of the lock button. Property: "Evdev
+Drag Lock Buttons".
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "M1" \*q
+Sets a \*qmaster drag lock button\*q that acts as a \*qMeta Key\*q
+indicating that the next button pressed is to be
+\*qdrag locked\*q. Property: "Evdev Drag Lock Buttons".
+.TP 7
+.TP 7
+.BI "Option \*qEmulate3Buttons\*q \*q" boolean \*q
+Enable/disable the emulation of the third (middle) mouse button for mice
+which only have two physical buttons. The third button is emulated by
+pressing both buttons simultaneously. Default: on, until a middle mouse
+button event is registered. Property: "Evdev Middle Button Emulation".
+.TP 7
+.BI "Option \*qEmulate3Timeout\*q \*q" integer \*q
+Sets the timeout (in milliseconds) that the driver waits before deciding
+if two buttons where pressed "simultaneously" when 3 button emulation is
+enabled. Default: 50. Property: "Evdev Middle Button Timeout".
+.BI "Option \*qEmulateWheel\*q \*q" boolean \*q
+Enable/disable "wheel" emulation. Wheel emulation means emulating button
+press/release events when the mouse is moved while a specific real button
+is pressed. Wheel button events (typically buttons 4 and 5) are
+usually used for scrolling. Wheel emulation is useful for getting wheel-like
+behaviour with trackballs. It can also be useful for mice with 4 or
+more buttons but no wheel. See the description of the
+.BR EmulateWheelButton ,
+.BR EmulateWheelInertia ,
+.BR EmulateWheelTimeout ,
+.BR XAxisMapping ,
+and
+.B YAxisMapping
+options. Default: off. Property "Evdev Wheel Emulation".
+.TP 7
+.BI "Option \*qEmulateWheelButton\*q \*q" integer \*q
+Specifies which button must be held down to enable wheel emulation mode.
+While this button is down, X and/or Y pointer movement will generate button
+press/release events as specified for the
+.B XAxisMapping
+and
+.B YAxisMapping
+settings. If the button is 0 and
+.BR EmulateWheel
+is on, any motion of the device is converted into wheel events. Default: 4.
+Property: "Evdev Wheel Emulation Button".
+.TP 7
+.BI "Option \*qEmulateWheelInertia\*q \*q" integer \*q
+Specifies how far (in pixels) the pointer must move to generate button
+press/release events in wheel emulation mode. Default: 10. Property: "Evdev
+Wheel Emulation Inertia".
+.TP 7
+.BI "Option \*qEmulateWheelTimeout\*q \*q" integer \*q
+Specifies the time in milliseconds the
+.BR EmulateWheelButton
+must be pressed before wheel emulation is started. If the
+.BR EmulateWheelButton
+is released before this timeout, the original button press/release event
+is sent. Default: 200. Property: "Evdev Wheel Emulation Timeout".
+.TP 7
+.BI "Option \*qGrabDevice\*q \*q" boolean \*q
+Force a grab on the event device. Doing so will ensure that no other driver
+can initialise the same device and it will also stop the device from sending
+events to /dev/kbd or /dev/input/mice. Events from this device will not be
+sent to virtual devices (e.g. rfkill or the Macintosh mouse button emulation).
+Default: disabled.
+.TP 7
+.BI "Option \*qInvertX\*q \*q" Bool \*q
+.TP 7
+.BI "Option \*qInvertY\*q \*q" Bool \*q
+Invert the given axis. Default: off. Property: "Evdev Axis Inversion".
+.TP 7
+.BI "Option \*qIgnoreRelativeAxes\*q \*q" Bool \*q
+.TP 7
+.BI "Option \*qIgnoreAbsoluteAxes\*q \*q" Bool \*q
+Ignore the specified type of axis. Default: unset. The X server cannot deal
+with devices that have both relative and absolute axes. Evdev tries to guess
+wich axes to ignore given the device type and disables absolute axes for
+mice and relative axes for tablets, touchscreens and touchpad. These options
+allow to forcibly disable an axis type. Mouse wheel axes are exempt and will
+work even if relative axes are ignored. No property, this configuration must
+be set in the configuration.
+.br
+If either option is set to False, the driver will not ignore the specified
+axes regardless of the presence of other axes. This may trigger buggy
+behavior and events from this axis are always forwarded. Users are
+discouraged from setting this option.
+.TP 7
+.BI "Option \*qReopenAttempts\*q \*q" integer \*q
+Number of reopen attempts after a read error occurs on the device (e.g. after
+waking up from suspend). In between each attempt is a 100ms wait. Default: 10.
+.TP 7
+.BI "Option \*qCalibration\*q \*q" "min-x max-x min-y max-y" \*q
+Calibrates the X and Y axes for devices that need to scale to a different
+coordinate system than reported to the X server. This feature is required
+for devices that need to scale to a different coordinate system than
+originally reported by the kernel (e.g. touchscreens). The scaling to the
+custom coordinate system is done in-driver and the X server is unaware of
+the transformation. Property: "Evdev Axis Calibration".
+.TP 7
+.BI "Option \*qSwapAxes\*q \*q" Bool \*q
+Swap x/y axes. Default: off. Property: "Evdev Axes Swap".
+.TP 7
+.BI "Option \*qXAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the X direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative X axis motion and button number
+.I N2
+is mapped to the positive X axis motion. Default: no mapping. Property:
+"Evdev Wheel Emulation Axes".
+.TP 7
+.BI "Option \*qYAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the Y direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative Y axis motion and button number
+.I N2
+is mapped to the positive Y axis motion. Default: "4 5". Property:
+"Evdev Wheel Emulation Axes".
+
+.SH SUPPORTED PROPERTIES
+The following properties are provided by the
+.B evdev
+driver.
+.TP 7
+.BI "Evdev Axis Calibration"
+4 32-bit values, order min-x, max-x, min-y, max-y or 0 values to disable
+in-driver axis calibration.
+.TP 7
+.BI "Evdev Axis Inversion"
+2 boolean values (8 bit, 0 or 1), order X, Y. 1 inverts the axis.
+.TP 7
+.BI "Evdev Axes Swap"
+1 boolean value (8 bit, 0 or 1). 1 swaps x/y axes.
+.TP 7
+.BI "Evdev Drag Lock Buttons"
+8-bit. Either 1 value or pairs of values. Value range 0-32, 0 disables a
+value.
+.TP 7
+.BI "Evdev Middle Button Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "Evdev Middle Button Timeout"
+1 16-bit positive value.
+.TP 7
+.BI "Evdev Wheel Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "Evdev Wheel Emulation Axes"
+4 8-bit values, order X up, X down, Y up, Y down. 0 disables a value.
+.TP 7
+.BI "Evdev Wheel Emulation Button"
+1 8-bit value, allowed range 0-32, 0 disables the button.
+.TP 7
+.BI "Evdev Wheel Emulation Inertia"
+1 16-bit positive value.
+.TP 7
+.BI "Evdev Wheel Emulation Timeout"
+1 16-bit positive value.
+
+.SH AUTHORS
+Kristian Høgsberg.
+.SH "SEE ALSO"
+__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__),
+README.mouse.
diff --git a/packaging/xorg-x11-drv-evdev.spec b/packaging/xorg-x11-drv-evdev.spec
new file mode 100644
index 0000000..548424c
--- /dev/null
+++ b/packaging/xorg-x11-drv-evdev.spec
@@ -0,0 +1,54 @@
+Name: xorg-x11-drv-evdev
+Summary: Xorg X11 evdev input driver
+Version: 2.3.2
+Release: 4
+Group: System/X Hardware Support
+License: MIT
+URL: http://www.x.org/
+Source0: http://xorg.freedesktop.org/releases/individual/driver/xf86-input-evdev-%{version}.tar.gz
+Requires: xorg-x11-server
+BuildRequires: pkgconfig(xorg-server)
+BuildRequires: pkgconfig(xkbfile)
+BuildRequires: pkgconfig(xproto)
+BuildRequires: pkgconfig(inputproto)
+BuildRequires: pkgconfig(xrandr)
+BuildRequires: pkgconfig(randrproto)
+BuildRequires: pkgconfig(xextproto)
+
+
+%description
+The Xorg X11 evdev input driver
+
+
+%package devel
+Summary: Development files for xorg evdev driver
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+This package contains xorg evdev development files
+
+
+%prep
+%setup -q -n xf86-input-evdev-%{version}
+
+%build
+
+%reconfigure --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%remove_docs
+
+%files
+%defattr(-,root,root,-)
+%(pkg-config xorg-server --variable=moduledir )/input/evdev_drv.so
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/xorg/evdev-properties.h
+%{_libdir}/pkgconfig/xorg-evdev.pc
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2b6c800
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,40 @@
+# Copyright 2005 Adam Jackson.
+#
+# 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
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, 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 (including the next
+# paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON 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.
+
+
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+AM_CFLAGS = $(XORG_CFLAGS)
+
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+
+INCLUDES=-I$(top_srcdir)/include/
+
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
+ @DRIVER_NAME@.h \
+ emuMB.c \
+ emuWheel.c \
+ draglock.c
+
diff --git a/src/draglock.c b/src/draglock.c
new file mode 100644
index 0000000..6157cae
--- /dev/null
+++ b/src/draglock.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ * Copyright 1993 by David Dawes <dawes@xfree86.org>
+ * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+ * Copyright 1994-2002 by The XFree86 Project, Inc.
+ * Copyright 2002 by Paul Elliott
+ * (Ported from xf86-input-mouse, above copyrights taken from there)
+ * Copyright © 2008 University of South Australia
+ * Copyright 2008 by Chris Salch
+ * Copyright 2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the authors
+ * not be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The authors make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/* Draglock code */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <X11/Xatom.h>
+#include <exevents.h>
+
+#include <evdev-properties.h>
+#include "evdev.h"
+
+#ifdef HAVE_PROPERTIES
+static Atom prop_dlock = 0; /* Drag lock buttons. */
+#endif
+
+void EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button);
+
+
+/* Setup and configuration code */
+void
+EvdevDragLockPreInit(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ char *option_string = NULL;
+ int meta_button = 0;
+ int lock_button = 0;
+ char *next_num = NULL;
+ char *end_str = NULL;
+ BOOL pairs = FALSE;
+
+ option_string = xf86CheckStrOption(pInfo->options, "DragLockButtons",NULL);
+
+ if (!option_string)
+ return;
+
+ next_num = option_string;
+
+ /* Loop until we hit the end of our option string */
+ while (next_num != NULL) {
+ lock_button = 0;
+ meta_button = strtol(next_num, &end_str, 10);
+
+ /* check to see if we found anything */
+ if (next_num != end_str) {
+ /* setup for the next number */
+ next_num = end_str;
+ } else {
+ /* we have nothing more to parse, drop out of the loop */
+ next_num = NULL;
+ }
+
+ /* Check for a button to lock if we have a meta button */
+ if (meta_button != 0 && next_num != NULL ) {
+ lock_button = strtol(next_num, &end_str, 10);
+
+ /* check to see if we found anything */
+ if (next_num != end_str) {
+ /* setup for the next number */
+ next_num = end_str;
+ } else {
+ /* we have nothing more to parse, drop out of the loop */
+ next_num = NULL;
+ }
+ }
+
+ /* Ok, let the user know what we found on this look */
+ if (meta_button != 0) {
+ if (lock_button == 0) {
+ if (!pairs) {
+ /* We only have a meta button */
+ pEvdev->dragLock.meta = meta_button;
+
+ xf86Msg(X_CONFIG, "%s: DragLockButtons : "
+ "%i as meta\n",
+ pInfo->name, meta_button);
+ } else {
+ xf86Msg(X_ERROR, "%s: DragLockButtons : "
+ "Incomplete pair specifying button pairs %s\n",
+ pInfo->name, option_string);
+ }
+ } else {
+
+ /* Do bounds checking to make sure we don't crash */
+ if ((meta_button <= EVDEV_MAXBUTTONS) && (meta_button >= 0 ) &&
+ (lock_button <= EVDEV_MAXBUTTONS) && (lock_button >= 0)) {
+
+ xf86Msg(X_CONFIG, "%s: DragLockButtons : %i -> %i\n",
+ pInfo->name, meta_button, lock_button);
+
+ pEvdev->dragLock.lock_pair[meta_button - 1] = lock_button;
+ pairs=TRUE;
+ } else {
+ /* Let the user know something was wrong
+ with this pair of buttons */
+ xf86Msg(X_CONFIG, "%s: DragLockButtons : "
+ "Invalid button pair %i -> %i\n",
+ pInfo->name, meta_button, lock_button);
+ }
+ }
+ } else {
+ xf86Msg(X_ERROR, "%s: Found DragLockButtons "
+ "with invalid lock button string : '%s'\n",
+ pInfo->name, option_string);
+
+ /* This should be the case anyhow, just make sure */
+ next_num = NULL;
+ }
+
+ /* Check for end of string, to avoid annoying error */
+ if (next_num != NULL && *next_num == '\0')
+ next_num = NULL;
+ }
+}
+
+/* Updates DragLock button state and fires button event messges */
+void
+EvdevDragLockLockButton(InputInfoPtr pInfo, unsigned int button)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ BOOL state = 0;
+
+ /* update button state */
+ state = pEvdev->dragLock.lock_state[button - 1] ? FALSE : TRUE;
+ pEvdev->dragLock.lock_state[button - 1] = state;
+
+ EvdevQueueButtonEvent(pInfo, button, state);
+}
+
+/* Filter button presses looking for either a meta button or the
+ * control of a button pair.
+ *
+ * @param button button number (1 for left, 3 for right)
+ * @param value TRUE if button press, FALSE if release
+ *
+ * @return TRUE if the event was swallowed here, FALSE otherwise.
+ */
+BOOL
+EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+
+ if (button == 0)
+ return FALSE;
+
+ /* Do we have a single meta key or
+ several button pairings? */
+ if (pEvdev->dragLock.meta != 0) {
+
+ if (pEvdev->dragLock.meta == button) {
+
+ /* setup up for button lock */
+ if (value)
+ pEvdev->dragLock.meta_state = TRUE;
+
+ return TRUE;
+ } else if (pEvdev->dragLock.meta_state) { /* waiting to lock */
+
+ pEvdev->dragLock.meta_state = FALSE;
+
+ EvdevDragLockLockButton(pInfo, button);
+
+ return TRUE;
+ }
+ } else if (pEvdev->dragLock.lock_pair[button - 1] && value) {
+ /* A meta button in a meta/lock pair was pressed */
+ EvdevDragLockLockButton(pInfo, pEvdev->dragLock.lock_pair[button - 1]);
+ return TRUE;
+ }
+
+ /* Eat events for buttons that are locked */
+ if (pEvdev->dragLock.lock_state[button - 1])
+ return TRUE;
+
+ return FALSE;
+}
+
+#ifdef HAVE_PROPERTIES
+/**
+ * Set the drag lock property.
+ * If only one value is supplied, then this is used as the meta button.
+ * If more than one value is supplied, then each value is the drag lock button
+ * for the pair. 0 disables a pair.
+ * i.e. to set bt 3 to draglock button 1, supply 0,0,1
+ */
+static int
+EvdevDragLockSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (atom == prop_dlock)
+ {
+ int i;
+
+ if (val->format != 8 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ /* Don't allow changes while a lock is active */
+ if (pEvdev->dragLock.meta)
+ {
+ if (pEvdev->dragLock.meta_state)
+ return BadAccess;
+ } else
+ {
+ for (i = 0; i < EVDEV_MAXBUTTONS; i++)
+ if (pEvdev->dragLock.lock_state[i])
+ return BadValue;
+ }
+
+ if (val->size == 0)
+ return BadMatch;
+ else if (val->size == 1)
+ {
+ int meta = *((CARD8*)val->data);
+ if (meta > EVDEV_MAXBUTTONS)
+ return BadValue;
+
+ if (!checkonly)
+ {
+ pEvdev->dragLock.meta = meta;
+ memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
+ }
+ } else if ((val->size % 2) == 0)
+ {
+ CARD8* vals = (CARD8*)val->data;
+
+ for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i++)
+ if (vals[i] > EVDEV_MAXBUTTONS)
+ return BadValue;
+
+ if (!checkonly)
+ {
+ pEvdev->dragLock.meta = 0;
+ memset(pEvdev->dragLock.lock_pair, 0, sizeof(pEvdev->dragLock.lock_pair));
+
+ for (i = 0; i < val->size && i < EVDEV_MAXBUTTONS; i += 2)
+ pEvdev->dragLock.lock_pair[vals[i] - 1] = vals[i + 1];
+ }
+ } else
+ return BadMatch;
+ }
+
+ return Success;
+}
+
+/**
+ * Initialise property for drag lock buttons setting.
+ */
+void
+EvdevDragLockInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (!dev->button) /* don't init prop for keyboards */
+ return;
+
+ prop_dlock = MakeAtom(EVDEV_PROP_DRAGLOCK, strlen(EVDEV_PROP_DRAGLOCK), TRUE);
+ if (pEvdev->dragLock.meta)
+ {
+ XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8,
+ PropModeReplace, 1, &pEvdev->dragLock.meta,
+ FALSE);
+ } else {
+ int highest = 0;
+ int i;
+ CARD8 pair[EVDEV_MAXBUTTONS] = {0};
+
+ for (i = 0; i < EVDEV_MAXBUTTONS; i++)
+ {
+ if (pEvdev->dragLock.lock_pair[i])
+ highest = i;
+ pair[i] = pEvdev->dragLock.lock_pair[i];
+ }
+
+ XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8, PropModeReplace,
+ highest + 1, pair, FALSE);
+ }
+
+ XISetDevicePropertyDeletable(dev, prop_dlock, FALSE);
+
+ XIRegisterPropertyHandler(dev, EvdevDragLockSetProperty, NULL, NULL);
+}
+
+#endif
diff --git a/src/emuMB.c b/src/emuMB.c
new file mode 100644
index 0000000..199c0d7
--- /dev/null
+++ b/src/emuMB.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ * Copyright 1993 by David Dawes <dawes@xfree86.org>
+ * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+ * Copyright 1994-2002 by The XFree86 Project, Inc.
+ * Copyright 2002 by Paul Elliott
+ * (Ported from xf86-input-mouse, above copyrights taken from there)
+ * Copyright © 2008 University of South Australia
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the authors
+ * not be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The authors make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/* Middle mouse button emulation code. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xatom.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+
+#include <evdev-properties.h>
+#include "evdev.h"
+
+enum {
+ MBEMU_DISABLED = 0,
+ MBEMU_ENABLED,
+ MBEMU_AUTO
+};
+
+#ifdef HAVE_PROPERTIES
+static Atom prop_mbemu = 0; /* Middle button emulation on/off property */
+static Atom prop_mbtimeout = 0; /* Middle button timeout property */
+#endif
+/*
+ * Lets create a simple finite-state machine for 3 button emulation:
+ *
+ * We track buttons 1 and 3 (left and right). There are 11 states:
+ * 0 ground - initial state
+ * 1 delayed left - left pressed, waiting for right
+ * 2 delayed right - right pressed, waiting for left
+ * 3 pressed middle - right and left pressed, emulated middle sent
+ * 4 pressed left - left pressed and sent
+ * 5 pressed right - right pressed and sent
+ * 6 released left - left released after emulated middle
+ * 7 released right - right released after emulated middle
+ * 8 repressed left - left pressed after released left
+ * 9 repressed right - right pressed after released right
+ * 10 pressed both - both pressed, not emulating middle
+ *
+ * At each state, we need handlers for the following events
+ * 0: no buttons down
+ * 1: left button down
+ * 2: right button down
+ * 3: both buttons down
+ * 4: emulate3Timeout passed without a button change
+ * Note that button events are not deltas, they are the set of buttons being
+ * pressed now. It's possible (ie, mouse hardware does it) to go from (eg)
+ * left down to right down without anything in between, so all cases must be
+ * handled.
+ *
+ * a handler consists of three values:
+ * 0: action1
+ * 1: action2
+ * 2: new emulation state
+ *
+ * action > 0: ButtonPress
+ * action = 0: nothing
+ * action < 0: ButtonRelease
+ *
+ * The comment preceeding each section is the current emulation state.
+ * The comments to the right are of the form
+ * <button state> (<events>) -> <new emulation state>
+ * which should be read as
+ * If the buttons are in <button state>, generate <events> then go to
+ * <new emulation state>.
+ */
+static signed char stateTab[11][5][3] = {
+/* 0 ground */
+ {
+ { 0, 0, 0 }, /* nothing -> ground (no change) */
+ { 0, 0, 1 }, /* left -> delayed left */
+ { 0, 0, 2 }, /* right -> delayed right */
+ { 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
+ { 0, 0, -1 } /* timeout N/A */
+ },
+/* 1 delayed left */
+ {
+ { 1, -1, 0 }, /* nothing (left event) -> ground */
+ { 0, 0, 1 }, /* left -> delayed left (no change) */
+ { 1, -1, 2 }, /* right (left event) -> delayed right */
+ { 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
+ { 1, 0, 4 }, /* timeout (left press) -> pressed left */
+ },
+/* 2 delayed right */
+ {
+ { 3, -3, 0 }, /* nothing (right event) -> ground */
+ { 3, -3, 1 }, /* left (right event) -> delayed left (no change) */
+ { 0, 0, 2 }, /* right -> delayed right (no change) */
+ { 2, 0, 3 }, /* left & right (middle press) -> pressed middle */
+ { 3, 0, 5 }, /* timeout (right press) -> pressed right */
+ },
+/* 3 pressed middle */
+ {
+ { -2, 0, 0 }, /* nothing (middle release) -> ground */
+ { 0, 0, 7 }, /* left -> released right */
+ { 0, 0, 6 }, /* right -> released left */
+ { 0, 0, 3 }, /* left & right -> pressed middle (no change) */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 4 pressed left */
+ {
+ { -1, 0, 0 }, /* nothing (left release) -> ground */
+ { 0, 0, 4 }, /* left -> pressed left (no change) */
+ { -1, 0, 2 }, /* right (left release) -> delayed right */
+ { 3, 0, 10 }, /* left & right (right press) -> pressed both */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 5 pressed right */
+ {
+ { -3, 0, 0 }, /* nothing (right release) -> ground */
+ { -3, 0, 1 }, /* left (right release) -> delayed left */
+ { 0, 0, 5 }, /* right -> pressed right (no change) */
+ { 1, 0, 10 }, /* left & right (left press) -> pressed both */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 6 released left */
+ {
+ { -2, 0, 0 }, /* nothing (middle release) -> ground */
+ { -2, 0, 1 }, /* left (middle release) -> delayed left */
+ { 0, 0, 6 }, /* right -> released left (no change) */
+ { 1, 0, 8 }, /* left & right (left press) -> repressed left */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 7 released right */
+ {
+ { -2, 0, 0 }, /* nothing (middle release) -> ground */
+ { 0, 0, 7 }, /* left -> released right (no change) */
+ { -2, 0, 2 }, /* right (middle release) -> delayed right */
+ { 3, 0, 9 }, /* left & right (right press) -> repressed right */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 8 repressed left */
+ {
+ { -2, -1, 0 }, /* nothing (middle release, left release) -> ground */
+ { -2, 0, 4 }, /* left (middle release) -> pressed left */
+ { -1, 0, 6 }, /* right (left release) -> released left */
+ { 0, 0, 8 }, /* left & right -> repressed left (no change) */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 9 repressed right */
+ {
+ { -2, -3, 0 }, /* nothing (middle release, right release) -> ground */
+ { -3, 0, 7 }, /* left (right release) -> released right */
+ { -2, 0, 5 }, /* right (middle release) -> pressed right */
+ { 0, 0, 9 }, /* left & right -> repressed right (no change) */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+/* 10 pressed both */
+ {
+ { -1, -3, 0 }, /* nothing (left release, right release) -> ground */
+ { -3, 0, 4 }, /* left (right release) -> pressed left */
+ { -1, 0, 5 }, /* right (left release) -> pressed right */
+ { 0, 0, 10 }, /* left & right -> pressed both (no change) */
+ { 0, 0, -1 }, /* timeout N/A */
+ },
+};
+
+
+int
+EvdevMBEmuTimer(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ int sigstate;
+ int id;
+
+ sigstate = xf86BlockSIGIO ();
+
+ pEvdev->emulateMB.pending = FALSE;
+ if ((id = stateTab[pEvdev->emulateMB.state][4][0]) != 0) {
+ EvdevPostButtonEvent(pInfo, abs(id), (id >= 0));
+ pEvdev->emulateMB.state =
+ stateTab[pEvdev->emulateMB.state][4][2];
+ } else {
+ ErrorF("Got unexpected buttonTimer in state %d\n",
+ pEvdev->emulateMB.state);
+ }
+
+ xf86UnblockSIGIO (sigstate);
+ return 0;
+}
+
+
+/**
+ * Emulate a middle button on button press.
+ *
+ * @param code button number (1 for left, 3 for right)
+ * @param press TRUE if press, FALSE if release.
+ *
+ * @return TRUE if event was swallowed by middle mouse button emulation, FALSE
+ * otherwise.
+ */
+BOOL
+EvdevMBEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ int id;
+ int *btstate;
+ int ret = FALSE;
+
+ if (!pEvdev->emulateMB.enabled)
+ return ret;
+
+ if (button == 2) {
+ EvdevMBEmuEnable(pInfo, FALSE);
+ return ret;
+ }
+
+ /* don't care about other buttons */
+ if (button != 1 && button != 3)
+ return ret;
+
+ btstate = &pEvdev->emulateMB.buttonstate;
+ if (press)
+ *btstate |= (button == 1) ? 0x1 : 0x2;
+ else
+ *btstate &= (button == 1) ? ~0x1 : ~0x2;
+
+ if ((id = stateTab[pEvdev->emulateMB.state][*btstate][0]) != 0)
+ {
+ EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ ret = TRUE;
+ }
+ if ((id = stateTab[pEvdev->emulateMB.state][*btstate][1]) != 0)
+ {
+ EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ ret = TRUE;
+ }
+
+ pEvdev->emulateMB.state =
+ stateTab[pEvdev->emulateMB.state][*btstate][2];
+
+ if (stateTab[pEvdev->emulateMB.state][4][0] != 0) {
+ pEvdev->emulateMB.expires = GetTimeInMillis () + pEvdev->emulateMB.timeout;
+ pEvdev->emulateMB.pending = TRUE;
+ ret = TRUE;
+ } else {
+ pEvdev->emulateMB.pending = FALSE;
+ }
+
+ return ret;
+}
+
+
+void EvdevMBEmuWakeupHandler(pointer data,
+ int i,
+ pointer LastSelectMask)
+{
+ InputInfoPtr pInfo = (InputInfoPtr)data;
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ int ms;
+
+ if (pEvdev->emulateMB.pending)
+ {
+ ms = pEvdev->emulateMB.expires - GetTimeInMillis();
+ if (ms <= 0)
+ EvdevMBEmuTimer(pInfo);
+ }
+}
+
+void EvdevMBEmuBlockHandler(pointer data,
+ struct timeval **waitTime,
+ pointer LastSelectMask)
+{
+ InputInfoPtr pInfo = (InputInfoPtr) data;
+ EvdevPtr pEvdev= (EvdevPtr) pInfo->private;
+ int ms;
+
+ if (pEvdev->emulateMB.pending)
+ {
+ ms = pEvdev->emulateMB.expires - GetTimeInMillis ();
+ if (ms <= 0)
+ ms = 0;
+ AdjustWaitForDelay (waitTime, ms);
+ }
+}
+
+void
+EvdevMBEmuPreInit(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ pEvdev->emulateMB.enabled = MBEMU_AUTO;
+
+ if (xf86FindOption(pInfo->options, "Emulate3Buttons"))
+ {
+ pEvdev->emulateMB.enabled = xf86SetBoolOption(pInfo->options,
+ "Emulate3Buttons",
+ MBEMU_ENABLED);
+ xf86Msg(X_INFO, "%s: Forcing middle mouse button emulation %s.\n",
+ pInfo->name, (pEvdev->emulateMB.enabled) ? "on" : "off");
+ }
+
+ pEvdev->emulateMB.timeout = xf86SetIntOption(pInfo->options,
+ "Emulate3Timeout", 50);
+}
+
+void
+EvdevMBEmuOn(InputInfoPtr pInfo)
+{
+ if (!pInfo->dev->button) /* don't init for keyboards */
+ return;
+
+ RegisterBlockAndWakeupHandlers (EvdevMBEmuBlockHandler,
+ EvdevMBEmuWakeupHandler,
+ (pointer)pInfo);
+}
+
+void
+EvdevMBEmuFinalize(InputInfoPtr pInfo)
+{
+ if (!pInfo->dev->button) /* don't cleanup for keyboards */
+ return;
+
+ RemoveBlockAndWakeupHandlers (EvdevMBEmuBlockHandler,
+ EvdevMBEmuWakeupHandler,
+ (pointer)pInfo);
+
+}
+
+/* Enable/disable middle mouse button emulation. */
+void
+EvdevMBEmuEnable(InputInfoPtr pInfo, BOOL enable)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ if (pEvdev->emulateMB.enabled == MBEMU_AUTO)
+ pEvdev->emulateMB.enabled = enable;
+}
+
+
+#ifdef HAVE_PROPERTIES
+static int
+EvdevMBEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (atom == prop_mbemu)
+ {
+ if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ pEvdev->emulateMB.enabled = *((BOOL*)val->data);
+ } else if (atom == prop_mbtimeout)
+ {
+ if (val->format != 32 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ pEvdev->emulateMB.timeout = *((CARD32*)val->data);
+ }
+
+ return Success;
+}
+
+/**
+ * Initialise property for MB emulation on/off.
+ */
+void
+EvdevMBEmuInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+ int rc;
+
+ if (!dev->button) /* don't init prop for keyboards */
+ return;
+
+ prop_mbemu = MakeAtom(EVDEV_PROP_MIDBUTTON, strlen(EVDEV_PROP_MIDBUTTON), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_mbemu, XA_INTEGER, 8,
+ PropModeReplace, 1,
+ &pEvdev->emulateMB.enabled,
+ FALSE);
+ if (rc != Success)
+ return;
+ XISetDevicePropertyDeletable(dev, prop_mbemu, FALSE);
+
+ prop_mbtimeout = MakeAtom(EVDEV_PROP_MIDBUTTON_TIMEOUT,
+ strlen(EVDEV_PROP_MIDBUTTON_TIMEOUT),
+ TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_mbtimeout, XA_INTEGER, 32, PropModeReplace, 1,
+ &pEvdev->emulateMB.timeout, FALSE);
+
+ if (rc != Success)
+ return;
+ XISetDevicePropertyDeletable(dev, prop_mbtimeout, FALSE);
+
+ XIRegisterPropertyHandler(dev, EvdevMBEmuSetProperty, NULL, NULL);
+}
+#endif
diff --git a/src/emuWheel.c b/src/emuWheel.c
new file mode 100644
index 0000000..9be4eb9
--- /dev/null
+++ b/src/emuWheel.c
@@ -0,0 +1,478 @@
+/*
+* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+* Copyright 1993 by David Dawes <dawes@xfree86.org>
+* Copyright 2002 by SuSE Linux AG, Author: Egbert Eich
+* Copyright 1994-2002 by The XFree86 Project, Inc.
+* Copyright 2002 by Paul Elliott
+* (Ported from xf86-input-mouse, above copyrights taken from there)
+* Copyright 2008 by Chris Salch
+* Copyright © 2008 Red Hat, Inc.
+*
+* Permission to use, copy, modify, distribute, and sell this software
+* and its documentation for any purpose is hereby granted without
+* fee, provided that the above copyright notice appear in all copies
+* and that both that copyright notice and this permission notice
+* appear in supporting documentation, and that the name of the authors
+* not be used in advertising or publicity pertaining to distribution of the
+* software without specific, written prior permission. The authors make no
+* representations about the suitability of this software for any
+* purpose. It is provided "as is" without express or implied
+* warranty.
+*
+* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*
+*/
+
+/* Mouse wheel emulation code. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xatom.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+
+#include <evdev-properties.h>
+#include "evdev.h"
+
+#define WHEEL_NOT_CONFIGURED 0
+
+#ifdef HAVE_PROPERTIES
+static Atom prop_wheel_emu = 0;
+static Atom prop_wheel_axismap = 0;
+static Atom prop_wheel_inertia = 0;
+static Atom prop_wheel_timeout = 0;
+static Atom prop_wheel_button = 0;
+#endif
+
+/* Local Funciton Prototypes */
+static BOOL EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char *axis_name);
+static int EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value);
+
+/* Filter mouse button events */
+BOOL
+EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ int ms;
+
+ /* Has wheel emulation been configured to be enabled? */
+ if (!pEvdev->emulateWheel.enabled)
+ return FALSE;
+
+ /* Check for EmulateWheelButton */
+ if (pEvdev->emulateWheel.button == button) {
+ pEvdev->emulateWheel.button_state = value;
+
+ if (value)
+ /* Start the timer when the button is pressed */
+ pEvdev->emulateWheel.expires = pEvdev->emulateWheel.timeout +
+ GetTimeInMillis();
+ else {
+ ms = pEvdev->emulateWheel.expires - GetTimeInMillis();
+ if (ms > 0) {
+ /*
+ * If the button is released early enough emit the button
+ * press/release events
+ */
+ EvdevQueueButtonClicks(pInfo, button, 1);
+ }
+ }
+
+ return TRUE;
+ }
+
+ /* Don't care about this event */
+ return FALSE;
+}
+
+/* Filter mouse wheel events */
+BOOL
+EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ WheelAxisPtr pAxis = NULL, pOtherAxis = NULL;
+ int value = pEv->value;
+
+ /* Has wheel emulation been configured to be enabled? */
+ if (!pEvdev->emulateWheel.enabled)
+ return FALSE;
+
+ /* Handle our motion events if the emuWheel button is pressed
+ * wheel button of 0 means always emulate wheel.
+ */
+ if (pEvdev->emulateWheel.button_state || !pEvdev->emulateWheel.button) {
+ /* Just return if the timeout hasn't expired yet */
+ if (pEvdev->emulateWheel.button)
+ {
+ int ms = pEvdev->emulateWheel.expires - GetTimeInMillis();
+ if (ms > 0)
+ return TRUE;
+ }
+
+ /* We don't want to intercept real mouse wheel events */
+ switch(pEv->code) {
+ case REL_X:
+ pAxis = &(pEvdev->emulateWheel.X);
+ pOtherAxis = &(pEvdev->emulateWheel.Y);
+ break;
+
+ case REL_Y:
+ pAxis = &(pEvdev->emulateWheel.Y);
+ pOtherAxis = &(pEvdev->emulateWheel.X);
+ break;
+
+ default:
+ break;
+ }
+
+ /* If we found REL_X or REL_Y, emulate a mouse wheel.
+ Reset the inertia of the other axis when a scroll event was sent
+ to avoid the buildup of erroneous scroll events if the user
+ doesn't move in a perfectly straight line.
+ */
+ if (pAxis)
+ {
+ if (EvdevWheelEmuInertia(pInfo, pAxis, value))
+ pOtherAxis->traveled_distance = 0;
+ }
+
+ /* Eat motion events while emulateWheel button pressed. */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Simulate inertia for our emulated mouse wheel.
+ Returns the number of wheel events generated.
+ */
+static int
+EvdevWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ int button;
+ int inertia;
+ int rc = 0;
+
+ /* if this axis has not been configured, just eat the motion */
+ if (!axis->up_button)
+ return rc;
+
+ axis->traveled_distance += value;
+
+ if (axis->traveled_distance < 0) {
+ button = axis->up_button;
+ inertia = -pEvdev->emulateWheel.inertia;
+ } else {
+ button = axis->down_button;
+ inertia = pEvdev->emulateWheel.inertia;
+ }
+
+ /* Produce button press events for wheel motion */
+ while(abs(axis->traveled_distance) > pEvdev->emulateWheel.inertia) {
+ axis->traveled_distance -= inertia;
+ EvdevQueueButtonClicks(pInfo, button, 1);
+ rc++;
+ }
+ return rc;
+}
+
+/* Handle button mapping here to avoid code duplication,
+returns true if a button mapping was found. */
+static BOOL
+EvdevWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char* axis_name)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ char *option_string;
+
+ pAxis->up_button = WHEEL_NOT_CONFIGURED;
+
+ /* Check to see if there is configuration for this axis */
+ option_string = xf86SetStrOption(pInfo->options, axis_name, NULL);
+ if (option_string) {
+ int up_button = 0;
+ int down_button = 0;
+ char *msg = NULL;
+
+ if ((sscanf(option_string, "%d %d", &up_button, &down_button) == 2) &&
+ ((up_button > 0) && (up_button <= EVDEV_MAXBUTTONS)) &&
+ ((down_button > 0) && (down_button <= EVDEV_MAXBUTTONS))) {
+
+ /* Use xstrdup to allocate a string for us */
+ msg = xstrdup("buttons XX and YY");
+
+ if (msg)
+ sprintf(msg, "buttons %d and %d", up_button, down_button);
+
+ pAxis->up_button = up_button;
+ pAxis->down_button = down_button;
+
+ /* Update the number of buttons if needed */
+ if (up_button > pEvdev->num_buttons) pEvdev->num_buttons = up_button;
+ if (down_button > pEvdev->num_buttons) pEvdev->num_buttons = down_button;
+
+ } else {
+ xf86Msg(X_WARNING, "%s: Invalid %s value:\"%s\"\n",
+ pInfo->name, axis_name, option_string);
+
+ }
+
+ /* Clean up and log what happened */
+ if (msg) {
+ xf86Msg(X_CONFIG, "%s: %s: %s\n",pInfo->name, axis_name, msg);
+ free(msg);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Setup the basic configuration options used by mouse wheel emulation */
+void
+EvdevWheelEmuPreInit(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+ char val[4];
+ int wheelButton;
+ int inertia;
+ int timeout;
+
+ val[0] = 0;
+ val[1] = 0;
+
+ if (xf86SetBoolOption(pInfo->options, "EmulateWheel", FALSE)) {
+ pEvdev->emulateWheel.enabled = TRUE;
+ } else
+ pEvdev->emulateWheel.enabled = FALSE;
+
+ wheelButton = xf86SetIntOption(pInfo->options, "EmulateWheelButton", 4);
+
+ if ((wheelButton < 0) || (wheelButton > EVDEV_MAXBUTTONS)) {
+ xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n",
+ pInfo->name, wheelButton);
+ xf86Msg(X_WARNING, "%s: Wheel emulation disabled.\n", pInfo->name);
+
+ pEvdev->emulateWheel.enabled = FALSE;
+ }
+
+ pEvdev->emulateWheel.button = wheelButton;
+
+ inertia = xf86SetIntOption(pInfo->options, "EmulateWheelInertia", 10);
+
+ if (inertia <= 0) {
+ xf86Msg(X_WARNING, "%s: Invalid EmulateWheelInertia value: %d\n",
+ pInfo->name, inertia);
+ xf86Msg(X_WARNING, "%s: Using built-in inertia value.\n",
+ pInfo->name);
+
+ inertia = 10;
+ }
+
+ pEvdev->emulateWheel.inertia = inertia;
+
+ timeout = xf86SetIntOption(pInfo->options, "EmulateWheelTimeout", 200);
+
+ if (timeout < 0) {
+ xf86Msg(X_WARNING, "%s: Invalid EmulateWheelTimeout value: %d\n",
+ pInfo->name, timeout);
+ xf86Msg(X_WARNING, "%s: Using built-in timeout value.\n",
+ pInfo->name);
+
+ timeout = 200;
+ }
+
+ pEvdev->emulateWheel.timeout = timeout;
+
+ /* Configure the Y axis or default it */
+ if (!EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.Y),
+ "YAxisMapping")) {
+ /* Default the Y axis to sane values */
+ pEvdev->emulateWheel.Y.up_button = 4;
+ pEvdev->emulateWheel.Y.down_button = 5;
+
+ /* Simpler to check just the largest value in this case */
+ /* XXX: we should post this to the server */
+ if (5 > pEvdev->num_buttons)
+ pEvdev->num_buttons = 5;
+
+ /* Display default Configuration */
+ xf86Msg(X_CONFIG, "%s: YAxisMapping: buttons %d and %d\n",
+ pInfo->name, pEvdev->emulateWheel.Y.up_button,
+ pEvdev->emulateWheel.Y.down_button);
+ }
+
+
+ /* This axis should default to an unconfigured state as most people
+ are not going to expect a Horizontal wheel. */
+ EvdevWheelEmuHandleButtonMap(pInfo, &(pEvdev->emulateWheel.X),
+ "XAxisMapping");
+
+ /* Used by the inertia code */
+ pEvdev->emulateWheel.X.traveled_distance = 0;
+ pEvdev->emulateWheel.Y.traveled_distance = 0;
+
+ xf86Msg(X_CONFIG, "%s: EmulateWheelButton: %d, "
+ "EmulateWheelInertia: %d, "
+ "EmulateWheelTimeout: %d\n",
+ pInfo->name, pEvdev->emulateWheel.button, inertia, timeout);
+}
+
+#ifdef HAVE_PROPERTIES
+static int
+EvdevWheelEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (atom == prop_wheel_emu)
+ {
+ if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ pEvdev->emulateWheel.enabled = *((BOOL*)val->data);
+ /* Don't enable with zero inertia, otherwise we may get stuck in an
+ * infinite loop */
+ if (pEvdev->emulateWheel.inertia <= 0)
+ {
+ pEvdev->emulateWheel.inertia = 10;
+ /* We may get here before the property is actually enabled */
+ if (prop_wheel_inertia)
+ XIChangeDeviceProperty(dev, prop_wheel_inertia, XA_INTEGER,
+ 16, PropModeReplace, 1,
+ &pEvdev->emulateWheel.inertia, TRUE);
+ }
+ }
+ }
+ else if (atom == prop_wheel_button)
+ {
+ int bt;
+
+ if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ bt = *((CARD8*)val->data);
+
+ if (bt < 0 || bt >= EVDEV_MAXBUTTONS)
+ return BadValue;
+
+ if (!checkonly)
+ pEvdev->emulateWheel.button = bt;
+ } else if (atom == prop_wheel_axismap)
+ {
+ if (val->format != 8 || val->size != 4 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ pEvdev->emulateWheel.X.up_button = *((CARD8*)val->data);
+ pEvdev->emulateWheel.X.down_button = *(((CARD8*)val->data) + 1);
+ pEvdev->emulateWheel.Y.up_button = *(((CARD8*)val->data) + 2);
+ pEvdev->emulateWheel.Y.down_button = *(((CARD8*)val->data) + 3);
+ }
+ } else if (atom == prop_wheel_inertia)
+ {
+ int inertia;
+
+ if (val->format != 16 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ inertia = *((CARD16*)val->data);
+
+ if (inertia < 0)
+ return BadValue;
+
+ if (!checkonly)
+ pEvdev->emulateWheel.inertia = inertia;
+ } else if (atom == prop_wheel_timeout)
+ {
+ int timeout;
+
+ if (val->format != 16 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ timeout = *((CARD16*)val->data);
+
+ if (timeout < 0)
+ return BadValue;
+
+ if (!checkonly)
+ pEvdev->emulateWheel.timeout = timeout;
+ }
+ return Success;
+}
+
+void
+EvdevWheelEmuInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+ int rc = TRUE;
+ char vals[4];
+
+ if (!dev->button) /* don't init prop for keyboards */
+ return;
+
+ prop_wheel_emu = MakeAtom(EVDEV_PROP_WHEEL, strlen(EVDEV_PROP_WHEEL), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_wheel_emu, XA_INTEGER, 8,
+ PropModeReplace, 1,
+ &pEvdev->emulateWheel.enabled, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_wheel_emu, FALSE);
+
+ vals[0] = pEvdev->emulateWheel.X.up_button;
+ vals[1] = pEvdev->emulateWheel.X.down_button;
+ vals[2] = pEvdev->emulateWheel.Y.up_button;
+ vals[3] = pEvdev->emulateWheel.Y.down_button;
+
+ prop_wheel_axismap = MakeAtom(EVDEV_PROP_WHEEL_AXES, strlen(EVDEV_PROP_WHEEL_AXES), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_wheel_axismap, XA_INTEGER, 8,
+ PropModeReplace, 4, vals, FALSE);
+
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_wheel_axismap, FALSE);
+
+ prop_wheel_inertia = MakeAtom(EVDEV_PROP_WHEEL_INERTIA, strlen(EVDEV_PROP_WHEEL_INERTIA), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_wheel_inertia, XA_INTEGER, 16,
+ PropModeReplace, 1,
+ &pEvdev->emulateWheel.inertia, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_wheel_inertia, FALSE);
+
+ prop_wheel_timeout = MakeAtom(EVDEV_PROP_WHEEL_TIMEOUT, strlen(EVDEV_PROP_WHEEL_TIMEOUT), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_wheel_timeout, XA_INTEGER, 16,
+ PropModeReplace, 1,
+ &pEvdev->emulateWheel.timeout, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_wheel_timeout, FALSE);
+
+ prop_wheel_button = MakeAtom(EVDEV_PROP_WHEEL_BUTTON, strlen(EVDEV_PROP_WHEEL_BUTTON), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_wheel_button, XA_INTEGER, 8,
+ PropModeReplace, 1,
+ &pEvdev->emulateWheel.button, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_wheel_button, FALSE);
+
+ XIRegisterPropertyHandler(dev, EvdevWheelEmuSetProperty, NULL, NULL);
+}
+#endif
diff --git a/src/evdev.c b/src/evdev.c
new file mode 100755
index 0000000..e86c6db
--- /dev/null
+++ b/src/evdev.c
@@ -0,0 +1,2699 @@
+/*
+ * Copyright © 2004-2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ * Adam Jackson (ajax@redhat.com)
+ * Peter Hutterer (peter.hutterer@redhat.com)
+ * Oliver McFadden (oliver.mcfadden@nokia.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/keysym.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <xorgVersion.h>
+#include <xkbsrv.h>
+
+#include "evdev.h"
+
+#ifdef HAVE_PROPERTIES
+#include <X11/Xatom.h>
+#include <evdev-properties.h>
+#include <xserver-properties.h>
+/* 1.6 has properties, but no labels */
+#ifdef AXIS_LABEL_PROP
+#define HAVE_LABELS
+#else
+#undef HAVE_LABELS
+#endif
+
+#endif
+
+#ifndef MAXDEVICES
+#include <inputstr.h> /* for MAX_DEVICES */
+#define MAXDEVICES MAX_DEVICES
+#endif
+
+/* 2.4 compatibility */
+#ifndef EVIOCGRAB
+#define EVIOCGRAB _IOW('E', 0x90, int)
+#endif
+
+#ifndef BTN_TASK
+#define BTN_TASK 0x117
+#endif
+
+#ifndef EV_SYN
+#define EV_SYN EV_RST
+#endif
+/* end compat */
+
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
+/* evdev flags */
+#define EVDEV_KEYBOARD_EVENTS (1 << 0)
+#define EVDEV_BUTTON_EVENTS (1 << 1)
+#define EVDEV_RELATIVE_EVENTS (1 << 2)
+#define EVDEV_ABSOLUTE_EVENTS (1 << 3)
+#define EVDEV_TOUCHPAD (1 << 4)
+#define EVDEV_INITIALIZED (1 << 5) /* WheelInit etc. called already? */
+#define EVDEV_TOUCHSCREEN (1 << 6)
+#define EVDEV_CALIBRATED (1 << 7) /* run-time calibrated? */
+#define EVDEV_TABLET (1 << 8) /* device looks like a tablet? */
+#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
+#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+#define EVDEV_RESOLUTION (1 << 12) /* device looks like a multi-touch screen? */
+
+#define MIN_KEYCODE 8
+#define GLYPHS_PER_KEY 2
+#define AltMask Mod1Mask
+#define NumLockMask Mod2Mask
+#define AltLangMask Mod3Mask
+#define KanaMask Mod4Mask
+#define ScrollLockMask Mod5Mask
+
+#define CAPSFLAG 1
+#define NUMFLAG 2
+#define SCROLLFLAG 4
+#define MODEFLAG 8
+#define COMPOSEFLAG 16
+
+static const char *evdevDefaults[] = {
+ "XkbRules", "evdev",
+ "XkbModel", "evdev",
+ "XkbLayout", "us",
+ NULL
+};
+
+static int EvdevOn(DeviceIntPtr);
+static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare);
+static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
+static void EvdevSwapAxes(EvdevPtr pEvdev);
+static void EvdevSetResolution(InputInfoPtr pInfo, int num_resolution, int resolution[4]);
+
+#ifdef HAVE_PROPERTIES
+static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
+static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
+static void EvdevInitProperty(DeviceIntPtr dev);
+static int EvdevSetProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly);
+static void EvdevSetMouseExist(int value);
+static void EvdevSetExtKeyboardExist(int value);
+static Atom prop_invert = 0;
+static Atom prop_reopen = 0;
+static Atom prop_calibration = 0;
+static Atom prop_swap = 0;
+static Atom prop_axis_label = 0;
+static Atom prop_btn_label = 0;
+#endif
+
+/* All devices the evdev driver has allocated and knows about.
+ * MAXDEVICES is safe as null-terminated array, as two devices (VCP and VCK)
+ * cannot be used by evdev, leaving us with a space of 2 at the end. */
+static EvdevPtr evdev_devices[MAXDEVICES] = {NULL};
+
+static size_t CountBits(unsigned long *array, size_t nlongs)
+{
+ unsigned int i;
+ size_t count = 0;
+
+ for (i = 0; i < nlongs; i++) {
+ unsigned long x = array[i];
+
+ while (x > 0)
+ {
+ count += (x & 0x1);
+ x >>= 1;
+ }
+ }
+ return count;
+}
+
+static int
+EvdevGetMajorMinor(InputInfoPtr pInfo)
+{
+ struct stat st;
+
+ if (fstat(pInfo->fd, &st) == -1)
+ {
+ xf86Msg(X_ERROR, "%s: stat failed (%s). cannot check for duplicates.\n",
+ pInfo->name, strerror(errno));
+ return 0;
+ }
+
+ return st.st_rdev;
+}
+
+/**
+ * Return TRUE if one of the devices we know about has the same min/maj
+ * number.
+ */
+static BOOL
+EvdevIsDuplicate(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ EvdevPtr* dev = evdev_devices;
+
+ if (pEvdev->min_maj)
+ {
+ while(*dev)
+ {
+ if ((*dev) != pEvdev &&
+ (*dev)->min_maj &&
+ (*dev)->min_maj == pEvdev->min_maj)
+ return TRUE;
+ dev++;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Add to internal device list.
+ */
+static void
+EvdevAddDevice(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ EvdevPtr* dev = evdev_devices;
+
+ while(*dev)
+ dev++;
+
+ *dev = pEvdev;
+}
+
+/**
+ * Remove from internal device list.
+ */
+static void
+EvdevRemoveDevice(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ EvdevPtr *dev = evdev_devices;
+ int count = 0;
+
+ while(*dev)
+ {
+ count++;
+ if (*dev == pEvdev)
+ {
+ memmove(dev, dev + 1,
+ sizeof(evdev_devices) - (count * sizeof(EvdevPtr)));
+ break;
+ }
+ dev++;
+ }
+}
+
+
+static void
+SetXkbOption(InputInfoPtr pInfo, char *name, char **option)
+{
+ char *s;
+
+ if ((s = xf86SetStrOption(pInfo->options, name, NULL))) {
+ if (!s[0]) {
+ free(s);
+ *option = NULL;
+ } else {
+ *option = s;
+ }
+ }
+}
+
+static int wheel_up_button = 4;
+static int wheel_down_button = 5;
+static int wheel_left_button = 6;
+static int wheel_right_button = 7;
+
+void
+EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
+{
+ int code = ev->code + MIN_KEYCODE;
+ static char warned[KEY_CNT];
+ EventQueuePtr pQueue;
+ EvdevPtr pEvdev = pInfo->private;
+
+ /* Filter all repeated events from device.
+ We'll do softrepeat in the server, but only since 1.6 */
+ if (value == 2
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) <= 2
+ && (ev->code == KEY_LEFTCTRL || ev->code == KEY_RIGHTCTRL ||
+ ev->code == KEY_LEFTSHIFT || ev->code == KEY_RIGHTSHIFT ||
+ ev->code == KEY_LEFTALT || ev->code == KEY_RIGHTALT ||
+ ev->code == KEY_LEFTMETA || ev->code == KEY_RIGHTMETA ||
+ ev->code == KEY_CAPSLOCK || ev->code == KEY_NUMLOCK ||
+ ev->code == KEY_SCROLLLOCK) /* XXX windows keys? */
+#endif
+ )
+ return;
+
+ if (code > 255)
+ {
+ if (ev->code <= KEY_MAX && !warned[ev->code])
+ {
+ xf86Msg(X_WARNING, "%s: unable to handle keycode %d\n",
+ pInfo->name, ev->code);
+ warned[ev->code] = 1;
+ }
+
+ /* The X server can't handle keycodes > 255. */
+ return;
+ }
+
+ if (pEvdev->num_queue >= EVDEV_MAXQUEUE)
+ {
+ xf86Msg(X_NONE, "%s: dropping event due to full queue!\n", pInfo->name);
+ return;
+ }
+
+ pQueue = &pEvdev->queue[pEvdev->num_queue];
+ pQueue->type = EV_QUEUE_KEY;
+ pQueue->key = code;
+ pQueue->val = value;
+ pEvdev->num_queue++;
+}
+
+void
+EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value)
+{
+ EventQueuePtr pQueue;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (pEvdev->num_queue >= EVDEV_MAXQUEUE)
+ {
+ xf86Msg(X_NONE, "%s: dropping event due to full queue!\n", pInfo->name);
+ return;
+ }
+
+ pQueue = &pEvdev->queue[pEvdev->num_queue];
+ pQueue->type = EV_QUEUE_BTN;
+ pQueue->key = button;
+ pQueue->val = value;
+ pEvdev->num_queue++;
+}
+
+/**
+ * Post button event right here, right now.
+ * Interface for MB emulation since these need to post immediately.
+ */
+void
+EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value)
+{
+ xf86PostButtonEvent(pInfo->dev, 0, button, value, 0, 0);
+}
+
+void
+EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ EvdevQueueButtonEvent(pInfo, button, 1);
+ EvdevQueueButtonEvent(pInfo, button, 0);
+ }
+}
+
+/**
+ * Coming back from resume may leave us with a file descriptor that can be
+ * opened but fails on the first read (ENODEV).
+ * In this case, try to open the device until it becomes available or until
+ * the predefined count expires.
+ */
+static CARD32
+EvdevReopenTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ InputInfoPtr pInfo = (InputInfoPtr)arg;
+ EvdevPtr pEvdev = pInfo->private;
+
+ do {
+ pInfo->fd = open(pEvdev->device, O_RDWR | O_NONBLOCK, 0);
+ } while (pInfo->fd < 0 && errno == EINTR);
+
+ if (pInfo->fd != -1)
+ {
+ if (EvdevCacheCompare(pInfo, TRUE) == Success)
+ {
+ xf86Msg(X_INFO, "%s: Device reopened after %d attempts.\n", pInfo->name,
+ pEvdev->reopen_attempts - pEvdev->reopen_left + 1);
+ EvdevOn(pInfo->dev);
+ } else
+ {
+ xf86Msg(X_ERROR, "%s: Device has changed - disabling.\n",
+ pInfo->name);
+ xf86DisableDevice(pInfo->dev, FALSE);
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ pEvdev->min_maj = 0; /* don't hog the device */
+ }
+ pEvdev->reopen_left = 0;
+ return 0;
+ }
+
+ pEvdev->reopen_left--;
+
+ if (!pEvdev->reopen_left)
+ {
+ xf86Msg(X_ERROR, "%s: Failed to reopen device after %d attempts.\n",
+ pInfo->name, pEvdev->reopen_attempts);
+ xf86DisableDevice(pInfo->dev, FALSE);
+ pEvdev->min_maj = 0; /* don't hog the device */
+ return 0;
+ }
+
+ return 100; /* come back in 100 ms */
+}
+
+#define ABS_X_VALUE 0x1
+#define ABS_Y_VALUE 0x2
+#define ABS_VALUE 0x4
+/**
+ * Take the valuators and process them accordingly.
+ */
+static void
+EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
+ int *first_v)
+{
+ int tmp;
+ EvdevPtr pEvdev = pInfo->private;
+
+ *num_v = *first_v = 0;
+
+ /* convert to relative motion for touchpads */
+ if (pEvdev->abs && (pEvdev->flags & EVDEV_TOUCHPAD)) {
+ if (pEvdev->tool) { /* meaning, touch is active */
+ if (pEvdev->old_vals[0] != -1)
+ pEvdev->delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0];
+ if (pEvdev->old_vals[1] != -1)
+ pEvdev->delta[REL_Y] = pEvdev->vals[1] - pEvdev->old_vals[1];
+ if (pEvdev->abs & ABS_X_VALUE)
+ pEvdev->old_vals[0] = pEvdev->vals[0];
+ if (pEvdev->abs & ABS_Y_VALUE)
+ pEvdev->old_vals[1] = pEvdev->vals[1];
+ } else {
+ pEvdev->old_vals[0] = pEvdev->old_vals[1] = -1;
+ }
+ pEvdev->abs = 0;
+ pEvdev->rel = 1;
+ }
+
+ if (pEvdev->rel) {
+ int first = REL_CNT, last = 0;
+ int i;
+
+ if (pEvdev->swap_axes) {
+ tmp = pEvdev->delta[REL_X];
+ pEvdev->delta[REL_X] = pEvdev->delta[REL_Y];
+ pEvdev->delta[REL_Y] = tmp;
+ }
+ if (pEvdev->invert_x)
+ pEvdev->delta[REL_X] *= -1;
+ if (pEvdev->invert_y)
+ pEvdev->delta[REL_Y] *= -1;
+
+ for (i = 0; i < REL_CNT; i++)
+ {
+ int map = pEvdev->axis_map[i];
+ if (map != -1)
+ {
+ v[map] = pEvdev->delta[i];
+ if (map < first)
+ first = map;
+ if (map > last)
+ last = map;
+ }
+ }
+
+ *num_v = (last - first + 1);
+ *first_v = first;
+ }
+ /*
+ * Some devices only generate valid abs coords when BTN_DIGI is
+ * pressed. On wacom tablets, this means that the pen is in
+ * proximity of the tablet. After the pen is removed, BTN_DIGI is
+ * released, and a (0, 0) absolute event is generated. Checking
+ * pEvdev->digi here, lets us ignore that event. pEvdev is
+ * initialized to 1 so devices that doesn't use this scheme still
+ * just works.
+ */
+ else if (pEvdev->abs && pEvdev->tool) {
+ memcpy(v, pEvdev->vals, sizeof(int) * pEvdev->num_vals);
+
+ if (pEvdev->swap_axes) {
+ int tmp = v[0];
+ v[0] = v[1];
+ v[1] = tmp;
+ }
+
+ if (pEvdev->flags & EVDEV_CALIBRATED)
+ {
+ v[0] = xf86ScaleAxis(v[0],
+ pEvdev->absinfo[ABS_X].maximum,
+ pEvdev->absinfo[ABS_X].minimum,
+ pEvdev->calibration.max_x, pEvdev->calibration.min_x);
+ v[1] = xf86ScaleAxis(v[1],
+ pEvdev->absinfo[ABS_Y].maximum,
+ pEvdev->absinfo[ABS_Y].minimum,
+ pEvdev->calibration.max_y, pEvdev->calibration.min_y);
+ }
+
+ if (pEvdev->invert_x)
+ v[0] = (pEvdev->absinfo[ABS_X].maximum - v[0] +
+ pEvdev->absinfo[ABS_X].minimum);
+ if (pEvdev->invert_y)
+ v[1] = (pEvdev->absinfo[ABS_Y].maximum - v[1] +
+ pEvdev->absinfo[ABS_Y].minimum);
+
+ *num_v = pEvdev->num_vals;
+ *first_v = 0;
+ }
+}
+
+/**
+ * Take a button input event and process it accordingly.
+ */
+static void
+EvdevProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ unsigned int button;
+ int value;
+ EvdevPtr pEvdev = pInfo->private;
+
+ button = EvdevUtilButtonEventToButtonNumber(pEvdev, ev->code);
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+
+ /* Handle drag lock */
+ if (EvdevDragLockFilterEvent(pInfo, button, value))
+ return;
+
+ if (EvdevWheelEmuFilterButton(pInfo, button, value))
+ return;
+
+ if (EvdevMBEmuFilterEvent(pInfo, button, value))
+ return;
+
+ if (button)
+ EvdevQueueButtonEvent(pInfo, button, value);
+ else
+ EvdevQueueKbdEvent(pInfo, ev, value);
+}
+
+/**
+ * Take the relative motion input event and process it accordingly.
+ */
+static void
+EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ static int value;
+ EvdevPtr pEvdev = pInfo->private;
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+
+ pEvdev->rel = 1;
+
+ switch (ev->code) {
+ case REL_WHEEL:
+ if (value > 0)
+ EvdevQueueButtonClicks(pInfo, wheel_up_button, value);
+ else if (value < 0)
+ EvdevQueueButtonClicks(pInfo, wheel_down_button, -value);
+ break;
+
+ case REL_DIAL:
+ case REL_HWHEEL:
+ if (value > 0)
+ EvdevQueueButtonClicks(pInfo, wheel_right_button, value);
+ else if (value < 0)
+ EvdevQueueButtonClicks(pInfo, wheel_left_button, -value);
+ break;
+
+ /* We don't post wheel events as axis motion. */
+ default:
+ /* Ignore EV_REL events if we never set up for them. */
+ if (!(pEvdev->flags & EVDEV_RELATIVE_EVENTS))
+ return;
+
+ /* Handle mouse wheel emulation */
+ if (EvdevWheelEmuFilterMotion(pInfo, ev))
+ return;
+
+ pEvdev->delta[ev->code] += value;
+ break;
+ }
+}
+
+/**
+ * Take the absolute motion input event and process it accordingly.
+ */
+static void
+EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ static int value;
+ EvdevPtr pEvdev = pInfo->private;
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+
+ /* Ignore EV_ABS events if we never set up for them. */
+ if (!(pEvdev->flags & EVDEV_ABSOLUTE_EVENTS))
+ return;
+
+ if (ev->code > ABS_MAX)
+ return;
+
+ pEvdev->vals[pEvdev->axis_map[ev->code]] = value;
+ if (ev->code == ABS_X)
+ pEvdev->abs |= ABS_X_VALUE;
+ else if (ev->code == ABS_Y)
+ pEvdev->abs |= ABS_Y_VALUE;
+ else
+ pEvdev->abs |= ABS_VALUE;
+}
+
+/**
+ * Take the key press/release input event and process it accordingly.
+ */
+static void
+EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ static int value;
+ EvdevPtr pEvdev = pInfo->private;
+
+ /* Get the signed value, earlier kernels had this as unsigned */
+ value = ev->value;
+
+ /* don't repeat mouse buttons */
+ if (ev->code >= BTN_MOUSE && ev->code < KEY_OK)
+ if (value == 2)
+ return;
+
+ switch (ev->code) {
+ case BTN_TOOL_PEN:
+ case BTN_TOOL_RUBBER:
+ case BTN_TOOL_BRUSH:
+ case BTN_TOOL_PENCIL:
+ case BTN_TOOL_AIRBRUSH:
+ case BTN_TOOL_FINGER:
+ case BTN_TOOL_MOUSE:
+ case BTN_TOOL_LENS:
+ pEvdev->tool = value ? ev->code : 0;
+ break;
+
+ case BTN_TOUCH:
+ pEvdev->tool = value ? ev->code : 0;
+ if (!(pEvdev->flags & (EVDEV_TOUCHSCREEN | EVDEV_TABLET)))
+ break;
+ /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as
+ * BTN_LEFT. */
+ ev->code = BTN_LEFT;
+ /* Intentional fallthrough! */
+
+ default:
+ EvdevProcessButtonEvent(pInfo, ev);
+ break;
+ }
+}
+
+/**
+ * Post the relative motion events.
+ */
+void
+EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+ int v[MAX_VALUATORS])
+{
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (pEvdev->rel) {
+ xf86PostMotionEventP(pInfo->dev, FALSE, *first_v, *num_v, v + *first_v);
+ }
+}
+
+/**
+ * Post the absolute motion events.
+ */
+void
+EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+ int v[MAX_VALUATORS])
+{
+ EvdevPtr pEvdev = pInfo->private;
+
+ /*
+ * Some devices only generate valid abs coords when BTN_DIGI is
+ * pressed. On wacom tablets, this means that the pen is in
+ * proximity of the tablet. After the pen is removed, BTN_DIGI is
+ * released, and a (0, 0) absolute event is generated. Checking
+ * pEvdev->digi here, lets us ignore that event. pEvdev is
+ * initialized to 1 so devices that doesn't use this scheme still
+ * just works.
+ */
+ if (pEvdev->abs && pEvdev->tool) {
+ xf86PostMotionEventP(pInfo->dev, TRUE, *first_v, *num_v, v);
+ }
+}
+
+/**
+ * Post the queued key/button events.
+ */
+static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+ int v[MAX_VALUATORS])
+{
+ int i;
+ EvdevPtr pEvdev = pInfo->private;
+
+ for (i = 0; i < pEvdev->num_queue; i++) {
+ switch (pEvdev->queue[i].type) {
+ case EV_QUEUE_KEY:
+ xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].key,
+ pEvdev->queue[i].val);
+ break;
+ case EV_QUEUE_BTN:
+ /* FIXME: Add xf86PostButtonEventP to the X server so that we may
+ * pass the valuators on ButtonPress/Release events, too. Currently
+ * only MotionNotify events contain the pointer position. */
+ xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key,
+ pEvdev->queue[i].val, 0, 0);
+ break;
+ }
+ }
+}
+
+/**
+ * Take the synchronization input event and process it accordingly; the motion
+ * notify events are sent first, then any button/key press/release events.
+ */
+static void
+EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ int num_v = 0, first_v = 0;
+ int v[MAX_VALUATORS];
+ EvdevPtr pEvdev = pInfo->private;
+
+ EvdevProcessValuators(pInfo, v, &num_v, &first_v);
+
+ EvdevPostRelativeMotionEvents(pInfo, &num_v, &first_v, v);
+ EvdevPostAbsoluteMotionEvents(pInfo, &num_v, &first_v, v);
+ EvdevPostQueuedEvents(pInfo, &num_v, &first_v, v);
+
+ memset(pEvdev->delta, 0, sizeof(pEvdev->delta));
+ memset(pEvdev->queue, 0, sizeof(pEvdev->queue));
+ pEvdev->num_queue = 0;
+ pEvdev->abs = 0;
+ pEvdev->rel = 0;
+}
+
+/**
+ * Process the events from the device; nothing is actually posted to the server
+ * until an EV_SYN event is received.
+ */
+static void
+EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ switch (ev->type) {
+ case EV_REL:
+ EvdevProcessRelativeMotionEvent(pInfo, ev);
+ break;
+ case EV_ABS:
+ EvdevProcessAbsoluteMotionEvent(pInfo, ev);
+ break;
+ case EV_KEY:
+ EvdevProcessKeyEvent(pInfo, ev);
+ break;
+ case EV_SYN:
+ EvdevProcessSyncEvent(pInfo, ev);
+ break;
+ }
+}
+
+#undef ABS_X_VALUE
+#undef ABS_Y_VALUE
+#undef ABS_VALUE
+
+/* just a magic number to reduce the number of reads */
+#define NUM_EVENTS 16
+
+static void
+EvdevReadInput(InputInfoPtr pInfo)
+{
+ struct input_event ev[NUM_EVENTS];
+ int i, len = sizeof(ev);
+ EvdevPtr pEvdev = pInfo->private;
+
+ while (len == sizeof(ev))
+ {
+ len = read(pInfo->fd, &ev, sizeof(ev));
+ if (len <= 0)
+ {
+ if (errno == ENODEV) /* May happen after resume */
+ {
+ EvdevMBEmuFinalize(pInfo);
+ xf86RemoveEnabledDevice(pInfo);
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ if (pEvdev->reopen_timer)
+ {
+ pEvdev->reopen_left = pEvdev->reopen_attempts;
+ pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 100, EvdevReopenTimer, pInfo);
+ }
+ } else if (errno != EAGAIN)
+ {
+ /* We use X_NONE here because it doesn't alloc */
+ xf86MsgVerb(X_NONE, 0, "%s: Read error: %s\n", pInfo->name,
+ strerror(errno));
+ }
+ break;
+ }
+
+ /* The kernel promises that we always only read a complete
+ * event, so len != sizeof ev is an error. */
+ if (len % sizeof(ev[0])) {
+ /* We use X_NONE here because it doesn't alloc */
+ xf86MsgVerb(X_NONE, 0, "%s: Read error: %s\n", pInfo->name, strerror(errno));
+ break;
+ }
+
+ for (i = 0; i < len/sizeof(ev[0]); i++)
+ EvdevProcessEvent(pInfo, &ev[i]);
+ }
+}
+
+#define TestBit(bit, array) ((array[(bit) / LONG_BITS]) & (1L << ((bit) % LONG_BITS)))
+
+static void
+EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ /* Nothing to do, dix handles all settings */
+}
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+static KeySym map[] = {
+ /* 0x00 */ NoSymbol, NoSymbol,
+ /* 0x01 */ XK_Escape, NoSymbol,
+ /* 0x02 */ XK_1, XK_exclam,
+ /* 0x03 */ XK_2, XK_at,
+ /* 0x04 */ XK_3, XK_numbersign,
+ /* 0x05 */ XK_4, XK_dollar,
+ /* 0x06 */ XK_5, XK_percent,
+ /* 0x07 */ XK_6, XK_asciicircum,
+ /* 0x08 */ XK_7, XK_ampersand,
+ /* 0x09 */ XK_8, XK_asterisk,
+ /* 0x0a */ XK_9, XK_parenleft,
+ /* 0x0b */ XK_0, XK_parenright,
+ /* 0x0c */ XK_minus, XK_underscore,
+ /* 0x0d */ XK_equal, XK_plus,
+ /* 0x0e */ XK_BackSpace, NoSymbol,
+ /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,
+ /* 0x10 */ XK_Q, NoSymbol,
+ /* 0x11 */ XK_W, NoSymbol,
+ /* 0x12 */ XK_E, NoSymbol,
+ /* 0x13 */ XK_R, NoSymbol,
+ /* 0x14 */ XK_T, NoSymbol,
+ /* 0x15 */ XK_Y, NoSymbol,
+ /* 0x16 */ XK_U, NoSymbol,
+ /* 0x17 */ XK_I, NoSymbol,
+ /* 0x18 */ XK_O, NoSymbol,
+ /* 0x19 */ XK_P, NoSymbol,
+ /* 0x1a */ XK_bracketleft, XK_braceleft,
+ /* 0x1b */ XK_bracketright,XK_braceright,
+ /* 0x1c */ XK_Return, NoSymbol,
+ /* 0x1d */ XK_Control_L, NoSymbol,
+ /* 0x1e */ XK_A, NoSymbol,
+ /* 0x1f */ XK_S, NoSymbol,
+ /* 0x20 */ XK_D, NoSymbol,
+ /* 0x21 */ XK_F, NoSymbol,
+ /* 0x22 */ XK_G, NoSymbol,
+ /* 0x23 */ XK_H, NoSymbol,
+ /* 0x24 */ XK_J, NoSymbol,
+ /* 0x25 */ XK_K, NoSymbol,
+ /* 0x26 */ XK_L, NoSymbol,
+ /* 0x27 */ XK_semicolon, XK_colon,
+ /* 0x28 */ XK_quoteright, XK_quotedbl,
+ /* 0x29 */ XK_quoteleft, XK_asciitilde,
+ /* 0x2a */ XK_Shift_L, NoSymbol,
+ /* 0x2b */ XK_backslash, XK_bar,
+ /* 0x2c */ XK_Z, NoSymbol,
+ /* 0x2d */ XK_X, NoSymbol,
+ /* 0x2e */ XK_C, NoSymbol,
+ /* 0x2f */ XK_V, NoSymbol,
+ /* 0x30 */ XK_B, NoSymbol,
+ /* 0x31 */ XK_N, NoSymbol,
+ /* 0x32 */ XK_M, NoSymbol,
+ /* 0x33 */ XK_comma, XK_less,
+ /* 0x34 */ XK_period, XK_greater,
+ /* 0x35 */ XK_slash, XK_question,
+ /* 0x36 */ XK_Shift_R, NoSymbol,
+ /* 0x37 */ XK_KP_Multiply, NoSymbol,
+ /* 0x38 */ XK_Alt_L, XK_Meta_L,
+ /* 0x39 */ XK_space, NoSymbol,
+ /* 0x3a */ XK_Caps_Lock, NoSymbol,
+ /* 0x3b */ XK_F1, NoSymbol,
+ /* 0x3c */ XK_F2, NoSymbol,
+ /* 0x3d */ XK_F3, NoSymbol,
+ /* 0x3e */ XK_F4, NoSymbol,
+ /* 0x3f */ XK_F5, NoSymbol,
+ /* 0x40 */ XK_F6, NoSymbol,
+ /* 0x41 */ XK_F7, NoSymbol,
+ /* 0x42 */ XK_F8, NoSymbol,
+ /* 0x43 */ XK_F9, NoSymbol,
+ /* 0x44 */ XK_F10, NoSymbol,
+ /* 0x45 */ XK_Num_Lock, NoSymbol,
+ /* 0x46 */ XK_Scroll_Lock, NoSymbol,
+ /* These KP keys should have the KP_7 keysyms in the numlock
+ * modifer... ? */
+ /* 0x47 */ XK_KP_Home, XK_KP_7,
+ /* 0x48 */ XK_KP_Up, XK_KP_8,
+ /* 0x49 */ XK_KP_Prior, XK_KP_9,
+ /* 0x4a */ XK_KP_Subtract, NoSymbol,
+ /* 0x4b */ XK_KP_Left, XK_KP_4,
+ /* 0x4c */ XK_KP_Begin, XK_KP_5,
+ /* 0x4d */ XK_KP_Right, XK_KP_6,
+ /* 0x4e */ XK_KP_Add, NoSymbol,
+ /* 0x4f */ XK_KP_End, XK_KP_1,
+ /* 0x50 */ XK_KP_Down, XK_KP_2,
+ /* 0x51 */ XK_KP_Next, XK_KP_3,
+ /* 0x52 */ XK_KP_Insert, XK_KP_0,
+ /* 0x53 */ XK_KP_Delete, XK_KP_Decimal,
+ /* 0x54 */ NoSymbol, NoSymbol,
+ /* 0x55 */ XK_F13, NoSymbol,
+ /* 0x56 */ XK_less, XK_greater,
+ /* 0x57 */ XK_F11, NoSymbol,
+ /* 0x58 */ XK_F12, NoSymbol,
+ /* 0x59 */ XK_F14, NoSymbol,
+ /* 0x5a */ XK_F15, NoSymbol,
+ /* 0x5b */ XK_F16, NoSymbol,
+ /* 0x5c */ XK_F17, NoSymbol,
+ /* 0x5d */ XK_F18, NoSymbol,
+ /* 0x5e */ XK_F19, NoSymbol,
+ /* 0x5f */ XK_F20, NoSymbol,
+ /* 0x60 */ XK_KP_Enter, NoSymbol,
+ /* 0x61 */ XK_Control_R, NoSymbol,
+ /* 0x62 */ XK_KP_Divide, NoSymbol,
+ /* 0x63 */ XK_Print, XK_Sys_Req,
+ /* 0x64 */ XK_Alt_R, XK_Meta_R,
+ /* 0x65 */ NoSymbol, NoSymbol, /* KEY_LINEFEED */
+ /* 0x66 */ XK_Home, NoSymbol,
+ /* 0x67 */ XK_Up, NoSymbol,
+ /* 0x68 */ XK_Prior, NoSymbol,
+ /* 0x69 */ XK_Left, NoSymbol,
+ /* 0x6a */ XK_Right, NoSymbol,
+ /* 0x6b */ XK_End, NoSymbol,
+ /* 0x6c */ XK_Down, NoSymbol,
+ /* 0x6d */ XK_Next, NoSymbol,
+ /* 0x6e */ XK_Insert, NoSymbol,
+ /* 0x6f */ XK_Delete, NoSymbol,
+ /* 0x70 */ NoSymbol, NoSymbol, /* KEY_MACRO */
+ /* 0x71 */ NoSymbol, NoSymbol,
+ /* 0x72 */ NoSymbol, NoSymbol,
+ /* 0x73 */ NoSymbol, NoSymbol,
+ /* 0x74 */ NoSymbol, NoSymbol,
+ /* 0x75 */ XK_KP_Equal, NoSymbol,
+ /* 0x76 */ NoSymbol, NoSymbol,
+ /* 0x77 */ NoSymbol, NoSymbol,
+ /* 0x78 */ XK_F21, NoSymbol,
+ /* 0x79 */ XK_F22, NoSymbol,
+ /* 0x7a */ XK_F23, NoSymbol,
+ /* 0x7b */ XK_F24, NoSymbol,
+ /* 0x7c */ XK_KP_Separator, NoSymbol,
+ /* 0x7d */ XK_Meta_L, NoSymbol,
+ /* 0x7e */ XK_Meta_R, NoSymbol,
+ /* 0x7f */ XK_Multi_key, NoSymbol,
+ /* 0x80 */ NoSymbol, NoSymbol,
+ /* 0x81 */ NoSymbol, NoSymbol,
+ /* 0x82 */ NoSymbol, NoSymbol,
+ /* 0x83 */ NoSymbol, NoSymbol,
+ /* 0x84 */ NoSymbol, NoSymbol,
+ /* 0x85 */ NoSymbol, NoSymbol,
+ /* 0x86 */ NoSymbol, NoSymbol,
+ /* 0x87 */ NoSymbol, NoSymbol,
+ /* 0x88 */ NoSymbol, NoSymbol,
+ /* 0x89 */ NoSymbol, NoSymbol,
+ /* 0x8a */ NoSymbol, NoSymbol,
+ /* 0x8b */ NoSymbol, NoSymbol,
+ /* 0x8c */ NoSymbol, NoSymbol,
+ /* 0x8d */ NoSymbol, NoSymbol,
+ /* 0x8e */ NoSymbol, NoSymbol,
+ /* 0x8f */ NoSymbol, NoSymbol,
+ /* 0x90 */ NoSymbol, NoSymbol,
+ /* 0x91 */ NoSymbol, NoSymbol,
+ /* 0x92 */ NoSymbol, NoSymbol,
+ /* 0x93 */ NoSymbol, NoSymbol,
+ /* 0x94 */ NoSymbol, NoSymbol,
+ /* 0x95 */ NoSymbol, NoSymbol,
+ /* 0x96 */ NoSymbol, NoSymbol,
+ /* 0x97 */ NoSymbol, NoSymbol,
+ /* 0x98 */ NoSymbol, NoSymbol,
+ /* 0x99 */ NoSymbol, NoSymbol,
+ /* 0x9a */ NoSymbol, NoSymbol,
+ /* 0x9b */ NoSymbol, NoSymbol,
+ /* 0x9c */ NoSymbol, NoSymbol,
+ /* 0x9d */ NoSymbol, NoSymbol,
+ /* 0x9e */ NoSymbol, NoSymbol,
+ /* 0x9f */ NoSymbol, NoSymbol,
+ /* 0xa0 */ NoSymbol, NoSymbol,
+ /* 0xa1 */ NoSymbol, NoSymbol,
+ /* 0xa2 */ NoSymbol, NoSymbol,
+ /* 0xa3 */ NoSymbol, NoSymbol,
+ /* 0xa4 */ NoSymbol, NoSymbol,
+ /* 0xa5 */ NoSymbol, NoSymbol,
+ /* 0xa6 */ NoSymbol, NoSymbol,
+ /* 0xa7 */ NoSymbol, NoSymbol,
+ /* 0xa8 */ NoSymbol, NoSymbol,
+ /* 0xa9 */ NoSymbol, NoSymbol,
+ /* 0xaa */ NoSymbol, NoSymbol,
+ /* 0xab */ NoSymbol, NoSymbol,
+ /* 0xac */ NoSymbol, NoSymbol,
+ /* 0xad */ NoSymbol, NoSymbol,
+ /* 0xae */ NoSymbol, NoSymbol,
+ /* 0xaf */ NoSymbol, NoSymbol,
+ /* 0xb0 */ NoSymbol, NoSymbol,
+ /* 0xb1 */ NoSymbol, NoSymbol,
+ /* 0xb2 */ NoSymbol, NoSymbol,
+ /* 0xb3 */ NoSymbol, NoSymbol,
+ /* 0xb4 */ NoSymbol, NoSymbol,
+ /* 0xb5 */ NoSymbol, NoSymbol,
+ /* 0xb6 */ NoSymbol, NoSymbol,
+ /* 0xb7 */ NoSymbol, NoSymbol,
+ /* 0xb8 */ NoSymbol, NoSymbol,
+ /* 0xb9 */ NoSymbol, NoSymbol,
+ /* 0xba */ NoSymbol, NoSymbol,
+ /* 0xbb */ NoSymbol, NoSymbol,
+ /* 0xbc */ NoSymbol, NoSymbol,
+ /* 0xbd */ NoSymbol, NoSymbol,
+ /* 0xbe */ NoSymbol, NoSymbol,
+ /* 0xbf */ NoSymbol, NoSymbol,
+ /* 0xc0 */ NoSymbol, NoSymbol,
+ /* 0xc1 */ NoSymbol, NoSymbol,
+ /* 0xc2 */ NoSymbol, NoSymbol,
+ /* 0xc3 */ NoSymbol, NoSymbol,
+ /* 0xc4 */ NoSymbol, NoSymbol,
+ /* 0xc5 */ NoSymbol, NoSymbol,
+ /* 0xc6 */ NoSymbol, NoSymbol,
+ /* 0xc7 */ NoSymbol, NoSymbol,
+ /* 0xc8 */ NoSymbol, NoSymbol,
+ /* 0xc9 */ NoSymbol, NoSymbol,
+ /* 0xca */ NoSymbol, NoSymbol,
+ /* 0xcb */ NoSymbol, NoSymbol,
+ /* 0xcc */ NoSymbol, NoSymbol,
+ /* 0xcd */ NoSymbol, NoSymbol,
+ /* 0xce */ NoSymbol, NoSymbol,
+ /* 0xcf */ NoSymbol, NoSymbol,
+ /* 0xd0 */ NoSymbol, NoSymbol,
+ /* 0xd1 */ NoSymbol, NoSymbol,
+ /* 0xd2 */ NoSymbol, NoSymbol,
+ /* 0xd3 */ NoSymbol, NoSymbol,
+ /* 0xd4 */ NoSymbol, NoSymbol,
+ /* 0xd5 */ NoSymbol, NoSymbol,
+ /* 0xd6 */ NoSymbol, NoSymbol,
+ /* 0xd7 */ NoSymbol, NoSymbol,
+ /* 0xd8 */ NoSymbol, NoSymbol,
+ /* 0xd9 */ NoSymbol, NoSymbol,
+ /* 0xda */ NoSymbol, NoSymbol,
+ /* 0xdb */ NoSymbol, NoSymbol,
+ /* 0xdc */ NoSymbol, NoSymbol,
+ /* 0xdd */ NoSymbol, NoSymbol,
+ /* 0xde */ NoSymbol, NoSymbol,
+ /* 0xdf */ NoSymbol, NoSymbol,
+ /* 0xe0 */ NoSymbol, NoSymbol,
+ /* 0xe1 */ NoSymbol, NoSymbol,
+ /* 0xe2 */ NoSymbol, NoSymbol,
+ /* 0xe3 */ NoSymbol, NoSymbol,
+ /* 0xe4 */ NoSymbol, NoSymbol,
+ /* 0xe5 */ NoSymbol, NoSymbol,
+ /* 0xe6 */ NoSymbol, NoSymbol,
+ /* 0xe7 */ NoSymbol, NoSymbol,
+ /* 0xe8 */ NoSymbol, NoSymbol,
+ /* 0xe9 */ NoSymbol, NoSymbol,
+ /* 0xea */ NoSymbol, NoSymbol,
+ /* 0xeb */ NoSymbol, NoSymbol,
+ /* 0xec */ NoSymbol, NoSymbol,
+ /* 0xed */ NoSymbol, NoSymbol,
+ /* 0xee */ NoSymbol, NoSymbol,
+ /* 0xef */ NoSymbol, NoSymbol,
+ /* 0xf0 */ NoSymbol, NoSymbol,
+ /* 0xf1 */ NoSymbol, NoSymbol,
+ /* 0xf2 */ NoSymbol, NoSymbol,
+ /* 0xf3 */ NoSymbol, NoSymbol,
+ /* 0xf4 */ NoSymbol, NoSymbol,
+ /* 0xf5 */ NoSymbol, NoSymbol,
+ /* 0xf6 */ NoSymbol, NoSymbol,
+ /* 0xf7 */ NoSymbol, NoSymbol,
+};
+
+static struct { KeySym keysym; CARD8 mask; } modifiers[] = {
+ { XK_Shift_L, ShiftMask },
+ { XK_Shift_R, ShiftMask },
+ { XK_Control_L, ControlMask },
+ { XK_Control_R, ControlMask },
+ { XK_Caps_Lock, LockMask },
+ { XK_Alt_L, AltMask },
+ { XK_Alt_R, AltMask },
+ { XK_Meta_L, Mod4Mask },
+ { XK_Meta_R, Mod4Mask },
+ { XK_Num_Lock, NumLockMask },
+ { XK_Scroll_Lock, ScrollLockMask },
+ { XK_Mode_switch, AltLangMask }
+};
+
+/* Server 1.6 and earlier */
+static int
+EvdevInitKeysyms(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+ KeySymsRec keySyms;
+ CARD8 modMap[MAP_LENGTH];
+ KeySym sym;
+ int i, j;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ /* Compute the modifier map */
+ memset(modMap, 0, sizeof modMap);
+
+ for (i = 0; i < ArrayLength(map) / GLYPHS_PER_KEY; i++) {
+ sym = map[i * GLYPHS_PER_KEY];
+ for (j = 0; j < ArrayLength(modifiers); j++) {
+ if (modifiers[j].keysym == sym)
+ modMap[i + MIN_KEYCODE] = modifiers[j].mask;
+ }
+ }
+
+ keySyms.map = map;
+ keySyms.mapWidth = GLYPHS_PER_KEY;
+ keySyms.minKeyCode = MIN_KEYCODE;
+ keySyms.maxKeyCode = MIN_KEYCODE + ArrayLength(map) / GLYPHS_PER_KEY - 1;
+
+ XkbSetRulesDflts(pEvdev->rmlvo.rules, pEvdev->rmlvo.model,
+ pEvdev->rmlvo.layout, pEvdev->rmlvo.variant,
+ pEvdev->rmlvo.options);
+ if (!XkbInitKeyboardDeviceStruct(device, &pEvdev->xkbnames,
+ &keySyms, modMap, NULL,
+ EvdevKbdCtrl))
+ return 0;
+
+ return 1;
+}
+#endif
+
+static void
+EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl)
+{
+ static struct { int xbit, code; } bits[] = {
+ { CAPSFLAG, LED_CAPSL },
+ { NUMFLAG, LED_NUML },
+ { SCROLLFLAG, LED_SCROLLL },
+ { MODEFLAG, LED_KANA },
+ { COMPOSEFLAG, LED_COMPOSE }
+ };
+
+ InputInfoPtr pInfo;
+ struct input_event ev[ArrayLength(bits)];
+ int i;
+
+ memset(ev, 0, sizeof(ev));
+
+ pInfo = device->public.devicePrivate;
+ for (i = 0; i < ArrayLength(bits); i++) {
+ ev[i].type = EV_LED;
+ ev[i].code = bits[i].code;
+ ev[i].value = (ctrl->leds & bits[i].xbit) > 0;
+ }
+
+ write(pInfo->fd, ev, sizeof ev);
+}
+
+static int
+EvdevAddKeyClass(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ /* sorry, no rules change allowed for you */
+ xf86ReplaceStrOption(pInfo->options, "xkb_rules", "evdev");
+ SetXkbOption(pInfo, "xkb_rules", &pEvdev->rmlvo.rules);
+ SetXkbOption(pInfo, "xkb_model", &pEvdev->rmlvo.model);
+ if (!pEvdev->rmlvo.model)
+ SetXkbOption(pInfo, "XkbModel", &pEvdev->rmlvo.model);
+ SetXkbOption(pInfo, "xkb_layout", &pEvdev->rmlvo.layout);
+ if (!pEvdev->rmlvo.layout)
+ SetXkbOption(pInfo, "XkbLayout", &pEvdev->rmlvo.layout);
+ SetXkbOption(pInfo, "xkb_variant", &pEvdev->rmlvo.variant);
+ if (!pEvdev->rmlvo.variant)
+ SetXkbOption(pInfo, "XkbVariant", &pEvdev->rmlvo.variant);
+ SetXkbOption(pInfo, "xkb_options", &pEvdev->rmlvo.options);
+ if (!pEvdev->rmlvo.options)
+ SetXkbOption(pInfo, "XkbOptions", &pEvdev->rmlvo.options);
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
+ if (!InitKeyboardDeviceStruct(device, &pEvdev->rmlvo, NULL, EvdevKbdCtrl))
+ return !Success;
+#else
+ if (!EvdevInitKeysyms(device))
+ return !Success;
+
+#endif
+
+ pInfo->flags |= XI86_KEYBOARD_CAPABLE;
+
+ return Success;
+}
+
+static int
+EvdevAddAbsClass(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+ int num_axes, axis, i = 0;
+ Atom *atoms;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (!TestBit(EV_ABS, pEvdev->bitmask))
+ return !Success;
+
+ num_axes = CountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
+ if (num_axes < 1)
+ return !Success;
+ pEvdev->num_vals = num_axes;
+ memset(pEvdev->vals, 0, num_axes * sizeof(int));
+ memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
+ atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+
+ for (axis = ABS_X; axis <= ABS_MAX; axis++) {
+ pEvdev->axis_map[axis] = -1;
+ if (!TestBit(axis, pEvdev->abs_bitmask))
+ continue;
+ pEvdev->axis_map[axis] = i;
+ i++;
+ }
+
+ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
+
+ if (!InitValuatorClassDeviceStruct(device, num_axes,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ atoms,
+#endif
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
+ GetMotionHistory,
+#endif
+ GetMotionHistorySize(), Absolute))
+ return !Success;
+
+ for (axis = ABS_X; axis <= ABS_MAX; axis++) {
+ int axnum = pEvdev->axis_map[axis];
+ if (axnum == -1)
+ continue;
+ xf86InitValuatorAxisStruct(device, axnum,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ atoms[axnum],
+#endif
+ pEvdev->absinfo[axis].minimum,
+ pEvdev->absinfo[axis].maximum,
+ 10000, 0, 10000);
+ xf86InitValuatorDefaults(device, axnum);
+ pEvdev->old_vals[axnum] = -1;
+ }
+
+ free(atoms);
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
+ if ((TestBit(ABS_X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_Y, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_RX, pEvdev->abs_bitmask) &&
+ TestBit(ABS_RY, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_HAT0X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_HAT0Y, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_HAT1X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_HAT1Y, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_HAT2X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_HAT2Y, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_HAT3X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_HAT3Y, pEvdev->abs_bitmask)) ||
+ (TestBit(ABS_TILT_X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_TILT_Y, pEvdev->abs_bitmask)))
+ pInfo->flags |= XI86_POINTER_CAPABLE;
+
+ return Success;
+}
+
+static int
+EvdevAddRelClass(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+ int num_axes, axis, i = 0;
+ Atom *atoms;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (!TestBit(EV_REL, pEvdev->bitmask))
+ return !Success;
+
+ num_axes = CountBits(pEvdev->rel_bitmask, NLONGS(REL_MAX));
+ if (num_axes < 1)
+ return !Success;
+
+ /* Wheels are special, we post them as button events. So let's ignore them
+ * in the axes list too */
+ if (TestBit(REL_WHEEL, pEvdev->rel_bitmask))
+ num_axes--;
+ if (TestBit(REL_HWHEEL, pEvdev->rel_bitmask))
+ num_axes--;
+ if (TestBit(REL_DIAL, pEvdev->rel_bitmask))
+ num_axes--;
+
+ if (num_axes <= 0)
+ return !Success;
+
+ pEvdev->num_vals = num_axes;
+ memset(pEvdev->vals, 0, num_axes * sizeof(int));
+ atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+
+ for (axis = REL_X; axis <= REL_MAX; axis++)
+ {
+ pEvdev->axis_map[axis] = -1;
+ /* We don't post wheel events, so ignore them here too */
+ if (axis == REL_WHEEL || axis == REL_HWHEEL || axis == REL_DIAL)
+ continue;
+ if (!TestBit(axis, pEvdev->rel_bitmask))
+ continue;
+ pEvdev->axis_map[axis] = i;
+ i++;
+ }
+
+ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
+
+ if (!InitValuatorClassDeviceStruct(device, num_axes,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ atoms,
+#endif
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
+ GetMotionHistory,
+#endif
+ GetMotionHistorySize(), Relative))
+ return !Success;
+
+ for (axis = REL_X; axis <= REL_MAX; axis++)
+ {
+ int axnum = pEvdev->axis_map[axis];
+
+ if (axnum == -1)
+ continue;
+ xf86InitValuatorAxisStruct(device, axnum,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ atoms[axnum],
+#endif
+ -1, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(device, axnum);
+ }
+
+ free(atoms);
+
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
+ pInfo->flags |= XI86_POINTER_CAPABLE;
+
+ return Success;
+}
+
+static int
+EvdevAddButtonClass(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+ Atom *labels;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ labels = malloc(pEvdev->num_buttons * sizeof(Atom));
+ EvdevInitButtonLabels(pEvdev, pEvdev->num_buttons, labels);
+
+ if (!InitButtonClassDeviceStruct(device, pEvdev->num_buttons,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ labels,
+#endif
+ pEvdev->btnmap))
+ return !Success;
+
+ free(labels);
+ return Success;
+}
+
+/**
+ * Init the button mapping for the device. By default, this is a 1:1 mapping,
+ * i.e. Button 1 maps to Button 1, Button 2 to 2, etc.
+ *
+ * If a mapping has been specified, the mapping is the default, with the
+ * user-defined ones overwriting the defaults.
+ * i.e. a user-defined mapping of "3 2 1" results in a mapping of 3 2 1 4 5 6 ...
+ *
+ * Invalid button mappings revert to the default.
+ *
+ * Note that index 0 is unused, button 0 does not exist.
+ * This mapping is initialised for all devices, but only applied if the device
+ * has buttons (in EvdevAddButtonClass).
+ */
+static void
+EvdevInitButtonMapping(InputInfoPtr pInfo)
+{
+ int i, nbuttons = 1;
+ char *mapping = NULL;
+ EvdevPtr pEvdev = pInfo->private;
+
+ /* Check for user-defined button mapping */
+ if ((mapping = xf86CheckStrOption(pInfo->options, "ButtonMapping", NULL)))
+ {
+ char *s = " ";
+ int btn = 0;
+
+ xf86Msg(X_CONFIG, "%s: ButtonMapping '%s'\n", pInfo->name, mapping);
+ while (s && *s != '\0' && nbuttons < EVDEV_MAXBUTTONS)
+ {
+ btn = strtol(mapping, &s, 10);
+
+ if (s == mapping || btn < 0 || btn > EVDEV_MAXBUTTONS)
+ {
+ xf86Msg(X_ERROR,
+ "%s: ... Invalid button mapping. Using defaults\n",
+ pInfo->name);
+ nbuttons = 1; /* ensure defaults start at 1 */
+ break;
+ }
+
+ pEvdev->btnmap[nbuttons++] = btn;
+ mapping = s;
+ }
+ }
+
+ for (i = nbuttons; i < ArrayLength(pEvdev->btnmap); i++)
+ pEvdev->btnmap[i] = i;
+
+}
+
+static void
+EvdevInitAnyClass(DeviceIntPtr device, EvdevPtr pEvdev)
+{
+ if (pEvdev->flags & EVDEV_RELATIVE_EVENTS &&
+ EvdevAddRelClass(device) == Success)
+ xf86Msg(X_INFO, "%s: initialized for relative axes.\n", device->name);
+ if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS &&
+ EvdevAddAbsClass(device) == Success)
+ xf86Msg(X_INFO, "%s: initialized for absolute axes.\n", device->name);
+}
+
+static void
+EvdevInitAbsClass(DeviceIntPtr device, EvdevPtr pEvdev)
+{
+ if (EvdevAddAbsClass(device) == Success) {
+
+ xf86Msg(X_INFO,"%s: initialized for absolute axes.\n", device->name);
+
+ } else {
+
+ xf86Msg(X_ERROR,"%s: failed to initialize for absolute axes.\n",
+ device->name);
+
+ pEvdev->flags &= ~EVDEV_ABSOLUTE_EVENTS;
+
+ }
+}
+
+static void
+EvdevInitRelClass(DeviceIntPtr device, EvdevPtr pEvdev)
+{
+ int has_abs_axes = pEvdev->flags & EVDEV_ABSOLUTE_EVENTS;
+
+ if (EvdevAddRelClass(device) == Success) {
+
+ xf86Msg(X_INFO,"%s: initialized for relative axes.\n", device->name);
+
+ if (has_abs_axes) {
+
+ xf86Msg(X_WARNING,"%s: ignoring absolute axes.\n", device->name);
+ pEvdev->flags &= ~EVDEV_ABSOLUTE_EVENTS;
+ }
+
+ } else {
+
+ xf86Msg(X_ERROR,"%s: failed to initialize for relative axes.\n",
+ device->name);
+
+ pEvdev->flags &= ~EVDEV_RELATIVE_EVENTS;
+
+ if (has_abs_axes)
+ EvdevInitAbsClass(device, pEvdev);
+ }
+}
+
+static void
+EvdevInitTouchDevice(DeviceIntPtr device, EvdevPtr pEvdev)
+{
+ if (pEvdev->flags & EVDEV_RELATIVE_EVENTS) {
+
+ xf86Msg(X_WARNING,"%s: touchpads, tablets and touchscreens ignore "
+ "relative axes.\n", device->name);
+
+ pEvdev->flags &= ~EVDEV_RELATIVE_EVENTS;
+ }
+
+ EvdevInitAbsClass(device, pEvdev);
+}
+
+static int
+EvdevInit(DeviceIntPtr device)
+{
+ int i;
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ /* clear all axis_map entries */
+ for(i = 0; i < max(ABS_CNT,REL_CNT); i++)
+ pEvdev->axis_map[i]=-1;
+
+ if (pEvdev->flags & EVDEV_KEYBOARD_EVENTS)
+ EvdevAddKeyClass(device);
+ if (pEvdev->flags & EVDEV_BUTTON_EVENTS)
+ EvdevAddButtonClass(device);
+
+ /* We don't allow relative and absolute axes on the same device. The
+ * reason is that some devices (MS Optical Desktop 2000) register both
+ * rel and abs axes for x/y.
+ *
+ * The abs axes register min/max; this min/max then also applies to the
+ * relative device (the mouse) and caps it at 0..255 for both axes.
+ * So, unless you have a small screen, you won't be enjoying it much;
+ * consequently, absolute axes are generally ignored.
+ *
+ * However, currenly only a device with absolute axes can be registered
+ * as a touch{pad,screen}. Thus, given such a device, absolute axes are
+ * used and relative axes are ignored.
+ */
+
+ if (pEvdev->flags & (EVDEV_UNIGNORE_RELATIVE | EVDEV_UNIGNORE_ABSOLUTE))
+ EvdevInitAnyClass(device, pEvdev);
+ else if (pEvdev->flags & (EVDEV_TOUCHPAD | EVDEV_TOUCHSCREEN | EVDEV_TABLET))
+ EvdevInitTouchDevice(device, pEvdev);
+ else if (pEvdev->flags & EVDEV_RELATIVE_EVENTS)
+ EvdevInitRelClass(device, pEvdev);
+#ifdef _F_INIT_ABS_ONLY_FOR_POINTER_
+ else if ( !(pEvdev->flags & EVDEV_KEYBOARD_EVENTS) && (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS) )
+#else
+ else if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)
+#endif
+ EvdevInitAbsClass(device, pEvdev);
+
+#ifdef HAVE_PROPERTIES
+ /* We drop the return value, the only time we ever want the handlers to
+ * unregister is when the device dies. In which case we don't have to
+ * unregister anyway */
+ EvdevInitProperty(device);
+ XIRegisterPropertyHandler(device, EvdevSetProperty, NULL, NULL);
+ EvdevMBEmuInitProperty(device);
+ EvdevWheelEmuInitProperty(device);
+ EvdevDragLockInitProperty(device);
+#endif
+
+ return Success;
+}
+
+/**
+ * Init all extras (wheel emulation, etc.) and grab the device.
+ *
+ * Coming from a resume, the grab may fail with ENODEV. In this case, we set a
+ * timer to wake up and try to reopen the device later.
+ */
+static int
+EvdevOn(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+ int rc = 0;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (pInfo->fd != -1 && pEvdev->grabDevice &&
+ (rc = ioctl(pInfo->fd, EVIOCGRAB, (void *)1)))
+ {
+ xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
+ strerror(errno));
+
+ /* ENODEV - device has disappeared after resume */
+ if (rc && errno == ENODEV)
+ {
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ }
+
+ if (pInfo->fd == -1)
+ {
+ pEvdev->reopen_left = pEvdev->reopen_attempts;
+ pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 100, EvdevReopenTimer, pInfo);
+ } else
+ {
+ pEvdev->min_maj = EvdevGetMajorMinor(pInfo);
+ if (EvdevIsDuplicate(pInfo))
+ {
+ xf86Msg(X_WARNING, "%s: Refusing to enable duplicate device.\n",
+ pInfo->name);
+ return !Success;
+ }
+
+ pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 0, NULL, NULL);
+
+ xf86FlushInput(pInfo->fd);
+ xf86AddEnabledDevice(pInfo);
+ EvdevMBEmuOn(pInfo);
+ pEvdev->flags |= EVDEV_INITIALIZED;
+ device->public.on = TRUE;
+ }
+
+ return Success;
+}
+
+
+static int
+EvdevProc(DeviceIntPtr device, int what)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ switch (what)
+ {
+ case DEVICE_INIT:
+ return EvdevInit(device);
+
+ case DEVICE_ON:
+ return EvdevOn(device);
+
+ case DEVICE_OFF:
+ if (pEvdev->flags & EVDEV_INITIALIZED)
+ EvdevMBEmuFinalize(pInfo);
+
+ if (pInfo->fd != -1)
+ {
+ if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
+ xf86Msg(X_WARNING, "%s: Release failed (%s)\n", pInfo->name,
+ strerror(errno));
+ xf86RemoveEnabledDevice(pInfo);
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ pEvdev->min_maj = 0;
+ pEvdev->flags &= ~EVDEV_INITIALIZED;
+ device->public.on = FALSE;
+ if (pEvdev->reopen_timer)
+ {
+ TimerFree(pEvdev->reopen_timer);
+ pEvdev->reopen_timer = NULL;
+ }
+ break;
+
+ case DEVICE_CLOSE:
+ xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
+ if (pInfo->fd != -1) {
+ close(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ EvdevRemoveDevice(pInfo);
+ pEvdev->min_maj = 0;
+ break;
+ }
+
+ return Success;
+}
+
+/**
+ * Get as much information as we can from the fd and cache it.
+ * If compare is True, then the information retrieved will be compared to the
+ * one already cached. If the information does not match, then this function
+ * returns an error.
+ *
+ * @return Success if the information was cached, or !Success otherwise.
+ */
+static int
+EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ size_t len;
+ int i;
+
+ char name[1024] = {0};
+ unsigned long bitmask[NLONGS(EV_CNT)] = {0};
+ unsigned long key_bitmask[NLONGS(KEY_CNT)] = {0};
+ unsigned long rel_bitmask[NLONGS(REL_CNT)] = {0};
+ unsigned long abs_bitmask[NLONGS(ABS_CNT)] = {0};
+ unsigned long led_bitmask[NLONGS(LED_CNT)] = {0};
+
+ if (ioctl(pInfo->fd, EVIOCGNAME(sizeof(name) - 1), name) < 0) {
+ xf86Msg(X_ERROR, "ioctl EVIOCGNAME failed: %s\n", strerror(errno));
+ goto error;
+ }
+
+ if (!compare) {
+ strcpy(pEvdev->name, name);
+ } else if (strcmp(pEvdev->name, name)) {
+ xf86Msg(X_ERROR, "%s: device name changed: %s != %s\n",
+ pInfo->name, pEvdev->name, name);
+ goto error;
+ }
+
+ len = ioctl(pInfo->fd, EVIOCGBIT(0, sizeof(bitmask)), bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
+ goto error;
+ }
+
+ if (!compare) {
+ memcpy(pEvdev->bitmask, bitmask, len);
+ } else if (memcmp(pEvdev->bitmask, bitmask, len)) {
+ xf86Msg(X_ERROR, "%s: device bitmask has changed\n", pInfo->name);
+ goto error;
+ }
+
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
+ goto error;
+ }
+
+ if (!compare) {
+ memcpy(pEvdev->rel_bitmask, rel_bitmask, len);
+ } else if (memcmp(pEvdev->rel_bitmask, rel_bitmask, len)) {
+ xf86Msg(X_ERROR, "%s: device rel_bitmask has changed\n", pInfo->name);
+ goto error;
+ }
+
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
+ goto error;
+ }
+
+ if (!compare) {
+ memcpy(pEvdev->abs_bitmask, abs_bitmask, len);
+ } else if (memcmp(pEvdev->abs_bitmask, abs_bitmask, len)) {
+ xf86Msg(X_ERROR, "%s: device abs_bitmask has changed\n", pInfo->name);
+ goto error;
+ }
+
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
+ goto error;
+ }
+
+ if (!compare) {
+ memcpy(pEvdev->led_bitmask, led_bitmask, len);
+ } else if (memcmp(pEvdev->led_bitmask, led_bitmask, len)) {
+ xf86Msg(X_ERROR, "%s: device led_bitmask has changed\n", pInfo->name);
+ goto error;
+ }
+
+ /*
+ * Do not try to validate absinfo data since it is not expected
+ * to be static, always refresh it in evdev structure.
+ */
+ for (i = ABS_X; i <= ABS_MAX; i++) {
+ if (TestBit(i, abs_bitmask)) {
+ len = ioctl(pInfo->fd, EVIOCGABS(i), &pEvdev->absinfo[i]);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGABSi(%d) failed: %s\n",
+ pInfo->name, i, strerror(errno));
+ goto error;
+ }
+ }
+ }
+
+ len = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
+ if (len < 0) {
+ xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
+ pInfo->name, strerror(errno));
+ goto error;
+ }
+
+ if (compare) {
+ /*
+ * Keys are special as user can adjust keymap at any time (on
+ * devices that support EVIOCSKEYCODE. However we do not expect
+ * buttons reserved for mice/tablets/digitizers and so on to
+ * appear/disappear so we will check only those in
+ * [BTN_MISC, KEY_OK) range.
+ */
+ size_t start_word = BTN_MISC / LONG_BITS;
+ size_t start_byte = start_word * sizeof(unsigned long);
+ size_t end_word = KEY_OK / LONG_BITS;
+ size_t end_byte = end_word * sizeof(unsigned long);
+
+ if (len >= start_byte &&
+ memcmp(&pEvdev->key_bitmask[start_word], &key_bitmask[start_word],
+ min(len, end_byte) - start_byte + 1)) {
+ xf86Msg(X_ERROR, "%s: device key_bitmask has changed\n", pInfo->name);
+ goto error;
+ }
+ }
+
+ /* Copy the data so we have reasonably up-to-date info */
+ memcpy(pEvdev->key_bitmask, key_bitmask, len);
+
+ return Success;
+
+error:
+ return !Success;
+
+}
+
+static int
+EvdevProbe(InputInfoPtr pInfo)
+{
+ int i, has_rel_axes, has_abs_axes, has_keys, num_buttons, has_scroll;
+ int kernel24 = 0;
+ int ignore_abs = 0, ignore_rel = 0;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
+ if (errno == EINVAL) {
+ /* keyboards are unsafe in 2.4 */
+ kernel24 = 1;
+ pEvdev->grabDevice = 0;
+ } else {
+ xf86Msg(X_ERROR, "Grab failed. Device already configured?\n");
+ return 1;
+ }
+ } else if (pEvdev->grabDevice) {
+ ioctl(pInfo->fd, EVIOCGRAB, (void *)0);
+ }
+
+ /* Trinary state for ignoring axes:
+ - unset: do the normal thing.
+ - TRUE: explicitly ignore them.
+ - FALSE: unignore axes, use them at all cost if they're present.
+ */
+ if (xf86FindOption(pInfo->options, "IgnoreRelativeAxes"))
+ {
+ if (xf86SetBoolOption(pInfo->options, "IgnoreRelativeAxes", FALSE))
+ ignore_rel = TRUE;
+ else
+ pEvdev->flags |= EVDEV_UNIGNORE_RELATIVE;
+
+ }
+ if (xf86FindOption(pInfo->options, "IgnoreAbsoluteAxes"))
+ {
+ if (xf86SetBoolOption(pInfo->options, "IgnoreAbsoluteAxes", FALSE))
+ ignore_abs = TRUE;
+ else
+ pEvdev->flags |= EVDEV_UNIGNORE_ABSOLUTE;
+ }
+
+ has_rel_axes = FALSE;
+ has_abs_axes = FALSE;
+ has_keys = FALSE;
+ has_scroll = FALSE;
+ num_buttons = 0;
+
+ /* count all buttons */
+ for (i = BTN_MISC; i < BTN_JOYSTICK; i++)
+ {
+ int mapping = 0;
+ if (TestBit(i, pEvdev->key_bitmask))
+ {
+ mapping = EvdevUtilButtonEventToButtonNumber(pEvdev, i);
+ if (mapping > num_buttons)
+ num_buttons = mapping;
+ }
+ }
+
+ if (num_buttons)
+ {
+ pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+ pEvdev->num_buttons = num_buttons;
+ xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name,
+ num_buttons);
+ }
+
+ for (i = 0; i < REL_MAX; i++) {
+ if (TestBit(i, pEvdev->rel_bitmask)) {
+ has_rel_axes = TRUE;
+ break;
+ }
+ }
+
+ if (has_rel_axes) {
+ if (TestBit(REL_WHEEL, pEvdev->rel_bitmask) ||
+ TestBit(REL_HWHEEL, pEvdev->rel_bitmask) ||
+ TestBit(REL_DIAL, pEvdev->rel_bitmask)) {
+ xf86Msg(X_INFO, "%s: Found scroll wheel(s)\n", pInfo->name);
+ has_scroll = TRUE;
+ if (!num_buttons)
+ xf86Msg(X_INFO, "%s: Forcing buttons for scroll wheel(s)\n",
+ pInfo->name);
+ num_buttons = (num_buttons < 3) ? 7 : num_buttons + 4;
+ pEvdev->num_buttons = num_buttons;
+ }
+
+ if (!ignore_rel)
+ {
+ xf86Msg(X_INFO, "%s: Found relative axes\n", pInfo->name);
+ pEvdev->flags |= EVDEV_RELATIVE_EVENTS;
+
+ if (TestBit(REL_X, pEvdev->rel_bitmask) &&
+ TestBit(REL_Y, pEvdev->rel_bitmask)) {
+ xf86Msg(X_INFO, "%s: Found x and y relative axes\n", pInfo->name);
+ }
+ } else {
+ xf86Msg(X_INFO, "%s: Relative axes present but ignored.\n", pInfo->name);
+ has_rel_axes = FALSE;
+ }
+ }
+
+ for (i = 0; i < ABS_MAX; i++) {
+ if (TestBit(i, pEvdev->abs_bitmask)) {
+ has_abs_axes = TRUE;
+ break;
+ }
+ }
+
+ if (ignore_abs && has_abs_axes)
+ {
+ xf86Msg(X_INFO, "%s: Absolute axes present but ignored.\n", pInfo->name);
+ has_abs_axes = FALSE;
+ } else if (has_abs_axes) {
+ xf86Msg(X_INFO, "%s: Found absolute axes\n", pInfo->name);
+ pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
+
+ if ((TestBit(ABS_X, pEvdev->abs_bitmask) &&
+ TestBit(ABS_Y, pEvdev->abs_bitmask))) {
+ xf86Msg(X_INFO, "%s: Found x and y absolute axes\n", pInfo->name);
+ if (TestBit(BTN_TOOL_PEN, pEvdev->key_bitmask))
+ {
+ xf86Msg(X_INFO, "%s: Found absolute tablet.\n", pInfo->name);
+ pEvdev->flags |= EVDEV_TABLET;
+ if (!pEvdev->num_buttons)
+ {
+ pEvdev->num_buttons = 7; /* LMR + scroll wheels */
+ pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+ }
+ } else if (TestBit(ABS_PRESSURE, pEvdev->abs_bitmask) ||
+ TestBit(BTN_TOUCH, pEvdev->key_bitmask)) {
+ if (num_buttons || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
+ xf86Msg(X_INFO, "%s: Found absolute touchpad.\n", pInfo->name);
+ pEvdev->flags |= EVDEV_TOUCHPAD;
+ memset(pEvdev->old_vals, -1, sizeof(int) * pEvdev->num_vals);
+ } else {
+ xf86Msg(X_INFO, "%s: Found absolute touchscreen\n", pInfo->name);
+ pEvdev->flags |= EVDEV_TOUCHSCREEN;
+ pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < BTN_MISC; i++) {
+ if (TestBit(i, pEvdev->key_bitmask)) {
+ xf86Msg(X_INFO, "%s: Found keys\n", pInfo->name);
+ pEvdev->flags |= EVDEV_KEYBOARD_EVENTS;
+ has_keys = TRUE;
+ break;
+ }
+ }
+
+ if (has_rel_axes || has_abs_axes || num_buttons) {
+ pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
+ XI86_CONFIGURED;
+ if (pEvdev->flags & EVDEV_TOUCHPAD) {
+ xf86Msg(X_INFO, "%s: Configuring as touchpad\n", pInfo->name);
+ pInfo->type_name = XI_TOUCHPAD;
+ } else if (pEvdev->flags & EVDEV_TABLET) {
+ xf86Msg(X_INFO, "%s: Configuring as tablet\n", pInfo->name);
+ pInfo->type_name = XI_TABLET;
+ } else if (pEvdev->flags & EVDEV_TOUCHSCREEN) {
+ xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
+ pInfo->type_name = XI_TOUCHSCREEN;
+ } else {
+ xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
+ pInfo->type_name = XI_MOUSE;
+ }
+ }
+
+ if (has_keys) {
+ if (kernel24) {
+ xf86Msg(X_INFO, "%s: Kernel < 2.6 is too old, ignoring keyboard\n",
+ pInfo->name);
+ } else {
+ xf86Msg(X_INFO, "%s: Configuring as keyboard\n", pInfo->name);
+ pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
+ pInfo->type_name = XI_KEYBOARD;
+ }
+ }
+
+ if (has_scroll && (pInfo->flags & XI86_CONFIGURED) &&
+ (pInfo->flags & XI86_POINTER_CAPABLE) == 0)
+ {
+ xf86Msg(X_INFO, "%s: Adding scrollwheel support\n", pInfo->name);
+ pInfo->flags |= XI86_POINTER_CAPABLE;
+ pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+ pEvdev->flags |= EVDEV_RELATIVE_EVENTS;
+ }
+
+ if ((pInfo->flags & XI86_CONFIGURED) == 0) {
+ xf86Msg(X_WARNING, "%s: Don't know how to use device\n",
+ pInfo->name);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+EvdevSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4])
+{
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (num_calibration == 0) {
+ pEvdev->flags &= ~EVDEV_CALIBRATED;
+ pEvdev->calibration.min_x = 0;
+ pEvdev->calibration.max_x = 0;
+ pEvdev->calibration.min_y = 0;
+ pEvdev->calibration.max_y = 0;
+ } else if (num_calibration == 4) {
+ pEvdev->flags |= EVDEV_CALIBRATED;
+ pEvdev->calibration.min_x = calibration[0];
+ pEvdev->calibration.max_x = calibration[1];
+ pEvdev->calibration.min_y = calibration[2];
+ pEvdev->calibration.max_y = calibration[3];
+ }
+}
+
+static InputInfoPtr
+EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr pInfo;
+ const char *device, *str;
+ int num_calibration = 0, calibration[4] = { 0, 0, 0, 0 };
+ int num_resolution = 0, resolution[4] = { 0, 0, 0, 0 };
+ EvdevPtr pEvdev;
+
+ if (!(pInfo = xf86AllocateInput(drv, 0)))
+ return NULL;
+
+ /* Initialise the InputInfoRec. */
+ pInfo->name = dev->identifier;
+ pInfo->flags = 0;
+ pInfo->type_name = "UNKNOWN";
+ pInfo->device_control = EvdevProc;
+ pInfo->read_input = EvdevReadInput;
+ pInfo->history_size = 0;
+ pInfo->control_proc = NULL;
+ pInfo->close_proc = NULL;
+ pInfo->switch_mode = NULL;
+ pInfo->conversion_proc = NULL;
+ pInfo->reverse_conversion_proc = NULL;
+ pInfo->dev = NULL;
+ pInfo->private_flags = 0;
+ pInfo->always_core_feedback = NULL;
+ pInfo->conf_idev = dev;
+
+ if (!(pEvdev = xcalloc(sizeof(EvdevRec), 1)))
+ return pInfo;
+
+ pInfo->private = pEvdev;
+
+ xf86CollectInputOptions(pInfo, evdevDefaults, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ /*
+ * We initialize pEvdev->tool to 1 so that device that doesn't use
+ * proximity will still report events.
+ */
+ pEvdev->tool = 1;
+
+ device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
+ if (!device) {
+ xf86Msg(X_ERROR, "%s: No device specified.\n", pInfo->name);
+ xf86DeleteInput(pInfo, 0);
+ return NULL;
+ }
+
+ pEvdev->device = device;
+
+ xf86Msg(X_CONFIG, "%s: Device: \"%s\"\n", pInfo->name, device);
+ do {
+ pInfo->fd = open(device, O_RDWR | O_NONBLOCK, 0);
+ } while (pInfo->fd < 0 && errno == EINTR);
+
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "Unable to open evdev device \"%s\".\n", device);
+ xf86DeleteInput(pInfo, 0);
+ return NULL;
+ }
+
+ /* Check major/minor of device node to avoid adding duplicate devices. */
+ pEvdev->min_maj = EvdevGetMajorMinor(pInfo);
+ if (EvdevIsDuplicate(pInfo))
+ {
+ xf86Msg(X_WARNING, "%s: device file already in use. Ignoring.\n",
+ pInfo->name);
+ close(pInfo->fd);
+ xf86DeleteInput(pInfo, 0);
+ return NULL;
+ }
+
+ pEvdev->reopen_attempts = xf86SetIntOption(pInfo->options, "ReopenAttempts", 10);
+ pEvdev->invert_x = xf86SetBoolOption(pInfo->options, "InvertX", FALSE);
+ pEvdev->invert_y = xf86SetBoolOption(pInfo->options, "InvertY", FALSE);
+ pEvdev->swap_axes = xf86SetBoolOption(pInfo->options, "SwapAxes", FALSE);
+
+ str = xf86CheckStrOption(pInfo->options, "Calibration", NULL);
+ if (str) {
+ num_calibration = sscanf(str, "%d %d %d %d",
+ &calibration[0], &calibration[1],
+ &calibration[2], &calibration[3]);
+ if (num_calibration == 4)
+ EvdevSetCalibration(pInfo, num_calibration, calibration);
+ else
+ xf86Msg(X_ERROR,
+ "%s: Insufficient calibration factors (%d). Ignoring calibration\n",
+ pInfo->name, num_calibration);
+ }
+
+ str = xf86CheckStrOption(pInfo->options, "Resolution", NULL);
+ if (str) {
+ num_resolution = sscanf(str, "%d %d %d %d",
+ &resolution[0], &resolution[1],
+ &resolution[2], &resolution[3]);
+ if (num_resolution == 4)
+ EvdevSetResolution(pInfo, num_resolution, resolution);
+ else
+ xf86Msg(X_ERROR,
+ "%s: Insufficient resolution factors (%d). Ignoring resolution\n",
+ pInfo->name, num_resolution);
+ }
+
+ /* Grabbing the event device stops in-kernel event forwarding. In other
+ words, it disables rfkill and the "Macintosh mouse button emulation".
+ Note that this needs a server that sets the console to RAW mode. */
+ pEvdev->grabDevice = xf86CheckBoolOption(dev->commonOptions, "GrabDevice", 0);
+
+ EvdevInitButtonMapping(pInfo);
+
+ if (EvdevCacheCompare(pInfo, FALSE) ||
+ EvdevProbe(pInfo)) {
+ close(pInfo->fd);
+ xf86DeleteInput(pInfo, 0);
+ return NULL;
+ }
+
+ if(pEvdev->flags & EVDEV_RESOLUTION)
+ {
+ EvdevSwapAxes(pEvdev);
+ }
+ else
+ {
+ pEvdev->absinfo[ABS_X].maximum = 0;
+ pEvdev->absinfo[ABS_X].minimum = 0;
+ pEvdev->absinfo[ABS_Y].maximum = 0;
+ pEvdev->absinfo[ABS_Y].minimum = 0;
+ }
+
+ EvdevAddDevice(pInfo);
+
+ if (pEvdev->flags & EVDEV_BUTTON_EVENTS)
+ {
+ EvdevMBEmuPreInit(pInfo);
+ EvdevWheelEmuPreInit(pInfo);
+ EvdevDragLockPreInit(pInfo);
+ }
+
+ return pInfo;
+}
+
+_X_EXPORT InputDriverRec EVDEV = {
+ 1,
+ "evdev",
+ NULL,
+ EvdevPreInit,
+ NULL,
+ NULL,
+ 0
+};
+
+static void
+EvdevUnplug(pointer p)
+{
+}
+
+static pointer
+EvdevPlug(pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin)
+{
+ xf86AddInputDriver(&EVDEV, module, 0);
+ return module;
+}
+
+static XF86ModuleVersionInfo EvdevVersionRec =
+{
+ "evdev",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0}
+};
+
+_X_EXPORT XF86ModuleData evdevModuleData =
+{
+ &EvdevVersionRec,
+ EvdevPlug,
+ EvdevUnplug
+};
+
+
+/* Return an index value for a given button event code
+ * returns 0 on non-button event.
+ */
+unsigned int
+EvdevUtilButtonEventToButtonNumber(EvdevPtr pEvdev, int code)
+{
+ unsigned int button = 0;
+
+ switch(code) {
+ case BTN_LEFT:
+ button = 1;
+ break;
+
+ case BTN_RIGHT:
+ button = 3;
+ break;
+
+ case BTN_MIDDLE:
+ button = 2;
+ break;
+
+ /* Treat BTN_[0-2] as LMR buttons on devices that do not advertise
+ BTN_LEFT, BTN_MIDDLE, BTN_RIGHT.
+ Otherwise, treat BTN_[0+n] as button 5+n.
+ XXX: This causes duplicate mappings for BTN_0 + n and BTN_SIDE + n
+ */
+ case BTN_0:
+ button = (TestBit(BTN_LEFT, pEvdev->key_bitmask)) ? 8 : 1;
+ break;
+ case BTN_1:
+ button = (TestBit(BTN_MIDDLE, pEvdev->key_bitmask)) ? 9 : 2;
+ break;
+ case BTN_2:
+ button = (TestBit(BTN_RIGHT, pEvdev->key_bitmask)) ? 10 : 3;
+ break;
+
+ /* FIXME: BTN_3.. and BTN_SIDE.. have the same button mapping */
+ case BTN_3:
+ case BTN_4:
+ case BTN_5:
+ case BTN_6:
+ case BTN_7:
+ case BTN_8:
+ case BTN_9:
+ button = (code - BTN_0 + 5);
+ break;
+
+ case BTN_SIDE:
+ case BTN_EXTRA:
+ case BTN_FORWARD:
+ case BTN_BACK:
+ case BTN_TASK:
+ button = (code - BTN_LEFT + 5);
+ break;
+
+ default:
+ if ((code > BTN_TASK) && (code < KEY_OK)) {
+ if (code < BTN_JOYSTICK) {
+ if (code < BTN_MOUSE)
+ button = (code - BTN_0 + 5);
+ else
+ button = (code - BTN_LEFT + 5);
+ }
+ }
+ }
+
+ if (button > EVDEV_MAXBUTTONS)
+ return 0;
+
+ return button;
+}
+
+#ifdef HAVE_PROPERTIES
+#ifdef HAVE_LABELS
+/* Aligned with linux/input.h.
+ Note that there are holes in the ABS_ range, these are simply replaced with
+ MISC here */
+static char* abs_labels[] = {
+ AXIS_LABEL_PROP_ABS_X, /* 0x00 */
+ AXIS_LABEL_PROP_ABS_Y, /* 0x01 */
+ AXIS_LABEL_PROP_ABS_Z, /* 0x02 */
+ AXIS_LABEL_PROP_ABS_RX, /* 0x03 */
+ AXIS_LABEL_PROP_ABS_RY, /* 0x04 */
+ AXIS_LABEL_PROP_ABS_RZ, /* 0x05 */
+ AXIS_LABEL_PROP_ABS_THROTTLE, /* 0x06 */
+ AXIS_LABEL_PROP_ABS_RUDDER, /* 0x07 */
+ AXIS_LABEL_PROP_ABS_WHEEL, /* 0x08 */
+ AXIS_LABEL_PROP_ABS_GAS, /* 0x09 */
+ AXIS_LABEL_PROP_ABS_BRAKE, /* 0x0a */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_HAT0X, /* 0x10 */
+ AXIS_LABEL_PROP_ABS_HAT0Y, /* 0x11 */
+ AXIS_LABEL_PROP_ABS_HAT1X, /* 0x12 */
+ AXIS_LABEL_PROP_ABS_HAT1Y, /* 0x13 */
+ AXIS_LABEL_PROP_ABS_HAT2X, /* 0x14 */
+ AXIS_LABEL_PROP_ABS_HAT2Y, /* 0x15 */
+ AXIS_LABEL_PROP_ABS_HAT3X, /* 0x16 */
+ AXIS_LABEL_PROP_ABS_HAT3Y, /* 0x17 */
+ AXIS_LABEL_PROP_ABS_PRESSURE, /* 0x18 */
+ AXIS_LABEL_PROP_ABS_DISTANCE, /* 0x19 */
+ AXIS_LABEL_PROP_ABS_TILT_X, /* 0x1a */
+ AXIS_LABEL_PROP_ABS_TILT_Y, /* 0x1b */
+ AXIS_LABEL_PROP_ABS_TOOL_WIDTH, /* 0x1c */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_MISC, /* undefined */
+ AXIS_LABEL_PROP_ABS_VOLUME /* 0x20 */
+};
+
+static char* rel_labels[] = {
+ AXIS_LABEL_PROP_REL_X,
+ AXIS_LABEL_PROP_REL_Y,
+ AXIS_LABEL_PROP_REL_Z,
+ AXIS_LABEL_PROP_REL_RX,
+ AXIS_LABEL_PROP_REL_RY,
+ AXIS_LABEL_PROP_REL_RZ,
+ AXIS_LABEL_PROP_REL_HWHEEL,
+ AXIS_LABEL_PROP_REL_DIAL,
+ AXIS_LABEL_PROP_REL_WHEEL,
+ AXIS_LABEL_PROP_REL_MISC
+};
+
+static char* btn_labels[][16] = {
+ { /* BTN_MISC group offset 0x100*/
+ BTN_LABEL_PROP_BTN_0, /* 0x00 */
+ BTN_LABEL_PROP_BTN_1, /* 0x01 */
+ BTN_LABEL_PROP_BTN_2, /* 0x02 */
+ BTN_LABEL_PROP_BTN_3, /* 0x03 */
+ BTN_LABEL_PROP_BTN_4, /* 0x04 */
+ BTN_LABEL_PROP_BTN_5, /* 0x05 */
+ BTN_LABEL_PROP_BTN_6, /* 0x06 */
+ BTN_LABEL_PROP_BTN_7, /* 0x07 */
+ BTN_LABEL_PROP_BTN_8, /* 0x08 */
+ BTN_LABEL_PROP_BTN_9 /* 0x09 */
+ },
+ { /* BTN_MOUSE group offset 0x110 */
+ BTN_LABEL_PROP_BTN_LEFT, /* 0x00 */
+ BTN_LABEL_PROP_BTN_RIGHT, /* 0x01 */
+ BTN_LABEL_PROP_BTN_MIDDLE, /* 0x02 */
+ BTN_LABEL_PROP_BTN_SIDE, /* 0x03 */
+ BTN_LABEL_PROP_BTN_EXTRA, /* 0x04 */
+ BTN_LABEL_PROP_BTN_FORWARD, /* 0x05 */
+ BTN_LABEL_PROP_BTN_BACK, /* 0x06 */
+ BTN_LABEL_PROP_BTN_TASK /* 0x07 */
+ },
+ { /* BTN_JOYSTICK group offset 0x120 */
+ BTN_LABEL_PROP_BTN_TRIGGER, /* 0x00 */
+ BTN_LABEL_PROP_BTN_THUMB, /* 0x01 */
+ BTN_LABEL_PROP_BTN_THUMB2, /* 0x02 */
+ BTN_LABEL_PROP_BTN_TOP, /* 0x03 */
+ BTN_LABEL_PROP_BTN_TOP2, /* 0x04 */
+ BTN_LABEL_PROP_BTN_PINKIE, /* 0x05 */
+ BTN_LABEL_PROP_BTN_BASE, /* 0x06 */
+ BTN_LABEL_PROP_BTN_BASE2, /* 0x07 */
+ BTN_LABEL_PROP_BTN_BASE3, /* 0x08 */
+ BTN_LABEL_PROP_BTN_BASE4, /* 0x09 */
+ BTN_LABEL_PROP_BTN_BASE5, /* 0x0a */
+ BTN_LABEL_PROP_BTN_BASE6, /* 0x0b */
+ NULL,
+ NULL,
+ NULL,
+ BTN_LABEL_PROP_BTN_DEAD /* 0x0f */
+ },
+ { /* BTN_GAMEPAD group offset 0x130 */
+ BTN_LABEL_PROP_BTN_A, /* 0x00 */
+ BTN_LABEL_PROP_BTN_B, /* 0x01 */
+ BTN_LABEL_PROP_BTN_C, /* 0x02 */
+ BTN_LABEL_PROP_BTN_X, /* 0x03 */
+ BTN_LABEL_PROP_BTN_Y, /* 0x04 */
+ BTN_LABEL_PROP_BTN_Z, /* 0x05 */
+ BTN_LABEL_PROP_BTN_TL, /* 0x06 */
+ BTN_LABEL_PROP_BTN_TR, /* 0x07 */
+ BTN_LABEL_PROP_BTN_TL2, /* 0x08 */
+ BTN_LABEL_PROP_BTN_TR2, /* 0x09 */
+ BTN_LABEL_PROP_BTN_SELECT, /* 0x0a */
+ BTN_LABEL_PROP_BTN_START, /* 0x0b */
+ BTN_LABEL_PROP_BTN_MODE, /* 0x0c */
+ BTN_LABEL_PROP_BTN_THUMBL, /* 0x0d */
+ BTN_LABEL_PROP_BTN_THUMBR /* 0x0e */
+ },
+ { /* BTN_DIGI group offset 0x140 */
+ BTN_LABEL_PROP_BTN_TOOL_PEN, /* 0x00 */
+ BTN_LABEL_PROP_BTN_TOOL_RUBBER, /* 0x01 */
+ BTN_LABEL_PROP_BTN_TOOL_BRUSH, /* 0x02 */
+ BTN_LABEL_PROP_BTN_TOOL_PENCIL, /* 0x03 */
+ BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH, /* 0x04 */
+ BTN_LABEL_PROP_BTN_TOOL_FINGER, /* 0x05 */
+ BTN_LABEL_PROP_BTN_TOOL_MOUSE, /* 0x06 */
+ BTN_LABEL_PROP_BTN_TOOL_LENS, /* 0x07 */
+ NULL,
+ NULL,
+ BTN_LABEL_PROP_BTN_TOUCH, /* 0x0a */
+ BTN_LABEL_PROP_BTN_STYLUS, /* 0x0b */
+ BTN_LABEL_PROP_BTN_STYLUS2, /* 0x0c */
+ BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP, /* 0x0d */
+ BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP /* 0x0e */
+ },
+ { /* BTN_WHEEL group offset 0x150 */
+ BTN_LABEL_PROP_BTN_GEAR_DOWN, /* 0x00 */
+ BTN_LABEL_PROP_BTN_GEAR_UP /* 0x01 */
+ }
+};
+
+#endif /* HAVE_LABELS */
+
+static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+{
+#ifdef HAVE_LABELS
+ Atom atom;
+ int axis;
+ char **labels;
+ int labels_len = 0;
+ char *misc_label;
+
+ if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)
+ {
+ labels = abs_labels;
+ labels_len = ArrayLength(abs_labels);
+ misc_label = AXIS_LABEL_PROP_ABS_MISC;
+ } else if ((pEvdev->flags & EVDEV_RELATIVE_EVENTS))
+ {
+ labels = rel_labels;
+ labels_len = ArrayLength(rel_labels);
+ misc_label = AXIS_LABEL_PROP_REL_MISC;
+ }
+
+ memset(atoms, 0, natoms * sizeof(Atom));
+
+ /* Now fill the ones we know */
+ for (axis = 0; axis < labels_len; axis++)
+ {
+ if (pEvdev->axis_map[axis] == -1)
+ continue;
+
+ atom = XIGetKnownProperty(labels[axis]);
+ if (!atom) /* Should not happen */
+ continue;
+
+ atoms[pEvdev->axis_map[axis]] = atom;
+ }
+#endif
+}
+
+static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
+{
+#ifdef HAVE_LABELS
+ Atom atom;
+ int button, bmap;
+
+ /* First, make sure all atoms are initialized */
+ atom = XIGetKnownProperty(BTN_LABEL_PROP_BTN_UNKNOWN);
+ for (button = 0; button < natoms; button++)
+ atoms[button] = atom;
+
+ for (button = BTN_MISC; button < BTN_JOYSTICK; button++)
+ {
+ if (TestBit(button, pEvdev->key_bitmask))
+ {
+ int group = (button % 0x100)/16;
+ int idx = button - ((button/16) * 16);
+
+ if (!btn_labels[group][idx])
+ continue;
+
+ atom = XIGetKnownProperty(btn_labels[group][idx]);
+ if (!atom)
+ continue;
+
+ /* Props are 0-indexed, button numbers start with 1 */
+ bmap = EvdevUtilButtonEventToButtonNumber(pEvdev, button) - 1;
+ atoms[bmap] = atom;
+ }
+ }
+
+ /* wheel buttons, hardcoded anyway */
+ if (natoms > 3)
+ atoms[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ if (natoms > 4)
+ atoms[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+ if (natoms > 5)
+ atoms[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ if (natoms > 6)
+ atoms[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+#endif
+}
+
+static void
+EvdevInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+ int rc;
+ BOOL invert[2];
+ char reopen;
+
+ prop_reopen = MakeAtom(EVDEV_PROP_REOPEN, strlen(EVDEV_PROP_REOPEN),
+ TRUE);
+
+ reopen = pEvdev->reopen_attempts;
+ rc = XIChangeDeviceProperty(dev, prop_reopen, XA_INTEGER, 8,
+ PropModeReplace, 1, &reopen, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_reopen, FALSE);
+
+ if (pEvdev->flags & (EVDEV_RELATIVE_EVENTS | EVDEV_ABSOLUTE_EVENTS))
+ {
+ invert[0] = pEvdev->invert_x;
+ invert[1] = pEvdev->invert_y;
+
+ prop_invert = MakeAtom(EVDEV_PROP_INVERT_AXES, strlen(EVDEV_PROP_INVERT_AXES), TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_invert, XA_INTEGER, 8,
+ PropModeReplace, 2,
+ invert, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_invert, FALSE);
+
+ prop_calibration = MakeAtom(EVDEV_PROP_CALIBRATION,
+ strlen(EVDEV_PROP_CALIBRATION), TRUE);
+ if (pEvdev->flags & EVDEV_CALIBRATED) {
+ int calibration[4];
+
+ calibration[0] = pEvdev->calibration.min_x;
+ calibration[1] = pEvdev->calibration.max_x;
+ calibration[2] = pEvdev->calibration.min_y;
+ calibration[3] = pEvdev->calibration.max_y;
+
+ rc = XIChangeDeviceProperty(dev, prop_calibration, XA_INTEGER,
+ 32, PropModeReplace, 4, calibration,
+ FALSE);
+ } else if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS) {
+ rc = XIChangeDeviceProperty(dev, prop_calibration, XA_INTEGER,
+ 32, PropModeReplace, 0, NULL,
+ FALSE);
+ }
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_calibration, FALSE);
+
+ prop_swap = MakeAtom(EVDEV_PROP_SWAP_AXES,
+ strlen(EVDEV_PROP_SWAP_AXES), TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_swap, XA_INTEGER, 8,
+ PropModeReplace, 1, &pEvdev->swap_axes, FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_swap, FALSE);
+
+#ifdef HAVE_LABELS
+ /* Axis labelling */
+ if ((pEvdev->num_vals > 0) && (prop_axis_label = XIGetKnownProperty(AXIS_LABEL_PROP)))
+ {
+ Atom atoms[pEvdev->num_vals];
+ EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
+ XIChangeDeviceProperty(dev, prop_axis_label, XA_ATOM, 32,
+ PropModeReplace, pEvdev->num_vals, atoms, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_axis_label, FALSE);
+ }
+ /* Button labelling */
+ if ((pEvdev->num_buttons > 0) && (prop_btn_label = XIGetKnownProperty(BTN_LABEL_PROP)))
+ {
+ Atom atoms[EVDEV_MAXBUTTONS];
+ EvdevInitButtonLabels(pEvdev, EVDEV_MAXBUTTONS, atoms);
+ XIChangeDeviceProperty(dev, prop_btn_label, XA_ATOM, 32,
+ PropModeReplace, pEvdev->num_buttons, atoms, FALSE);
+ XISetDevicePropertyDeletable(dev, prop_btn_label, FALSE);
+ }
+#endif /* HAVE_LABELS */
+ }
+
+}
+
+static void EvdevSwapAxes(EvdevPtr pEvdev)
+{
+ if(pEvdev->swap_axes)
+ {
+ pEvdev->absinfo[ABS_Y].maximum = pEvdev->resolution.min_x;
+ pEvdev->absinfo[ABS_Y].minimum = pEvdev->resolution.max_x;
+ pEvdev->absinfo[ABS_X].maximum = pEvdev->resolution.min_y;
+ pEvdev->absinfo[ABS_X].minimum = pEvdev->resolution.max_y;
+ }
+ else
+ {
+ pEvdev->absinfo[ABS_X].maximum = pEvdev->resolution.min_x;
+ pEvdev->absinfo[ABS_X].minimum = pEvdev->resolution.max_x;
+ pEvdev->absinfo[ABS_Y].maximum = pEvdev->resolution.min_y;
+ pEvdev->absinfo[ABS_Y].minimum = pEvdev->resolution.max_y;
+ }
+}
+
+static void
+EvdevSetResolution(InputInfoPtr pInfo, int num_resolution, int resolution[4])
+{
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (num_resolution == 0) {
+ pEvdev->flags &= ~EVDEV_RESOLUTION;
+ pEvdev->resolution.min_x = 0;
+ pEvdev->resolution.max_x = 0;
+ pEvdev->resolution.min_y = 0;
+ pEvdev->resolution.max_y = 0;
+ } else if (num_resolution == 4) {
+ pEvdev->flags |= EVDEV_RESOLUTION;
+ pEvdev->resolution.min_x = resolution[0];
+ pEvdev->resolution.max_x = resolution[1];
+ pEvdev->resolution.min_y = resolution[2];
+ pEvdev->resolution.max_y = resolution[3];
+ }
+}
+
+static int
+EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (atom == prop_invert)
+ {
+ BOOL* data;
+ if (val->format != 8 || val->size != 2 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ data = (BOOL*)val->data;
+ pEvdev->invert_x = data[0];
+ pEvdev->invert_y = data[1];
+ }
+ } else if (atom == prop_reopen)
+ {
+ if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+ return BadMatch;
+
+ if (!checkonly)
+ pEvdev->reopen_attempts = *((CARD8*)val->data);
+ } else if (atom == prop_calibration)
+ {
+ if (val->format != 32 || val->type != XA_INTEGER)
+ return BadMatch;
+ if (val->size != 4 && val->size != 0)
+ return BadMatch;
+
+ if (!checkonly)
+ EvdevSetCalibration(pInfo, val->size, val->data);
+ } else if (atom == prop_swap)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ pEvdev->swap_axes = *((BOOL*)val->data);
+ EvdevSwapAxes(pEvdev);
+ } else if (atom == prop_axis_label || atom == prop_btn_label)
+ return BadAccess; /* Axis/Button labels can't be changed */
+
+ return Success;
+}
+#endif
diff --git a/src/evdev.h b/src/evdev.h
new file mode 100644
index 0000000..e702694
--- /dev/null
+++ b/src/evdev.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright © 2004-2008 Red Hat, Inc.
+ * Copyright © 2008 University of South Australia
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Kristian Høgsberg (krh@redhat.com)
+ * Adam Jackson (ajax@redhat.com)
+ * Peter Hutterer (peter@cs.unisa.edu.au)
+ * Oliver McFadden (oliver.mcfadden@nokia.com)
+ */
+
+#ifndef EVDEV_H
+#define EVDEV_H
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+#include <xf86Xinput.h>
+#include <xf86_OSproc.h>
+#include <xkbstr.h>
+
+#ifndef EV_CNT /* linux 2.4 kernels and earlier lack _CNT defines */
+#define EV_CNT (EV_MAX+1)
+#endif
+#ifndef KEY_CNT
+#define KEY_CNT (KEY_MAX+1)
+#endif
+#ifndef REL_CNT
+#define REL_CNT (REL_MAX+1)
+#endif
+#ifndef ABS_CNT
+#define ABS_CNT (ABS_MAX+1)
+#endif
+#ifndef LED_CNT
+#define LED_CNT (LED_MAX+1)
+#endif
+
+#define EVDEV_MAXBUTTONS 32
+#define EVDEV_MAXQUEUE 32
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
+#define HAVE_PROPERTIES 1
+#endif
+
+#ifndef MAX_VALUATORS
+#define MAX_VALUATORS 36
+#endif
+
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+typedef struct {
+ char *rules;
+ char *model;
+ char *layout;
+ char *variant;
+ char *options;
+} XkbRMLVOSet;
+#endif
+
+
+#define LONG_BITS (sizeof(long) * 8)
+
+/* Number of longs needed to hold the given number of bits */
+#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
+
+/* axis specific data for wheel emulation */
+typedef struct {
+ int up_button;
+ int down_button;
+ int traveled_distance;
+} WheelAxis, *WheelAxisPtr;
+
+/* Event queue used to defer keyboard/button events until EV_SYN time. */
+typedef struct {
+ enum {
+ EV_QUEUE_KEY, /* xf86PostKeyboardEvent() */
+ EV_QUEUE_BTN, /* xf86PostButtonEvent() */
+ } type;
+ int key; /* May be either a key code or button number. */
+ int val; /* State of the key/button; pressed or released. */
+} EventQueueRec, *EventQueuePtr;
+
+typedef struct {
+ const char *device;
+ int grabDevice; /* grab the event device? */
+
+ int num_vals; /* number of valuators */
+ int axis_map[max(ABS_CNT, REL_CNT)]; /* Map evdev <axis> to index */
+ int vals[MAX_VALUATORS];
+ int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
+
+ int flags;
+ int tool;
+ int num_buttons; /* number of buttons */
+ BOOL swap_axes;
+ BOOL invert_x;
+ BOOL invert_y;
+
+ int delta[REL_CNT];
+ unsigned int abs, rel;
+
+ /* XKB stuff has to be per-device rather than per-driver */
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 5
+ XkbComponentNamesRec xkbnames;
+#endif
+ XkbRMLVOSet rmlvo;
+
+ /* Middle mouse button emulation */
+ struct {
+ BOOL enabled;
+ BOOL pending; /* timer waiting? */
+ int buttonstate; /* phys. button state */
+ int state; /* state machine (see bt3emu.c) */
+ Time expires; /* time of expiry */
+ Time timeout;
+ } emulateMB;
+ struct {
+ int meta; /* meta key to lock any button */
+ BOOL meta_state; /* meta_button state */
+ unsigned int lock_pair[EVDEV_MAXBUTTONS]; /* specify a meta/lock pair */
+ BOOL lock_state[EVDEV_MAXBUTTONS]; /* state of any locked buttons */
+ } dragLock;
+ struct {
+ BOOL enabled;
+ int button;
+ int button_state;
+ int inertia;
+ WheelAxis X;
+ WheelAxis Y;
+ Time expires; /* time of expiry */
+ Time timeout;
+ } emulateWheel;
+ /* run-time calibration */
+ struct {
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+ } calibration;
+
+ struct {
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+ } resolution;
+
+ unsigned char btnmap[32]; /* config-file specified button mapping */
+
+ int reopen_attempts; /* max attempts to re-open after read failure */
+ int reopen_left; /* number of attempts left to re-open the device */
+ OsTimerPtr reopen_timer;
+
+ /* Cached info from device. */
+ char name[1024];
+ unsigned long bitmask[NLONGS(EV_CNT)];
+ unsigned long key_bitmask[NLONGS(KEY_CNT)];
+ unsigned long rel_bitmask[NLONGS(REL_CNT)];
+ unsigned long abs_bitmask[NLONGS(ABS_CNT)];
+ unsigned long led_bitmask[NLONGS(LED_CNT)];
+ struct input_absinfo absinfo[ABS_CNT];
+
+ /* minor/major number */
+ dev_t min_maj;
+
+ /* Event queue used to defer keyboard/button events until EV_SYN time. */
+ int num_queue;
+ EventQueueRec queue[EVDEV_MAXQUEUE];
+} EvdevRec, *EvdevPtr;
+
+/* Event posting functions */
+void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
+void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value);
+void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count);
+void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+ int v[MAX_VALUATORS]);
+void EvdevPostAbsoluteMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+ int v[MAX_VALUATORS]);
+unsigned int EvdevUtilButtonEventToButtonNumber(EvdevPtr pEvdev, int code);
+
+/* Middle Button emulation */
+int EvdevMBEmuTimer(InputInfoPtr);
+BOOL EvdevMBEmuFilterEvent(InputInfoPtr, int, BOOL);
+void EvdevMBEmuWakeupHandler(pointer, int, pointer);
+void EvdevMBEmuBlockHandler(pointer, struct timeval**, pointer);
+void EvdevMBEmuPreInit(InputInfoPtr);
+void EvdevMBEmuOn(InputInfoPtr);
+void EvdevMBEmuFinalize(InputInfoPtr);
+void EvdevMBEmuEnable(InputInfoPtr, BOOL);
+
+/* Mouse Wheel emulation */
+void EvdevWheelEmuPreInit(InputInfoPtr pInfo);
+BOOL EvdevWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
+BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
+
+/* Draglock code */
+void EvdevDragLockPreInit(InputInfoPtr pInfo);
+BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
+
+#ifdef HAVE_PROPERTIES
+void EvdevMBEmuInitProperty(DeviceIntPtr);
+void EvdevWheelEmuInitProperty(DeviceIntPtr);
+void EvdevDragLockInitProperty(DeviceIntPtr);
+#endif
+#endif
diff --git a/xorg-evdev.pc.in b/xorg-evdev.pc.in
new file mode 100644
index 0000000..20710a6
--- /dev/null
+++ b/xorg-evdev.pc.in
@@ -0,0 +1,6 @@
+sdkdir=@sdkdir@
+
+Name: xorg-evdev
+Description: X.Org evdev input driver.
+Version: @PACKAGE_VERSION@
+Cflags: -I${sdkdir}