Tizen 2.0 Release
authorHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 14:59:37 +0000 (23:59 +0900)
committerHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 14:59:37 +0000 (23:59 +0900)
22 files changed:
10-diamondtouch.fdi [new file with mode: 0644]
10-logitech.fdi [new file with mode: 0644]
10-stantum.fdi [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0755]
include/Makefile.am [new file with mode: 0644]
include/evdevmultitouch-properties.h [new file with mode: 0755]
man/Makefile.am [new file with mode: 0644]
man/evdevmultitouch.man [new file with mode: 0644]
packaging/xorg-x11-drv-evdev-multitouch.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/draglock.c [new file with mode: 0755]
src/emuMB.c [new file with mode: 0755]
src/emuWheel.c [new file with mode: 0755]
src/evdevmultitouch.c [new file with mode: 0755]
src/evdevmultitouch.h [new file with mode: 0755]
xorg-evdev-multitouch.pc.in [new file with mode: 0644]

diff --git a/10-diamondtouch.fdi b/10-diamondtouch.fdi
new file mode 100644 (file)
index 0000000..dc0bc15
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- this is probably a bit imprecise -->
+<deviceinfo version="0.2">
+  <device>
+    <match key="info.product" contains="DiamondTouch">
+      <match key="info.category" contains="input">
+        <merge key="input.x11_driver" type="string">evdevmultitouch</merge>
+      </match>
+  </device>
+</deviceinfo>
diff --git a/10-logitech.fdi b/10-logitech.fdi
new file mode 100644 (file)
index 0000000..4151d70
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- this is probably a bit imprecise -->
+<deviceinfo version="0.2">
+  <device>
+    <match key="info.product" contains="Logitech Optical USB Mouse">
+      <match key="info.category" contains="input">
+        <match key="info.capabilities" contains="input.mouse">
+            <merge key="input.x11_driver" type="string">evdevmultitouchmultitouch</merge>
+        </match>
+      </match>
+    </match>
+  </device>
+</deviceinfo>
diff --git a/10-stantum.fdi b/10-stantum.fdi
new file mode 100644 (file)
index 0000000..33d080d
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- this is probably a bit imprecise -->
+<deviceinfo version="0.2">
+  <device>
+    <match key="info.product" contains="Stantum MTP USB Controller">
+      <match key="info.category" contains="input">
+        <merge key="input.x11_driver" type="string">evdevmultitouch</merge>
+      </match>
+    </match>
+  </device>
+</deviceinfo>
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..e903784
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Sung-Jin Park <sj76.park@samsung.com>
+Sangjin Lee <lsj119@samsung.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..b76958b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,115 @@
+Various copyright notices found in this driver:
+
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+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/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..7b3990f
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,6 @@
+[Title] SEL Verification - Fix a bug that causes SEGV when X server tries to remove a multitouch device
+[Issue#] S1-7024
+[Problem] A segmentation fault was made when X server tries to remove a multitouch device.
+[Cause] X multitouch driver tries to free a pointer(device name) which was not allocated by malloc.
+[Solution] Allocate a pointer by malloc() for the device name.
+[SCMRequest] N/A
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..d23f650
--- /dev/null
@@ -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-multitouch.pc
+
+EXTRA_DIST = ChangeLog
+
+MAINTAINERCLEANFILES=ChangeLog
+
+.PHONY: ChangeLog
+
+ChangeLog:
+       $(CHANGELOG_CMD)
+
+dist-hook: ChangeLog
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3b3e134
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+xf86-input-evdevmultitouch - 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-evdevmultitouch
+
+        http://cgit.freedesktop.org/xorg/driver/xf86-input-evdevmultitouch
+
+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 (executable)
index 0000000..904cd67
--- /dev/null
@@ -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 100755 (executable)
index 0000000..5dabddc
--- /dev/null
@@ -0,0 +1,87 @@
+#  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-multitouch],
+        2.3.1,
+        [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+        xf86-input-evdev-multitouch)
+
+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.
+#PKG_CHECK_MODULES(HAL,hal)
+#AC_SUBST(HAL_CFLAGS)
+#AC_SUBST(HAL_LIBS)
+
+#CFLAGS="$CFLAGS $XORG_CFLAGS $HAL_CFLAGS"' -I$(top_srcdir)/src'
+#LIBS="$LIBS $XORG_LIBS $HAL_LIBS"
+CFLAGS="$CFLAGS $XORG_CFLAGS"' -I$(top_srcdir)/src'
+LIBS="$LIBS $XORG_LIBS"
+AC_SUBST(CFLAGS)
+AC_SUBST(LIBS)
+
+# Checks for header files.
+AC_HEADER_STDC
+
+DRIVER_NAME=evdevmultitouch
+AC_SUBST([DRIVER_NAME])
+
+AC_OUTPUT([Makefile
+           src/Makefile
+           man/Makefile
+           include/Makefile
+           xorg-evdev-multitouch.pc])
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..1f93750
--- /dev/null
@@ -0,0 +1,2 @@
+EXTRA_DIST = evdevmultitouch-properties.h
+sdk_HEADERS = evdevmultitouch-properties.h
diff --git a/include/evdevmultitouch-properties.h b/include/evdevmultitouch-properties.h
new file mode 100755 (executable)
index 0000000..0be50c0
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * xserver-xorg-input-evdev-multitouch
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Sung-Jin Park <sj76.park@samsung.com>
+ *          Sangjin LEE <lsj119@samsung.com>
+ *
+ * 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 © 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 _EVDEVMULTITOUCH_PROPERTIES_H_
+#define _EVDEVMULTITOUCH_PROPERTIES_H_
+
+/* Middle mouse button emulation */
+/* BOOL */
+#define EVDEVMULTITOUCH_PROP_MIDBUTTON "EvdevMultitouch Middle Button Emulation"
+/* CARD32 */
+#define EVDEVMULTITOUCH_PROP_MIDBUTTON_TIMEOUT "EvdevMultitouch Middle Button Timeout"
+
+/* Wheel emulation */
+/* BOOL */
+#define EVDEVMULTITOUCH_PROP_WHEEL "EvdevMultitouch Wheel Emulation"
+/* CARD8, 4 values [x up, x down, y up, y down], 0 to disable a value*/
+#define EVDEVMULTITOUCH_PROP_WHEEL_AXES "EvdevMultitouch Wheel Emulation Axes"
+/* CARD16 */
+#define EVDEVMULTITOUCH_PROP_WHEEL_INERTIA "EvdevMultitouch Wheel Emulation Inertia"
+/* CARD16 */
+#define EVDEVMULTITOUCH_PROP_WHEEL_TIMEOUT "EvdevMultitouch Wheel Emulation Timeout"
+/* CARD8, value range 0-32, 0 to always scroll */
+#define EVDEVMULTITOUCH_PROP_WHEEL_BUTTON "EvdevMultitouch Wheel Emulation Button"
+
+/* Drag lock */
+/* CARD8, either 1 value or pairs, value range 0-32, 0 to disable a value*/
+#define EVDEVMULTITOUCH_PROP_DRAGLOCK "EvdevMultitouch Drag Lock Buttons"
+
+/* Axis inversion */
+/* BOOL, 2 values [x, y], 1 inverts axis */
+#define EVDEVMULTITOUCH_PROP_INVERT_AXES "EvdevMultitouch Axis Inversion"
+
+/* Reopen attempts. */
+/* CARD8 */
+#define EVDEVMULTITOUCH_PROP_REOPEN "EvdevMultitouch Reopen Attempts"
+
+/* Run-time calibration */
+/* CARD32, 4 values [minx, maxx, miny, maxy], or no values for unset */
+#define EVDEVMULTITOUCH_PROP_CALIBRATION "EvdevMultitouch Axis Calibration"
+
+/* Swap x and y axis. */
+/* BOOL */
+#define EVDEVMULTITOUCH_PROP_SWAP_AXES "EvdevMultitouch Axes Swap"
+
+#endif
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644 (file)
index 0000000..276f2f0
--- /dev/null
@@ -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/evdevmultitouch.man b/man/evdevmultitouch.man
new file mode 100644 (file)
index 0000000..abd31e2
--- /dev/null
@@ -0,0 +1,231 @@
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH EVDEVMULTITOUCHh __drivermansuffix__ __vendorversion__
+.SH NAME
+evdevmultitouch \- Generic Linux input driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qInputDevice\*q"
+.BI "  Identifier \*q" devname \*q
+.B  "  Driver \*qevdevmultitouch\*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 evdevmultitouch 
+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 evdevmultitouch
+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 evdevmultitouch 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 evdevmultitouch
+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: "EvdevMultitouch
+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: "EvdevMultitouch 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: "EvdevMultitouch 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: "EvdevMultitouch 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 "EvdevMultitouch 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: "EvdevMultitouch 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: "EvdevMultitouch
+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: "EvdevMultitouch 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: "EvdevMultitouch 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. EvdevMultitouch 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: "EvdevMultitouch Axis Calibration".
+.TP 7
+.BI "Option \*qSwapAxes\*q \*q" Bool \*q
+Swap x/y axes. Default: off. Property: "EvdevMultitouch 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:
+"EvdevMultitouch 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:
+"EvdevMultitouch Wheel Emulation Axes".
+
+.SH SUPPORTED PROPERTIES
+The following properties are provided by the
+.B evdevmultitouch
+driver.
+.TP 7
+.BI "EvdevMultitouch 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 "EvdevMultitouch Axis Inversion"
+2 boolean values (8 bit, 0 or 1), order X, Y. 1 inverts the axis.
+.TP 7
+.BI "EvdevMultitouch Axes Swap"
+1 boolean value (8 bit, 0 or 1). 1 swaps x/y axes.
+.TP 7
+.BI "EvdevMultitouch Drag Lock Buttons"
+8-bit. Either 1 value or pairs of values. Value range 0-32, 0 disables a
+value.
+.TP 7
+.BI "EvdevMultitouch Middle Button Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "EvdevMultitouch Middle Button Timeout"
+1 16-bit positive value.
+.TP 7
+.BI "EvdevMultitouch Wheel Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "EvdevMultitouch Wheel Emulation Axes"
+4 8-bit values, order X up, X down, Y up, Y down. 0 disables a value.
+.TP 7
+.BI "EvdevMultitouch Wheel Emulation Button"
+1 8-bit value, allowed range 0-32, 0 disables the button.
+.TP 7
+.BI "EvdevMultitouch Wheel Emulation Inertia"
+1 16-bit positive value.
+.TP 7
+.BI "EvdevMultitouch 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-multitouch.spec b/packaging/xorg-x11-drv-evdev-multitouch.spec
new file mode 100644 (file)
index 0000000..5a99f83
--- /dev/null
@@ -0,0 +1,64 @@
+#sbs-git:slp/pkgs/xorg/driver/xserver-xorg-input-evdev-multitouch xserver-xorg-input-evdev-multitouch 2.3.2 b89f300e6969a0b8cef3bbe5720ec5300baf4ad3
+Name:  xorg-x11-drv-evdev-multitouch
+Summary:    X.Org evdev multitouch input driver.
+Version: 2.3.2
+Release:    2
+Group:      TO_BE/FILLED_IN
+License:    TO BE FILLED IN
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires:  pkgconfig(xorg-macros)
+BuildRequires:  pkgconfig(xorg-server)
+BuildRequires:  pkgconfig(xproto)
+BuildRequires:  pkgconfig(randrproto)
+BuildRequires:  pkgconfig(inputproto)
+BuildRequires:  pkgconfig(kbproto)
+BuildRequires:  pkgconfig(resourceproto)
+BuildRequires:  pkgconfig(xkbfile)
+
+%description
+X.Org X server -- evdev input multitouch 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 evdev multitouch driver module.
+
+%package devel
+Summary:    Development files for xorg evdev multitouch driver
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+This package contains xorg evdev multitouch development files
+
+%prep
+%setup -q
+
+%build
+export CFLAGS+=" -Wall -g -D_F_SUPPORT_PREFERRED_NAME_ -D_F_GESTURE_EXTENSION_ "
+
+%autogen --disable-static
+%configure --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/usr/share/license
+cp -af COPYING %{buildroot}/usr/share/license/%{name}
+%make_install
+
+
+%files
+%defattr(-,root,root,-)
+/usr/lib/xorg/modules/input/evdevmultitouch_drv.so
+/usr/share/license/%{name}
+
+%files devel
+%defattr(-,root,root,-)
+/usr/include/xorg/evdevmultitouch-properties.h
+/usr/lib/pkgconfig/xorg-evdev-multitouch.pc
+/usr/share/man/man4/evdevmultitouch.4.gz
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..16bdf00
--- /dev/null
@@ -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 100755 (executable)
index 0000000..c7a983d
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ *
+ * xserver-xorg-input-evdev-multitouch
+ *
+ * Contact: Sung-Jin Park <sj76.park@samsung.com>
+ *          Sangjin LEE <lsj119@samsung.com>
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <evdevmultitouch-properties.h>
+#include "evdevmultitouch.h"
+
+#ifdef HAVE_PROPERTIES
+static Atom prop_dlock     = 0; /* Drag lock buttons. */
+#endif
+
+void EvdevMultitouchDragLockLockButton(InputInfoPtr pInfo, unsigned int button);
+
+
+/* Setup and configuration code */
+void
+EvdevMultitouchDragLockPreInit(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)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 */
+                    pEvdevMultitouch->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 <= EVDEVMULTITOUCH_MAXBUTTONS) && (meta_button > 0 ) &&
+                    (lock_button <= EVDEVMULTITOUCH_MAXBUTTONS) && (lock_button >= 0)) {
+
+                    xf86Msg(X_CONFIG, "%s: DragLockButtons : %i -> %i\n",
+                            pInfo->name, meta_button, lock_button);
+
+                    pEvdevMultitouch->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
+EvdevMultitouchDragLockLockButton(InputInfoPtr pInfo, unsigned int button)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    BOOL state = 0;
+
+    /* update button state */
+    state = pEvdevMultitouch->dragLock.lock_state[button - 1] ? FALSE : TRUE;
+    pEvdevMultitouch->dragLock.lock_state[button - 1] = state;
+
+    EvdevMultitouchQueueButtonEvent(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
+EvdevMultitouchDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+
+    if (button == 0)
+        return FALSE;
+
+    /* Do we have a single meta key or
+       several button pairings? */
+    if (pEvdevMultitouch->dragLock.meta != 0) {
+
+        if (pEvdevMultitouch->dragLock.meta == button) {
+
+            /* setup up for button lock */
+            if (value)
+                pEvdevMultitouch->dragLock.meta_state = TRUE;
+
+            return TRUE;
+        } else if (pEvdevMultitouch->dragLock.meta_state) { /* waiting to lock */
+
+            pEvdevMultitouch->dragLock.meta_state = FALSE;
+
+            EvdevMultitouchDragLockLockButton(pInfo, button);
+
+            return TRUE;
+        }
+    } else if (pEvdevMultitouch->dragLock.lock_pair[button - 1] && value) {
+        /* A meta button in a meta/lock pair was pressed */
+        EvdevMultitouchDragLockLockButton(pInfo, pEvdevMultitouch->dragLock.lock_pair[button - 1]);
+        return TRUE;
+    }
+
+    /* Eat events for buttons that are locked */
+    if (pEvdevMultitouch->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
+EvdevMultitouchDragLockSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+                         BOOL checkonly)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = 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 (pEvdevMultitouch->dragLock.meta)
+        {
+            if (pEvdevMultitouch->dragLock.meta_state)
+                return BadAccess;
+        } else
+        {
+            for (i = 0; i < EVDEVMULTITOUCH_MAXBUTTONS; i++)
+                if (pEvdevMultitouch->dragLock.lock_state[i])
+                    return BadValue;
+        }
+
+        if (val->size == 0)
+            return BadMatch;
+        else if (val->size == 1)
+        {
+            int meta = *((CARD8*)val->data);
+            if (meta > EVDEVMULTITOUCH_MAXBUTTONS)
+                return BadValue;
+
+            if (!checkonly)
+            {
+                pEvdevMultitouch->dragLock.meta = meta;
+                memset(pEvdevMultitouch->dragLock.lock_pair, 0, sizeof(pEvdevMultitouch->dragLock.lock_pair));
+            }
+        } else if ((val->size % 2) == 0)
+        {
+            CARD8* vals = (CARD8*)val->data;
+
+            for (i = 0; i < val->size && i < EVDEVMULTITOUCH_MAXBUTTONS; i++)
+                if (vals[i] > EVDEVMULTITOUCH_MAXBUTTONS)
+                    return BadValue;
+
+            if (!checkonly)
+            {
+                pEvdevMultitouch->dragLock.meta = 0;
+                memset(pEvdevMultitouch->dragLock.lock_pair, 0, sizeof(pEvdevMultitouch->dragLock.lock_pair));
+
+                for (i = 0; i < val->size && i < EVDEVMULTITOUCH_MAXBUTTONS; i += 2)
+                    pEvdevMultitouch->dragLock.lock_pair[vals[i] - 1] = vals[i + 1];
+            }
+        } else
+            return BadMatch;
+    }
+
+    return Success;
+}
+
+/**
+ * Initialise property for drag lock buttons setting.
+ */
+void
+EvdevMultitouchDragLockInitProperty(DeviceIntPtr dev)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+
+    if (!dev->button) /* don't init prop for keyboards */
+        return;
+
+    prop_dlock = MakeAtom(EVDEVMULTITOUCH_PROP_DRAGLOCK, strlen(EVDEVMULTITOUCH_PROP_DRAGLOCK), TRUE);
+    if (pEvdevMultitouch->dragLock.meta)
+    {
+        XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8,
+                               PropModeReplace, 1, &pEvdevMultitouch->dragLock.meta,
+                               FALSE);
+    } else {
+        int highest = 0;
+        int i;
+        CARD8 pair[EVDEVMULTITOUCH_MAXBUTTONS] = {0};
+
+        for (i = 0; i < EVDEVMULTITOUCH_MAXBUTTONS; i++)
+        {
+            if (pEvdevMultitouch->dragLock.lock_pair[i])
+                highest = i;
+            pair[i] = pEvdevMultitouch->dragLock.lock_pair[i];
+        }
+
+        XIChangeDeviceProperty(dev, prop_dlock, XA_INTEGER, 8, PropModeReplace,
+                               highest + 1, pair, FALSE);
+    }
+
+    XISetDevicePropertyDeletable(dev, prop_dlock, FALSE);
+
+    XIRegisterPropertyHandler(dev, EvdevMultitouchDragLockSetProperty, NULL, NULL);
+}
+
+#endif
diff --git a/src/emuMB.c b/src/emuMB.c
new file mode 100755 (executable)
index 0000000..6d03e83
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ *
+ * xserver-xorg-input-evdev-multitouch
+ *
+ * Contact: Sung-Jin Park <sj76.park@samsung.com>
+ *          Sangjin LEE <lsj119@samsung.com>
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <evdevmultitouch-properties.h>
+#include "evdevmultitouch.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
+EvdevMultitouchMBEmuTimer(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int        sigstate;
+    int id;
+
+    sigstate = xf86BlockSIGIO ();
+
+    pEvdevMultitouch->emulateMB.pending = FALSE;
+    if ((id = stateTab[pEvdevMultitouch->emulateMB.state][4][0]) != 0) {
+        EvdevMultitouchPostButtonEvent(pInfo, abs(id), (id >= 0));
+        pEvdevMultitouch->emulateMB.state =
+            stateTab[pEvdevMultitouch->emulateMB.state][4][2];
+    } else {
+        ErrorF("Got unexpected buttonTimer in state %d\n",
+                pEvdevMultitouch->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
+EvdevMultitouchMBEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int id;
+    int *btstate;
+    int ret = FALSE;
+
+    if (!pEvdevMultitouch->emulateMB.enabled)
+        return ret;
+
+    if (button == 2) {
+        EvdevMultitouchMBEmuEnable(pInfo, FALSE);
+        return ret;
+    }
+
+    /* don't care about other buttons */
+    if (button != 1 && button != 3)
+        return ret;
+
+    btstate = &pEvdevMultitouch->emulateMB.buttonstate;
+    if (press)
+        *btstate |= (button == 1) ? 0x1 : 0x2;
+    else
+        *btstate &= (button == 1) ? ~0x1 : ~0x2;
+
+    if ((id = stateTab[pEvdevMultitouch->emulateMB.state][*btstate][0]) != 0)
+    {
+        EvdevMultitouchQueueButtonEvent(pInfo, abs(id), (id >= 0));
+        ret = TRUE;
+    }
+    if ((id = stateTab[pEvdevMultitouch->emulateMB.state][*btstate][1]) != 0)
+    {
+        EvdevMultitouchQueueButtonEvent(pInfo, abs(id), (id >= 0));
+        ret = TRUE;
+    }
+
+    pEvdevMultitouch->emulateMB.state =
+        stateTab[pEvdevMultitouch->emulateMB.state][*btstate][2];
+
+    if (stateTab[pEvdevMultitouch->emulateMB.state][4][0] != 0) {
+        pEvdevMultitouch->emulateMB.expires = GetTimeInMillis () + pEvdevMultitouch->emulateMB.timeout;
+        pEvdevMultitouch->emulateMB.pending = TRUE;
+        ret = TRUE;
+    } else {
+        pEvdevMultitouch->emulateMB.pending = FALSE;
+    }
+
+    return ret;
+}
+
+
+void EvdevMultitouchMBEmuWakeupHandler(pointer data,
+                             int i,
+                             pointer LastSelectMask)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)data;
+    EvdevMultitouchPtr     pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    int ms;
+
+    if (pEvdevMultitouch->emulateMB.pending)
+    {
+        ms = pEvdevMultitouch->emulateMB.expires - GetTimeInMillis();
+        if (ms <= 0)
+            EvdevMultitouchMBEmuTimer(pInfo);
+    }
+}
+
+void EvdevMultitouchMBEmuBlockHandler(pointer data,
+                            struct timeval **waitTime,
+                            pointer LastSelectMask)
+{
+    InputInfoPtr    pInfo = (InputInfoPtr) data;
+    EvdevMultitouchPtr        pEvdevMultitouch= (EvdevMultitouchPtr) pInfo->private;
+    int             ms;
+
+    if (pEvdevMultitouch->emulateMB.pending)
+    {
+        ms = pEvdevMultitouch->emulateMB.expires - GetTimeInMillis ();
+        if (ms <= 0)
+            ms = 0;
+        AdjustWaitForDelay (waitTime, ms);
+    }
+}
+
+void
+EvdevMultitouchMBEmuPreInit(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    pEvdevMultitouch->emulateMB.enabled = MBEMU_AUTO;
+
+    if (xf86FindOption(pInfo->options, "Emulate3Buttons"))
+    {
+        pEvdevMultitouch->emulateMB.enabled = xf86SetBoolOption(pInfo->options,
+                                                      "Emulate3Buttons",
+                                                      MBEMU_ENABLED);
+        xf86Msg(X_INFO, "%s: Forcing middle mouse button emulation %s.\n",
+                pInfo->name, (pEvdevMultitouch->emulateMB.enabled) ? "on" : "off");
+    }
+
+    pEvdevMultitouch->emulateMB.timeout = xf86SetIntOption(pInfo->options,
+                                                 "Emulate3Timeout", 50);
+}
+
+void
+EvdevMultitouchMBEmuOn(InputInfoPtr pInfo)
+{
+    if (!pInfo->dev->button) /* don't init for keyboards */
+        return;
+
+    RegisterBlockAndWakeupHandlers (EvdevMultitouchMBEmuBlockHandler,
+                                    EvdevMultitouchMBEmuWakeupHandler,
+                                    (pointer)pInfo);
+}
+
+void
+EvdevMultitouchMBEmuFinalize(InputInfoPtr pInfo)
+{
+    if (!pInfo->dev->button) /* don't cleanup for keyboards */
+        return;
+
+    RemoveBlockAndWakeupHandlers (EvdevMultitouchMBEmuBlockHandler,
+                                  EvdevMultitouchMBEmuWakeupHandler,
+                                  (pointer)pInfo);
+
+}
+
+/* Enable/disable middle mouse button emulation. */
+void
+EvdevMultitouchMBEmuEnable(InputInfoPtr pInfo, BOOL enable)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    if (pEvdevMultitouch->emulateMB.enabled == MBEMU_AUTO)
+        pEvdevMultitouch->emulateMB.enabled = enable;
+}
+
+
+#ifdef HAVE_PROPERTIES
+static int
+EvdevMultitouchMBEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+                      BOOL checkonly)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+
+    if (atom == prop_mbemu)
+    {
+        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly)
+            pEvdevMultitouch->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)
+            pEvdevMultitouch->emulateMB.timeout = *((CARD32*)val->data);
+    }
+
+    return Success;
+}
+
+/**
+ * Initialise property for MB emulation on/off.
+ */
+void
+EvdevMultitouchMBEmuInitProperty(DeviceIntPtr dev)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+    int          rc;
+
+    if (!dev->button) /* don't init prop for keyboards */
+        return;
+
+    prop_mbemu = MakeAtom(EVDEVMULTITOUCH_PROP_MIDBUTTON, strlen(EVDEVMULTITOUCH_PROP_MIDBUTTON), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_mbemu, XA_INTEGER, 8,
+                                PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateMB.enabled,
+                                FALSE);
+    if (rc != Success)
+        return;
+    XISetDevicePropertyDeletable(dev, prop_mbemu, FALSE);
+
+    prop_mbtimeout = MakeAtom(EVDEVMULTITOUCH_PROP_MIDBUTTON_TIMEOUT,
+                              strlen(EVDEVMULTITOUCH_PROP_MIDBUTTON_TIMEOUT),
+                              TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_mbtimeout, XA_INTEGER, 32, PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateMB.timeout, FALSE);
+
+    if (rc != Success)
+        return;
+    XISetDevicePropertyDeletable(dev, prop_mbtimeout, FALSE);
+
+    XIRegisterPropertyHandler(dev, EvdevMultitouchMBEmuSetProperty, NULL, NULL);
+}
+#endif
diff --git a/src/emuWheel.c b/src/emuWheel.c
new file mode 100755 (executable)
index 0000000..665fbf0
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+* xserver-xorg-input-evdev-multitouch
+*
+* Contact: Sung-Jin Park <sj76.park@samsung.com>
+*          Sangjin LEE <lsj119@samsung.com>
+*
+* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+*
+* 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 <evdevmultitouch-properties.h>
+#include "evdevmultitouch.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 EvdevMultitouchWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char *axis_name);
+static int EvdevMultitouchWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value);
+
+/* Filter mouse button events */
+BOOL
+EvdevMultitouchWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    int ms;
+
+    /* Has wheel emulation been configured to be enabled? */
+    if (!pEvdevMultitouch->emulateWheel.enabled)
+       return FALSE;
+
+    /* Check for EmulateWheelButton */
+    if (pEvdevMultitouch->emulateWheel.button == button) {
+       pEvdevMultitouch->emulateWheel.button_state = value;
+
+        if (value)
+            /* Start the timer when the button is pressed */
+            pEvdevMultitouch->emulateWheel.expires = pEvdevMultitouch->emulateWheel.timeout +
+                                           GetTimeInMillis();
+        else {
+            ms = pEvdevMultitouch->emulateWheel.expires - GetTimeInMillis();
+            if (ms > 0) {
+                /*
+                 * If the button is released early enough emit the button
+                 * press/release events
+                 */
+                EvdevMultitouchQueueButtonClicks(pInfo, button, 1);
+            }
+        }
+
+       return TRUE;
+    }
+
+    /* Don't care about this event */
+    return FALSE;
+}
+
+/* Filter mouse wheel events */
+BOOL
+EvdevMultitouchWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    WheelAxisPtr pAxis = NULL, pOtherAxis = NULL;
+    int value = pEv->value;
+
+    /* Has wheel emulation been configured to be enabled? */
+    if (!pEvdevMultitouch->emulateWheel.enabled)
+       return FALSE;
+
+    /* Handle our motion events if the emuWheel button is pressed
+     * wheel button of 0 means always emulate wheel.
+     */
+    if (pEvdevMultitouch->emulateWheel.button_state || !pEvdevMultitouch->emulateWheel.button) {
+        /* Just return if the timeout hasn't expired yet */
+        if (pEvdevMultitouch->emulateWheel.button)
+        {
+            int ms = pEvdevMultitouch->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 = &(pEvdevMultitouch->emulateWheel.X);
+           pOtherAxis = &(pEvdevMultitouch->emulateWheel.Y);
+           break;
+
+       case REL_Y:
+           pAxis = &(pEvdevMultitouch->emulateWheel.Y);
+           pOtherAxis = &(pEvdevMultitouch->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 (EvdevMultitouchWheelEmuInertia(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
+EvdevMultitouchWheelEmuInertia(InputInfoPtr pInfo, WheelAxisPtr axis, int value)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)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 = -pEvdevMultitouch->emulateWheel.inertia;
+    } else {
+       button = axis->down_button;
+       inertia = pEvdevMultitouch->emulateWheel.inertia;
+    }
+
+    /* Produce button press events for wheel motion */
+    while(abs(axis->traveled_distance) > pEvdevMultitouch->emulateWheel.inertia) {
+       axis->traveled_distance -= inertia;
+       EvdevMultitouchQueueButtonClicks(pInfo, button, 1);
+       rc++;
+    }
+    return rc;
+}
+
+/* Handle button mapping here to avoid code duplication,
+returns true if a button mapping was found. */
+static BOOL
+EvdevMultitouchWheelEmuHandleButtonMap(InputInfoPtr pInfo, WheelAxisPtr pAxis, char* axis_name)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)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 <= EVDEVMULTITOUCH_MAXBUTTONS)) &&
+           ((down_button > 0) && (down_button <= EVDEVMULTITOUCH_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 > pEvdevMultitouch->num_buttons) pEvdevMultitouch->num_buttons = up_button;
+           if (down_button > pEvdevMultitouch->num_buttons) pEvdevMultitouch->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
+EvdevMultitouchWheelEmuPreInit(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = (EvdevMultitouchPtr)pInfo->private;
+    char val[4];
+    int wheelButton;
+    int inertia;
+    int timeout;
+
+    val[0] = 0;
+    val[1] = 0;
+
+    if (xf86SetBoolOption(pInfo->options, "EmulateWheel", FALSE)) {
+       pEvdevMultitouch->emulateWheel.enabled = TRUE;
+    } else
+        pEvdevMultitouch->emulateWheel.enabled = FALSE;
+
+    wheelButton = xf86SetIntOption(pInfo->options, "EmulateWheelButton", 4);
+
+    if ((wheelButton < 0) || (wheelButton > EVDEVMULTITOUCH_MAXBUTTONS)) {
+        xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n",
+                pInfo->name, wheelButton);
+        xf86Msg(X_WARNING, "%s: Wheel emulation disabled.\n", pInfo->name);
+
+        pEvdevMultitouch->emulateWheel.enabled = FALSE;
+    }
+
+    pEvdevMultitouch->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;
+    }
+
+    pEvdevMultitouch->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;
+    }
+
+    pEvdevMultitouch->emulateWheel.timeout = timeout;
+
+    /* Configure the Y axis or default it */
+    if (!EvdevMultitouchWheelEmuHandleButtonMap(pInfo, &(pEvdevMultitouch->emulateWheel.Y),
+                "YAxisMapping")) {
+        /* Default the Y axis to sane values */
+        pEvdevMultitouch->emulateWheel.Y.up_button = 4;
+        pEvdevMultitouch->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 > pEvdevMultitouch->num_buttons)
+            pEvdevMultitouch->num_buttons = 5;
+
+        /* Display default Configuration */
+        xf86Msg(X_CONFIG, "%s: YAxisMapping: buttons %d and %d\n",
+                pInfo->name, pEvdevMultitouch->emulateWheel.Y.up_button,
+                pEvdevMultitouch->emulateWheel.Y.down_button);
+    }
+
+
+    /* This axis should default to an unconfigured state as most people
+       are not going to expect a Horizontal wheel. */
+    EvdevMultitouchWheelEmuHandleButtonMap(pInfo, &(pEvdevMultitouch->emulateWheel.X),
+            "XAxisMapping");
+
+    /* Used by the inertia code */
+    pEvdevMultitouch->emulateWheel.X.traveled_distance = 0;
+    pEvdevMultitouch->emulateWheel.Y.traveled_distance = 0;
+
+    xf86Msg(X_CONFIG, "%s: EmulateWheelButton: %d, "
+            "EmulateWheelInertia: %d, "
+            "EmulateWheelTimeout: %d\n",
+            pInfo->name, pEvdevMultitouch->emulateWheel.button, inertia, timeout);
+}
+
+#ifdef HAVE_PROPERTIES
+static int
+EvdevMultitouchWheelEmuSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+                         BOOL checkonly)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+
+    if (atom == prop_wheel_emu)
+    {
+        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly)
+        {
+            pEvdevMultitouch->emulateWheel.enabled = *((BOOL*)val->data);
+            /* Don't enable with zero inertia, otherwise we may get stuck in an
+             * infinite loop */
+            if (pEvdevMultitouch->emulateWheel.inertia <= 0)
+            {
+                pEvdevMultitouch->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,
+                            &pEvdevMultitouch->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 >= EVDEVMULTITOUCH_MAXBUTTONS)
+            return BadValue;
+
+        if (!checkonly)
+            pEvdevMultitouch->emulateWheel.button = bt;
+    } else if (atom == prop_wheel_axismap)
+    {
+        if (val->format != 8 || val->size != 4 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly)
+        {
+            pEvdevMultitouch->emulateWheel.X.up_button = *((CARD8*)val->data);
+            pEvdevMultitouch->emulateWheel.X.down_button = *(((CARD8*)val->data) + 1);
+            pEvdevMultitouch->emulateWheel.Y.up_button = *(((CARD8*)val->data) + 2);
+            pEvdevMultitouch->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)
+            pEvdevMultitouch->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)
+            pEvdevMultitouch->emulateWheel.timeout = timeout;
+    }
+    return Success;
+}
+
+void
+EvdevMultitouchWheelEmuInitProperty(DeviceIntPtr dev)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+    int          rc     = TRUE;
+    char         vals[4];
+
+    if (!dev->button) /* don't init prop for keyboards */
+        return;
+
+    prop_wheel_emu = MakeAtom(EVDEVMULTITOUCH_PROP_WHEEL, strlen(EVDEVMULTITOUCH_PROP_WHEEL), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_wheel_emu, XA_INTEGER, 8,
+                                PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateWheel.enabled, FALSE);
+    if (rc != Success)
+        return;
+
+    XISetDevicePropertyDeletable(dev, prop_wheel_emu, FALSE);
+
+    vals[0] = pEvdevMultitouch->emulateWheel.X.up_button;
+    vals[1] = pEvdevMultitouch->emulateWheel.X.down_button;
+    vals[2] = pEvdevMultitouch->emulateWheel.Y.up_button;
+    vals[3] = pEvdevMultitouch->emulateWheel.Y.down_button;
+
+    prop_wheel_axismap = MakeAtom(EVDEVMULTITOUCH_PROP_WHEEL_AXES, strlen(EVDEVMULTITOUCH_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(EVDEVMULTITOUCH_PROP_WHEEL_INERTIA, strlen(EVDEVMULTITOUCH_PROP_WHEEL_INERTIA), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_wheel_inertia, XA_INTEGER, 16,
+                                PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateWheel.inertia, FALSE);
+    if (rc != Success)
+        return;
+
+    XISetDevicePropertyDeletable(dev, prop_wheel_inertia, FALSE);
+
+    prop_wheel_timeout = MakeAtom(EVDEVMULTITOUCH_PROP_WHEEL_TIMEOUT, strlen(EVDEVMULTITOUCH_PROP_WHEEL_TIMEOUT), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_wheel_timeout, XA_INTEGER, 16,
+                                PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateWheel.timeout, FALSE);
+    if (rc != Success)
+        return;
+
+    XISetDevicePropertyDeletable(dev, prop_wheel_timeout, FALSE);
+
+    prop_wheel_button = MakeAtom(EVDEVMULTITOUCH_PROP_WHEEL_BUTTON, strlen(EVDEVMULTITOUCH_PROP_WHEEL_BUTTON), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_wheel_button, XA_INTEGER, 8,
+                                PropModeReplace, 1,
+                                &pEvdevMultitouch->emulateWheel.button, FALSE);
+    if (rc != Success)
+        return;
+
+    XISetDevicePropertyDeletable(dev, prop_wheel_button, FALSE);
+
+    XIRegisterPropertyHandler(dev, EvdevMultitouchWheelEmuSetProperty, NULL, NULL);
+}
+#endif
diff --git a/src/evdevmultitouch.c b/src/evdevmultitouch.c
new file mode 100755 (executable)
index 0000000..a43bcd3
--- /dev/null
@@ -0,0 +1,3842 @@
+/*
+ *
+ * xserver-xorg-input-evdev-multitouch
+ *
+ * Contact: Sung-Jin Park <sj76.park@samsung.com>
+ *          Sangjin LEE <lsj119@samsung.com>
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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)
+ *     Benjamin Tissoires (tissoire@cena.fr)
+ */
+
+#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 <xorg/input.h>
+#include <xorg/inputstr.h>
+#include <xorg/optionstr.h>
+#include <exevents.h>
+#include <xorgVersion.h>
+#include <xkbsrv.h>
+
+#include "evdevmultitouch.h"
+
+#ifdef HAVE_PROPERTIES
+#include <X11/Xatom.h>
+#include <evdevmultitouch-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])))
+
+#ifndef True
+#define True   TRUE
+#endif
+#ifndef False
+#define False FALSE
+#endif
+
+#define POLL_DISABLE   '0'
+#define POLL_ENABLE            '1'
+#define POLL_REQUEST   '2'
+#define SYSFS_POLL     "/sys/class/input/event2/device/poll"
+
+#define ABS_MT_SLOT             0x2f
+#define ABS_MT_TOUCH_MAJOR     0x30    /* Major axis of touching ellipse */
+#define ABS_MT_TOUCH_MINOR     0x31    /* Minor axis (omit if circular) */
+#define ABS_MT_WIDTH_MAJOR     0x32    /* Major axis of approaching ellipse */
+#define ABS_MT_WIDTH_MINOR     0x33    /* Minor axis (omit if circular) */
+#define ABS_MT_ORIENTATION     0x34    /* Ellipse orientation */
+#define ABS_MT_POSITION_X      0x35    /* Center X ellipse position */
+#define ABS_MT_POSITION_Y      0x36    /* Center Y ellipse position */
+#define ABS_MT_TOOL_TYPE       0x37    /* Type of touching device */
+#define ABS_MT_BLOB_ID         0x38    /* Group a set of packets as a blob */
+#define ABS_MT_TRACKING_ID             0x39    /* Unique ID of initiated contact */
+
+#define SYN_REPORT             0
+#define SYN_CONFIG             1
+#define SYN_MT_REPORT          2
+
+/* evdevmultitouch flags */
+#define EVDEVMULTITOUCH_KEYBOARD_EVENTS        (1 << 0)
+#define EVDEVMULTITOUCH_BUTTON_EVENTS  (1 << 1)
+#define EVDEVMULTITOUCH_RELATIVE_EVENTS        (1 << 2)
+#define EVDEVMULTITOUCH_ABSOLUTE_EVENTS        (1 << 3)
+#define EVDEVMULTITOUCH_TOUCHPAD               (1 << 4)
+#define EVDEVMULTITOUCH_INITIALIZED    (1 << 5) /* WheelInit etc. called already? */
+#define EVDEVMULTITOUCH_TOUCHSCREEN    (1 << 6)
+#define EVDEVMULTITOUCH_CALIBRATED     (1 << 7) /* run-time calibrated? */
+#define EVDEVMULTITOUCH_TABLET         (1 << 8) /* device looks like a tablet? */
+#define EVDEVMULTITOUCH_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
+#define EVDEVMULTITOUCH_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+#define EVDEVMULTITOUCH_MULTITOUCH (1 << 11) /* device looks like a multi-touch screen? */
+#define EVDEVMULTITOUCH_RESOLUTION (1 << 12) /* device has a resolution setting? */
+
+#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 *evdevmultitouchDefaults[] = {
+    "XkbRules",     "evdevmultitouch",
+    "XkbModel",     "evdevmultitouch",
+    "XkbLayout",    "us",
+    NULL
+};
+
+#ifdef _F_GESTURE_EXTENSION_
+extern void mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e);
+static void EvdevMultitouchFrameSync(InputInfoPtr pInfo, MTSyncType sync);
+#endif//_F_GESTURE_EXTENSION_
+static void EvdevMultitouchOff(DeviceIntPtr device);
+static int EvdevMultitouchOn(DeviceIntPtr);
+static int EvdevMultitouchCacheCompare(InputInfoPtr pInfo, BOOL compare);
+static void EvdevMultitouchKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
+static void EvdevMultitouchProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev);
+static void EvdevMultitouchCopyFromData(InputInfoPtr pInfo, EvdevMultitouchDataMTPtr pData);
+static void EvdevMultitouchReinitPEvdevMultitouch(InputInfoPtr pInfo);
+static void EvdevMultitouchFakeOmittedEvents(InputInfoPtr pInfo);
+static void EvdevMultitouchProcessEvent(InputInfoPtr pInfo, struct input_event *ev);
+static void EvdevMultitouchEndOfMultiTouch(InputInfoPtr pInfo,EvdevMultitouchDataMTPtr pData);
+static void EvdevMultitouchSetMultitouch(InputInfoPtr pInfo, int num_multitouch);
+static void EvdevMultitouchGetGrabInfo(InputInfoPtr pInfo, BOOL val);
+static void EvdevMultitouchSetResolution(InputInfoPtr pInfo, int num_resolution, int resolution[4]);
+static void EvdevMultitouchSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4]);
+static InputInfoPtr EvdevMultitouchCreateSubDevice(InputInfoPtr pInfo, int id);
+static void EvdevMultitouchDeleteSubDevice(InputInfoPtr pInfo, InputInfoPtr subdev);
+static void EvdevMultitouchSwapAxes(EvdevMultitouchPtr pEvdevMultitouch);
+static void EvdevMultitouchSetTransform(InputInfoPtr pInfo, int num_transform, float *tmatrix);
+
+#ifdef HAVE_PROPERTIES
+static void EvdevMultitouchInitAxesLabels(EvdevMultitouchPtr pEvdevMultitouch, int natoms, Atom *atoms);
+static void EvdevMultitouchInitButtonLabels(EvdevMultitouchPtr pEvdevMultitouch, int natoms, Atom *atoms);
+static void EvdevMultitouchInitProperty(DeviceIntPtr dev);
+static int EvdevMultitouchSetProperty(DeviceIntPtr dev, Atom atom,
+                            XIPropertyValuePtr val, BOOL checkonly);
+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;
+static Atom prop_tracking_id = 0;
+static Atom prop_multitouch = 0;
+static Atom prop_transform = 0;
+static Atom prop_grabinfo = 0;
+#endif
+
+int g_pressed = 0;
+static InputInfoPtr pCreatorInfo = NULL;
+
+/* All devices the evdevmultitouch driver has allocated and knows about.
+ * MAXDEVICES is safe as null-terminated array, as two devices (VCP and VCK)
+ * cannot be used by evdevmultitouch, leaving us with a space of 2 at the end. */
+static EvdevMultitouchPtr evdevmultitouch_devices[MAXDEVICES] = {NULL};
+
+static size_t EvdevMultitouchCountBits(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
+EvdevMultitouchGetMajorMinor(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;
+}
+
+static BOOL
+EvdevMultitouchIsCoreDevice(InputInfoPtr pInfo) {
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    return pEvdevMultitouch->core_device == pInfo;
+}
+
+/**
+ * Return TRUE if one of the devices we know about has the same min/maj
+ * number.
+ */
+static BOOL
+EvdevMultitouchIsDuplicate(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    EvdevMultitouchPtr* dev   = evdevmultitouch_devices;
+
+    if (pEvdevMultitouch->min_maj)
+    {
+        while(*dev)
+        {
+            if ((*dev) != pEvdevMultitouch &&
+                (*dev)->min_maj &&
+                (*dev)->min_maj == pEvdevMultitouch->min_maj)
+                return TRUE;
+            dev++;
+        }
+    }
+    return FALSE;
+}
+
+/**
+ * Add to internal device list.
+ */
+static void
+EvdevMultitouchAddDevice(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    EvdevMultitouchPtr* dev = evdevmultitouch_devices;
+
+    while(*dev)
+        dev++;
+
+    *dev = pEvdevMultitouch;
+}
+
+/**
+ * Remove from internal device list.
+ */
+static void
+EvdevMultitouchRemoveDevice(InputInfoPtr pInfo)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    EvdevMultitouchPtr *dev   = evdevmultitouch_devices;
+    int count       = 0;
+
+    while(*dev)
+    {
+        count++;
+        if (*dev == pEvdevMultitouch)
+        {
+            memmove(dev, dev + 1,
+                    sizeof(evdevmultitouch_devices) - (count * sizeof(EvdevMultitouchPtr)));
+            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
+EvdevMultitouchQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
+{
+    int code = ev->code + MIN_KEYCODE;
+    static char warned[KEY_CNT];
+    EventQueuePtr pQueue;
+    EvdevMultitouchPtr pEvdevMultitouch = 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 (pEvdevMultitouch->num_queue >= EVDEVMULTITOUCH_MAXQUEUE)
+    {
+        xf86Msg(X_NONE, "%s: dropping event due to full queue!\n", pInfo->name);
+        return;
+    }
+
+    pQueue = &pEvdevMultitouch->queue[pEvdevMultitouch->num_queue];
+    pQueue->type = EV_QUEUE_KEY;
+    pQueue->key = code;
+    pQueue->val = value;
+    pEvdevMultitouch->num_queue++;
+}
+
+void
+EvdevMultitouchQueueButtonEvent(InputInfoPtr pInfo, int button, int value)
+{
+    EventQueuePtr pQueue;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if (pEvdevMultitouch->num_queue >= EVDEVMULTITOUCH_MAXQUEUE)
+    {
+        xf86Msg(X_NONE, "%s: dropping event due to full queue!\n", pInfo->name);
+        return;
+    }
+
+    pQueue = &pEvdevMultitouch->queue[pEvdevMultitouch->num_queue];
+    pQueue->type = EV_QUEUE_BTN;
+    pQueue->key = button;
+    pQueue->val = value;
+    pEvdevMultitouch->num_queue++;
+}
+
+/**
+ * Post button event right here, right now.
+ * Interface for MB emulation since these need to post immediately.
+ */
+void
+EvdevMultitouchPostButtonEvent(InputInfoPtr pInfo, int button, int value)
+{
+    xf86PostButtonEvent(pInfo->dev, 0, button, value, 0, 0);
+}
+
+void
+EvdevMultitouchQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        EvdevMultitouchQueueButtonEvent(pInfo, button, 1);
+        EvdevMultitouchQueueButtonEvent(pInfo, button, 0);
+    }
+}
+
+/**
+ * 
+ */
+static CARD32
+EvdevMultitouchSubdevTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)arg;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int i;
+    
+    for (i=0;i<pEvdevMultitouch->num_multitouch;i++) {
+        if (pEvdevMultitouch->vals_mt[i].containsValues) {
+            EvdevMultitouchEndOfMultiTouch(pInfo, &(pEvdevMultitouch->vals_mt[i]));
+        }
+    }
+    
+    return 0;
+    //return pEvdevMultitouch->timeout; /* come back in 100 ms */
+}
+
+/**
+ * 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
+EvdevMultitouchReopenTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)arg;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    do {
+        pInfo->fd = open(pEvdevMultitouch->device, O_RDWR | O_NONBLOCK, 0);
+    } while (pInfo->fd < 0 && errno == EINTR);
+
+    if (pInfo->fd != -1)
+    {
+        if (EvdevMultitouchCacheCompare(pInfo, TRUE) == Success)
+        {
+            xf86Msg(X_INFO, "%s: Device reopened after %d attempts.\n", pInfo->name,
+                    pEvdevMultitouch->reopen_attempts - pEvdevMultitouch->reopen_left + 1);
+            EvdevMultitouchOn(pInfo->dev);
+        } else
+        {
+            xf86Msg(X_ERROR, "%s: Device has changed - disabling.\n",
+                    pInfo->name);
+            xf86DisableDevice(pInfo->dev, FALSE);
+            close(pInfo->fd);
+            pInfo->fd = -1;
+            pEvdevMultitouch->min_maj = 0; /* don't hog the device */
+        }
+        pEvdevMultitouch->reopen_left = 0;
+        return 0;
+    }
+
+    pEvdevMultitouch->reopen_left--;
+
+    if (!pEvdevMultitouch->reopen_left)
+    {
+        xf86Msg(X_ERROR, "%s: Failed to reopen device after %d attempts.\n",
+                pInfo->name, pEvdevMultitouch->reopen_attempts);
+        xf86DisableDevice(pInfo->dev, FALSE);
+        pEvdevMultitouch->min_maj = 0; /* don't hog the device */
+        return 0;
+    }
+
+    return 100; /* come back in 100 ms */
+}
+
+static CARD32
+EvdevMultitouchMultitouchSettingTimer(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)arg;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    int n_multitouch = xf86SetIntOption(pInfo->options, "MultiTouch", 0);
+
+    if( n_multitouch >= 2 )
+           EvdevMultitouchSetMultitouch(pInfo, n_multitouch);
+    pEvdevMultitouch->multitouch_setting_timer = TimerSet(pEvdevMultitouch->multitouch_setting_timer, 0, 0, NULL, NULL);
+       
+    return 0;
+}
+
+#define ABS_X_VALUE 0x1
+#define ABS_Y_VALUE 0x2
+#define ABS_VALUE   0x4
+#define ABS_MT_X_VALUE   0x8
+#define ABS_MT_Y_VALUE   0x10
+#define ABS_MT_TOUCH_MAJOR_VALUE 0x20
+/**
+ * Take the valuators and process them accordingly.
+ */
+static void
+EvdevMultitouchProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
+                      int *first_v)
+{
+    int tmp;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    pixman_vector_t p;
+
+    *num_v = *first_v = 0;
+
+    /* convert to relative motion for touchpads */
+    if (pEvdevMultitouch->abs && (pEvdevMultitouch->flags & EVDEVMULTITOUCH_TOUCHPAD)) {
+        if (pEvdevMultitouch->tool) { /* meaning, touch is active */
+            if (pEvdevMultitouch->old_vals[0] != -1)
+                pEvdevMultitouch->delta[REL_X] = pEvdevMultitouch->vals[0] - pEvdevMultitouch->old_vals[0];
+            if (pEvdevMultitouch->old_vals[1] != -1)
+                pEvdevMultitouch->delta[REL_Y] = pEvdevMultitouch->vals[1] - pEvdevMultitouch->old_vals[1];
+            if (pEvdevMultitouch->abs & ABS_X_VALUE)
+                pEvdevMultitouch->old_vals[0] = pEvdevMultitouch->vals[0];
+            if (pEvdevMultitouch->abs & ABS_Y_VALUE)
+                pEvdevMultitouch->old_vals[1] = pEvdevMultitouch->vals[1];
+        } else {
+            pEvdevMultitouch->old_vals[0] = pEvdevMultitouch->old_vals[1] = -1;
+        }
+        pEvdevMultitouch->abs = 0;
+        pEvdevMultitouch->rel = 1;
+    }
+
+    if (pEvdevMultitouch->rel) {
+        int first = REL_CNT, last = 0;
+        int i;
+
+        if (pEvdevMultitouch->swap_axes) {
+            tmp = pEvdevMultitouch->delta[REL_X];
+            pEvdevMultitouch->delta[REL_X] = pEvdevMultitouch->delta[REL_Y];
+            pEvdevMultitouch->delta[REL_Y] = tmp;
+        }
+        if (pEvdevMultitouch->invert_x)
+            pEvdevMultitouch->delta[REL_X] *= -1;
+        if (pEvdevMultitouch->invert_y)
+            pEvdevMultitouch->delta[REL_Y] *= -1;
+
+        for (i = 0; i < REL_CNT; i++)
+        {
+            int map = pEvdevMultitouch->axis_map[i];
+            if (map != -1)
+            {
+                v[map] = pEvdevMultitouch->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
+     * pEvdevMultitouch->digi here, lets us ignore that event.  pEvdevMultitouch is
+     * initialized to 1 so devices that doesn't use this scheme still
+     * just works.
+     */
+    else if (pEvdevMultitouch->abs && pEvdevMultitouch->tool) {
+        memcpy(v, pEvdevMultitouch->vals, sizeof(int) * pEvdevMultitouch->num_vals);
+        if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_CALIBRATED)
+        {
+            v[0] = xf86ScaleAxis(v[0],
+                    pEvdevMultitouch->absinfo[ABS_X].maximum,
+                    pEvdevMultitouch->absinfo[ABS_X].minimum,
+                    pEvdevMultitouch->calibration.max_x, pEvdevMultitouch->calibration.min_x);
+            v[1] = xf86ScaleAxis(v[1],
+                    pEvdevMultitouch->absinfo[ABS_Y].maximum,
+                    pEvdevMultitouch->absinfo[ABS_Y].minimum,
+                    pEvdevMultitouch->calibration.max_y, pEvdevMultitouch->calibration.min_y);
+        }
+
+        if (pEvdevMultitouch->swap_axes) {
+            int tmp = v[0];
+            v[0] = v[1];
+            v[1] = tmp;
+        }
+
+        if (pEvdevMultitouch->invert_x)
+            v[0] = (pEvdevMultitouch->absinfo[ABS_X].maximum - v[0] +
+                    pEvdevMultitouch->absinfo[ABS_X].minimum);
+        if (pEvdevMultitouch->invert_y)
+            v[1] = (pEvdevMultitouch->absinfo[ABS_Y].maximum - v[1] +
+                    pEvdevMultitouch->absinfo[ABS_Y].minimum);
+
+       if( pEvdevMultitouch->use_transform )
+       {
+               p.vector[0] = pixman_int_to_fixed(v[0]);
+               p.vector[1] = pixman_int_to_fixed(v[1]);
+               p.vector[2] = pixman_int_to_fixed(1);
+
+               pixman_transform_point(&pEvdevMultitouch->inv_transform, &p);
+
+               v[0] = pixman_fixed_to_int(p.vector[0]);
+               v[1] = pixman_fixed_to_int(p.vector[1]);
+       }
+
+        *num_v = pEvdevMultitouch->num_vals;
+        *first_v = 0;
+    }
+}
+
+/**
+ * Take a button input event and process it accordingly.
+ */
+static void
+EvdevMultitouchProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    unsigned int button;
+    int value;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    button = EvdevMultitouchUtilButtonEventToButtonNumber(pEvdevMultitouch, ev->code);
+
+    /* Get the signed value, earlier kernels had this as unsigned */
+    value = ev->value;
+
+    /* Handle drag lock */
+    if (EvdevMultitouchDragLockFilterEvent(pInfo, button, value))
+        return;
+
+    if (EvdevMultitouchWheelEmuFilterButton(pInfo, button, value))
+        return;
+
+    if (pEvdevMultitouch->num_multitouch)
+        return;
+    
+    if (EvdevMultitouchMBEmuFilterEvent(pInfo, button, value))
+        return;
+
+    if (button)
+        EvdevMultitouchQueueButtonEvent(pInfo, button, value);
+    else
+        EvdevMultitouchQueueKbdEvent(pInfo, ev, value);
+}
+
+/**
+ * Take the relative motion input event and process it accordingly.
+ */
+static void
+EvdevMultitouchProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    static int value;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    /* Get the signed value, earlier kernels had this as unsigned */
+    value = ev->value;
+
+    pEvdevMultitouch->rel = 1;
+
+    switch (ev->code) {
+        case REL_WHEEL:
+            if (value > 0)
+                EvdevMultitouchQueueButtonClicks(pInfo, wheel_up_button, value);
+            else if (value < 0)
+                EvdevMultitouchQueueButtonClicks(pInfo, wheel_down_button, -value);
+            break;
+
+        case REL_DIAL:
+        case REL_HWHEEL:
+            if (value > 0)
+                EvdevMultitouchQueueButtonClicks(pInfo, wheel_right_button, value);
+            else if (value < 0)
+                EvdevMultitouchQueueButtonClicks(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 (!(pEvdevMultitouch->flags & EVDEVMULTITOUCH_RELATIVE_EVENTS))
+                return;
+
+            /* Handle mouse wheel emulation */
+            if (EvdevMultitouchWheelEmuFilterMotion(pInfo, ev))
+                return;
+
+            pEvdevMultitouch->delta[ev->code] += value;
+            break;
+    }
+}
+
+/**
+ * Take the absolute motion input event and process it accordingly.
+ */
+static void
+EvdevMultitouchProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    static int value;
+    EvdevMultitouchPtr pEvdevMultitouch = 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 (!(pEvdevMultitouch->flags & EVDEVMULTITOUCH_ABSOLUTE_EVENTS))
+        return;
+
+    if (ev->code > ABS_MAX)
+        return;
+
+    pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ev->code]] = value;
+
+    if(pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH)
+    {
+        if(ev->code == ABS_MT_TOUCH_MAJOR)
+        {
+#ifdef _DEBUG_MT_SEQUENCE_
+            ErrorF("[AbsoluteMotionEvent] ABS_MT_TOUCH_MAJOR (value=%d)\n", value);
+#endif
+            pEvdevMultitouch->abs |= ABS_MT_TOUCH_MAJOR_VALUE;
+        }
+        else if (ev->code == ABS_MT_POSITION_X)
+        {
+#ifdef _DEBUG_MT_SEQUENCE_
+            ErrorF("[AbsoluteMotionEvent] ABS_MT_POSITION_X (value=%d)\n", value);
+#endif
+            EvdevMultitouchFakeOmittedEvents(pInfo);
+            pEvdevMultitouch->abs |= ABS_MT_X_VALUE;
+        }
+        else if (ev->code == ABS_MT_POSITION_Y)
+        {
+#ifdef _DEBUG_MT_SEQUENCE_
+            ErrorF("[AbsoluteMotionEvent] ABS_MT_POSITION_Y (value=%d)\n", value);
+#endif
+            EvdevMultitouchFakeOmittedEvents(pInfo);
+            pEvdevMultitouch->abs |= ABS_MT_Y_VALUE;
+        }
+        else
+            pEvdevMultitouch->abs |= ABS_VALUE;
+    }
+    else
+    {
+        if (ev->code == ABS_X)
+        {
+#ifdef _DEBUG_MT_SEQUENCE_
+            ErrorF("[AbsoluteMotionEvent] ABS_X (value=%d)\n", value);
+#endif
+            pEvdevMultitouch->abs |= ABS_X_VALUE;
+        }
+        else if (ev->code == ABS_Y)
+        {
+#ifdef _DEBUG_MT_SEQUENCE_
+            ErrorF("[AbsoluteMotionEvent] ABS_Y (value=%d)\n", value);
+#endif
+            pEvdevMultitouch->abs |= ABS_Y_VALUE;
+        }
+        else
+            pEvdevMultitouch->abs |= ABS_VALUE;
+    }        
+}
+
+/**
+ * Take the key press/release input event and process it accordingly.
+ */
+static void
+EvdevMultitouchProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    static int value;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if(pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH)
+        return;
+
+    /* 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;
+
+#ifdef _DEBUG_MT_SEQUENCE_
+       if( ev->code == BTN_TOUCH || ev->code == BTN_LEFT )
+               ErrorF("[KeyEvent] BTN_TOUCH (value=%d)\n", value);
+#endif
+
+    switch (ev->code) {
+        case BTN_TOUCH:
+        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:
+            pEvdevMultitouch->tool = value ? ev->code : 0;
+            if (!(pEvdevMultitouch->flags & EVDEVMULTITOUCH_TOUCHSCREEN || pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH))
+                break;
+            /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as
+             * BTN_LEFT. */
+            ev->code = BTN_LEFT;
+            /* Intentional fallthrough! */
+
+        default:
+            EvdevMultitouchProcessButtonEvent(pInfo, ev);
+            break;
+    }
+}
+
+static void EvdevMultitouchEndOfMultiTouch(InputInfoPtr pInfo,EvdevMultitouchDataMTPtr pData)
+{
+    InputInfoPtr pSubdev = pData->pInfo;
+    EvdevMultitouchPtr pEvdevMultitouchSubdev = pSubdev->private;
+    pEvdevMultitouchSubdev->id = -1;
+    pData->containsValues = FALSE;
+    pData->id = -1;
+}
+
+#ifdef _F_GESTURE_EXTENSION_
+static void EvdevMultitouchFrameSync(InputInfoPtr pInfo, MTSyncType sync)
+{
+       AnyEvent event;
+
+       memset(&event, 0, sizeof(event));
+       event.header = ET_Internal;
+       event.type = ET_MTSync;
+       event.length = sizeof(event);
+       event.time = GetTimeInMillis();
+       event.deviceid = pInfo->dev->id;
+       event.sync = sync;
+       mieqEnqueue (pInfo->dev, (InternalEvent*)&event);
+}
+#endif//_F_GESTURE_EXTENSION_
+
+/**
+ * Post the multtouch motion events.
+ */
+static void
+EvdevMultitouchPostMTMotionEvents(InputInfoPtr pInfo,struct input_event *ev)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private, pEvdevMultitouchSubdev;
+    EvdevMultitouchDataMTPtr pData;
+    InputInfoPtr pSubdev;
+    int i;
+    static int num_of_pressed = 0;
+
+    for (i=0;i<pEvdevMultitouch->num_multitouch;++i) {
+        pData = &(pEvdevMultitouch->vals_mt[i]);
+        if (!pData->containsValues) {
+            continue;
+        }
+        pSubdev = pData->pInfo;
+        if (!pSubdev)
+            continue;
+
+        pData->containsValues = FALSE;
+        EvdevMultitouchCopyFromData(pSubdev, pData);
+        pEvdevMultitouchSubdev = pSubdev->private;
+        pEvdevMultitouchSubdev->mt = 0;
+        pEvdevMultitouchSubdev->abs = pData->abs;
+        pEvdevMultitouchSubdev->rel = 0;
+        pEvdevMultitouchSubdev->tool = 1;
+        /* droping of the pressed/released events */
+        memset(pEvdevMultitouchSubdev->queue, 0, sizeof(pEvdevMultitouchSubdev->queue));
+        pEvdevMultitouchSubdev->num_queue = 0;
+
+        /* generate button press/release event */
+        if(pEvdevMultitouchSubdev->abs & ABS_MT_TOUCH_MAJOR_VALUE)
+        {
+            if(pEvdevMultitouchSubdev->vals[pEvdevMultitouchSubdev->axis_map[ABS_MT_TOUCH_MAJOR]] )
+            {
+                if(pEvdevMultitouchSubdev->touch_state == 0)
+                {
+                       num_of_pressed += (pData->id+1);
+                       if( num_of_pressed && !g_pressed )
+                       {
+                          g_pressed = 1;
+#ifdef _F_GESTURE_EXTENSION_
+                          EvdevMultitouchFrameSync(pInfo, MTOUCH_FRAME_SYNC_BEGIN);
+#endif//_F_GESTURE_EXTENSION_
+                       }
+                    EvdevMultitouchQueueButtonEvent(pSubdev, 1, 1);
+                    pEvdevMultitouchSubdev->touch_state = 1;
+                }
+            }
+            else
+            {
+                 num_of_pressed -= (pData->id+1);
+                 if(num_of_pressed < 0)
+                       num_of_pressed = 0;
+                 /* last finger release */
+                 if( !num_of_pressed )
+                 {
+                       g_pressed = 0;
+                 }
+                EvdevMultitouchQueueButtonEvent(pSubdev, 1, 0);
+                pEvdevMultitouchSubdev->touch_state = 0;
+                pEvdevMultitouchSubdev->evtime = 0;
+            }
+        }
+        EvdevMultitouchProcessSyncEvent(pSubdev, ev);
+        
+    }
+}
+
+static void
+EvdevMultitouchPostMTMotionEventsBySingle(InputInfoPtr pInfo,struct input_event *ev)
+{
+    EvdevMultitouchPtr pEvdevMultitouch, pEvdevMultitouchSubdev;
+    EvdevMultitouchDataMTPtr pData;
+    InputInfoPtr pSubdev;
+
+    if( !pInfo || !pInfo->private )
+       return;
+
+    pEvdevMultitouch = pInfo->private;
+
+    pData = &(pEvdevMultitouch->vals_mt[0]);
+
+    if (!pData->containsValues) {
+        return;
+    }
+    
+    pSubdev = pInfo;
+    pData->containsValues = FALSE;
+    EvdevMultitouchCopyFromData(pSubdev, pData);
+    pEvdevMultitouchSubdev = pSubdev->private;
+    pEvdevMultitouchSubdev->mt = 0;
+    pEvdevMultitouchSubdev->abs = pData->abs;
+    pEvdevMultitouchSubdev->rel = 0;
+    pEvdevMultitouchSubdev->tool = 1;
+    /* droping of the pressed/released events */
+    memset(pEvdevMultitouchSubdev->queue, 0, sizeof(pEvdevMultitouchSubdev->queue));
+    pEvdevMultitouchSubdev->num_queue = 0;
+
+    /* generate button press/release event */
+    if(pEvdevMultitouchSubdev->abs & ABS_MT_TOUCH_MAJOR_VALUE)
+    {
+        if(pEvdevMultitouchSubdev->vals[pEvdevMultitouchSubdev->axis_map[ABS_MT_TOUCH_MAJOR]] )
+        {
+            if(pEvdevMultitouchSubdev->touch_state == 0)
+            {
+                EvdevMultitouchQueueButtonEvent(pSubdev, 1, 1);
+                pEvdevMultitouchSubdev->touch_state = 1;
+                 g_pressed = 1;
+#ifdef _F_GESTURE_EXTENSION_
+                 EvdevMultitouchFrameSync(pInfo, MTOUCH_FRAME_SYNC_BEGIN);
+#endif//_F_GESTURE_EXTENSION_
+            }
+        }
+        else
+        {
+            g_pressed = 0;
+            EvdevMultitouchQueueButtonEvent(pSubdev, 1, 0);
+            pEvdevMultitouchSubdev->touch_state = 0;
+            pEvdevMultitouchSubdev->evtime = 0;
+        }
+    }
+
+    EvdevMultitouchProcessSyncEvent(pSubdev, ev);
+}
+
+/**
+ * Post the relative motion events.
+ */
+void
+EvdevMultitouchPostRelativeMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+                              int v[MAX_VALUATORS])
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if (pEvdevMultitouch->rel) {
+        xf86PostMotionEventP(pInfo->dev, FALSE, *first_v, *num_v, v + *first_v);
+    }
+}
+
+/**
+ * Post the absolute motion events.
+ */
+void
+EvdevMultitouchPostAbsoluteMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+                              int v[MAX_VALUATORS])
+{
+    EvdevMultitouchPtr pEvdevMultitouch = 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
+     * pEvdevMultitouch->digi here, lets us ignore that event.  pEvdevMultitouch is
+     * initialized to 1 so devices that doesn't use this scheme still
+     * just works.
+     */
+    if (pEvdevMultitouch->abs && pEvdevMultitouch->tool) {
+        xf86PostMotionEventP(pInfo->dev, TRUE, *first_v, *num_v, v);
+    }
+}
+
+/**
+ * Post the queued key/button events.
+ */
+static void EvdevMultitouchPostQueuedEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+                                  int v[MAX_VALUATORS])
+{
+    int i;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    for (i = 0; i < pEvdevMultitouch->num_queue; i++) {
+        switch (pEvdevMultitouch->queue[i].type) {
+        case EV_QUEUE_KEY:
+            xf86PostKeyboardEvent(pInfo->dev, pEvdevMultitouch->queue[i].key,
+                                  pEvdevMultitouch->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, pEvdevMultitouch->queue[i].key,
+                                pEvdevMultitouch->queue[i].val, 0, 0);
+            break;
+        }
+    }
+}
+static void
+EvdevMultitouchCopyFromData(InputInfoPtr pInfo, EvdevMultitouchDataMTPtr pData) {
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    memcpy(pEvdevMultitouch->vals, pData->vals, MAX_VALUATORS * sizeof(int));
+    /* we drop the buttons/key events */
+}
+
+static void
+EvdevMultitouchStoreMTData(InputInfoPtr pInfo, EvdevMultitouchDataMTPtr pData) {
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int id,x,y;
+    Time currentTime = GetTimeInMillis();
+
+    id = pEvdevMultitouch->current_id;
+
+    if(pEvdevMultitouch->abs & ABS_MT_X_VALUE)
+        x = pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ABS_MT_POSITION_X]];
+    else
+        x = pData->vals[pEvdevMultitouch->axis_map[ABS_X]]; 
+        
+    if(pEvdevMultitouch->abs & ABS_MT_Y_VALUE)    
+        y = pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ABS_MT_POSITION_Y]];
+    else
+        y = pData->vals[pEvdevMultitouch->axis_map[ABS_Y]];
+
+    {
+        EvdevMultitouchPtr pEvdevMultitouchSub = pData->pInfo->private;
+        pEvdevMultitouchSub->evtime = currentTime;
+    }
+
+    pData->id = id;
+    memcpy(pData->vals, pEvdevMultitouch->vals, MAX_VALUATORS * sizeof(int));
+    pData->vals[pEvdevMultitouch->axis_map[ABS_X]] = x;
+    pData->vals[pEvdevMultitouch->axis_map[ABS_Y]] = y;
+    pData->containsValues = TRUE;
+    pData->expires = currentTime + pEvdevMultitouch->timeout;
+    pData->abs = pEvdevMultitouch->abs;
+
+    return;
+}
+
+/**
+ * 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
+EvdevMultitouchProcessMTSyncReport(InputInfoPtr pInfo, struct input_event *ev)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int id;
+
+    id = pEvdevMultitouch->current_id;
+    
+    if (id < 0) {
+        EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+        return;
+    }
+
+    if(pEvdevMultitouch->num_multitouch == 0) //Single mode
+    {
+        if(id != 0)
+        {
+            EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+            return;
+        }
+    }
+    else
+    {
+        if (id > pEvdevMultitouch->num_multitouch-1)
+        {
+            EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+            return;
+        }      
+    }
+
+    EvdevMultitouchStoreMTData(pInfo, &(pEvdevMultitouch->vals_mt[id]));
+    EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+    pEvdevMultitouch->mt = 1;
+    pEvdevMultitouch->sync_mt = 1;
+}
+
+static void
+EvdevMultitouchReinitPEvdevMultitouch(InputInfoPtr pInfo) {
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    memset(pEvdevMultitouch->delta, 0, sizeof(pEvdevMultitouch->delta));
+    memset(pEvdevMultitouch->queue, 0, sizeof(pEvdevMultitouch->queue));
+    pEvdevMultitouch->num_queue = 0;
+    pEvdevMultitouch->abs = 0;
+    pEvdevMultitouch->rel = 0;
+    pEvdevMultitouch->mt = 0;
+    pEvdevMultitouch->num_mt = 0;
+    pEvdevMultitouch->current_id = -1;
+    pEvdevMultitouch->sync_mt = 0;
+}
+
+/**
+ * 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
+EvdevMultitouchProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    int num_v = 0, first_v = 0;
+    int v[MAX_VALUATORS];
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    
+    if (ev->code == SYN_MT_REPORT) {
+        EvdevMultitouchProcessMTSyncReport(pInfo, ev);
+        return;
+    }
+
+    if( 0 <= pEvdevMultitouch->current_id && !pEvdevMultitouch->sync_mt )
+    {
+#ifdef _DEBUG_MT_SEQUENCE_
+       if( pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ABS_MT_TOUCH_MAJOR]] )
+               ErrorF("[SyncEvent] Press or Motion !(current->id=%d)\n", pEvdevMultitouch->current_id);
+       else
+               ErrorF("[SyncEvent] Release!(current->id=%d)\n\n", pEvdevMultitouch->current_id);
+#endif
+
+        EvdevMultitouchProcessMTSyncReport(pInfo, ev);
+    }
+
+    if (pEvdevMultitouch->mt) {
+        if(pEvdevMultitouch->num_multitouch > 1)
+        {
+            EvdevMultitouchPostMTMotionEvents(pInfo, ev);
+        }
+        else
+        {
+            EvdevMultitouchPostMTMotionEventsBySingle(pInfo, ev);
+        }
+    } else {
+        EvdevMultitouchProcessValuators(pInfo, v, &num_v, &first_v);
+
+        EvdevMultitouchPostRelativeMotionEvents(pInfo, &num_v, &first_v, v);
+        EvdevMultitouchPostAbsoluteMotionEvents(pInfo, &num_v, &first_v, v);
+        EvdevMultitouchPostQueuedEvents(pInfo, &num_v, &first_v, v);
+#ifdef _F_GESTURE_EXTENSION_
+       if( !g_pressed )
+            EvdevMultitouchFrameSync(pInfo, MTOUCH_FRAME_SYNC_END);
+#endif//_F_GESTURE_EXTENSION_
+    }
+    
+    EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+}
+
+/**
+ * Take the trackingID input event and process it accordingly.
+ */
+static void
+EvdevMultitouchProcessTrackingIDEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    // begining of a new touch
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    pEvdevMultitouch->last_slot = pEvdevMultitouch->current_id = ev->value;
+#ifdef _DEBUG_MT_SEQUENCE_
+    ErrorF("[TrackingIDEvent] current_id=%d, last_slot=%d\n", pEvdevMultitouch->current_id, pEvdevMultitouch->last_slot);
+#endif
+}
+
+/**
+ * Process the events from the device; nothing is actually posted to the server
+ * until an EV_SYN event is received.
+ */
+static char* ev_name(int type, int code, int value)
+{
+   static char ename[100];
+
+   char *stype = NULL;
+   char *scode = NULL;
+   char *svalue = NULL;
+
+   char ttype[50];
+   char tcode[50];
+   char tvalue[50];
+   
+   switch(type)
+   {
+   case EV_SYN:
+      stype = "EV_SYNC";
+      switch(code)
+      {
+      case SYN_REPORT:
+         scode = "SYN_REPORT";
+         break;
+      case SYN_CONFIG:
+         scode = "SYN_CONFIG";
+         break;
+      case SYN_MT_REPORT:
+         scode = "SYN_MT_REPORT";
+         break;
+      }
+      break;
+   case EV_KEY:
+      stype = "EV_KEY";
+      break;
+   case EV_REL:
+      stype = "EV_REL";
+      break;
+   case EV_ABS:
+      stype = "EV_ABS";
+      switch(code)
+      {
+      case ABS_X:
+         scode =  "ABS_X";
+         break;
+      case ABS_Y:
+         scode =  "ABS_Y";
+         break;
+      case ABS_PRESSURE:
+         scode =  "ABS_PRESSURE";
+         break;
+      case ABS_MT_TOUCH_MAJOR:
+         scode =  "ABS_MT_TOUCH_MAJOR";
+         break;
+      case ABS_MT_TOUCH_MINOR:
+         scode =  "ABS_MT_TOUCH_MINOR";
+         break;
+      case ABS_MT_WIDTH_MAJOR:
+         scode =  "ABS_MT_WIDTH_MAJOR";
+         break;
+      case ABS_MT_WIDTH_MINOR:
+         scode =  "ABS_MT_WIDTH_MINOR";
+         break;
+      case ABS_MT_ORIENTATION:
+         scode =  "ABS_MT_ORIENTATION";
+         break;
+      case ABS_MT_POSITION_X:
+         scode =  "ABS_MT_POSITION_X";
+         break;
+      case ABS_MT_POSITION_Y:
+         scode =  "ABS_MT_POSITION_Y";
+         break;
+      case ABS_MT_TOOL_TYPE:
+         scode =  "ABS_MT_TOOL_TYPE";
+         break;
+      case ABS_MT_BLOB_ID:
+         scode =  "ABS_MT_BLOB_ID";
+         break;
+      case ABS_MT_TRACKING_ID:
+         scode =  "ABS_MT_TRACKING_ID";
+         break;
+      case ABS_MT_SLOT:
+         scode =  "ABS_MT_SLOT";
+         break;
+      }
+   default:
+      break;
+   }
+
+   if(!stype)
+   {
+      sprintf(ttype, "T(0x%x)", type);
+      stype = ttype;
+   }
+
+   if(!scode)
+   {
+      sprintf(tcode, "C(0x%x)", code);
+      scode = tcode;
+   }
+
+   if(!svalue)
+   {
+      sprintf(tvalue, "V(%d)",value);
+      svalue = tvalue;
+   }
+
+   sprintf(ename, "%s : %s : %s", stype, scode, svalue);
+   return ename;
+}
+
+static void EvdevMultitouchFakeOmittedEvents(InputInfoPtr pInfo)
+{
+       EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+       if( !(pEvdevMultitouch->abs & ABS_MT_TOUCH_MAJOR_VALUE) )
+       {
+               pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ABS_MT_TOUCH_MAJOR]] = 1;
+               pEvdevMultitouch->abs |= ABS_MT_TOUCH_MAJOR_VALUE;
+#ifdef _DEBUG_MT_SEQUENCE_
+               ErrorF("\t...Fake ABS_MT_TOUCH_MAJOR\n");
+#endif
+       }
+
+       if( pEvdevMultitouch->current_id < 0 )
+       {
+               pEvdevMultitouch->current_id = pEvdevMultitouch->last_slot;
+#ifdef _DEBUG_MT_SEQUENCE_
+               ErrorF("\t...Fake ABS_MT_SLOT (current_id=%d)\n", pEvdevMultitouch->current_id);
+#endif
+       }
+}
+
+static void
+EvdevMultitouchProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+       
+    switch (ev->type) {
+        case EV_REL:
+            return;
+        case EV_ABS:
+            switch(ev->code)
+            {
+            case ABS_X:
+            case ABS_Y:
+            case ABS_PRESSURE:
+                return;
+            }
+                       
+            if( ev->code == ABS_MT_TRACKING_ID )
+            {
+#ifdef _DEBUG_MT_SEQUENCE_
+                 ErrorF("[ProcessEvent] ABS_MT_TRACKING_ID (value=%d)\n", ev->value);
+#endif
+
+                 if( pEvdevMultitouch->mt_slot_supported )
+                 {//MT protocol B Type
+                        if( pEvdevMultitouch->current_id < 0 )
+                        {
+                               pEvdevMultitouch->current_id = pEvdevMultitouch->last_slot;
+                        }
+                         
+                        if( 0 > ev->value )//ABS_MT_TRACKING_ID == -1
+                         {
+#ifdef _DEBUG_MT_SEQUENCE_
+                             ErrorF("\t...Fake ABS_MT_TOUCH_MAJOR\n");
+#endif
+                               pEvdevMultitouch->vals[pEvdevMultitouch->axis_map[ABS_MT_TOUCH_MAJOR]] = 0;
+                               pEvdevMultitouch->abs |= ABS_MT_TOUCH_MAJOR_VALUE;
+                         }
+                 }
+                 else
+                 {//MT protocol A Type
+                         EvdevMultitouchProcessTrackingIDEvent(pInfo, ev);
+                 }
+            }
+                
+            if (ev->code == ABS_MT_SLOT)
+            {
+#ifdef _DEBUG_MT_SEQUENCE_
+                 ErrorF("[ProcessEvent] ABS_MT_SLOT (value=%d)\n", ev->value);
+#endif
+                 if( pEvdevMultitouch->last_slot != ev->value )
+                {
+                       ev->code = SYN_REPORT;
+                       EvdevMultitouchProcessSyncEvent(pInfo, ev);
+                       ev->code = ABS_MT_SLOT;
+                }
+
+                EvdevMultitouchProcessTrackingIDEvent(pInfo, ev);
+            }
+            else
+            {
+                EvdevMultitouchProcessAbsoluteMotionEvent(pInfo, ev);
+            }
+            break;
+        case EV_KEY:
+            return;
+        case EV_SYN:
+#ifdef _DEBUG_MT_SEQUENCE_
+            if( ev->code == SYN_MT_REPORT )
+               ErrorF("[ProcessEvent] SYN_MT_REPORT (value=%d)\n", ev->value);
+            else
+               ErrorF("[ProcessEvent] SYN_REPORT (value=%d)\n", ev->value);
+#endif
+            EvdevMultitouchProcessSyncEvent(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
+
+/**
+ * Empty callback for subdevice.
+ */
+static void
+EvdevMultitouchSubdevReadInput(InputInfoPtr pInfo) {
+    return;
+}
+
+static void
+EvdevMultitouchReadInput(InputInfoPtr pInfo)
+{
+    struct input_event ev[NUM_EVENTS];
+    int i, len = sizeof(ev);
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    while (len == sizeof(ev))
+    {
+        len = read(pInfo->fd, &ev, sizeof(ev));
+        if (len <= 0)
+        {
+            if (errno == ENODEV) /* May happen after resume */
+            {
+                EvdevMultitouchMBEmuFinalize(pInfo);
+                xf86RemoveEnabledDevice(pInfo);
+                close(pInfo->fd);
+                pInfo->fd = -1;
+                if (pEvdevMultitouch->reopen_timer)
+                {
+                    pEvdevMultitouch->reopen_left = pEvdevMultitouch->reopen_attempts;
+                    pEvdevMultitouch->reopen_timer = TimerSet(pEvdevMultitouch->reopen_timer, 0, 100, EvdevMultitouchReopenTimer, 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++)
+            EvdevMultitouchProcessEvent(pInfo, &ev[i]);
+    }
+}
+
+#define TestBit(bit, array) ((array[(bit) / LONG_BITS]) & (1L << ((bit) % LONG_BITS)))
+
+static void
+EvdevMultitouchPtrCtrlProc(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
+EvdevMultitouchInitKeysyms(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+    KeySymsRec keySyms;
+    CARD8 modMap[MAP_LENGTH];
+    KeySym sym;
+    int i, j;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = 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(pEvdevMultitouch->rmlvo.rules, pEvdevMultitouch->rmlvo.model,
+            pEvdevMultitouch->rmlvo.layout, pEvdevMultitouch->rmlvo.variant,
+            pEvdevMultitouch->rmlvo.options);
+    if (!XkbInitKeyboardDeviceStruct(device, &pEvdevMultitouch->xkbnames,
+                &keySyms, modMap, NULL,
+                EvdevMultitouchKbdCtrl))
+        return 0;
+
+    return 1;
+}
+#endif
+
+static void
+EvdevMultitouchKbdCtrl(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
+EvdevMultitouchAddKeyClass(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    /* sorry, no rules change allowed for you */
+    xf86ReplaceStrOption(pInfo->options, "xkb_rules", "evdevmultitouch");
+    SetXkbOption(pInfo, "xkb_rules", &pEvdevMultitouch->rmlvo.rules);
+    SetXkbOption(pInfo, "xkb_model", &pEvdevMultitouch->rmlvo.model);
+    if (!pEvdevMultitouch->rmlvo.model)
+        SetXkbOption(pInfo, "XkbModel", &pEvdevMultitouch->rmlvo.model);
+    SetXkbOption(pInfo, "xkb_layout", &pEvdevMultitouch->rmlvo.layout);
+    if (!pEvdevMultitouch->rmlvo.layout)
+        SetXkbOption(pInfo, "XkbLayout", &pEvdevMultitouch->rmlvo.layout);
+    SetXkbOption(pInfo, "xkb_variant", &pEvdevMultitouch->rmlvo.variant);
+    if (!pEvdevMultitouch->rmlvo.variant)
+        SetXkbOption(pInfo, "XkbVariant", &pEvdevMultitouch->rmlvo.variant);
+    SetXkbOption(pInfo, "xkb_options", &pEvdevMultitouch->rmlvo.options);
+    if (!pEvdevMultitouch->rmlvo.options)
+        SetXkbOption(pInfo, "XkbOptions", &pEvdevMultitouch->rmlvo.options);
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 5
+    if (!InitKeyboardDeviceStruct(device, &pEvdevMultitouch->rmlvo, NULL, EvdevMultitouchKbdCtrl))
+        return !Success;
+#else
+    if (!EvdevMultitouchInitKeysyms(device))
+        return !Success;
+
+#endif
+
+    return Success;
+}
+
+static int
+EvdevMultitouchAddAbsClass(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+    EvdevMultitouchPtr g_pEvdevMultitouch;
+    int num_axes, axis, i = 0;
+    Atom *atoms;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    g_pEvdevMultitouch = pEvdevMultitouch->core_device->private;
+
+    if (!TestBit(EV_ABS, g_pEvdevMultitouch->bitmask))
+            return !Success;
+
+    num_axes = EvdevMultitouchCountBits(g_pEvdevMultitouch->abs_bitmask, NLONGS(ABS_MAX));
+    if (num_axes < 1)
+        return !Success;
+    pEvdevMultitouch->num_vals = num_axes;
+    memset(pEvdevMultitouch->vals, 0, num_axes * sizeof(int));
+    memset(pEvdevMultitouch->old_vals, -1, num_axes * sizeof(int));
+    atoms = malloc(pEvdevMultitouch->num_vals * sizeof(Atom));
+
+    if( !atoms )
+    {
+        ErrorF("[X11][EvdevMultitouchAddAbsClass] Failed to allocate memory !\n", __FUNCTION__);
+        return !Success;
+    }
+
+    for (axis = ABS_X; axis <= ABS_MAX; axis++) {
+        pEvdevMultitouch->axis_map[axis] = -1;
+        if (!TestBit(axis, pEvdevMultitouch->abs_bitmask))
+            continue;
+        pEvdevMultitouch->axis_map[axis] = i;
+        i++;
+    }
+
+    EvdevMultitouchInitAxesLabels(g_pEvdevMultitouch, g_pEvdevMultitouch->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))
+    {
+        free(atoms);
+        return !Success;
+    }
+
+    for (axis = ABS_X; axis <= ABS_MAX; axis++) {
+        int axnum = g_pEvdevMultitouch->axis_map[axis];
+        if (axnum == -1)
+            continue;
+        xf86InitValuatorAxisStruct(device, axnum,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+                                   atoms[axnum],
+#endif
+                                   pEvdevMultitouch->absinfo[axis].minimum,
+                                   pEvdevMultitouch->absinfo[axis].maximum,
+                                   10000, 0, 10000, Absolute);
+        xf86InitValuatorDefaults(device, axnum);
+        pEvdevMultitouch->old_vals[axnum] = -1;
+    }
+
+    free(atoms);
+
+    if (!InitPtrFeedbackClassDeviceStruct(device, EvdevMultitouchPtrCtrlProc))
+        return !Success;
+
+#if 0
+    if ((TestBit(ABS_X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_Y, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_RX, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_RY, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_HAT0X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_HAT0Y, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_HAT1X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_HAT1Y, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_HAT2X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_HAT2Y, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_HAT3X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_HAT3Y, pEvdevMultitouch->abs_bitmask)) ||
+        (TestBit(ABS_TILT_X, pEvdevMultitouch->abs_bitmask) &&
+         TestBit(ABS_TILT_Y, pEvdevMultitouch->abs_bitmask)))
+        pInfo->flags |= XI86_POINTER_CAPABLE;
+#endif
+
+    return Success;
+}
+
+static int
+EvdevMultitouchAddRelClass(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+    int num_axes, axis, i = 0;
+    Atom *atoms;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    if (!TestBit(EV_REL, pEvdevMultitouch->bitmask))
+        return !Success;
+
+    num_axes = EvdevMultitouchCountBits(pEvdevMultitouch->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, pEvdevMultitouch->rel_bitmask))
+        num_axes--;
+    if (TestBit(REL_HWHEEL, pEvdevMultitouch->rel_bitmask))
+        num_axes--;
+    if (TestBit(REL_DIAL, pEvdevMultitouch->rel_bitmask))
+        num_axes--;
+
+    if (num_axes <= 0)
+        return !Success;
+
+    pEvdevMultitouch->num_vals = num_axes;
+    memset(pEvdevMultitouch->vals, 0, num_axes * sizeof(int));
+    atoms = malloc(pEvdevMultitouch->num_vals * sizeof(Atom));
+
+    if( !atoms )
+    {
+        ErrorF("[X11][EvdevMultitouchAddRelClass] Failed to allocate memory !\n", __FUNCTION__);
+        return !Success;
+    }
+
+    for (axis = REL_X; axis <= REL_MAX; axis++)
+    {
+        pEvdevMultitouch->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, pEvdevMultitouch->rel_bitmask))
+            continue;
+        pEvdevMultitouch->axis_map[axis] = i;
+        i++;
+    }
+
+    EvdevMultitouchInitAxesLabels(pEvdevMultitouch, pEvdevMultitouch->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))
+    {
+        free(atoms);
+        return !Success;
+    }
+
+    for (axis = REL_X; axis <= REL_MAX; axis++)
+    {
+        int axnum = pEvdevMultitouch->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, Relative);
+        xf86InitValuatorDefaults(device, axnum);
+    }
+
+    free(atoms);
+
+    if (!InitPtrFeedbackClassDeviceStruct(device, EvdevMultitouchPtrCtrlProc))
+        return !Success;
+
+    return Success;
+}
+
+static int
+EvdevMultitouchAddButtonClass(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+    Atom *labels;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    labels = malloc(pEvdevMultitouch->num_buttons * sizeof(Atom));
+
+    if( !labels )
+        return !Success;
+
+    EvdevMultitouchInitButtonLabels(pEvdevMultitouch, pEvdevMultitouch->num_buttons, labels);
+
+    if (!InitButtonClassDeviceStruct(device, pEvdevMultitouch->num_buttons,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+                                     labels,
+#endif
+                                     pEvdevMultitouch->btnmap))
+    {
+        free(labels);
+        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 EvdevMultitouchAddButtonClass).
+ */
+static void
+EvdevMultitouchInitButtonMapping(InputInfoPtr pInfo)
+{
+    int         i, nbuttons     = 1;
+    char       *mapping         = NULL;
+    EvdevMultitouchPtr    pEvdevMultitouch          = 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 < EVDEVMULTITOUCH_MAXBUTTONS)
+        {
+            btn = strtol(mapping, &s, 10);
+
+            if (s == mapping || btn < 0 || btn > EVDEVMULTITOUCH_MAXBUTTONS)
+            {
+                xf86Msg(X_ERROR,
+                        "%s: ... Invalid button mapping. Using defaults\n",
+                        pInfo->name);
+                nbuttons = 1; /* ensure defaults start at 1 */
+                break;
+            }
+
+            pEvdevMultitouch->btnmap[nbuttons++] = btn;
+            mapping = s;
+        }
+    }
+
+    for (i = nbuttons; i < ArrayLength(pEvdevMultitouch->btnmap); i++)
+        pEvdevMultitouch->btnmap[i] = i;
+
+}
+
+static void
+EvdevMultitouchInitAnyClass(DeviceIntPtr device, EvdevMultitouchPtr pEvdevMultitouch)
+{
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_RELATIVE_EVENTS &&
+        EvdevMultitouchAddRelClass(device) == Success)
+        xf86Msg(X_INFO, "%s: initialized for relative axes.\n", device->name);
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_ABSOLUTE_EVENTS &&
+        EvdevMultitouchAddAbsClass(device) == Success)
+        xf86Msg(X_INFO, "%s: initialized for absolute axes.\n", device->name);
+}
+
+static void
+EvdevMultitouchInitAbsClass(DeviceIntPtr device, EvdevMultitouchPtr pEvdevMultitouch)
+{
+    if (EvdevMultitouchAddAbsClass(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);
+
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_ABSOLUTE_EVENTS;
+
+    }
+}
+
+static void
+EvdevMultitouchInitRelClass(DeviceIntPtr device, EvdevMultitouchPtr pEvdevMultitouch)
+{
+    int has_abs_axes = pEvdevMultitouch->flags & EVDEVMULTITOUCH_ABSOLUTE_EVENTS;
+
+    if (EvdevMultitouchAddRelClass(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);
+            pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_ABSOLUTE_EVENTS;
+        }
+
+    } else {
+
+        xf86Msg(X_ERROR,"%s: failed to initialize for relative axes.\n",
+                device->name);
+
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_RELATIVE_EVENTS;
+
+        if (has_abs_axes)
+            EvdevMultitouchInitAbsClass(device, pEvdevMultitouch);
+    }
+}
+
+static void
+EvdevMultitouchInitTouchDevice(DeviceIntPtr device, EvdevMultitouchPtr pEvdevMultitouch)
+{
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_RELATIVE_EVENTS) {
+
+        xf86Msg(X_WARNING,"%s: touchpads, tablets and (multi)touchscreens ignore "
+                "relative axes.\n", device->name);
+
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_RELATIVE_EVENTS;
+    }
+
+    EvdevMultitouchInitAbsClass(device, pEvdevMultitouch);
+}
+
+static int
+EvdevMultitouchInit(DeviceIntPtr device)
+{
+    int i;
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    /* clear all axis_map entries */
+    for(i = 0; i < max(ABS_CNT,REL_CNT); i++)
+      pEvdevMultitouch->axis_map[i]=-1;
+
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_KEYBOARD_EVENTS)
+       EvdevMultitouchAddKeyClass(device);
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_BUTTON_EVENTS)
+       EvdevMultitouchAddButtonClass(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 (pEvdevMultitouch->flags & (EVDEVMULTITOUCH_UNIGNORE_RELATIVE | EVDEVMULTITOUCH_UNIGNORE_ABSOLUTE))
+        EvdevMultitouchInitAnyClass(device, pEvdevMultitouch);
+    else if (pEvdevMultitouch->flags & (EVDEVMULTITOUCH_TOUCHPAD | EVDEVMULTITOUCH_TOUCHSCREEN | EVDEVMULTITOUCH_TABLET | EVDEVMULTITOUCH_MULTITOUCH))
+        EvdevMultitouchInitTouchDevice(device, pEvdevMultitouch);
+    else if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_RELATIVE_EVENTS)
+        EvdevMultitouchInitRelClass(device, pEvdevMultitouch);
+    else if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_ABSOLUTE_EVENTS)
+        EvdevMultitouchInitAbsClass(device, pEvdevMultitouch);
+
+#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 */
+    EvdevMultitouchInitProperty(device);
+    XIRegisterPropertyHandler(device, EvdevMultitouchSetProperty, NULL, NULL);
+    EvdevMultitouchMBEmuInitProperty(device);
+    EvdevMultitouchWheelEmuInitProperty(device);
+    EvdevMultitouchDragLockInitProperty(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
+EvdevMultitouchOn(DeviceIntPtr device)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch;
+    int rc = 0;
+    BOOL finish = False;
+
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    /* If this is an object device,
+     * just add device to subdev list */
+    if (!EvdevMultitouchIsCoreDevice(pInfo)) {
+        finish = True;
+    } else {
+       if (pInfo->fd != -1 && pEvdevMultitouch->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)
+        {
+            pEvdevMultitouch->reopen_left = pEvdevMultitouch->reopen_attempts;
+            pEvdevMultitouch->reopen_timer = TimerSet(pEvdevMultitouch->reopen_timer, 0, 100, EvdevMultitouchReopenTimer, pInfo);
+        } else
+        {
+            pEvdevMultitouch->min_maj = EvdevMultitouchGetMajorMinor(pInfo);
+            if (EvdevMultitouchIsDuplicate(pInfo))
+            {
+                xf86Msg(X_WARNING, "%s: Refusing to enable duplicate device.\n",
+                        pInfo->name);
+                
+                return !Success;
+            }
+
+            pEvdevMultitouch->reopen_timer = TimerSet(pEvdevMultitouch->reopen_timer, 0, 0, NULL, NULL);
+
+            xf86FlushInput(pInfo->fd);
+            
+            EvdevMultitouchSetMultitouch(pInfo, pEvdevMultitouch->num_multitouch);
+            
+            finish = True;
+        }
+    }
+
+    if (finish) {
+        if( !strstr(pInfo->name, "subdev" ) )
+       {
+               xf86AddEnabledDevice(pInfo);
+               pEvdevMultitouch->last_slot = 0;
+               EvdevMultitouchReinitPEvdevMultitouch(pInfo);
+       }
+        EvdevMultitouchMBEmuOn(pInfo);
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_INITIALIZED;
+        device->public.on = TRUE;
+
+        pEvdevMultitouch->multitouch_setting_timer = TimerSet(pEvdevMultitouch->multitouch_setting_timer, 0, 100, EvdevMultitouchMultitouchSettingTimer, pInfo);
+    }
+
+    return Success;
+}
+
+static void
+EvdevMultitouchOff(DeviceIntPtr device)
+{
+       InputInfoPtr pInfo;
+       EvdevMultitouchPtr pEvdevMultitouch;
+
+       pInfo = device->public.devicePrivate;
+       pEvdevMultitouch = pInfo->private;
+}
+
+static int
+EvdevMultitouchProc(DeviceIntPtr device, int what)
+{
+    InputInfoPtr pInfo;
+    EvdevMultitouchPtr pEvdevMultitouch, g_pEvdevMultitouch;
+    int i;
+
+
+    pInfo = device->public.devicePrivate;
+    pEvdevMultitouch = pInfo->private;
+
+    switch (what)
+    {
+    case DEVICE_INIT:
+       return EvdevMultitouchInit(device);
+
+    case DEVICE_ON:
+        return EvdevMultitouchOn(device);
+
+    case DEVICE_OFF:
+        EvdevMultitouchOff(device);
+        if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_INITIALIZED)
+            EvdevMultitouchMBEmuFinalize(pInfo);
+        if (EvdevMultitouchIsCoreDevice(pInfo)){
+            EvdevMultitouchSetMultitouch(pInfo, 0);
+            if (pInfo->fd != -1)
+            {
+                if (pEvdevMultitouch->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;
+            }
+            if( pEvdevMultitouch->multitouch_setting_timer )
+            {
+                 TimerFree(pEvdevMultitouch->multitouch_setting_timer);
+                pEvdevMultitouch->multitouch_setting_timer = NULL;
+            }
+            if (pEvdevMultitouch->reopen_timer)
+            {
+                TimerFree(pEvdevMultitouch->reopen_timer);
+                pEvdevMultitouch->reopen_timer = NULL;
+            }
+        } else {
+            /* removing it in the list of the core device */
+            g_pEvdevMultitouch = pEvdevMultitouch->core_device->private;
+            for (i=0; i<MAX_VALUATORS_MT; ++i) {
+                if (g_pEvdevMultitouch->vals_mt[i].pInfo == pInfo) {
+                    g_pEvdevMultitouch->vals_mt[i].pInfo = NULL;
+                    break;
+                }
+            }
+            if (pInfo->fd >= 0)
+            {
+                xf86RemoveEnabledDevice(pInfo);
+            }
+        }
+        pEvdevMultitouch->min_maj = 0;
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_INITIALIZED;
+        device->public.on = FALSE;
+    break;
+
+    case DEVICE_CLOSE:
+        xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
+        if (EvdevMultitouchIsCoreDevice(pInfo)) { // master only
+            //EvdevMultitouchDeleteAllSubdevices(pInfo);
+            
+            if (pInfo->fd != -1) {
+                close(pInfo->fd);
+                pInfo->fd = -1;
+            }
+            EvdevMultitouchRemoveDevice(pInfo);
+        }
+        pEvdevMultitouch->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
+EvdevMultitouchCacheCompare(InputInfoPtr pInfo, BOOL compare)
+{
+    int i;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int len;
+
+    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(pEvdevMultitouch->name, name);
+    } else if (strcmp(pEvdevMultitouch->name, name)) {
+        xf86Msg(X_ERROR, "%s: device name changed: %s != %s\n",
+                pInfo->name, pEvdevMultitouch->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(pEvdevMultitouch->bitmask, bitmask, len);
+    } else if (memcmp(pEvdevMultitouch->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(pEvdevMultitouch->rel_bitmask, rel_bitmask, len);
+    } else if (memcmp(pEvdevMultitouch->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( TestBit(ABS_MT_SLOT, abs_bitmask) && TestBit(ABS_MT_TRACKING_ID, abs_bitmask) )
+    {
+         ErrorF("[X11] MT Protocol B Type : ABS_MT_SLOT is supported : \n");
+         pEvdevMultitouch->mt_slot_supported = (BOOL)1;
+    }
+    else
+    {
+         ErrorF("[X11] MT Protocol A Type : ABS_MT_SLOT is NOT supported\n");
+         pEvdevMultitouch->mt_slot_supported = (BOOL)0;
+    }
+
+    if (!compare) {
+        memcpy(pEvdevMultitouch->abs_bitmask, abs_bitmask, len);
+    } else if (memcmp(pEvdevMultitouch->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(pEvdevMultitouch->led_bitmask, led_bitmask, len);
+    } else if (memcmp(pEvdevMultitouch->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 evdevmultitouch structure.
+     */
+       if( !xf86CheckStrOption(pInfo->options, "Resolution", NULL) )
+       {
+           for (i = ABS_X; i <= ABS_MAX; i++) {
+               if (TestBit(i, abs_bitmask)) {
+                   len = ioctl(pInfo->fd, EVIOCGABS(i), &pEvdevMultitouch->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(&pEvdevMultitouch->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(pEvdevMultitouch->key_bitmask, key_bitmask, len);
+
+    return Success;
+
+error:
+    return !Success;
+
+}
+
+static int
+EvdevMultitouchProbe(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;
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if (pEvdevMultitouch->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
+        if (errno == EINVAL) {
+            /* keyboards are unsafe in 2.4 */
+            kernel24 = 1;
+            pEvdevMultitouch->grabDevice = 0;
+        } else {
+            xf86Msg(X_ERROR, "Grab failed. Device already configured?\n");
+            return 1;
+        }
+    } else if (pEvdevMultitouch->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
+            pEvdevMultitouch->flags |= EVDEVMULTITOUCH_UNIGNORE_RELATIVE;
+
+    }
+    if (xf86FindOption(pInfo->options, "IgnoreAbsoluteAxes"))
+    {
+        if (xf86SetBoolOption(pInfo->options, "IgnoreAbsoluteAxes", FALSE))
+           ignore_abs = TRUE;
+        else
+            pEvdevMultitouch->flags |= EVDEVMULTITOUCH_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, pEvdevMultitouch->key_bitmask))
+        {
+            mapping = EvdevMultitouchUtilButtonEventToButtonNumber(pEvdevMultitouch, i);
+            if (mapping > num_buttons)
+                num_buttons = mapping;
+        }
+    }
+
+    if (num_buttons)
+    {
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_BUTTON_EVENTS;
+        pEvdevMultitouch->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, pEvdevMultitouch->rel_bitmask)) {
+            has_rel_axes = TRUE;
+            break;
+        }
+    }
+
+    if (has_rel_axes) {
+        if (TestBit(REL_WHEEL, pEvdevMultitouch->rel_bitmask) ||
+            TestBit(REL_HWHEEL, pEvdevMultitouch->rel_bitmask) ||
+            TestBit(REL_DIAL, pEvdevMultitouch->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;
+            pEvdevMultitouch->num_buttons = num_buttons;
+        }
+
+        if (!ignore_rel)
+        {
+            xf86Msg(X_INFO, "%s: Found relative axes\n", pInfo->name);
+            pEvdevMultitouch->flags |= EVDEVMULTITOUCH_RELATIVE_EVENTS;
+
+            if (TestBit(REL_X, pEvdevMultitouch->rel_bitmask) &&
+                TestBit(REL_Y, pEvdevMultitouch->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, pEvdevMultitouch->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);
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_ABSOLUTE_EVENTS;
+
+        if ((TestBit(ABS_X, pEvdevMultitouch->abs_bitmask) &&
+             TestBit(ABS_Y, pEvdevMultitouch->abs_bitmask))) {
+            xf86Msg(X_INFO, "%s: Found x and y absolute axes\n", pInfo->name);
+            if (TestBit(BTN_TOOL_PEN, pEvdevMultitouch->key_bitmask))
+            {
+                xf86Msg(X_INFO, "%s: Found absolute tablet.\n", pInfo->name);
+                pEvdevMultitouch->flags |= EVDEVMULTITOUCH_TABLET;
+            } else if ((TestBit(ABS_MT_POSITION_X, pEvdevMultitouch->abs_bitmask) &&
+                        TestBit(ABS_MT_POSITION_Y, pEvdevMultitouch->abs_bitmask))) {
+                xf86Msg(X_INFO, "%s: Found absolute multitouch tablet.\n", pInfo->name);
+                pEvdevMultitouch->flags |= EVDEVMULTITOUCH_MULTITOUCH;
+            } else if (TestBit(ABS_PRESSURE, pEvdevMultitouch->abs_bitmask) ||
+                TestBit(BTN_TOUCH, pEvdevMultitouch->key_bitmask)) {
+                if (num_buttons || TestBit(BTN_TOOL_FINGER, pEvdevMultitouch->key_bitmask)) {
+                    xf86Msg(X_INFO, "%s: Found absolute touchpad.\n", pInfo->name);
+                    pEvdevMultitouch->flags |= EVDEVMULTITOUCH_TOUCHPAD;
+                    memset(pEvdevMultitouch->old_vals, -1, sizeof(int) * pEvdevMultitouch->num_vals);
+                } else {
+                    xf86Msg(X_INFO, "%s: Found absolute touchscreen\n", pInfo->name);
+                    pEvdevMultitouch->flags |= EVDEVMULTITOUCH_TOUCHSCREEN;
+                    pEvdevMultitouch->flags |= EVDEVMULTITOUCH_BUTTON_EVENTS;
+                }
+            }
+        }
+    }
+
+    for (i = 0; i < BTN_MISC; i++) {
+        if (TestBit(i, pEvdevMultitouch->key_bitmask)) {
+            xf86Msg(X_INFO, "%s: Found keys\n", pInfo->name);
+            pEvdevMultitouch->flags |= EVDEVMULTITOUCH_KEYBOARD_EVENTS;
+            has_keys = TRUE;
+            break;
+        }
+    }
+
+    if (has_rel_axes || has_abs_axes || num_buttons) {
+       if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_TOUCHPAD) {
+           xf86Msg(X_INFO, "%s: Configuring as touchpad\n", pInfo->name);
+           pInfo->type_name = XI_TOUCHPAD;
+       } else if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_TABLET) {
+           xf86Msg(X_INFO, "%s: Configuring as tablet\n", pInfo->name);
+           pInfo->type_name = XI_TABLET;
+        } else if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_TOUCHSCREEN) {
+            xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
+            pInfo->type_name = XI_TOUCHSCREEN;
+        } else if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH) {
+            xf86Msg(X_INFO, "%s: Configuring as multitouch screen\n", pInfo->name);
+            pInfo->type_name = "MULTITOUCHSCREEN";
+        } 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->type_name = XI_KEYBOARD;
+        }
+    }
+
+    if (has_scroll)
+    {
+        xf86Msg(X_INFO, "%s: Adding scrollwheel support\n", pInfo->name);
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_BUTTON_EVENTS;
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_RELATIVE_EVENTS;
+    }
+
+    return 0;
+}
+
+static void
+EvdevMultitouchSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4])
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if (num_calibration == 0) {
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_CALIBRATED;
+        pEvdevMultitouch->calibration.min_x = 0;
+        pEvdevMultitouch->calibration.max_x = 0;
+        pEvdevMultitouch->calibration.min_y = 0;
+        pEvdevMultitouch->calibration.max_y = 0;
+    } else if (num_calibration == 4) {
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_CALIBRATED;
+        pEvdevMultitouch->calibration.min_x = calibration[0];
+        pEvdevMultitouch->calibration.max_x = calibration[1];
+        pEvdevMultitouch->calibration.min_y = calibration[2];
+        pEvdevMultitouch->calibration.max_y = calibration[3];
+    }
+}
+
+static void
+EvdevMultitouchSetResolution(InputInfoPtr pInfo, int num_resolution, int resolution[4])
+{
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+    if (num_resolution == 0) {
+        pEvdevMultitouch->flags &= ~EVDEVMULTITOUCH_RESOLUTION;
+        pEvdevMultitouch->resolution.min_x = 0;
+        pEvdevMultitouch->resolution.max_x = 0;
+        pEvdevMultitouch->resolution.min_y = 0;
+        pEvdevMultitouch->resolution.max_y = 0;
+    } else if (num_resolution == 4) {
+        pEvdevMultitouch->flags |= EVDEVMULTITOUCH_RESOLUTION;
+        pEvdevMultitouch->resolution.min_x = resolution[0];
+        pEvdevMultitouch->resolution.max_x = resolution[1];
+        pEvdevMultitouch->resolution.min_y = resolution[2];
+        pEvdevMultitouch->resolution.max_y = resolution[3];
+    }
+}
+
+static void EvdevMultitouchSetTransform(InputInfoPtr pInfo, int num_transform, float *tmatrix)
+{
+       int x, y;
+       struct pixman_transform tr;
+       EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+
+       if( num_transform != 9 )
+       {
+               pEvdevMultitouch->use_transform = False;
+               return;
+       }
+       pEvdevMultitouch->use_transform = True;
+
+       memcpy(pEvdevMultitouch->transform, tmatrix, sizeof(pEvdevMultitouch->transform));
+       for (y=0; y<3; y++)
+               for (x=0; x<3; x++)
+                       tr.matrix[y][x] = pixman_double_to_fixed((double)*tmatrix++);
+
+       pixman_transform_invert(&pEvdevMultitouch->inv_transform, &tr);
+}
+
+static void
+EvdevMultitouchSetMultitouch(InputInfoPtr pInfo, int num_multitouch) {
+    EvdevMultitouchPtr pEvdevMultitouch = pInfo->private;
+    int i, rc;
+
+    if( !(pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH) ) 
+    { 
+            ErrorF("[X11][%s] Device is not a multitouch screen !(flags=%d)\n", __FUNCTION__, pEvdevMultitouch->flags); 
+            return; 
+    }
+
+    if (num_multitouch > MAX_VALUATORS_MT)
+        num_multitouch = MAX_VALUATORS_MT;
+    if (num_multitouch < 0)
+        num_multitouch = 0;
+
+    for (i=0;i<num_multitouch;++i) {
+        if (pEvdevMultitouch->vals_mt[i].pInfo == NULL){
+            pEvdevMultitouch->vals_mt[i].containsValues = FALSE;
+            pEvdevMultitouch->vals_mt[i].id = -1;
+            pEvdevMultitouch->vals_mt[i].pInfo = EvdevMultitouchCreateSubDevice(pInfo, i);
+        }
+    }
+    for (i=num_multitouch;i<MAX_VALUATORS_MT;++i) {
+        pEvdevMultitouch->vals_mt[i].containsValues = FALSE;
+        pEvdevMultitouch->vals_mt[i].id = -1;
+        if (pEvdevMultitouch->vals_mt[i].pInfo && pEvdevMultitouch->vals_mt[i].pInfo != pInfo) {
+            EvdevMultitouchDeleteSubDevice(pInfo, pEvdevMultitouch->vals_mt[i].pInfo);
+            pEvdevMultitouch->vals_mt[i].pInfo = NULL;
+        }
+    }
+    
+    pEvdevMultitouch->num_multitouch = num_multitouch;
+
+    rc = XIChangeDeviceProperty(pInfo->dev, prop_multitouch, XA_INTEGER, 8, 
+               PropModeReplace, 1, &pEvdevMultitouch->num_multitouch, FALSE);
+
+    if (rc != Success)
+           ErrorF("[X11][%s] Failed to Change device property !\n", __FUNCTION__);
+}
+
+Bool
+IsMaster(DeviceIntPtr dev)
+{
+    return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD;
+}
+
+DeviceIntPtr
+GetPairedDevice(DeviceIntPtr dev)
+{
+    if (!IsMaster(dev) && dev->master)
+        dev = dev->master;
+
+    return dev->spriteInfo->paired;
+}
+
+DeviceIntPtr
+GetMaster(DeviceIntPtr dev, int which)
+{
+    DeviceIntPtr master;
+
+    if (IsMaster(dev))
+        master = dev;
+    else
+        master = dev->master;
+
+    if (master)
+    {
+        if (which == MASTER_KEYBOARD)
+        {
+            if (master->type != MASTER_KEYBOARD)
+                master = GetPairedDevice(master);
+        } else
+        {
+            if (master->type != MASTER_POINTER)
+                master = GetPairedDevice(master);
+        }
+    }
+
+    return master;
+}
+
+static void
+EvdevMultitouchGetGrabInfo(InputInfoPtr pInfo, BOOL  val)
+{
+       DeviceIntPtr master_pointer;
+
+       if( val == 1 )
+       {
+               if( pInfo->dev->deviceGrab.grab )
+               {
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo] Device id=%d (grabbed) !\n", pInfo->dev->id);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  (event) type=%d\n", pInfo->dev->deviceGrab.grab->type);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  grabtype=%d\n", pInfo->dev->deviceGrab.grab->grabtype);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  resource=0x%x\n", (unsigned int)pInfo->dev->deviceGrab.grab->resource);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  keyboardMode=%d\n", pInfo->dev->deviceGrab.grab->keyboardMode);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  pointerMode=%d\n", pInfo->dev->deviceGrab.grab->pointerMode);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  sync.frozen=%d\n", pInfo->dev->deviceGrab.sync.frozen);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  fromPassiveGrab=%d\n", pInfo->dev->deviceGrab.fromPassiveGrab);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  implicitGrab=%d\n", pInfo->dev->deviceGrab.implicitGrab);
+               }
+               else if( (master_pointer = GetMaster(pInfo->dev, MASTER_POINTER)) && master_pointer->deviceGrab.grab )
+               {
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo] Device id=%d (master_pointer, grabbed) !\n", master_pointer->id);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  (event) type=%d\n", master_pointer->deviceGrab.grab->type);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  grabtype=%d\n", master_pointer->deviceGrab.grab->grabtype);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  resource=0x%x\n", (unsigned int)master_pointer->deviceGrab.grab->resource);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  keyboardMode=%d\n", master_pointer->deviceGrab.grab->keyboardMode);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  pointerMode=%d\n", master_pointer->deviceGrab.grab->pointerMode);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  sync.frozen=%d\n", master_pointer->deviceGrab.sync.frozen);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  fromPassiveGrab=%d\n", master_pointer->deviceGrab.fromPassiveGrab);
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo]  implicitGrab=%d\n", master_pointer->deviceGrab.implicitGrab);
+               }
+               else
+                       ErrorF("[X11][EvdevMultitouchGetGrabInfo] Device id=%d (ungrabbed) !\n", pInfo->dev->id);
+       }
+}
+
+static int
+EvdevMultitouchPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+{
+    int rc = BadAlloc;
+    const char *device, *str;
+    int num_calibration = 0, calibration[4] = { 0, 0, 0, 0 };
+    int num_resolution = 0, resolution[4] = { 0, 0, 0, 0 };
+    int num_transform = 0; float tr[9];
+    EvdevMultitouchPtr pEvdevMultitouch;
+    char *type;
+    char *name;
+
+    if(!pInfo)
+    {
+        xf86DrvMsg(-1, X_ERROR, "[X11][EvdevMultitouchPreInit] pInfo is NULL !\n");
+        goto error;
+    }
+
+    /* Initialise the InputInfoRec. */
+    pInfo->flags = 0;
+    pInfo->type_name = "UNKNOWN";
+    pInfo->device_control = EvdevMultitouchProc;
+    pInfo->switch_mode = NULL;
+    pInfo->dev = NULL;
+
+    if (!(pEvdevMultitouch = calloc(sizeof(EvdevMultitouchRec), 1)))
+        goto error;
+
+    pInfo->private = pEvdevMultitouch;
+
+    xf86CollectInputOptions(pInfo, evdevmultitouchDefaults);
+    xf86ProcessCommonOptions(pInfo, pInfo->options);
+    pEvdevMultitouch->id = -1;
+
+ #ifdef _F_SUPPORT_PREFERRED_NAME_
+    if (!strstr(pInfo->name, "subdev") && !strstr(pInfo->name, "Virtual")) {
+        str = xf86CheckStrOption(pInfo->options, "PreferredName", NULL);
+        if (str) {
+            pInfo->name = str;
+        }
+        else {
+            name = malloc((strlen("Touchscreen")+1)*sizeof(char));
+            if(!name)
+            {
+               ErrorF("[X11][EvdevMultitouchPreInit] Failed to allocate memory for a name of a touchscreen device !\n");
+               goto error;
+            }
+            snprintf(name, strlen("Touchscreen")+1, "Touchscreen");
+            pInfo->name = name;
+        }
+    }
+#endif//_F_SUPPORT_PREFERRED_NAME_
+     /* If Type == Object, this is a device for an object to use */
+    type = xf86CheckStrOption(pInfo->options, "Type", NULL);
+
+    xf86Msg(X_INFO, "%s: EvdevMultitouch Type %s found\n", pInfo->name, type);
+       
+    if (type != NULL && strcmp(type, "Object") == 0) {
+        EvdevMultitouchPtr pCreatorEvdevMultitouch;
+        if (!pCreatorInfo){
+            return Success;
+        }
+        pCreatorEvdevMultitouch = pCreatorInfo->private;
+        xf86Msg(X_INFO, "%s: EvdevMultitouch subdevice found\n", pInfo->name);
+        memcpy(pEvdevMultitouch, pCreatorEvdevMultitouch, sizeof(EvdevMultitouchRec));
+        pInfo->read_input = EvdevMultitouchSubdevReadInput;
+        pEvdevMultitouch->associated = FALSE;
+        pInfo->type_name = pCreatorInfo->type_name;
+        pEvdevMultitouch->num_multitouch = 1;
+        //EvdevMultitouchInitButtonMapping(pInfo);
+   } else {
+        pInfo->read_input = EvdevMultitouchReadInput;
+
+        pEvdevMultitouch->core_device = pInfo;
+        pEvdevMultitouch->associated = FALSE;
+
+        memset(pEvdevMultitouch->vals, 0, MAX_VALUATORS * sizeof(int));
+        memset(pEvdevMultitouch->old_vals, -1, MAX_VALUATORS * sizeof(int));
+        
+        /*
+         * We initialize pEvdevMultitouch->tool to 1 so that device that doesn't use
+         * proximity will still report events.
+         */
+        pEvdevMultitouch->tool = 1;
+
+        device = xf86CheckStrOption(pInfo->options, "Device", NULL);
+        if (!device) {
+            xf86Msg(X_ERROR, "%s: No device specified.\n", pInfo->name);
+            rc = BadValue;
+            goto error;
+        }
+
+        pEvdevMultitouch->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 evdevmultitouch device \"%s\".\n", device);
+            rc = BadValue;
+            goto error;
+        }
+
+        /* Check major/minor of device node to avoid adding duplicate devices. */
+        pEvdevMultitouch->min_maj = EvdevMultitouchGetMajorMinor(pInfo);
+        if (EvdevMultitouchIsDuplicate(pInfo))
+        {
+            xf86Msg(X_WARNING, "%s: device file already in use. Ignoring.\n",
+                    pInfo->name);
+            close(pInfo->fd);
+            rc = BadValue;
+            goto error;
+        }
+
+        pEvdevMultitouch->reopen_attempts = xf86SetIntOption(pInfo->options, "ReopenAttempts", 10);
+        pEvdevMultitouch->invert_x = xf86SetBoolOption(pInfo->options, "InvertX", FALSE);
+        pEvdevMultitouch->invert_y = xf86SetBoolOption(pInfo->options, "InvertY", FALSE);
+        pEvdevMultitouch->num_multitouch = xf86SetIntOption(pInfo->options, "MultiTouch", 0);
+        pEvdevMultitouch->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)
+                EvdevMultitouchSetCalibration(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)
+                EvdevMultitouchSetResolution(pInfo, num_resolution, resolution);
+            else
+                xf86Msg(X_ERROR,
+                        "%s: Insufficient resolution factors (%d). Ignoring resolution\n",
+                        pInfo->name, num_resolution);
+        }
+
+        pEvdevMultitouch->use_transform = False;
+        str = xf86CheckStrOption(pInfo->options, "Transform", NULL);
+        if (str) {
+            num_transform = sscanf(str, "%f %f %f %f %f %f %f %f %f",
+                                     &tr[0], &tr[1], &tr[2],
+                                     &tr[3], &tr[4], &tr[5], 
+                                     &tr[6], &tr[7], &tr[8]);
+            if (num_transform == 9)
+                EvdevMultitouchSetTransform(pInfo, num_transform, tr);
+            else
+            {
+                xf86Msg(X_ERROR,
+                        "%s: Insufficient transform factors (%d). Ignoring transform\n",
+                        pInfo->name, num_transform);
+            }
+        }
+
+        /* 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. */
+        pEvdevMultitouch->grabDevice = xf86CheckBoolOption(pInfo->options, "GrabDevice", 0);
+
+        /* Get setting for checking wether a point is still alive */
+        pEvdevMultitouch->timeout = xf86CheckIntOption(pInfo->options,
+                "SubdevTimeout", DEFAULT_TIMEOUT);
+        if (pEvdevMultitouch->timeout < 1) {
+            pEvdevMultitouch->timeout = 1;
+        }
+        xf86Msg(X_INFO, "%s: SubdevTimeout set to %d\n",
+                pInfo->name, (int)pEvdevMultitouch->timeout);
+
+        EvdevMultitouchInitButtonMapping(pInfo);
+
+        if (EvdevMultitouchCacheCompare(pInfo, FALSE) ||
+            EvdevMultitouchProbe(pInfo)) {
+            close(pInfo->fd);
+            rc = BadValue;
+            goto error;
+        }
+        
+        if ((pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH) && !pEvdevMultitouch->num_buttons) {
+            /* absolute multitouch screen :
+             * forcing num_buttons = 1
+             */
+            pEvdevMultitouch->num_buttons = 1;
+            pEvdevMultitouch->flags |= EVDEVMULTITOUCH_BUTTON_EVENTS;
+        }
+
+        if(pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH)
+        {
+            pEvdevMultitouch->num_multitouch = 1;
+            pEvdevMultitouch->vals_mt[0].pInfo = pInfo;
+        }
+
+       if(pEvdevMultitouch->flags & EVDEVMULTITOUCH_RESOLUTION)
+       {
+               EvdevMultitouchSwapAxes(pEvdevMultitouch);
+       }
+
+        // register only the core device
+        EvdevMultitouchAddDevice(pInfo);
+    }
+
+    pEvdevMultitouch->use_transform = False;
+
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_BUTTON_EVENTS)
+    {
+        EvdevMultitouchMBEmuPreInit(pInfo);
+        EvdevMultitouchWheelEmuPreInit(pInfo);
+        EvdevMultitouchDragLockPreInit(pInfo);
+    }
+
+    return Success;
+
+error:
+    if ((pInfo) && (pInfo->fd >= 0))
+        close(pInfo->fd);
+    return rc;
+}
+
+_X_EXPORT InputDriverRec EVDEVMULTITOUCHh = {
+    1,
+    "evdevmultitouch",
+    NULL,
+    EvdevMultitouchPreInit,
+    NULL,
+    NULL,
+    0
+};
+
+static void
+EvdevMultitouchUnplug(pointer  p)
+{
+}
+
+static pointer
+EvdevMultitouchPlug(pointer    module,
+          pointer      options,
+          int          *errmaj,
+          int          *errmin)
+{
+    xf86AddInputDriver(&EVDEVMULTITOUCHh, module, 0);
+    return module;
+}
+
+static XF86ModuleVersionInfo EvdevMultitouchVersionRec =
+{
+    "evdevmultitouch",
+    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 evdevmultitouchModuleData =
+{
+    &EvdevMultitouchVersionRec,
+    EvdevMultitouchPlug,
+    EvdevMultitouchUnplug
+};
+
+
+/* Return an index value for a given button event code
+ * returns 0 on non-button event.
+ */
+unsigned int
+EvdevMultitouchUtilButtonEventToButtonNumber(EvdevMultitouchPtr pEvdevMultitouch, 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, pEvdevMultitouch->key_bitmask)) ?  8 : 1;
+        break;
+    case BTN_1:
+        button = (TestBit(BTN_MIDDLE, pEvdevMultitouch->key_bitmask)) ?  9 : 2;
+        break;
+    case BTN_2:
+        button = (TestBit(BTN_RIGHT, pEvdevMultitouch->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 > EVDEVMULTITOUCH_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 EvdevMultitouchInitAxesLabels(EvdevMultitouchPtr pEvdevMultitouch, int natoms, Atom *atoms)
+{
+#ifdef HAVE_LABELS
+    Atom atom;
+    int axis;
+    char **labels;
+    int labels_len = 0;
+    char *misc_label;
+
+    if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_ABSOLUTE_EVENTS)
+    {
+        labels     = abs_labels;
+        labels_len = ArrayLength(abs_labels);
+        misc_label = AXIS_LABEL_PROP_ABS_MISC;
+    } else if ((pEvdevMultitouch->flags & EVDEVMULTITOUCH_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 (pEvdevMultitouch->axis_map[axis] == -1)
+            continue;
+
+        atom = XIGetKnownProperty(labels[axis]);
+        if (!atom) /* Should not happen */
+            continue;
+
+        atoms[pEvdevMultitouch->axis_map[axis]] = atom;
+    }
+#endif
+}
+
+static void EvdevMultitouchInitButtonLabels(EvdevMultitouchPtr pEvdevMultitouch, 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, pEvdevMultitouch->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 = EvdevMultitouchUtilButtonEventToButtonNumber(pEvdevMultitouch, button) - 1;
+            if( bmap >= 0 )
+                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
+EvdevMultitouchInitProperty(DeviceIntPtr dev)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = pInfo->private;
+    int          rc;
+    int          val;
+    BOOL         invert[2];
+    char         reopen;
+
+    prop_reopen = MakeAtom(EVDEVMULTITOUCH_PROP_REOPEN, strlen(EVDEVMULTITOUCH_PROP_REOPEN),
+            TRUE);
+
+    reopen = pEvdevMultitouch->reopen_attempts;
+    rc = XIChangeDeviceProperty(dev, prop_reopen, XA_INTEGER, 8,
+                                PropModeReplace, 1, &reopen, FALSE);
+    if (rc != Success)
+        return;
+
+    XISetDevicePropertyDeletable(dev, prop_reopen, FALSE);
+
+    if (pEvdevMultitouch->flags & (EVDEVMULTITOUCH_RELATIVE_EVENTS | EVDEVMULTITOUCH_ABSOLUTE_EVENTS))
+    {
+        invert[0] = pEvdevMultitouch->invert_x;
+        invert[1] = pEvdevMultitouch->invert_y;
+
+        prop_invert = MakeAtom(EVDEVMULTITOUCH_PROP_INVERT_AXES, strlen(EVDEVMULTITOUCH_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(EVDEVMULTITOUCH_PROP_CALIBRATION,
+                strlen(EVDEVMULTITOUCH_PROP_CALIBRATION), TRUE);
+        rc = XIChangeDeviceProperty(dev, prop_calibration, XA_INTEGER, 32,
+                PropModeReplace, 0, NULL, FALSE);
+        if (rc != Success)
+            return;
+
+        XISetDevicePropertyDeletable(dev, prop_calibration, FALSE);
+
+        prop_swap = MakeAtom(EVDEVMULTITOUCH_PROP_SWAP_AXES,
+                strlen(EVDEVMULTITOUCH_PROP_SWAP_AXES), TRUE);
+
+        rc = XIChangeDeviceProperty(dev, prop_swap, XA_INTEGER, 8,
+                PropModeReplace, 1, &pEvdevMultitouch->swap_axes, FALSE);
+        if (rc != Success)
+            return;
+
+        XISetDevicePropertyDeletable(dev, prop_swap, FALSE);
+        
+        if (pEvdevMultitouch->flags & EVDEVMULTITOUCH_MULTITOUCH)
+        {
+            /* tracking ids for mt */
+            prop_tracking_id = MakeAtom(EVDEVMULTITOUCH_PROP_TRACKING_ID,
+                    strlen(EVDEVMULTITOUCH_PROP_TRACKING_ID), TRUE);
+            rc = XIChangeDeviceProperty(dev, prop_tracking_id, XA_INTEGER, 32,
+                    PropModeReplace, 1, &pEvdevMultitouch->id, FALSE);
+            if (rc != Success)
+                return;
+
+            XISetDevicePropertyDeletable(dev, prop_tracking_id, FALSE);
+
+            /* flag to emulate or not a touchscreen for mt */
+            prop_multitouch = MakeAtom(EVDEVMULTITOUCH_PROP_MULTITOUCH_SUBDEVICES,
+                    strlen(EVDEVMULTITOUCH_PROP_MULTITOUCH_SUBDEVICES), TRUE);
+            rc = XIChangeDeviceProperty(dev, prop_multitouch, XA_INTEGER, 8,
+                    PropModeReplace, 1, &pEvdevMultitouch->num_multitouch, FALSE);
+            if (rc != Success)
+                return;
+
+            XISetDevicePropertyDeletable(dev, prop_multitouch, FALSE);
+        }
+
+       //property for checking pointer grab status
+       val = 0;
+       prop_grabinfo = MakeAtom(EVDEVMULTITOUCH_PROP_GRABINFO, strlen(EVDEVMULTITOUCH_PROP_GRABINFO),  TRUE);
+       rc = XIChangeDeviceProperty(dev, prop_grabinfo, XA_INTEGER, 8, PropModeReplace, 1, &val, FALSE);
+
+       if (rc != Success)
+           return;
+
+       XISetDevicePropertyDeletable(dev, prop_grabinfo, FALSE);
+
+       if( EvdevMultitouchIsCoreDevice(pInfo) )//master only
+       {
+               /* matrix to transform */
+               prop_transform = MakeAtom(EVDEVMULTITOUCH_PROP_TRANSFORM, strlen(EVDEVMULTITOUCH_PROP_TRANSFORM),  TRUE);
+               rc = XIChangeDeviceProperty(dev, prop_transform, XIGetKnownProperty(XATOM_FLOAT), 32, PropModeReplace, 9, pEvdevMultitouch->transform, FALSE);
+
+               if (rc != Success)
+                   return;
+
+               XISetDevicePropertyDeletable(dev, prop_transform, FALSE);
+       }
+
+#ifdef HAVE_LABELS
+        /* Axis labelling */
+        if ((pEvdevMultitouch->num_vals > 0) && (prop_axis_label = XIGetKnownProperty(AXIS_LABEL_PROP)))
+        {
+            Atom atoms[pEvdevMultitouch->num_vals];
+            EvdevMultitouchInitAxesLabels(pEvdevMultitouch, pEvdevMultitouch->num_vals, atoms);
+            XIChangeDeviceProperty(dev, prop_axis_label, XA_ATOM, 32,
+                                   PropModeReplace, pEvdevMultitouch->num_vals, atoms, FALSE);
+            XISetDevicePropertyDeletable(dev, prop_axis_label, FALSE);
+        }
+        /* Button labelling */
+        if ((pEvdevMultitouch->num_buttons > 0) && (prop_btn_label = XIGetKnownProperty(BTN_LABEL_PROP)))
+        {
+            Atom atoms[EVDEVMULTITOUCH_MAXBUTTONS];
+            EvdevMultitouchInitButtonLabels(pEvdevMultitouch, EVDEVMULTITOUCH_MAXBUTTONS, atoms);
+            XIChangeDeviceProperty(dev, prop_btn_label, XA_ATOM, 32,
+                                   PropModeReplace, pEvdevMultitouch->num_buttons, atoms, FALSE);
+            XISetDevicePropertyDeletable(dev, prop_btn_label, FALSE);
+        }
+#endif /* HAVE_LABELS */
+    }
+
+}
+
+static void EvdevMultitouchSwapAxes(EvdevMultitouchPtr pEvdevMultitouch)
+{
+    if(pEvdevMultitouch->swap_axes)
+    {
+       pEvdevMultitouch->absinfo[ABS_Y].maximum = pEvdevMultitouch->resolution.max_x;
+       pEvdevMultitouch->absinfo[ABS_Y].minimum = pEvdevMultitouch->resolution.min_x;
+       pEvdevMultitouch->absinfo[ABS_X].maximum = pEvdevMultitouch->resolution.max_y;
+       pEvdevMultitouch->absinfo[ABS_X].minimum = pEvdevMultitouch->resolution.min_y;
+    }
+    else
+    {
+       pEvdevMultitouch->absinfo[ABS_X].maximum = pEvdevMultitouch->resolution.max_x;
+       pEvdevMultitouch->absinfo[ABS_X].minimum = pEvdevMultitouch->resolution.min_x;
+       pEvdevMultitouch->absinfo[ABS_Y].maximum = pEvdevMultitouch->resolution.max_y;
+       pEvdevMultitouch->absinfo[ABS_Y].minimum = pEvdevMultitouch->resolution.min_y;
+    }
+}
+
+static int
+EvdevMultitouchSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+                 BOOL checkonly)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevMultitouchPtr     pEvdevMultitouch = 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;
+            pEvdevMultitouch->invert_x = data[0];
+            pEvdevMultitouch->invert_y = data[1];
+        }
+    } else if (atom == prop_reopen)
+    {
+        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly)
+            pEvdevMultitouch->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)
+            EvdevMultitouchSetCalibration(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)
+            pEvdevMultitouch->swap_axes = *((BOOL*)val->data);
+        EvdevMultitouchSwapAxes(pEvdevMultitouch);
+    } else if (atom == prop_axis_label || atom == prop_btn_label)
+        return BadAccess; /* Axis/Button labels can't be changed */
+    else if (atom == prop_tracking_id)
+    {
+        if (val->format != 32 || val->type != XA_INTEGER || val->size != 1)
+            return BadMatch;
+
+        if (!checkonly)
+            pEvdevMultitouch->id = *((int*)val->data);
+    } else if (atom == prop_multitouch)
+    {
+        BOOL data;
+        if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+            return BadMatch;
+        if (!checkonly) {
+            data = *((BOOL*)val->data);
+            if (pEvdevMultitouch->num_multitouch != data)
+                EvdevMultitouchSetMultitouch(pInfo,data);
+        }
+    } else if (atom == prop_transform)
+    {
+        float *f;
+        if (val->format != 32 || val->type != XIGetKnownProperty(XATOM_FLOAT) || val->size != 9)
+            return BadMatch;
+        if (!checkonly) {
+            f = (float*)val->data;
+            EvdevMultitouchSetTransform(pInfo, val->size, f);
+        }
+    }
+    else if (atom == prop_grabinfo)
+    {
+        BOOL data;
+        if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+            return BadMatch;
+        if (!checkonly) {
+            data = *((BOOL*)val->data);
+            EvdevMultitouchGetGrabInfo(pInfo, (BOOL)data);
+        }
+    }
+
+    return Success;
+}
+#endif
+
+/* Duplicate xf86 options and convert them to InputOption */
+static InputOption *EvdevMultitouchOptionDupConvert(pointer original)
+{
+    InputOption *iopts = NULL, *new;
+    InputInfoRec dummy;
+
+    memset(&dummy, 0, sizeof(dummy));
+    dummy.options = xf86OptionListDuplicate(original);
+
+    while(dummy.options)
+    {
+        new = calloc(1, sizeof(struct _InputOption));
+
+        new->opt_name = xf86OptionName(dummy.options);
+        new->opt_val = xf86OptionValue(dummy.options);
+        new->list.next = iopts;
+        iopts = new;
+        dummy.options = xf86NextOption(dummy.options);
+    }
+
+    return iopts;
+}
+static void EvdevMultitouchFreeInputOpts(InputOption* opts)
+{
+    InputOption *tmp = opts;
+
+    while(opts)
+    {
+        tmp = opts->list.next;
+        free(opts->opt_name);
+        free(opts->opt_val);
+        free(opts);
+        opts = tmp;
+    }
+}
+static void EvdevMultitouchReplaceOption(InputOption *opts,const char* key, char * value)
+{
+
+    while(opts)
+    {
+        if (xf86NameCmp(opts->opt_name, key) == 0)
+        {
+
+            free(opts->opt_val);
+            opts->opt_val = strdup(value);
+        }
+        opts = opts->list.next;
+    }
+}
+
+/**
+ * New device creation through xorg/input
+ *
+ * @return 0 if successful, 1 if failure
+ */
+static InputInfoPtr
+EvdevMultitouchCreateSubDevice(InputInfoPtr pInfo, int id) {
+    InputInfoPtr pSubdev;
+
+    DeviceIntPtr dev; /* dummy */
+    InputOption *input_options = NULL;
+    InputOption *iopts = NULL;
+    char* name;
+
+    pInfo->options = xf86AddNewOption(pInfo->options, "Type", "core");
+    pInfo->options = xf86AddNewOption(pInfo->options, "SendCoreEvents", "off");
+
+    /* Create new device */
+    input_options = EvdevMultitouchOptionDupConvert(pInfo->options);
+    EvdevMultitouchReplaceOption(input_options, "type","Object");
+    EvdevMultitouchReplaceOption(input_options, "MultiTouch","1");
+
+    name = malloc( (strlen(pInfo->name) + strlen(" subdev ") + 20 )*sizeof(char)); // 20 for adding the id
+
+    if( !name )
+    {
+        EvdevMultitouchFreeInputOpts(input_options);
+        xf86DrvMsg(-1, X_ERROR, "[X11][%s] Failed to allocate memory !\n", __FUNCTION__);
+        return NULL;
+    }
+
+    sprintf(name, "%s subdev %i", pInfo->name, id);
+    EvdevMultitouchReplaceOption(input_options, "name",name);
+
+    pCreatorInfo = pInfo;
+    NewInputDeviceRequest(input_options, NULL, &dev);
+    pSubdev = dev->public.devicePrivate;
+    pCreatorInfo = NULL;
+
+    EvdevMultitouchFreeInputOpts(input_options);
+
+    free(name);
+    return pSubdev;
+}
+
+static void
+EvdevMultitouchDeleteSubDevice(InputInfoPtr pInfo, InputInfoPtr subdev)
+{
+    /* We need to explicitely flush the events so as not deleting
+     * a device that still has events in queue
+     */
+    xf86Msg(X_INFO, "%s: Removing subdevice %s\n", pInfo->name,subdev->name);
+    DeleteInputDeviceRequest(subdev->dev);
+}
diff --git a/src/evdevmultitouch.h b/src/evdevmultitouch.h
new file mode 100755 (executable)
index 0000000..6ae4ab0
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * xserver-xorg-input-evdev-multitouch
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Sung-Jin Park <sj76.park@samsung.com>
+ *          Sangjin LEE <lsj119@samsung.com>
+ *
+ * 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 © 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)
+ *     Benjamin Tissoires (tissoire@cena.fr)
+ */
+
+#ifndef EVDEVMULTITOUCH_H
+#define EVDEVMULTITOUCH_H
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+#include <xf86Xinput.h>
+#include <xf86_OSproc.h>
+#include <xkbstr.h>
+
+#include <math.h>
+#include <pixman.h>
+
+#ifdef _F_GESTURE_EXTENSION_
+typedef enum _MTSyncType
+{
+       MTOUCH_FRAME_SYNC_END,
+       MTOUCH_FRAME_SYNC_BEGIN
+} MTSyncType;
+
+enum EventType
+{
+    ET_MTSync = 0x7E,
+    ET_Internal = 0xFF /* First byte */
+};
+
+typedef struct _AnyEvent AnyEvent;
+struct _AnyEvent
+{
+    unsigned char header; /**< Always ET_Internal */
+    enum EventType type;  /**< One of EventType */
+    int length;           /**< Length in bytes */
+    Time time;            /**< Time in ms */
+    int deviceid;
+    MTSyncType sync;
+    int x;
+    int y;
+};
+
+union _InternalEvent {
+       struct {
+           unsigned char header; /**< Always ET_Internal */
+           enum EventType type;  /**< One of ET_* */
+           int length;           /**< Length in bytes */
+           Time time;            /**< Time in ms. */
+       } any;
+       AnyEvent any_event;
+};
+#endif//_F_GESTURE_EXTENSION_
+
+#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 EVDEVMULTITOUCH_MAXBUTTONS 32
+#define EVDEVMULTITOUCH_MAXQUEUE 32
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
+#define HAVE_PROPERTIES 1
+#endif
+
+#ifndef MAX_VALUATORS
+#define MAX_VALUATORS 36
+#endif
+
+#define MAX_VALUATORS_MT 10
+#define DEFAULT_TIMEOUT 100
+
+#define EVDEVMULTITOUCH_PROP_TRACKING_ID "EvdevMultitouch Tracking ID"
+#define EVDEVMULTITOUCH_PROP_MULTITOUCH_SUBDEVICES "EvdevMultitouch MultiTouch"
+#define EVDEVMULTITOUCH_PROP_TRANSFORM "EvdevMultitouch Transform Matrix"
+#define EVDEVMULTITOUCH_PROP_GRABINFO  "EvdevMultitouch Grab Info"
+
+#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 _EvdevMultitouchDataMTRec{
+    int id;
+    int slot;
+    int abs;
+   BOOL containsValues;
+    Time expires;
+    int vals[MAX_VALUATORS];
+    InputInfoPtr pInfo;
+} EvdevMultitouchDataMTRec, *EvdevMultitouchDataMTPtr;
+
+
+/**
+ * EvdevMultitouch device information, including list of current object
+ */
+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 evdevmultitouch <axis> to index */
+    int vals[MAX_VALUATORS];
+    int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
+    EvdevMultitouchDataMTRec vals_mt[MAX_VALUATORS_MT];
+
+    int flags;
+    int tool;
+    int num_buttons;            /* number of buttons */
+    BOOL swap_axes;
+    BOOL invert_x;
+    BOOL invert_y;
+    int num_multitouch;
+    OsTimerPtr multitouch_setting_timer;
+
+    int delta[REL_CNT];
+    unsigned int abs, rel, mt;
+
+    /* 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[EVDEVMULTITOUCH_MAXBUTTONS];  /* specify a meta/lock pair */
+       BOOL                lock_state[EVDEVMULTITOUCH_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[EVDEVMULTITOUCH_MAXQUEUE];
+
+    Time timeout; /* Maximum difference between consecutive fseq values
+                           that will allow a packet to be dropped */
+    
+    OsTimerPtr subdevice_timer;
+    int current_id;
+    int num_mt;
+    int id;
+    int last_slot;
+    BOOL mt_slot_supported;
+    BOOL sync_mt;
+    BOOL associated;
+
+    float transform[9];
+    BOOL use_transform;
+    struct pixman_transform inv_transform;
+
+    int touch_state;
+    Time evtime;
+    InputInfoPtr core_device;
+    
+} EvdevMultitouchRec, *EvdevMultitouchPtr;
+
+/* Event posting functions */
+void EvdevMultitouchQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value);
+void EvdevMultitouchQueueButtonEvent(InputInfoPtr pInfo, int button, int value);
+void EvdevMultitouchPostButtonEvent(InputInfoPtr pInfo, int button, int value);
+void EvdevMultitouchQueueButtonClicks(InputInfoPtr pInfo, int button, int count);
+void EvdevMultitouchPostRelativeMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+                                  int v[MAX_VALUATORS]);
+void EvdevMultitouchPostAbsoluteMotionEvents(InputInfoPtr pInfo, int *num_v, int *first_v,
+                                  int v[MAX_VALUATORS]);
+unsigned int EvdevMultitouchUtilButtonEventToButtonNumber(EvdevMultitouchPtr pEvdevMultitouch, int code);
+
+/* Middle Button emulation */
+int  EvdevMultitouchMBEmuTimer(InputInfoPtr);
+BOOL EvdevMultitouchMBEmuFilterEvent(InputInfoPtr, int, BOOL);
+void EvdevMultitouchMBEmuWakeupHandler(pointer, int, pointer);
+void EvdevMultitouchMBEmuBlockHandler(pointer, struct timeval**, pointer);
+void EvdevMultitouchMBEmuPreInit(InputInfoPtr);
+void EvdevMultitouchMBEmuOn(InputInfoPtr);
+void EvdevMultitouchMBEmuFinalize(InputInfoPtr);
+void EvdevMultitouchMBEmuEnable(InputInfoPtr, BOOL);
+
+/* Mouse Wheel emulation */
+void EvdevMultitouchWheelEmuPreInit(InputInfoPtr pInfo);
+BOOL EvdevMultitouchWheelEmuFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
+BOOL EvdevMultitouchWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
+
+/* Draglock code */
+void EvdevMultitouchDragLockPreInit(InputInfoPtr pInfo);
+BOOL EvdevMultitouchDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
+
+#ifdef HAVE_PROPERTIES
+void EvdevMultitouchMBEmuInitProperty(DeviceIntPtr);
+void EvdevMultitouchWheelEmuInitProperty(DeviceIntPtr);
+void EvdevMultitouchDragLockInitProperty(DeviceIntPtr);
+#endif
+#endif
diff --git a/xorg-evdev-multitouch.pc.in b/xorg-evdev-multitouch.pc.in
new file mode 100644 (file)
index 0000000..cd92664
--- /dev/null
@@ -0,0 +1,6 @@
+sdkdir=@sdkdir@
+
+Name: xorg-evdev-multitouch
+Description: X.Org evdev multitouch input driver.
+Version: @PACKAGE_VERSION@
+Cflags: -I${sdkdir}