summaryrefslogtreecommitdiff
path: root/driver/xf86-input-synaptics/src
diff options
context:
space:
mode:
authorAlexandr Shadchin <shadchin@cvs.openbsd.org>2011-04-09 08:38:43 +0000
committerAlexandr Shadchin <shadchin@cvs.openbsd.org>2011-04-09 08:38:43 +0000
commitd7e280ac3a05f25fa5b098f203aa40e92d040a5d (patch)
treee716a94142e8509677a0147ad6242d5072351dc8 /driver/xf86-input-synaptics/src
parentb9f5f7ebfd9cf7882a73f6072406855aae88cc9e (diff)
Import xf86-input-synaptics 1.4.0
ok matthieu@
Diffstat (limited to 'driver/xf86-input-synaptics/src')
-rw-r--r--driver/xf86-input-synaptics/src/Makefile.am49
-rw-r--r--driver/xf86-input-synaptics/src/Makefile.in547
-rw-r--r--driver/xf86-input-synaptics/src/alpscomm.c237
-rw-r--r--driver/xf86-input-synaptics/src/alpscomm.h33
-rw-r--r--driver/xf86-input-synaptics/src/eventcomm.c499
-rw-r--r--driver/xf86-input-synaptics/src/eventcomm.h37
-rw-r--r--driver/xf86-input-synaptics/src/properties.c673
-rw-r--r--driver/xf86-input-synaptics/src/ps2comm.c676
-rw-r--r--driver/xf86-input-synaptics/src/ps2comm.h103
-rw-r--r--driver/xf86-input-synaptics/src/psmcomm.c185
-rw-r--r--driver/xf86-input-synaptics/src/synaptics.c2661
-rw-r--r--driver/xf86-input-synaptics/src/synapticsstr.h249
-rw-r--r--driver/xf86-input-synaptics/src/synproto.h106
13 files changed, 6055 insertions, 0 deletions
diff --git a/driver/xf86-input-synaptics/src/Makefile.am b/driver/xf86-input-synaptics/src/Makefile.am
new file mode 100644
index 000000000..980ab5ef7
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/Makefile.am
@@ -0,0 +1,49 @@
+# 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.
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS = $(XORG_CFLAGS)
+
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c synapticsstr.h \
+ alpscomm.c alpscomm.h \
+ ps2comm.c ps2comm.h \
+ synproto.h \
+ properties.c
+
+if BUILD_EVENTCOMM
+@DRIVER_NAME@_drv_la_SOURCES += \
+ eventcomm.c eventcomm.h
+endif
+
+if BUILD_PSMCOMM
+@DRIVER_NAME@_drv_la_SOURCES += \
+ psmcomm.c
+endif
+
diff --git a/driver/xf86-input-synaptics/src/Makefile.in b/driver/xf86-input-synaptics/src/Makefile.in
new file mode 100644
index 000000000..0e170333f
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/Makefile.in
@@ -0,0 +1,547 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# 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.
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BUILD_EVENTCOMM_TRUE@am__append_1 = \
+@BUILD_EVENTCOMM_TRUE@ eventcomm.c eventcomm.h
+
+@BUILD_PSMCOMM_TRUE@am__append_2 = \
+@BUILD_PSMCOMM_TRUE@ psmcomm.c
+
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)"
+@DRIVER_NAME@_drv_laLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(@DRIVER_NAME@_drv_la_LTLIBRARIES)
+@DRIVER_NAME@_drv_la_LIBADD =
+am__@DRIVER_NAME@_drv_la_SOURCES_DIST = @DRIVER_NAME@.c synapticsstr.h \
+ alpscomm.c alpscomm.h ps2comm.c ps2comm.h synproto.h \
+ properties.c eventcomm.c eventcomm.h psmcomm.c
+@BUILD_EVENTCOMM_TRUE@am__objects_1 = eventcomm.lo
+@BUILD_PSMCOMM_TRUE@am__objects_2 = psmcomm.lo
+am_@DRIVER_NAME@_drv_la_OBJECTS = @DRIVER_NAME@.lo alpscomm.lo \
+ ps2comm.lo properties.lo $(am__objects_1) $(am__objects_2)
+@DRIVER_NAME@_drv_la_OBJECTS = $(am_@DRIVER_NAME@_drv_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(@DRIVER_NAME@_drv_la_SOURCES)
+DIST_SOURCES = $(am__@DRIVER_NAME@_drv_la_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADMIN_MAN_DIR = @ADMIN_MAN_DIR@
+ADMIN_MAN_SUFFIX = @ADMIN_MAN_SUFFIX@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APP_MAN_DIR = @APP_MAN_DIR@
+APP_MAN_SUFFIX = @APP_MAN_SUFFIX@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EVENTCOMM_FALSE = @BUILD_EVENTCOMM_FALSE@
+BUILD_EVENTCOMM_TRUE = @BUILD_EVENTCOMM_TRUE@
+BUILD_PSMCOMM_FALSE = @BUILD_PSMCOMM_FALSE@
+BUILD_PSMCOMM_TRUE = @BUILD_PSMCOMM_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHANGELOG_CMD = @CHANGELOG_CMD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CWARNFLAGS = @CWARNFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_FALSE = @DEBUG_FALSE@
+DEBUG_TRUE = @DEBUG_TRUE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DRIVER_MAN_DIR = @DRIVER_MAN_DIR@
+DRIVER_MAN_SUFFIX = @DRIVER_MAN_SUFFIX@
+DRIVER_NAME = @DRIVER_NAME@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FILE_MAN_DIR = @FILE_MAN_DIR@
+FILE_MAN_SUFFIX = @FILE_MAN_SUFFIX@
+GREP = @GREP@
+HAS_XORG_CONF_DIR_FALSE = @HAS_XORG_CONF_DIR_FALSE@
+HAS_XORG_CONF_DIR_TRUE = @HAS_XORG_CONF_DIR_TRUE@
+INSTALL_CMD = @INSTALL_CMD@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIB_MAN_DIR = @LIB_MAN_DIR@
+LIB_MAN_SUFFIX = @LIB_MAN_SUFFIX@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MAN_SUBSTS = @MAN_SUBSTS@
+MISC_MAN_DIR = @MISC_MAN_DIR@
+MISC_MAN_SUFFIX = @MISC_MAN_SUFFIX@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XI_CFLAGS = @XI_CFLAGS@
+XI_LIBS = @XI_LIBS@
+XORG_CFLAGS = @XORG_CFLAGS@
+XORG_LIBS = @XORG_LIBS@
+XORG_MAN_PAGE = @XORG_MAN_PAGE@
+XTST_CFLAGS = @XTST_CFLAGS@
+XTST_LIBS = @XTST_LIBS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+configdir = @configdir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+inputdir = @inputdir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sdkdir = @sdkdir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+# 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.
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CFLAGS = $(XORG_CFLAGS)
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c synapticsstr.h \
+ alpscomm.c alpscomm.h ps2comm.c ps2comm.h synproto.h \
+ properties.c $(am__append_1) $(am__append_2)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-@DRIVER_NAME@_drv_laLTLIBRARIES: $(@DRIVER_NAME@_drv_la_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(@DRIVER_NAME@_drv_ladir)" || $(mkdir_p) "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)"
+ @list='$(@DRIVER_NAME@_drv_la_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(@DRIVER_NAME@_drv_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(@DRIVER_NAME@_drv_laLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-@DRIVER_NAME@_drv_laLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(@DRIVER_NAME@_drv_la_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)/$$p"; \
+ done
+
+clean-@DRIVER_NAME@_drv_laLTLIBRARIES:
+ -test -z "$(@DRIVER_NAME@_drv_la_LTLIBRARIES)" || rm -f $(@DRIVER_NAME@_drv_la_LTLIBRARIES)
+ @list='$(@DRIVER_NAME@_drv_la_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+@DRIVER_NAME@_drv.la: $(@DRIVER_NAME@_drv_la_OBJECTS) $(@DRIVER_NAME@_drv_la_DEPENDENCIES)
+ $(LINK) -rpath $(@DRIVER_NAME@_drv_ladir) $(@DRIVER_NAME@_drv_la_LDFLAGS) $(@DRIVER_NAME@_drv_la_OBJECTS) $(@DRIVER_NAME@_drv_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/@DRIVER_NAME@.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alpscomm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eventcomm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/properties.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ps2comm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psmcomm.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(@DRIVER_NAME@_drv_ladir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-@DRIVER_NAME@_drv_laLTLIBRARIES clean-generic \
+ clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-@DRIVER_NAME@_drv_laLTLIBRARIES
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-@DRIVER_NAME@_drv_laLTLIBRARIES \
+ uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean \
+ clean-@DRIVER_NAME@_drv_laLTLIBRARIES clean-generic \
+ clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install \
+ install-@DRIVER_NAME@_drv_laLTLIBRARIES install-am \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-@DRIVER_NAME@_drv_laLTLIBRARIES \
+ uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/driver/xf86-input-synaptics/src/alpscomm.c b/driver/xf86-input-synaptics/src/alpscomm.c
new file mode 100644
index 000000000..84d213656
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/alpscomm.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2001 Stefan Gmeiner
+ * Copyright © 2003 Neil Brown
+ * Copyright © 2003-2005,2007 Peter Osterlund
+ *
+ * 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:
+ * Stefan Gmeiner (riddlebox@freesurf.ch)
+ * Neil Brown (neilb@cse.unsw.edu.au)
+ * Peter Osterlund (petero2@telia.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include "alpscomm.h"
+#include "synproto.h"
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include <xf86.h>
+
+
+/* Wait for the channel to go silent, which means we're in sync */
+static void
+ALPS_sync(int fd)
+{
+ byte buffer[64];
+ while (xf86WaitForInput(fd, 250000) > 0) {
+ xf86ReadSerial(fd, &buffer, 64);
+ }
+}
+
+/*
+ * send the ALPS init sequence, ie 4 consecutive "disable"s before the "enable"
+ * This "magic knock" is performed both for the trackpad and for the pointing
+ * stick. Not all models have a pointing stick, but trying to initialize it
+ * anyway doesn't seem to hurt.
+ */
+static void
+ALPS_initialize(int fd)
+{
+ xf86FlushInput(fd);
+ ps2_putbyte(fd, PS2_CMD_SET_DEFAULT);
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1);
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1);
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_2_1);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_ENABLE);
+
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1);
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1);
+ ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_DISABLE);
+ ps2_putbyte(fd, PS2_CMD_ENABLE);
+
+ ALPS_sync(fd);
+}
+
+static Bool
+ALPSQueryHardware(InputInfoPtr pInfo)
+{
+ ALPS_initialize(pInfo->fd);
+ return TRUE;
+}
+
+static Bool
+ALPS_packet_ok(struct CommData *comm)
+{
+ /* ALPS absolute mode packets start with 0b11111mrl */
+ if ((comm->protoBuf[0] & 0xf8) == 0xf8)
+ return TRUE;
+ return FALSE;
+}
+
+static Bool
+ALPS_get_packet(struct CommData *comm, InputInfoPtr pInfo)
+{
+ int c;
+
+ while ((c = XisbRead(comm->buffer)) >= 0) {
+ unsigned char u = (unsigned char)c;
+
+ comm->protoBuf[comm->protoBufTail++] = u;
+
+ if (comm->protoBufTail == 3) { /* PS/2 packet received? */
+ if ((comm->protoBuf[0] & 0xc8) == 0x08) {
+ comm->protoBufTail = 0;
+ return TRUE;
+ }
+ }
+
+ if (comm->protoBufTail >= 6) { /* Full packet received */
+ comm->protoBufTail = 0;
+ if (ALPS_packet_ok(comm))
+ return TRUE;
+ while ((c = XisbRead(comm->buffer)) >= 0)
+ ; /* If packet is invalid, re-sync */
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * ALPS abolute Mode
+ * byte 0: 1 1 1 1 1 mid0 rig0 lef0
+ * byte 1: 0 x6 x5 x4 x3 x2 x1 x0
+ * byte 2: 0 x10 x9 x8 x7 up1 fin ges
+ * byte 3: 0 y9 y8 y7 1 mid1 rig1 lef1
+ * byte 4: 0 y6 y5 y4 y3 y2 y1 y0
+ * byte 5: 0 z6 z5 z4 z3 z2 z1 z0
+ *
+ * On a dualpoint, {mid,rig,lef}0 are the stick, 1 are the pad.
+ * We just 'or' them together for now.
+ *
+ * The touchpad on an 'Acer Aspire' has 4 buttons:
+ * left,right,up,down.
+ * This device always sets {mid,rig,lef}0 to 1 and
+ * reflects left,right,down,up in lef1,rig1,mid1,up1.
+ */
+static void
+ALPS_process_packet(unsigned char *packet, struct SynapticsHwState *hw)
+{
+ int x = 0, y = 0, z = 0;
+ int left = 0, right = 0, middle = 0;
+ int i;
+
+ x = (packet[1] & 0x7f) | ((packet[2] & 0x78) << (7-3));
+ y = (packet[4] & 0x7f) | ((packet[3] & 0x70) << (7-4));
+ z = packet[5];
+
+ if (z == 127) { /* DualPoint stick is relative, not absolute */
+ hw->left = packet[3] & 1;
+ hw->right = (packet[3] >> 1) & 1;
+ return;
+ }
+
+ /* Handle normal packets */
+ hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0;
+ hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE;
+ for (i = 0; i < 8; i++)
+ hw->multi[i] = FALSE;
+
+ if (z > 0) {
+ hw->x = x;
+ hw->y = y;
+ }
+ hw->z = z;
+ hw->numFingers = (z > 0) ? 1 : 0;
+ hw->fingerWidth = 5;
+
+ left |= (packet[2] ) & 1;
+ left |= (packet[3] ) & 1;
+ right |= (packet[3] >> 1) & 1;
+ if (packet[0] == 0xff) {
+ int back = (packet[3] >> 2) & 1;
+ int forward = (packet[2] >> 2) & 1;
+ if (back && forward) {
+ middle = 1;
+ back = 0;
+ forward = 0;
+ }
+ hw->down = back;
+ hw->up = forward;
+ } else {
+ left |= (packet[0] ) & 1;
+ right |= (packet[0] >> 1) & 1;
+ middle |= (packet[0] >> 2) & 1;
+ middle |= (packet[3] >> 2) & 1;
+ }
+
+ hw->left = left;
+ hw->right = right;
+ hw->middle = middle;
+}
+
+static Bool
+ALPSReadHwState(InputInfoPtr pInfo,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm, struct SynapticsHwState *hwRet)
+{
+ unsigned char *buf = comm->protoBuf;
+ struct SynapticsHwState *hw = &(comm->hwState);
+
+ if (!ALPS_get_packet(comm, pInfo))
+ return FALSE;
+
+ ALPS_process_packet(buf, hw);
+
+ *hwRet = *hw;
+ return TRUE;
+}
+
+static Bool
+ALPSAutoDevProbe(InputInfoPtr pInfo)
+{
+ return FALSE;
+}
+
+struct SynapticsProtocolOperations alps_proto_operations = {
+ NULL,
+ NULL,
+ ALPSQueryHardware,
+ ALPSReadHwState,
+ ALPSAutoDevProbe,
+ SynapticsDefaultDimensions
+};
diff --git a/driver/xf86-input-synaptics/src/alpscomm.h b/driver/xf86-input-synaptics/src/alpscomm.h
new file mode 100644
index 000000000..547cf72ba
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/alpscomm.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2004 Peter Osterlund
+ *
+ * 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 Osterlund (petero2@telia.com)
+ */
+
+#ifndef _ALPSCOMM_H_
+#define _ALPSCOMM_H_
+
+#include "ps2comm.h"
+
+
+#endif /* _ALPSCOMM_H_ */
diff --git a/driver/xf86-input-synaptics/src/eventcomm.c b/driver/xf86-input-synaptics/src/eventcomm.c
new file mode 100644
index 000000000..1a31c544f
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/eventcomm.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright © 2004-2007 Peter Osterlund
+ *
+ * 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 Osterlund (petero2@telia.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include "eventcomm.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+#include "synproto.h"
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include <xf86.h>
+
+
+#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
+
+#define LONG_BITS (sizeof(long) * 8)
+#define NBITS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
+#define OFF(x) ((x) % LONG_BITS)
+#define LONG(x) ((x) / LONG_BITS)
+#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+/*****************************************************************************
+ * Function Definitions
+ ****************************************************************************/
+
+static void
+EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ BOOL *need_grab;
+
+ if (!priv->proto_data)
+ priv->proto_data = calloc(1, sizeof(BOOL));
+
+ need_grab = (BOOL*)priv->proto_data;
+
+ if (para->grab_event_device) {
+ /* Try to grab the event device so that data don't leak to /dev/input/mice */
+ int ret;
+ SYSCALL(ret = ioctl(pInfo->fd, EVIOCGRAB, (pointer)1));
+ if (ret < 0) {
+ xf86Msg(X_WARNING, "%s can't grab event device, errno=%d\n",
+ pInfo->name, errno);
+ }
+ }
+
+ *need_grab = FALSE;
+}
+
+static Bool
+event_query_is_touchpad(int fd, BOOL grab)
+{
+ int ret = FALSE, rc;
+ unsigned long evbits[NBITS(EV_MAX)] = {0};
+ unsigned long absbits[NBITS(ABS_MAX)] = {0};
+ unsigned long keybits[NBITS(KEY_MAX)] = {0};
+
+ if (grab)
+ {
+ SYSCALL(rc = ioctl(fd, EVIOCGRAB, (pointer)1));
+ if (rc < 0)
+ return FALSE;
+ }
+
+ /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */
+
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(0, sizeof(evbits)), evbits));
+ if (rc < 0)
+ goto unwind;
+ if (!TEST_BIT(EV_SYN, evbits) ||
+ !TEST_BIT(EV_ABS, evbits) ||
+ !TEST_BIT(EV_KEY, evbits))
+ goto unwind;
+
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
+ if (rc < 0)
+ goto unwind;
+ if (!TEST_BIT(ABS_X, absbits) ||
+ !TEST_BIT(ABS_Y, absbits))
+ goto unwind;
+
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
+ if (rc < 0)
+ goto unwind;
+
+ /* we expect touchpad either report raw pressure or touches */
+ if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits))
+ goto unwind;
+ /* all Synaptics-like touchpad report BTN_TOOL_FINGER */
+ if (!TEST_BIT(BTN_TOOL_FINGER, keybits))
+ goto unwind;
+ if (TEST_BIT(BTN_TOOL_PEN, keybits))
+ goto unwind; /* Don't match wacom tablets */
+
+ ret = TRUE;
+
+unwind:
+ if (grab)
+ SYSCALL(ioctl(fd, EVIOCGRAB, (pointer)0));
+
+ return (ret == TRUE);
+}
+
+typedef struct {
+ short vendor;
+ short product;
+ enum TouchpadModel model;
+} model_lookup_t;
+#define PRODUCT_ANY 0x0000
+
+static model_lookup_t model_lookup_table[] = {
+ {0x0002, 0x0007, MODEL_SYNAPTICS},
+ {0x0002, 0x0008, MODEL_ALPS},
+ {0x05ac, PRODUCT_ANY, MODEL_APPLETOUCH},
+ {0x0, 0x0, 0x0}
+};
+
+static void
+event_query_info(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ short id[4];
+ int rc;
+ model_lookup_t *model_lookup;
+
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGID, id));
+ if (rc < 0)
+ return;
+
+ for(model_lookup = model_lookup_table; model_lookup->vendor; model_lookup++) {
+ if(model_lookup->vendor == id[ID_VENDOR] &&
+ (model_lookup->product == id[ID_PRODUCT] || model_lookup->product == PRODUCT_ANY))
+ priv->model = model_lookup->model;
+ }
+}
+
+/* Query device for axis ranges */
+static void
+event_query_axis_ranges(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ struct input_absinfo abs = {0};
+ unsigned long absbits[NBITS(ABS_MAX)] = {0};
+ unsigned long keybits[NBITS(KEY_MAX)] = {0};
+ char buf[256];
+ int rc;
+
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_X), &abs));
+ if (rc >= 0)
+ {
+ xf86Msg(X_PROBED, "%s: x-axis range %d - %d\n", pInfo->name,
+ abs.minimum, abs.maximum);
+ priv->minx = abs.minimum;
+ priv->maxx = abs.maximum;
+ /* The kernel's fuzziness concept seems a bit weird, but it can more or
+ * less be applied as hysteresis directly, i.e. no factor here. Though,
+ * we don't trust a zero fuzz as it probably is just a lazy value. */
+ if (abs.fuzz > 0)
+ priv->synpara.hyst_x = abs.fuzz;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
+ priv->resx = abs.resolution;
+#endif
+ } else
+ xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
+ strerror(errno));
+
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_Y), &abs));
+ if (rc >= 0)
+ {
+ xf86Msg(X_PROBED, "%s: y-axis range %d - %d\n", pInfo->name,
+ abs.minimum, abs.maximum);
+ priv->miny = abs.minimum;
+ priv->maxy = abs.maximum;
+ /* don't trust a zero fuzz */
+ if (abs.fuzz > 0)
+ priv->synpara.hyst_y = abs.fuzz;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
+ priv->resy = abs.resolution;
+#endif
+ } else
+ xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", pInfo->name,
+ strerror(errno));
+
+ priv->has_pressure = FALSE;
+ priv->has_width = FALSE;
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
+ if (rc >= 0)
+ {
+ priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
+ priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
+ }
+ else
+ xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", pInfo->name,
+ strerror(errno));
+
+ if (priv->has_pressure)
+ {
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_PRESSURE), &abs));
+ if (rc >= 0)
+ {
+ xf86Msg(X_PROBED, "%s: pressure range %d - %d\n", pInfo->name,
+ abs.minimum, abs.maximum);
+ priv->minp = abs.minimum;
+ priv->maxp = abs.maximum;
+ }
+ } else
+ xf86Msg(X_INFO,
+ "%s: device does not report pressure, will use touch data.\n",
+ pInfo->name);
+
+ if (priv->has_width)
+ {
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_TOOL_WIDTH), &abs));
+ if (rc >= 0)
+ {
+ xf86Msg(X_PROBED, "%s: finger width range %d - %d\n", pInfo->name,
+ abs.minimum, abs.maximum);
+ priv->minw = abs.minimum;
+ priv->maxw = abs.maximum;
+ }
+ }
+
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
+ if (rc >= 0)
+ {
+ buf[0] = 0;
+ if ((priv->has_left = (TEST_BIT(BTN_LEFT, keybits) != 0)))
+ strcat(buf, " left");
+ if ((priv->has_right = (TEST_BIT(BTN_RIGHT, keybits) != 0)))
+ strcat(buf, " right");
+ if ((priv->has_middle = (TEST_BIT(BTN_MIDDLE, keybits) != 0)))
+ strcat(buf, " middle");
+ if ((priv->has_double = (TEST_BIT(BTN_TOOL_DOUBLETAP, keybits) != 0)))
+ strcat(buf, " double");
+ if ((priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0)))
+ strcat(buf, " triple");
+
+ if ((TEST_BIT(BTN_0, keybits) != 0) ||
+ (TEST_BIT(BTN_1, keybits) != 0) ||
+ (TEST_BIT(BTN_2, keybits) != 0) ||
+ (TEST_BIT(BTN_3, keybits) != 0))
+ {
+ priv->has_scrollbuttons = 1;
+ strcat(buf, " scroll-buttons");
+ }
+
+ xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->name, buf);
+ }
+}
+
+static Bool
+EventQueryHardware(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ BOOL *need_grab = (BOOL*)priv->proto_data;
+
+ if (!event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
+ return FALSE;
+
+ xf86Msg(X_PROBED, "%s: touchpad found\n", pInfo->name);
+
+ return TRUE;
+}
+
+static Bool
+SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
+{
+ int rc = TRUE;
+ ssize_t len;
+
+ len = read(pInfo->fd, ev, sizeof(*ev));
+ if (len <= 0)
+ {
+ /* We use X_NONE here because it doesn't alloc */
+ if (errno != EAGAIN)
+ xf86MsgVerb(X_NONE, 0, "%s: Read error %s\n", pInfo->name, strerror(errno));
+ rc = FALSE;
+ } else if (len % sizeof(*ev)) {
+ xf86MsgVerb(X_NONE, 0, "%s: Read error, invalid number of bytes.", pInfo->name);
+ rc = FALSE;
+ }
+ return rc;
+}
+
+static Bool
+EventReadHwState(InputInfoPtr pInfo,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm, struct SynapticsHwState *hwRet)
+{
+ struct input_event ev;
+ Bool v;
+ struct SynapticsHwState *hw = &(comm->hwState);
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ SynapticsParameters *para = &priv->synpara;
+
+ while (SynapticsReadEvent(pInfo, &ev)) {
+ switch (ev.type) {
+ case EV_SYN:
+ switch (ev.code) {
+ case SYN_REPORT:
+ if (comm->oneFinger)
+ hw->numFingers = 1;
+ else if (comm->twoFingers)
+ hw->numFingers = 2;
+ else if (comm->threeFingers)
+ hw->numFingers = 3;
+ else
+ hw->numFingers = 0;
+ *hwRet = *hw;
+ return TRUE;
+ }
+ case EV_KEY:
+ v = (ev.value ? TRUE : FALSE);
+ switch (ev.code) {
+ case BTN_LEFT:
+ hw->left = v;
+ break;
+ case BTN_RIGHT:
+ hw->right = v;
+ break;
+ case BTN_MIDDLE:
+ hw->middle = v;
+ break;
+ case BTN_FORWARD:
+ hw->up = v;
+ break;
+ case BTN_BACK:
+ hw->down = v;
+ break;
+ case BTN_0:
+ hw->multi[0] = v;
+ break;
+ case BTN_1:
+ hw->multi[1] = v;
+ break;
+ case BTN_2:
+ hw->multi[2] = v;
+ break;
+ case BTN_3:
+ hw->multi[3] = v;
+ break;
+ case BTN_4:
+ hw->multi[4] = v;
+ break;
+ case BTN_5:
+ hw->multi[5] = v;
+ break;
+ case BTN_6:
+ hw->multi[6] = v;
+ break;
+ case BTN_7:
+ hw->multi[7] = v;
+ break;
+ case BTN_TOOL_FINGER:
+ comm->oneFinger = v;
+ break;
+ case BTN_TOOL_DOUBLETAP:
+ comm->twoFingers = v;
+ break;
+ case BTN_TOOL_TRIPLETAP:
+ comm->threeFingers = v;
+ break;
+ case BTN_TOUCH:
+ if (!priv->has_pressure)
+ hw->z = v ? para->finger_high + 1 : 0;
+ break;
+ }
+ break;
+ case EV_ABS:
+ switch (ev.code) {
+ case ABS_X:
+ hw->x = ev.value;
+ break;
+ case ABS_Y:
+ hw->y = ev.value;
+ break;
+ case ABS_PRESSURE:
+ hw->z = ev.value;
+ break;
+ case ABS_TOOL_WIDTH:
+ hw->fingerWidth = ev.value;
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+/* filter for the AutoDevProbe scandir on /dev/input */
+static int EventDevOnly(const struct dirent *dir) {
+ return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
+}
+
+/**
+ * Probe the open device for dimensions.
+ */
+static void
+EventReadDevDimensions(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ BOOL *need_grab = (BOOL*)priv->proto_data;
+
+ if (event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
+ event_query_axis_ranges(pInfo);
+ event_query_info(pInfo);
+}
+
+static Bool
+EventAutoDevProbe(InputInfoPtr pInfo)
+{
+ /* We are trying to find the right eventX device or fall back to
+ the psaux protocol and the given device from XF86Config */
+ int i;
+ Bool touchpad_found = FALSE;
+ struct dirent **namelist;
+
+ i = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort);
+ if (i < 0) {
+ xf86Msg(X_ERROR, "Couldn't open %s\n", DEV_INPUT_EVENT);
+ return FALSE;
+ }
+ else if (i == 0) {
+ xf86Msg(X_ERROR, "%s The /dev/input/event* device nodes seem to be missing\n",
+ pInfo->name);
+ free(namelist);
+ return FALSE;
+ }
+
+ while (i--) {
+ char fname[64];
+ int fd = -1;
+
+ if (!touchpad_found) {
+ sprintf(fname, "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
+ SYSCALL(fd = open(fname, O_RDONLY));
+ if (fd < 0)
+ continue;
+
+ if (event_query_is_touchpad(fd, TRUE)) {
+ touchpad_found = TRUE;
+ xf86Msg(X_PROBED, "%s auto-dev sets device to %s\n",
+ pInfo->name, fname);
+ pInfo->options =
+ xf86ReplaceStrOption(pInfo->options, "Device", fname);
+ }
+ SYSCALL(close(fd));
+ }
+ free(namelist[i]);
+ }
+ free(namelist);
+
+ if (!touchpad_found) {
+ xf86Msg(X_ERROR, "%s no synaptics event device found\n", pInfo->name);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+struct SynapticsProtocolOperations event_proto_operations = {
+ EventDeviceOnHook,
+ NULL,
+ EventQueryHardware,
+ EventReadHwState,
+ EventAutoDevProbe,
+ EventReadDevDimensions
+};
diff --git a/driver/xf86-input-synaptics/src/eventcomm.h b/driver/xf86-input-synaptics/src/eventcomm.h
new file mode 100644
index 000000000..8fd7bcbb0
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/eventcomm.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2004 Peter Osterlund
+ *
+ * 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 Osterlund (petero2@telia.com)
+ */
+
+#ifndef _EVENTCOMM_H_
+#define _EVENTCOMM_H_
+
+#include <linux/input.h>
+#include <linux/version.h>
+
+/* for auto-dev: */
+#define DEV_INPUT_EVENT "/dev/input"
+#define EVENT_DEV_NAME "event"
+
+#endif /* _EVENTCOMM_H_ */
diff --git a/driver/xf86-input-synaptics/src/properties.c b/driver/xf86-input-synaptics/src/properties.c
new file mode 100644
index 000000000..23b5a6a4c
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/properties.c
@@ -0,0 +1,673 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include "xf86Module.h"
+
+#include <X11/Xatom.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include "synaptics-properties.h"
+
+#ifndef XATOM_FLOAT
+#define XATOM_FLOAT "FLOAT"
+#endif
+static Atom float_type;
+
+Atom prop_edges = 0;
+Atom prop_finger = 0;
+Atom prop_tap_time = 0;
+Atom prop_tap_move = 0;
+Atom prop_tap_durations = 0;
+Atom prop_tap_fast = 0;
+Atom prop_middle_timeout = 0;
+Atom prop_twofinger_pressure = 0;
+Atom prop_twofinger_width = 0;
+Atom prop_scrolldist = 0;
+Atom prop_scrolledge = 0;
+Atom prop_scrolltwofinger = 0;
+Atom prop_speed = 0;
+Atom prop_edgemotion_pressure = 0;
+Atom prop_edgemotion_speed = 0;
+Atom prop_edgemotion_always = 0;
+Atom prop_buttonscroll = 0;
+Atom prop_buttonscroll_repeat = 0;
+Atom prop_buttonscroll_time = 0;
+Atom prop_off = 0;
+Atom prop_lockdrags = 0;
+Atom prop_lockdrags_time = 0;
+Atom prop_tapaction = 0;
+Atom prop_clickaction = 0;
+Atom prop_circscroll = 0;
+Atom prop_circscroll_dist = 0;
+Atom prop_circscroll_trigger = 0;
+Atom prop_circpad = 0;
+Atom prop_palm = 0;
+Atom prop_palm_dim = 0;
+Atom prop_coastspeed = 0;
+Atom prop_pressuremotion = 0;
+Atom prop_pressuremotion_factor = 0;
+Atom prop_grab = 0;
+Atom prop_gestures = 0;
+Atom prop_capabilities = 0;
+Atom prop_resolution = 0;
+Atom prop_area = 0;
+Atom prop_noise_cancellation = 0;
+
+static Atom
+InitAtom(DeviceIntPtr dev, char *name, int format, int nvalues, int *values)
+{
+ int i;
+ Atom atom;
+ uint8_t val_8[9]; /* we never have more than 9 values in an atom */
+ uint16_t val_16[9];
+ uint32_t val_32[9];
+ pointer converted;
+
+
+ for (i = 0; i < nvalues; i++)
+ {
+ switch(format)
+ {
+ case 8: val_8[i] = values[i]; break;
+ case 16: val_16[i] = values[i]; break;
+ case 32: val_32[i] = values[i]; break;
+ }
+ }
+
+ switch(format)
+ {
+ case 8: converted = val_8; break;
+ case 16: converted = val_16; break;
+ case 32: converted = val_32; break;
+ }
+
+ atom = MakeAtom(name, strlen(name), TRUE);
+ XIChangeDeviceProperty(dev, atom, XA_INTEGER, format,
+ PropModeReplace, nvalues,
+ converted, FALSE);
+ XISetDevicePropertyDeletable(dev, atom, FALSE);
+ return atom;
+}
+
+static Atom
+InitFloatAtom(DeviceIntPtr dev, char *name, int nvalues, float *values)
+{
+ Atom atom;
+
+ atom = MakeAtom(name, strlen(name), TRUE);
+ XIChangeDeviceProperty(dev, atom, float_type, 32, PropModeReplace,
+ nvalues, values, FALSE);
+ XISetDevicePropertyDeletable(dev, atom, FALSE);
+ return atom;
+}
+
+void
+InitDeviceProperties(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+ SynapticsParameters *para = &priv->synpara;
+ int values[9]; /* we never have more than 9 values in an atom */
+ float fvalues[4]; /* never have more than 4 float values */
+
+ float_type = XIGetKnownProperty(XATOM_FLOAT);
+ if (!float_type)
+ {
+ float_type = MakeAtom(XATOM_FLOAT, strlen(XATOM_FLOAT), TRUE);
+ if (!float_type)
+ {
+ xf86Msg(X_ERROR, "%s: Failed to init float atom. "
+ "Disabling property support.\n", pInfo->name);
+ return;
+ }
+ }
+
+ values[0] = para->left_edge;
+ values[1] = para->right_edge;
+ values[2] = para->top_edge;
+ values[3] = para->bottom_edge;
+
+ prop_edges = InitAtom(pInfo->dev, SYNAPTICS_PROP_EDGES, 32, 4, values);
+
+ values[0] = para->finger_low;
+ values[1] = para->finger_high;
+ values[2] = para->finger_press;
+
+ prop_finger = InitAtom(pInfo->dev, SYNAPTICS_PROP_FINGER, 32, 3, values);
+ prop_tap_time = InitAtom(pInfo->dev, SYNAPTICS_PROP_TAP_TIME, 32, 1, &para->tap_time);
+ prop_tap_move = InitAtom(pInfo->dev, SYNAPTICS_PROP_TAP_MOVE, 32, 1, &para->tap_move);
+
+ values[0] = para->single_tap_timeout;
+ values[1] = para->tap_time_2;
+ values[2] = para->click_time;
+
+ prop_tap_durations = InitAtom(pInfo->dev, SYNAPTICS_PROP_TAP_DURATIONS, 32, 3, values);
+ prop_tap_fast = InitAtom(pInfo->dev, SYNAPTICS_PROP_TAP_FAST, 8, 1, &para->fast_taps);
+ prop_middle_timeout = InitAtom(pInfo->dev, SYNAPTICS_PROP_MIDDLE_TIMEOUT,
+ 32, 1, &para->emulate_mid_button_time);
+ prop_twofinger_pressure = InitAtom(pInfo->dev, SYNAPTICS_PROP_TWOFINGER_PRESSURE,
+ 32, 1, &para->emulate_twofinger_z);
+ prop_twofinger_width = InitAtom(pInfo->dev, SYNAPTICS_PROP_TWOFINGER_WIDTH,
+ 32, 1, &para->emulate_twofinger_w);
+
+ values[0] = para->scroll_dist_vert;
+ values[1] = para->scroll_dist_horiz;
+ prop_scrolldist = InitAtom(pInfo->dev, SYNAPTICS_PROP_SCROLL_DISTANCE, 32, 2, values);
+
+ values[0] = para->scroll_edge_vert;
+ values[1] = para->scroll_edge_horiz;
+ values[2] = para->scroll_edge_corner;
+ prop_scrolledge = InitAtom(pInfo->dev, SYNAPTICS_PROP_SCROLL_EDGE,8, 3, values);
+ values[0] = para->scroll_twofinger_vert;
+ values[1] = para->scroll_twofinger_horiz;
+ prop_scrolltwofinger = InitAtom(pInfo->dev, SYNAPTICS_PROP_SCROLL_TWOFINGER,8, 2, values);
+
+ fvalues[0] = para->min_speed;
+ fvalues[1] = para->max_speed;
+ fvalues[2] = para->accl;
+ fvalues[3] = para->trackstick_speed;
+ prop_speed = InitFloatAtom(pInfo->dev, SYNAPTICS_PROP_SPEED, 4, fvalues);
+
+ values[0] = para->edge_motion_min_z;
+ values[1] = para->edge_motion_max_z;
+ prop_edgemotion_pressure = InitAtom(pInfo->dev, SYNAPTICS_PROP_EDGEMOTION_PRESSURE, 32, 2, values);
+
+ values[0] = para->edge_motion_min_speed;
+ values[1] = para->edge_motion_max_speed;
+ prop_edgemotion_speed = InitAtom(pInfo->dev, SYNAPTICS_PROP_EDGEMOTION_SPEED, 32, 2, values);
+ prop_edgemotion_always = InitAtom(pInfo->dev, SYNAPTICS_PROP_EDGEMOTION, 8, 1, &para->edge_motion_use_always);
+
+ if (priv->has_scrollbuttons)
+ {
+ values[0] = para->updown_button_scrolling;
+ values[1] = para->leftright_button_scrolling;
+ prop_buttonscroll = InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING, 8, 2, values);
+
+ values[0] = para->updown_button_repeat;
+ values[1] = para->leftright_button_repeat;
+ prop_buttonscroll_repeat = InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT, 8, 2, values);
+ prop_buttonscroll_time = InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING_TIME, 32, 1, &para->scroll_button_repeat);
+ }
+
+ prop_off = InitAtom(pInfo->dev, SYNAPTICS_PROP_OFF, 8, 1, &para->touchpad_off);
+ prop_lockdrags = InitAtom(pInfo->dev, SYNAPTICS_PROP_LOCKED_DRAGS, 8, 1, &para->locked_drags);
+ prop_lockdrags_time = InitAtom(pInfo->dev, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT, 32, 1, &para->locked_drag_time);
+
+ memcpy(values, para->tap_action, MAX_TAP * sizeof(int));
+ prop_tapaction = InitAtom(pInfo->dev, SYNAPTICS_PROP_TAP_ACTION, 8, MAX_TAP, values);
+
+ memcpy(values, para->click_action, MAX_CLICK * sizeof(int));
+ prop_clickaction = InitAtom(pInfo->dev, SYNAPTICS_PROP_CLICK_ACTION, 8, MAX_CLICK, values);
+
+ prop_circscroll = InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_SCROLLING, 8, 1, &para->circular_scrolling);
+
+ fvalues[0] = para->scroll_dist_circ;
+ prop_circscroll_dist = InitFloatAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST, 1, fvalues);
+
+ prop_circscroll_trigger = InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER, 8, 1, &para->circular_trigger);
+ prop_circpad = InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_PAD, 8, 1, &para->circular_pad);
+ prop_palm = InitAtom(pInfo->dev, SYNAPTICS_PROP_PALM_DETECT, 8, 1, &para->palm_detect);
+
+ values[0] = para->palm_min_width;
+ values[1] = para->palm_min_z;
+
+ prop_palm_dim = InitAtom(pInfo->dev, SYNAPTICS_PROP_PALM_DIMENSIONS, 32, 2, values);
+
+ fvalues[0] = para->coasting_speed;
+ fvalues[1] = para->coasting_friction;
+ prop_coastspeed = InitFloatAtom(pInfo->dev, SYNAPTICS_PROP_COASTING_SPEED, 2, fvalues);
+
+ values[0] = para->press_motion_min_z;
+ values[1] = para->press_motion_max_z;
+ prop_pressuremotion = InitAtom(pInfo->dev, SYNAPTICS_PROP_PRESSURE_MOTION, 32, 2, values);
+
+ fvalues[0] = para->press_motion_min_factor;
+ fvalues[1] = para->press_motion_max_factor;
+
+ prop_pressuremotion_factor = InitFloatAtom(pInfo->dev, SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, 2, fvalues);
+
+ prop_grab = InitAtom(pInfo->dev, SYNAPTICS_PROP_GRAB, 8, 1, &para->grab_event_device);
+
+ values[0] = para->tap_and_drag_gesture;
+ prop_gestures = InitAtom(pInfo->dev, SYNAPTICS_PROP_GESTURES, 8, 1, values);
+
+ values[0] = priv->has_left;
+ values[1] = priv->has_middle;
+ values[2] = priv->has_right;
+ values[3] = priv->has_double;
+ values[4] = priv->has_triple;
+ values[5] = priv->has_pressure;
+ values[6] = priv->has_width;
+ prop_capabilities = InitAtom(pInfo->dev, SYNAPTICS_PROP_CAPABILITIES, 8, 7, values);
+
+ values[0] = para->resolution_vert;
+ values[1] = para->resolution_horiz;
+ prop_resolution = InitAtom(pInfo->dev, SYNAPTICS_PROP_RESOLUTION, 32, 2, values);
+
+ values[0] = para->area_left_edge;
+ values[1] = para->area_right_edge;
+ values[2] = para->area_top_edge;
+ values[3] = para->area_bottom_edge;
+ prop_area = InitAtom(pInfo->dev, SYNAPTICS_PROP_AREA, 32, 4, values);
+
+ values[0] = para->hyst_x;
+ values[1] = para->hyst_y;
+ prop_noise_cancellation = InitAtom(pInfo->dev,
+ SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 2, values);
+
+}
+
+int
+SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+ SynapticsParameters *para = &priv->synpara;
+ SynapticsParameters tmp;
+
+ /* If checkonly is set, no parameters may be changed. So just let the code
+ * change temporary variables and forget about it. */
+ if (checkonly)
+ {
+ tmp = *para;
+ para = &tmp;
+ }
+
+ if (property == prop_edges)
+ {
+ INT32 *edges;
+ if (prop->size != 4 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ edges = (INT32*)prop->data;
+ if (edges[0] > edges[1] || edges[2] > edges[3])
+ return BadValue;
+
+ para->left_edge = edges[0];
+ para->right_edge = edges[1];
+ para->top_edge = edges[2];
+ para->bottom_edge = edges[3];
+
+ } else if (property == prop_finger)
+ {
+ INT32 *finger;
+ if (prop->size != 3 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ finger = (INT32*)prop->data;
+ if (finger[0] > finger[1])
+ return BadValue;
+
+ para->finger_low = finger[0];
+ para->finger_high = finger[1];
+ para->finger_press = finger[2];
+
+ } else if (property == prop_tap_time)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->tap_time = *(INT32*)prop->data;
+
+ } else if (property == prop_tap_move)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->tap_move = *(INT32*)prop->data;
+ } else if (property == prop_tap_durations)
+ {
+ INT32 *timeouts;
+
+ if (prop->size != 3 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ timeouts = (INT32*)prop->data;
+
+ para->single_tap_timeout = timeouts[0];
+ para->tap_time_2 = timeouts[1];
+ para->click_time = timeouts[2];
+
+ } else if (property == prop_tap_fast)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->fast_taps = *(BOOL*)prop->data;
+
+ } else if (property == prop_middle_timeout)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->emulate_mid_button_time = *(INT32*)prop->data;
+ } else if (property == prop_twofinger_pressure)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->emulate_twofinger_z = *(INT32*)prop->data;
+ } else if (property == prop_twofinger_width)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->emulate_twofinger_w = *(INT32*)prop->data;
+ } else if (property == prop_scrolldist)
+ {
+ INT32 *dist;
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ dist = (INT32*)prop->data;
+ para->scroll_dist_vert = dist[0];
+ para->scroll_dist_horiz = dist[1];
+ } else if (property == prop_scrolledge)
+ {
+ CARD8 *edge;
+ if (prop->size != 3 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ edge = (BOOL*)prop->data;
+ para->scroll_edge_vert = edge[0];
+ para->scroll_edge_horiz = edge[1];
+ para->scroll_edge_corner = edge[2];
+ } else if (property == prop_scrolltwofinger)
+ {
+ CARD8 *twofinger;
+
+ if (prop->size != 2 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ twofinger = (BOOL*)prop->data;
+ para->scroll_twofinger_vert = twofinger[0];
+ para->scroll_twofinger_horiz = twofinger[1];
+ } else if (property == prop_speed)
+ {
+ float *speed;
+
+ if (prop->size != 4 || prop->format != 32 || prop->type != float_type)
+ return BadMatch;
+
+ speed = (float*)prop->data;
+ para->min_speed = speed[0];
+ para->max_speed = speed[1];
+ para->accl = speed[2];
+ para->trackstick_speed = speed[3];
+
+ } else if (property == prop_edgemotion_pressure)
+ {
+ CARD32 *pressure;
+
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ pressure = (CARD32*)prop->data;
+ if (pressure[0] > pressure[1])
+ return BadValue;
+
+ para->edge_motion_min_z = pressure[0];
+ para->edge_motion_max_z = pressure[1];
+
+ } else if (property == prop_edgemotion_speed)
+ {
+ CARD32 *speed;
+
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ speed = (CARD32*)prop->data;
+ if (speed[0] > speed[1])
+ return BadValue;
+
+ para->edge_motion_min_speed = speed[0];
+ para->edge_motion_max_speed = speed[1];
+
+ } else if (property == prop_edgemotion_always)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->edge_motion_use_always = *(BOOL*)prop->data;
+
+ } else if (property == prop_buttonscroll)
+ {
+ BOOL *scroll;
+
+ if (!priv->has_scrollbuttons)
+ return BadMatch;
+
+ if (prop->size != 2 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ scroll = (BOOL*)prop->data;
+ para->updown_button_scrolling = scroll[0];
+ para->leftright_button_scrolling = scroll[1];
+
+ } else if (property == prop_buttonscroll_repeat)
+ {
+ BOOL *repeat;
+
+ if (!priv->has_scrollbuttons)
+ return BadMatch;
+
+ if (prop->size != 2 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ repeat = (BOOL*)prop->data;
+ para->updown_button_repeat = repeat[0];
+ para->leftright_button_repeat = repeat[1];
+ } else if (property == prop_buttonscroll_time)
+ {
+ if (!priv->has_scrollbuttons)
+ return BadMatch;
+
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->scroll_button_repeat = *(INT32*)prop->data;
+
+ } else if (property == prop_off)
+ {
+ CARD8 off;
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ off = *(CARD8*)prop->data;
+
+ if (off > 2)
+ return BadValue;
+
+ para->touchpad_off = off;
+ } else if (property == prop_gestures)
+ {
+ BOOL *gestures;
+
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ gestures = (BOOL*)prop->data;
+ para->tap_and_drag_gesture = gestures[0];
+ } else if (property == prop_lockdrags)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->locked_drags = *(BOOL*)prop->data;
+ } else if (property == prop_lockdrags_time)
+ {
+ if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->locked_drag_time = *(INT32*)prop->data;
+ } else if (property == prop_tapaction)
+ {
+ int i;
+ CARD8 *action;
+
+ if (prop->size > MAX_TAP || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ action = (CARD8*)prop->data;
+
+ for (i = 0; i < MAX_TAP; i++)
+ para->tap_action[i] = action[i];
+ } else if (property == prop_clickaction)
+ {
+ int i;
+ CARD8 *action;
+
+ if (prop->size > MAX_CLICK || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ action = (CARD8*)prop->data;
+
+ for (i = 0; i < MAX_CLICK; i++)
+ para->click_action[i] = action[i];
+ } else if (property == prop_circscroll)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->circular_scrolling = *(BOOL*)prop->data;
+
+ } else if (property == prop_circscroll_dist)
+ {
+ float circdist;
+
+ if (prop->size != 1 || prop->format != 32 || prop->type != float_type)
+ return BadMatch;
+
+ circdist = *(float*)prop->data;
+ para->scroll_dist_circ = circdist;
+ } else if (property == prop_circscroll_trigger)
+ {
+ int trigger;
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ trigger = *(CARD8*)prop->data;
+ if (trigger > 8)
+ return BadValue;
+
+ para->circular_trigger = trigger;
+
+ } else if (property == prop_circpad)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->circular_pad = *(BOOL*)prop->data;
+ } else if (property == prop_palm)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->palm_detect = *(BOOL*)prop->data;
+ } else if (property == prop_palm_dim)
+ {
+ INT32 *dim;
+
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ dim = (INT32*)prop->data;
+
+ para->palm_min_width = dim[0];
+ para->palm_min_z = dim[1];
+ } else if (property == prop_coastspeed)
+ {
+ float *coast_speeds;
+
+ if (prop->size != 2 || prop->format != 32 || prop->type != float_type)
+ return BadMatch;
+
+ coast_speeds = (float*)prop->data;
+ para->coasting_speed = coast_speeds[0];
+ para->coasting_friction = coast_speeds[1];
+ } else if (property == prop_pressuremotion)
+ {
+ float *press;
+ if (prop->size != 2 || prop->format != 32 || prop->type != float_type)
+ return BadMatch;
+
+ press = (float*)prop->data;
+ if (press[0] > press[1])
+ return BadValue;
+
+ para->press_motion_min_z = press[0];
+ para->press_motion_max_z = press[1];
+ } else if (property == prop_grab)
+ {
+ if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ para->grab_event_device = *(BOOL*)prop->data;
+ } else if (property == prop_capabilities)
+ {
+ /* read-only */
+ return BadValue;
+ } else if (property == prop_resolution)
+ {
+ /* read-only */
+ return BadValue;
+ } else if (property == prop_area)
+ {
+ INT32 *area;
+ if (prop->size != 4 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ area = (INT32*)prop->data;
+ if ((((area[0] != 0) && (area[1] != 0)) && (area[0] > area[1]) ) || (((area[2] != 0) && (area[3] != 0)) && (area[2] > area[3])))
+ return BadValue;
+
+ para->area_left_edge = area[0];
+ para->area_right_edge = area[1];
+ para->area_top_edge = area[2];
+ para->area_bottom_edge = area[3];
+ } else if (property == prop_noise_cancellation) {
+ INT32 *hyst;
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ hyst = (INT32*)prop->data;
+ if (hyst[0] < 0 || hyst[1] < 0)
+ return BadValue;
+ para->hyst_x = hyst[0];
+ para->hyst_y = hyst[1];
+ }
+
+ return Success;
+}
+
diff --git a/driver/xf86-input-synaptics/src/ps2comm.c b/driver/xf86-input-synaptics/src/ps2comm.c
new file mode 100644
index 000000000..4e372b371
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/ps2comm.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright © 1997 C. Scott Ananian
+ * Copyright © 1998-2000 Bruce Kalk
+ * Copyright © 2001 Stefan Gmeiner
+ * Copyright © 2002 Linuxcare Inc. David Kennedy
+ * Copyright © 2003 Fred Hucht <fred@thp.Uni-Duisburg.de>
+ *
+ * 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:
+ * Stefan Gmeiner (riddlebox@freesurf.ch)
+ * C. Scott Ananian (cananian@alumni.priceton.edu)
+ * Bruce Kalk (kall@compass.com)
+ * Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com)
+ * Fred Hucht (fred@thp.Uni-Duisburg.de)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include "ps2comm.h"
+#include "synproto.h"
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include <xf86.h>
+
+#define MAX_UNSYNC_PACKETS 10 /* i.e. 10 to 60 bytes */
+/*
+ * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
+ * section 2.3.2, which says that they should be valid regardless of the
+ * actual size of the sensor.
+ */
+#define XMIN_NOMINAL 1472
+#define XMAX_NOMINAL 5472
+#define YMIN_NOMINAL 1408
+#define YMAX_NOMINAL 4448
+
+#define XMAX_VALID 6143
+
+/* synaptics queries */
+#define SYN_QUE_IDENTIFY 0x00
+#define SYN_QUE_MODES 0x01
+#define SYN_QUE_CAPABILITIES 0x02
+#define SYN_QUE_MODEL 0x03
+#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
+#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
+#define SYN_QUE_RESOLUTION 0x08
+#define SYN_QUE_EXT_CAPAB 0x09
+
+/* status request response bits (PS2_CMD_STATUS_REQUEST) */
+#define PS2_RES_REMOTE(r) ((r) & (1 << 22))
+#define PS2_RES_ENABLE(r) ((r) & (1 << 21))
+#define PS2_RES_SCALING(r) ((r) & (1 << 20))
+#define PS2_RES_LEFT(r) ((r) & (1 << 18))
+#define PS2_RES_MIDDLE(r) ((r) & (1 << 17))
+#define PS2_RES_RIGHT(r) ((r) & (1 << 16))
+#define PS2_RES_RESOLUTION(r) (((r) >> 8) & 0x03)
+#define PS2_RES_SAMPLE_RATE(r) ((r) & 0xff)
+
+#ifdef DEBUG
+#define PS2DBG(x) (x)
+#else
+#define PS2DBG(x)
+#endif
+
+struct SynapticsHwInfo {
+ unsigned int model_id; /* Model-ID */
+ unsigned int capabilities; /* Capabilities */
+ unsigned int ext_cap; /* Extended Capabilities */
+ unsigned int identity; /* Identification */
+};
+
+/*****************************************************************************
+ * PS/2 Utility functions.
+ * Many parts adapted from tpconfig.c by C. Scott Ananian
+ ****************************************************************************/
+
+/*
+ * Read a byte from the ps/2 port
+ */
+static Bool
+ps2_getbyte(int fd, byte *b)
+{
+ if (xf86WaitForInput(fd, 50000) > 0) {
+ if (xf86ReadSerial(fd, b, 1) != 1) {
+ PS2DBG(ErrorF("ps2_getbyte: No byte read\n"));
+ return FALSE;
+ }
+ PS2DBG(ErrorF("ps2_getbyte: byte %02X read\n", *b));
+ return TRUE;
+ }
+ PS2DBG(ErrorF("ps2_getbyte: timeout xf86WaitForInput\n"));
+ return FALSE;
+}
+
+/*
+ * Write a byte to the ps/2 port, wait for ACK
+ */
+Bool
+ps2_putbyte(int fd, byte b)
+{
+ byte ack;
+
+ if (xf86WriteSerial(fd, &b, 1) != 1) {
+ PS2DBG(ErrorF("ps2_putbyte: error xf86WriteSerial\n"));
+ return FALSE;
+ }
+ PS2DBG(ErrorF("ps2_putbyte: byte %02X send\n", b));
+ /* wait for an ACK */
+ if (!ps2_getbyte(fd, &ack)) {
+ return FALSE;
+ }
+ if (ack != PS2_ACK) {
+ PS2DBG(ErrorF("ps2_putbyte: wrong acknowledge 0x%02x\n", ack));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Use the Synaptics extended ps/2 syntax to write a special command byte. Needed by
+ * ps2_send_cmd and ps2_set_mode.
+ * special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
+ * is the command. A 0xF3 or 0xE9 must follow (see ps2_send_cmd, ps2_set_mode)
+ */
+static Bool
+ps2_special_cmd(int fd, byte cmd)
+{
+ int i;
+
+ /* initialize with 'inert' command */
+ if (!ps2_putbyte(fd, PS2_CMD_SET_SCALING_1_1))
+ return FALSE;
+
+ /* send 4x 2-bits with set resolution command */
+ for (i = 0; i < 4; i++) {
+ if (!ps2_putbyte(fd, PS2_CMD_SET_RESOLUTION) ||
+ !ps2_putbyte(fd, (cmd >> 6) & 0x3))
+ return FALSE;
+ cmd <<= 2;
+ }
+ return TRUE;
+}
+
+/*
+ * Send a command to the synpatics touchpad by special commands
+ */
+static Bool
+ps2_send_cmd(int fd, byte c)
+{
+ PS2DBG(ErrorF("send command: 0x%02X\n", c));
+ return (ps2_special_cmd(fd, c) &&
+ ps2_putbyte(fd, PS2_CMD_STATUS_REQUEST));
+}
+
+/*****************************************************************************
+ * Synaptics communications functions
+ ****************************************************************************/
+
+/*
+ * Set the synaptics touchpad mode byte by special commands
+ */
+static Bool
+ps2_synaptics_set_mode(int fd, byte mode)
+{
+ PS2DBG(ErrorF("set mode byte to: 0x%02X\n", mode));
+ return (ps2_special_cmd(fd, mode) &&
+ ps2_putbyte(fd, PS2_CMD_SET_SAMPLE_RATE) &&
+ ps2_putbyte(fd, 0x14));
+}
+
+/*
+ * reset the touchpad
+ */
+static Bool
+ps2_synaptics_reset(int fd)
+{
+ byte r[2];
+
+ xf86FlushInput(fd);
+ PS2DBG(ErrorF("Reset the Touchpad...\n"));
+ if (!ps2_putbyte(fd, PS2_CMD_RESET)) {
+ PS2DBG(ErrorF("...failed\n"));
+ return FALSE;
+ }
+ xf86WaitForInput(fd, 4000000);
+ if (ps2_getbyte(fd, &r[0]) && ps2_getbyte(fd, &r[1])) {
+ if (r[0] == 0xAA && r[1] == 0x00) {
+ PS2DBG(ErrorF("...done\n"));
+ return TRUE;
+ } else {
+ PS2DBG(ErrorF("...failed. Wrong reset ack 0x%02x, 0x%02x\n", r[0], r[1]));
+ return FALSE;
+ }
+ }
+ PS2DBG(ErrorF("...failed\n"));
+ return FALSE;
+}
+
+/*
+ * Read the model-id bytes from the touchpad
+ * see also SYN_MODEL_* macros
+ */
+static Bool
+ps2_synaptics_model_id(int fd, struct SynapticsHwInfo *synhw)
+{
+ byte mi[3];
+
+ PS2DBG(ErrorF("Read mode id...\n"));
+
+ synhw->model_id = 0;
+ if (ps2_send_cmd(fd, SYN_QUE_MODEL) &&
+ ps2_getbyte(fd, &mi[0]) &&
+ ps2_getbyte(fd, &mi[1]) &&
+ ps2_getbyte(fd, &mi[2])) {
+ synhw->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2];
+ PS2DBG(ErrorF("model-id %06X\n", synhw->model_id));
+ PS2DBG(ErrorF("...done.\n"));
+ return TRUE;
+ }
+ PS2DBG(ErrorF("...failed.\n"));
+ return FALSE;
+}
+
+/*
+ * Read the capability-bits from the touchpad
+ * see also the SYN_CAP_* macros
+ */
+static Bool
+ps2_synaptics_capability(int fd, struct SynapticsHwInfo *synhw)
+{
+ byte cap[3];
+
+ PS2DBG(ErrorF("Read capabilites...\n"));
+
+ synhw->capabilities = 0;
+ synhw->ext_cap = 0;
+ if (ps2_send_cmd(fd, SYN_QUE_CAPABILITIES) &&
+ ps2_getbyte(fd, &cap[0]) &&
+ ps2_getbyte(fd, &cap[1]) &&
+ ps2_getbyte(fd, &cap[2])) {
+ synhw->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+ PS2DBG(ErrorF("capabilities %06X\n", synhw->capabilities));
+ if (SYN_CAP_VALID(synhw)) {
+ if (SYN_EXT_CAP_REQUESTS(synhw)) {
+ if (ps2_send_cmd(fd, SYN_QUE_EXT_CAPAB) &&
+ ps2_getbyte(fd, &cap[0]) &&
+ ps2_getbyte(fd, &cap[1]) &&
+ ps2_getbyte(fd, &cap[2])) {
+ synhw->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+ PS2DBG(ErrorF("ext-capability %06X\n", synhw->ext_cap));
+ } else {
+ PS2DBG(ErrorF("synaptics says, that it has extended-capabilities, "
+ "but I cannot read them."));
+ }
+ }
+ PS2DBG(ErrorF("...done.\n"));
+ return TRUE;
+ }
+ }
+ PS2DBG(ErrorF("...failed.\n"));
+ return FALSE;
+}
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static Bool
+ps2_synaptics_identify(int fd, struct SynapticsHwInfo *synhw)
+{
+ byte id[3];
+
+ PS2DBG(ErrorF("Identify Touchpad...\n"));
+
+ synhw->identity = 0;
+ if (ps2_send_cmd(fd, SYN_QUE_IDENTIFY) &&
+ ps2_getbyte(fd, &id[0]) &&
+ ps2_getbyte(fd, &id[1]) &&
+ ps2_getbyte(fd, &id[2])) {
+ synhw->identity = (id[0] << 16) | (id[1] << 8) | id[2];
+ PS2DBG(ErrorF("ident %06X\n", synhw->identity));
+ if (SYN_ID_IS_SYNAPTICS(synhw)) {
+ PS2DBG(ErrorF("...done.\n"));
+ return TRUE;
+ }
+ }
+ PS2DBG(ErrorF("...failed.\n"));
+ return FALSE;
+}
+
+static Bool
+ps2_synaptics_enable_device(int fd)
+{
+ return ps2_putbyte(fd, PS2_CMD_ENABLE);
+}
+
+static Bool
+ps2_synaptics_disable_device(int fd)
+{
+ xf86FlushInput(fd);
+ return ps2_putbyte(fd, PS2_CMD_DISABLE);
+}
+
+static Bool
+ps2_query_is_synaptics(int fd, struct SynapticsHwInfo* synhw)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (ps2_synaptics_disable_device(fd))
+ break;
+ }
+
+ xf86WaitForInput(fd, 20000);
+ xf86FlushInput(fd);
+ if (ps2_synaptics_identify(fd, synhw)) {
+ return TRUE;
+ } else {
+ xf86Msg(X_ERROR, "Query no Synaptics: %06X\n", synhw->identity);
+ return FALSE;
+ }
+}
+
+void
+ps2_print_ident(const struct SynapticsHwInfo *synhw)
+{
+ xf86Msg(X_PROBED, " Synaptics Touchpad, model: %d\n", SYN_ID_MODEL(synhw));
+ xf86Msg(X_PROBED, " Firmware: %d.%d\n", SYN_ID_MAJOR(synhw),
+ SYN_ID_MINOR(synhw));
+
+ if (SYN_MODEL_ROT180(synhw))
+ xf86Msg(X_PROBED, " 180 degree mounted touchpad\n");
+ if (SYN_MODEL_PORTRAIT(synhw))
+ xf86Msg(X_PROBED, " portrait touchpad\n");
+ xf86Msg(X_PROBED, " Sensor: %d\n", SYN_MODEL_SENSOR(synhw));
+ if (SYN_MODEL_NEWABS(synhw))
+ xf86Msg(X_PROBED, " new absolute packet format\n");
+ if (SYN_MODEL_PEN(synhw))
+ xf86Msg(X_PROBED, " pen detection\n");
+
+ if (SYN_CAP_EXTENDED(synhw)) {
+ xf86Msg(X_PROBED, " Touchpad has extended capability bits\n");
+ if (SYN_CAP_MULTI_BUTTON_NO(synhw))
+ xf86Msg(X_PROBED, " -> %d multi buttons, i.e. besides standard buttons\n",
+ (int)(SYN_CAP_MULTI_BUTTON_NO(synhw)));
+ if (SYN_CAP_MIDDLE_BUTTON(synhw))
+ xf86Msg(X_PROBED, " -> middle button\n");
+ if (SYN_CAP_FOUR_BUTTON(synhw))
+ xf86Msg(X_PROBED, " -> four buttons\n");
+ if (SYN_CAP_MULTIFINGER(synhw))
+ xf86Msg(X_PROBED, " -> multifinger detection\n");
+ if (SYN_CAP_PALMDETECT(synhw))
+ xf86Msg(X_PROBED, " -> palm detection\n");
+ if (SYN_CAP_PASSTHROUGH(synhw))
+ xf86Msg(X_PROBED, " -> pass-through port\n");
+ }
+}
+
+static void
+PS2DeviceOffHook(InputInfoPtr pInfo)
+{
+ ps2_synaptics_reset(pInfo->fd);
+ ps2_synaptics_enable_device(pInfo->fd);
+}
+
+static Bool
+PS2QueryHardware(InputInfoPtr pInfo)
+{
+ int mode;
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ struct SynapticsHwInfo *synhw;
+
+ if (!priv->proto_data)
+ priv->proto_data = calloc(1, sizeof(struct SynapticsHwInfo));
+ synhw = (struct SynapticsHwInfo*)priv->proto_data;
+
+ /* is the synaptics touchpad active? */
+ if (!ps2_query_is_synaptics(pInfo->fd, synhw))
+ return FALSE;
+
+ xf86Msg(X_PROBED, "%s synaptics touchpad found\n", pInfo->name);
+
+ if (!ps2_synaptics_reset(pInfo->fd))
+ xf86Msg(X_ERROR, "%s reset failed\n", pInfo->name);
+
+ if (!ps2_synaptics_identify(pInfo->fd, synhw))
+ return FALSE;
+
+ if (!ps2_synaptics_model_id(pInfo->fd, synhw))
+ return FALSE;
+
+ if (!ps2_synaptics_capability(pInfo->fd, synhw))
+ return FALSE;
+
+ mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
+ if (SYN_ID_MAJOR(synhw) >= 4)
+ mode |= SYN_BIT_DISABLE_GESTURE;
+ if (SYN_CAP_EXTENDED(synhw))
+ mode |= SYN_BIT_W_MODE;
+ if (!ps2_synaptics_set_mode(pInfo->fd, mode))
+ return FALSE;
+
+ ps2_synaptics_enable_device(pInfo->fd);
+
+ ps2_print_ident(synhw);
+
+ return TRUE;
+}
+
+/*
+ * Decide if the current packet stored in priv->protoBuf is valid.
+ */
+static Bool
+ps2_packet_ok(struct SynapticsHwInfo *synhw, struct CommData *comm)
+{
+ unsigned char *buf = comm->protoBuf;
+ int newabs = SYN_MODEL_NEWABS(synhw);
+
+ if (newabs ? ((buf[0] & 0xC0) != 0x80) : ((buf[0] & 0xC0) != 0xC0)) {
+ DBG(4, "Synaptics driver lost sync at 1st byte\n");
+ return FALSE;
+ }
+
+ if (!newabs && ((buf[1] & 0x60) != 0x00)) {
+ DBG(4, "Synaptics driver lost sync at 2nd byte\n");
+ return FALSE;
+ }
+
+ if ((newabs ? ((buf[3] & 0xC0) != 0xC0) : ((buf[3] & 0xC0) != 0x80))) {
+ DBG(4, "Synaptics driver lost sync at 4th byte\n");
+ return FALSE;
+ }
+
+ if (!newabs && ((buf[4] & 0x60) != 0x00)) {
+ DBG(4, "Synaptics driver lost sync at 5th byte\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+ps2_synaptics_get_packet(InputInfoPtr pInfo, struct SynapticsHwInfo *synhw,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm)
+{
+ int count = 0;
+ int c;
+ unsigned char u;
+
+ while ((c = XisbRead(comm->buffer)) >= 0) {
+ u = (unsigned char)c;
+
+ /* test if there is a reset sequence received */
+ if ((c == 0x00) && (comm->lastByte == 0xAA)) {
+ if (xf86WaitForInput(pInfo->fd, 50000) == 0) {
+ DBG(7, "Reset received\n");
+ proto_ops->QueryHardware(pInfo);
+ } else
+ DBG(3, "faked reset received\n");
+ }
+ comm->lastByte = u;
+
+ /* to avoid endless loops */
+ if (count++ > 30) {
+ xf86Msg(X_ERROR, "Synaptics driver lost sync... got gigantic packet!\n");
+ return FALSE;
+ }
+
+ comm->protoBuf[comm->protoBufTail++] = u;
+
+ /* Check that we have a valid packet. If not, we are out of sync,
+ so we throw away the first byte in the packet.*/
+ if (comm->protoBufTail >= 6) {
+ if (!ps2_packet_ok(synhw, comm)) {
+ int i;
+ for (i = 0; i < comm->protoBufTail - 1; i++)
+ comm->protoBuf[i] = comm->protoBuf[i + 1];
+ comm->protoBufTail--;
+ comm->outOfSync++;
+ if (comm->outOfSync > MAX_UNSYNC_PACKETS) {
+ comm->outOfSync = 0;
+ DBG(3, "Synaptics synchronization lost too long -> reset touchpad.\n");
+ proto_ops->QueryHardware(pInfo); /* including a reset */
+ continue;
+ }
+ }
+ }
+
+ if (comm->protoBufTail >= 6) { /* Full packet received */
+ if (comm->outOfSync > 0) {
+ comm->outOfSync = 0;
+ DBG(4, "Synaptics driver resynced.\n");
+ }
+ comm->protoBufTail = 0;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static Bool
+PS2ReadHwState(InputInfoPtr pInfo,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm, struct SynapticsHwState *hwRet)
+{
+ unsigned char *buf = comm->protoBuf;
+ struct SynapticsHwState *hw = &(comm->hwState);
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ SynapticsParameters *para = &priv->synpara;
+ struct SynapticsHwInfo *synhw;
+ int newabs;
+ int w, i;
+
+ synhw = (struct SynapticsHwInfo*)priv->proto_data;
+ if (!synhw)
+ {
+ xf86Msg(X_ERROR,
+ "%s: PS2ReadHwState, synhw is NULL. This is a bug.\n",
+ pInfo->name);
+ return FALSE;
+ }
+
+ newabs = SYN_MODEL_NEWABS(synhw);
+
+ if (!ps2_synaptics_get_packet(pInfo, synhw, proto_ops, comm))
+ return FALSE;
+
+ /* Handle normal packets */
+ hw->x = hw->y = hw->z = hw->numFingers = hw->fingerWidth = 0;
+ hw->left = hw->right = hw->up = hw->down = hw->middle = FALSE;
+ for (i = 0; i < 8; i++)
+ hw->multi[i] = FALSE;
+
+ if (newabs) { /* newer protos...*/
+ DBG(7, "using new protocols\n");
+ hw->x = (((buf[3] & 0x10) << 8) |
+ ((buf[1] & 0x0f) << 8) |
+ buf[4]);
+ hw->y = (((buf[3] & 0x20) << 7) |
+ ((buf[1] & 0xf0) << 4) |
+ buf[5]);
+
+ hw->z = buf[2];
+ w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
+
+ if (SYN_CAP_EXTENDED(synhw)) {
+ if (SYN_CAP_MIDDLE_BUTTON(synhw)) {
+ hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+ }
+ if (SYN_CAP_FOUR_BUTTON(synhw)) {
+ hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+ if (hw->left)
+ hw->up = !hw->up;
+ hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+ if (hw->right)
+ hw->down = !hw->down;
+ }
+ if (SYN_CAP_MULTI_BUTTON_NO(synhw)) {
+ if ((buf[3] & 2) ? !hw->right : hw->right) {
+ switch (SYN_CAP_MULTI_BUTTON_NO(synhw) & ~0x01) {
+ default:
+ break;
+ case 8:
+ hw->multi[7] = ((buf[5] & 0x08)) ? 1 : 0;
+ hw->multi[6] = ((buf[4] & 0x08)) ? 1 : 0;
+ case 6:
+ hw->multi[5] = ((buf[5] & 0x04)) ? 1 : 0;
+ hw->multi[4] = ((buf[4] & 0x04)) ? 1 : 0;
+ case 4:
+ hw->multi[3] = ((buf[5] & 0x02)) ? 1 : 0;
+ hw->multi[2] = ((buf[4] & 0x02)) ? 1 : 0;
+ case 2:
+ hw->multi[1] = ((buf[5] & 0x01)) ? 1 : 0;
+ hw->multi[0] = ((buf[4] & 0x01)) ? 1 : 0;
+ }
+ }
+ }
+ }
+ } else { /* old proto...*/
+ DBG(7, "using old protocol\n");
+ hw->x = (((buf[1] & 0x1F) << 8) |
+ buf[2]);
+ hw->y = (((buf[4] & 0x1F) << 8) |
+ buf[5]);
+
+ hw->z = (((buf[0] & 0x30) << 2) |
+ (buf[3] & 0x3F));
+ w = (((buf[1] & 0x80) >> 4) |
+ ((buf[0] & 0x04) >> 1));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
+ }
+
+ hw->y = YMAX_NOMINAL + YMIN_NOMINAL - hw->y;
+
+ if (hw->z >= para->finger_high) {
+ int w_ok = 0;
+ /*
+ * Use capability bits to decide if the w value is valid.
+ * If not, set it to 5, which corresponds to a finger of
+ * normal width.
+ */
+ if (SYN_CAP_EXTENDED(synhw)) {
+ if ((w >= 0) && (w <= 1)) {
+ w_ok = SYN_CAP_MULTIFINGER(synhw);
+ } else if (w == 2) {
+ w_ok = SYN_MODEL_PEN(synhw);
+ } else if ((w >= 4) && (w <= 15)) {
+ w_ok = SYN_CAP_PALMDETECT(synhw);
+ }
+ }
+ if (!w_ok)
+ w = 5;
+
+ switch (w) {
+ case 0:
+ hw->numFingers = 2;
+ hw->fingerWidth = 5;
+ break;
+ case 1:
+ hw->numFingers = 3;
+ hw->fingerWidth = 5;
+ break;
+ default:
+ hw->numFingers = 1;
+ hw->fingerWidth = w;
+ break;
+ }
+ }
+
+ *hwRet = *hw;
+ return TRUE;
+}
+
+static Bool
+PS2AutoDevProbe(InputInfoPtr pInfo)
+{
+ return FALSE;
+}
+
+struct SynapticsProtocolOperations psaux_proto_operations = {
+ NULL,
+ PS2DeviceOffHook,
+ PS2QueryHardware,
+ PS2ReadHwState,
+ PS2AutoDevProbe,
+ SynapticsDefaultDimensions
+};
diff --git a/driver/xf86-input-synaptics/src/ps2comm.h b/driver/xf86-input-synaptics/src/ps2comm.h
new file mode 100644
index 000000000..fec56346d
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/ps2comm.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#ifndef _PS2COMM_H_
+#define _PS2COMM_H_
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "xf86_OSproc.h"
+
+/* acknowledge for commands and parameter */
+#define PS2_ACK 0xFA
+#define PS2_ERROR 0xFC
+
+/* standard PS/2 commands */
+#define PS2_CMD_RESET 0xFF
+#define PS2_CMD_RESEND 0xFE
+#define PS2_CMD_SET_DEFAULT 0xF6
+#define PS2_CMD_DISABLE 0xF5
+#define PS2_CMD_ENABLE 0xF4
+#define PS2_CMD_SET_SAMPLE_RATE 0xF3
+#define PS2_CMD_READ_DEVICE_TYPE 0xF2
+#define PS2_CMD_SET_REMOTE_MODE 0xF0
+#define PS2_CMD_SET_WRAP_MODE 0xEE
+#define PS2_CMD_RESET_WRAP_MODE 0xEC
+#define PS2_CMD_READ_DATA 0xEB
+#define PS2_CMD_SET_STREAM_MODE 0xEA
+#define PS2_CMD_STATUS_REQUEST 0xE9
+#define PS2_CMD_SET_RESOLUTION 0xE8
+#define PS2_CMD_SET_SCALING_2_1 0xE7
+#define PS2_CMD_SET_SCALING_1_1 0xE6
+
+/* synaptics modes */
+#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
+#define SYN_BIT_HIGH_RATE (1 << 6)
+#define SYN_BIT_SLEEP_MODE (1 << 3)
+#define SYN_BIT_DISABLE_GESTURE (1 << 2)
+#define SYN_BIT_W_MODE (1 << 0)
+
+/* synaptics model ID bits */
+#define SYN_MODEL_ROT180(synhw) ((synhw)->model_id & (1 << 23))
+#define SYN_MODEL_PORTRAIT(synhw) ((synhw)->model_id & (1 << 22))
+#define SYN_MODEL_SENSOR(synhw) (((synhw)->model_id >> 16) & 0x3f)
+#define SYN_MODEL_HARDWARE(synhw) (((synhw)->model_id >> 9) & 0x7f)
+#define SYN_MODEL_NEWABS(synhw) ((synhw)->model_id & (1 << 7))
+#define SYN_MODEL_PEN(synhw) ((synhw)->model_id & (1 << 6))
+#define SYN_MODEL_SIMPLIC(synhw) ((synhw)->model_id & (1 << 5))
+#define SYN_MODEL_GEOMETRY(synhw) ((synhw)->model_id & 0x0f)
+
+/* synaptics capability bits */
+#define SYN_CAP_EXTENDED(synhw) ((synhw)->capabilities & (1 << 23))
+#define SYN_CAP_MIDDLE_BUTTON(synhw) ((synhw)->capabilities & (1 << 18))
+#define SYN_CAP_PASSTHROUGH(synhw) ((synhw)->capabilities & (1 << 7))
+#define SYN_CAP_SLEEP(synhw) ((synhw)->capabilities & (1 << 4))
+#define SYN_CAP_FOUR_BUTTON(synhw) ((synhw)->capabilities & (1 << 3))
+#define SYN_CAP_MULTIFINGER(synhw) ((synhw)->capabilities & (1 << 1))
+#define SYN_CAP_PALMDETECT(synhw) ((synhw)->capabilities & (1 << 0))
+#define SYN_CAP_VALID(synhw) ((((synhw)->capabilities & 0x00ff00) >> 8) == 0x47)
+#define SYN_EXT_CAP_REQUESTS(synhw) (((synhw)->capabilities & 0x700000) == 0x100000)
+#define SYN_CAP_MULTI_BUTTON_NO(synhw) (((synhw)->ext_cap & 0x00f000) >> 12)
+
+/* synaptics modes query bits */
+#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
+#define SYN_MODE_RATE(m) ((m) & (1 << 6))
+#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
+#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
+#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
+#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
+#define SYN_MODE_VALID(m) (((m) & 0xffff00) == 0x3B47)
+
+/* synaptics identify query bits */
+#define SYN_ID_MODEL(synhw) (((synhw)->identity >> 4) & 0x0f)
+#define SYN_ID_MAJOR(synhw) ((synhw)->identity & 0x0f)
+#define SYN_ID_MINOR(synhw) (((synhw)->identity >> 16) & 0xff)
+#define SYN_ID_IS_SYNAPTICS(synhw) ((((synhw)->identity >> 8) & 0xff) == 0x47)
+
+typedef unsigned char byte;
+
+
+Bool ps2_putbyte(int fd, byte b);
+
+struct SynapticsHwInfo;
+void ps2_print_ident(const struct SynapticsHwInfo *synhw);
+
+#endif /* _PS2COMM_H_ */
diff --git a/driver/xf86-input-synaptics/src/psmcomm.c b/driver/xf86-input-synaptics/src/psmcomm.c
new file mode 100644
index 000000000..741cd1d20
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/psmcomm.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright © 1997 C. Scott Ananian
+ * Copyright © 1998-2000 Bruce Kalk
+ * Copyright © 2001 Stefan Gmeiner
+ * Copyright © 2002 Linuxcare Inc. David Kennedy
+ * Copyright © 2003 Fred Hucht
+ * Copyright © 2004 Arne Schwabe
+ *
+ * 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:
+ * Stefan Gmeiner (riddlebox@freesurf.ch)
+ * C. Scott Ananian (cananian@alumni.priceton.edu)
+ * Bruce Kalk (kall@compass.com)
+ * Linuxcare Inc. David Kennedy (dkennedy@linuxcare.com)
+ * Fred Hucht (fred@thp.Uni-Duisburg.de)
+ * Arne Schwabe <schwabe@uni-paderborn.de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mouse.h>
+#include <errno.h>
+#include <string.h>
+#include "synproto.h"
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include "ps2comm.h" /* ps2_print_ident() */
+#include <xf86.h>
+
+#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
+
+struct SynapticsHwInfo {
+ unsigned int model_id; /* Model-ID */
+ unsigned int capabilities; /* Capabilities */
+ unsigned int ext_cap; /* Extended Capabilities */
+ unsigned int identity; /* Identification */
+};
+
+/*
+ * Identify Touchpad
+ * See also the SYN_ID_* macros
+ */
+static Bool
+psm_synaptics_identify(int fd, synapticshw_t *ident)
+{
+ int ret;
+
+ SYSCALL(ret = ioctl(fd, MOUSE_SYN_GETHWINFO, ident));
+ if (ret == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* This define is used in a ioctl but not in mouse.h :/ */
+#define PSM_LEVEL_NATIVE 2
+
+static Bool
+PSMQueryIsSynaptics(InputInfoPtr pInfo)
+{
+ int ret;
+ int level = PSM_LEVEL_NATIVE;
+ mousehw_t mhw;
+
+ /* Put the device in native protocol mode to be sure
+ * Otherwise HWINFO will not return the right id
+ * And we will need native mode anyway ...
+ */
+ SYSCALL(ret = ioctl(pInfo->fd, MOUSE_SETLEVEL, &level));
+ if (ret != 0) {
+ xf86Msg(X_ERROR, "%s Can't set native mode\n", pInfo->name);
+ return FALSE;
+ }
+ SYSCALL(ret = ioctl(pInfo->fd, MOUSE_GETHWINFO, &mhw));
+ if (ret != 0) {
+ xf86Msg(X_ERROR, "%s Can't get hardware info\n", pInfo->name);
+ return FALSE;
+ }
+
+ if (mhw.model == MOUSE_MODEL_SYNAPTICS) {
+ return TRUE;
+ } else {
+ xf86Msg(X_ERROR, "%s Found no Synaptics, found Mouse model %d instead\n",
+ pInfo->name, mhw.model);
+ return FALSE;
+ }
+}
+
+static void
+convert_hw_info(const synapticshw_t *psm_ident, struct SynapticsHwInfo *synhw)
+{
+ memset(synhw, 0, sizeof(*synhw));
+ synhw->model_id = ((psm_ident->infoRot180 << 23) |
+ (psm_ident->infoPortrait << 22) |
+ (psm_ident->infoSensor << 16) |
+ (psm_ident->infoHardware << 9) |
+ (psm_ident->infoNewAbs << 7) |
+ (psm_ident->capPen << 6) |
+ (psm_ident->infoSimplC << 5) |
+ (psm_ident->infoGeometry));
+ synhw->capabilities = ((psm_ident->capExtended << 23) |
+ (psm_ident->capPassthrough << 7) |
+ (psm_ident->capSleep << 4) |
+ (psm_ident->capFourButtons << 3) |
+ (psm_ident->capMultiFinger << 1) |
+ (psm_ident->capPalmDetect));
+ synhw->ext_cap = 0;
+ synhw->identity = ((psm_ident->infoMajor) |
+ (0x47 << 8) |
+ (psm_ident->infoMinor << 16));
+}
+
+static Bool
+PSMQueryHardware(InputInfoPtr pInfo)
+{
+ synapticshw_t psm_ident;
+ struct SynapticsHwInfo *synhw;
+ SynapticsPrivate *priv;
+
+ priv = (SynapticsPrivate *)pInfo->private;
+
+ if(!priv->proto_data)
+ priv->proto_data = calloc(1, sizeof(struct SynapticsHwInfo));
+ synhw = (struct SynapticsHwInfo*)priv->proto_data;
+
+ /* is the synaptics touchpad active? */
+ if (!PSMQueryIsSynaptics(pInfo))
+ return FALSE;
+
+ xf86Msg(X_PROBED, "%s synaptics touchpad found\n", pInfo->name);
+
+ if (!psm_synaptics_identify(pInfo->fd, &psm_ident))
+ return FALSE;
+
+ convert_hw_info(&psm_ident, synhw);
+
+ ps2_print_ident(synhw);
+
+ return TRUE;
+}
+
+static Bool
+PSMReadHwState(InputInfoPtr pInfo,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm, struct SynapticsHwState *hwRet)
+{
+ return psaux_proto_operations.ReadHwState(pInfo, proto_ops, comm, hwRet);
+}
+
+static Bool PSMAutoDevProbe(InputInfoPtr pInfo)
+{
+ return FALSE;
+}
+
+struct SynapticsProtocolOperations psm_proto_operations = {
+ NULL,
+ NULL,
+ PSMQueryHardware,
+ PSMReadHwState,
+ PSMAutoDevProbe,
+ SynapticsDefaultDimensions
+};
diff --git a/driver/xf86-input-synaptics/src/synaptics.c b/driver/xf86-input-synaptics/src/synaptics.c
new file mode 100644
index 000000000..56ce725e6
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/synaptics.c
@@ -0,0 +1,2661 @@
+/*
+ * Copyright © 1999 Henry Davies
+ * Copyright © 2001 Stefan Gmeiner
+ * Copyright © 2002 S. Lehner
+ * Copyright © 2002 Peter Osterlund
+ * Copyright © 2002 Linuxcare Inc. David Kennedy
+ * Copyright © 2003 Hartwig Felger
+ * Copyright © 2003 Jörg Bösner
+ * Copyright © 2003 Fred Hucht
+ * Copyright © 2004 Alexei Gilchrist
+ * Copyright © 2004 Matthias Ihmig
+ * Copyright © 2006 Stefan Bethge
+ * Copyright © 2006 Christian Thaeter
+ * Copyright © 2007 Joseph P. Skudlarek
+ * Copyright © 2008 Fedor P. Goncharov
+ * Copyright © 2008-2009 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:
+ * Joseph P. Skudlarek <Jskud@Jskud.com>
+ * Christian Thaeter <chth@gmx.net>
+ * Stefan Bethge <stefan.bethge@web.de>
+ * Matthias Ihmig <m.ihmig@gmx.net>
+ * Alexei Gilchrist <alexei@physics.uq.edu.au>
+ * Jörg Bösner <ich@joerg-boesner.de>
+ * Hartwig Felger <hgfelger@hgfelger.de>
+ * Peter Osterlund <petero2@telia.com>
+ * S. Lehner <sam_x@bluemail.ch>
+ * Stefan Gmeiner <riddlebox@freesurf.ch>
+ * Henry Davies <hdavies@ameritech.net> for the
+ * Linuxcare Inc. David Kennedy <dkennedy@linuxcare.com>
+ * Fred Hucht <fred@thp.Uni-Duisburg.de>
+ * Fedor P. Goncharov <fedgo@gorodok.net>
+ * Simon Thum <simon.thum@gmx.de>
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <xorg-server.h>
+#include <unistd.h>
+#include <misc.h>
+#include <xf86.h>
+#include <sys/shm.h>
+#include <math.h>
+#include <stdio.h>
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+
+#include "synaptics.h"
+#include "synapticsstr.h"
+#include "synaptics-properties.h"
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+#include <X11/Xatom.h>
+#include <xserver-properties.h>
+#include <ptrveloc.h>
+#endif
+
+typedef enum {
+ NO_EDGE = 0,
+ BOTTOM_EDGE = 1,
+ TOP_EDGE = 2,
+ LEFT_EDGE = 4,
+ RIGHT_EDGE = 8,
+ LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+ RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+ RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+ LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
+} edge_type;
+
+#define MAX(a, b) (((a)>(b))?(a):(b))
+#define MIN(a, b) (((a)<(b))?(a):(b))
+#define TIME_DIFF(a, b) ((int)((a)-(b)))
+
+#define SQR(x) ((x) * (x))
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+#endif
+
+#define INPUT_BUFFER_SIZE 200
+
+/*****************************************************************************
+ * Forward declaration
+ ****************************************************************************/
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+static int SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+#else
+static InputInfoPtr SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+#endif
+static void SynapticsUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+static Bool DeviceControl(DeviceIntPtr, int);
+static void ReadInput(InputInfoPtr);
+static int HandleState(InputInfoPtr, struct SynapticsHwState*);
+static int ControlProc(InputInfoPtr, xDeviceCtl*);
+static int SwitchMode(ClientPtr, DeviceIntPtr, int);
+static Bool DeviceInit(DeviceIntPtr);
+static Bool DeviceOn(DeviceIntPtr);
+static Bool DeviceOff(DeviceIntPtr);
+static Bool DeviceClose(DeviceIntPtr);
+static Bool QueryHardware(InputInfoPtr);
+static void ReadDevDimensions(InputInfoPtr);
+static void ScaleCoordinates(SynapticsPrivate *priv, struct SynapticsHwState *hw);
+static void CalculateScalingCoeffs(SynapticsPrivate *priv);
+
+void InitDeviceProperties(InputInfoPtr pInfo);
+int SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
+ BOOL checkonly);
+
+InputDriverRec SYNAPTICS = {
+ 1,
+ "synaptics",
+ NULL,
+ SynapticsPreInit,
+ SynapticsUnInit,
+ NULL,
+};
+
+static XF86ModuleVersionInfo VersionRec = {
+ "synaptics",
+ 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}
+};
+
+static pointer
+SetupProc(pointer module, pointer options, int *errmaj, int *errmin)
+{
+ xf86AddInputDriver(&SYNAPTICS, module, 0);
+ return module;
+}
+
+_X_EXPORT XF86ModuleData synapticsModuleData = {
+ &VersionRec,
+ &SetupProc,
+ NULL
+};
+
+
+/*****************************************************************************
+ * Function Definitions
+ ****************************************************************************/
+/**
+ * Fill in default dimensions for backends that cannot query the hardware.
+ * Eventually, we want the edges to be 1900/5400 for x, 1900/4000 for y.
+ * These values are based so that calculate_edge_widths() will give us the
+ * right values.
+ *
+ * The default values 1900, etc. come from the dawn of time, when men where
+ * men, or possibly apes.
+ */
+void
+SynapticsDefaultDimensions(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+
+ if (priv->minx >= priv->maxx)
+ {
+ priv->minx = 1615;
+ priv->maxx = 5685;
+ priv->resx = 0;
+
+ xf86Msg(X_PROBED,
+ "%s: invalid x-axis range. defaulting to %d - %d\n",
+ pInfo->name, priv->minx, priv->maxx);
+ }
+
+ if (priv->miny >= priv->maxy)
+ {
+ priv->miny = 1729;
+ priv->maxy = 4171;
+ priv->resx = 0;
+
+ xf86Msg(X_PROBED,
+ "%s: invalid y-axis range. defaulting to %d - %d\n",
+ pInfo->name, priv->miny, priv->maxy);
+ }
+
+ if (priv->minp >= priv->maxp)
+ {
+ priv->minp = 0;
+ priv->maxp = 256;
+
+ xf86Msg(X_PROBED,
+ "%s: invalid pressure range. defaulting to %d - %d\n",
+ pInfo->name, priv->minp, priv->maxp);
+ }
+
+ if (priv->minw >= priv->maxw)
+ {
+ priv->minw = 0;
+ priv->maxw = 16;
+
+ xf86Msg(X_PROBED,
+ "%s: invalid finger width range. defaulting to %d - %d\n",
+ pInfo->name, priv->minw, priv->maxw);
+ }
+}
+
+static void
+SetDeviceAndProtocol(InputInfoPtr pInfo)
+{
+ char *str_par, *device;
+ SynapticsPrivate *priv = pInfo->private;
+ enum SynapticsProtocol proto = SYN_PROTO_PSAUX;
+
+ device = xf86SetStrOption(pInfo->options, "Device", NULL);
+ if (!device) {
+ device = xf86SetStrOption(pInfo->options, "Path", NULL);
+ if (device) {
+ pInfo->options =
+ xf86ReplaceStrOption(pInfo->options, "Device", device);
+ }
+ }
+ if (device && strstr(device, "/dev/input/event")) {
+#ifdef BUILD_EVENTCOMM
+ proto = SYN_PROTO_EVENT;
+#endif
+ } else {
+ str_par = xf86FindOptionValue(pInfo->options, "Protocol");
+ if (str_par && !strcmp(str_par, "psaux")) {
+ /* Already set up */
+#ifdef BUILD_EVENTCOMM
+ } else if (str_par && !strcmp(str_par, "event")) {
+ proto = SYN_PROTO_EVENT;
+#endif /* BUILD_EVENTCOMM */
+#ifdef BUILD_PSMCOMM
+ } else if (str_par && !strcmp(str_par, "psm")) {
+ proto = SYN_PROTO_PSM;
+#endif /* BUILD_PSMCOMM */
+ } else if (str_par && !strcmp(str_par, "alps")) {
+ proto = SYN_PROTO_ALPS;
+ } else { /* default to auto-dev */
+#ifdef BUILD_EVENTCOMM
+ if (!device && event_proto_operations.AutoDevProbe(pInfo))
+ proto = SYN_PROTO_EVENT;
+#endif
+ }
+ }
+ switch (proto) {
+ case SYN_PROTO_PSAUX:
+ priv->proto_ops = &psaux_proto_operations;
+ break;
+#ifdef BUILD_EVENTCOMM
+ case SYN_PROTO_EVENT:
+ priv->proto_ops = &event_proto_operations;
+ break;
+#endif /* BUILD_EVENTCOMM */
+#ifdef BUILD_PSMCOMM
+ case SYN_PROTO_PSM:
+ priv->proto_ops = &psm_proto_operations;
+ break;
+#endif /* BUILD_PSMCOMM */
+ case SYN_PROTO_ALPS:
+ priv->proto_ops = &alps_proto_operations;
+ break;
+ }
+}
+
+/*
+ * Allocate and initialize read-only memory for the SynapticsParameters data to hold
+ * driver settings.
+ * The function will allocate shared memory if priv->shm_config is TRUE.
+ */
+static Bool
+alloc_shm_data(InputInfoPtr pInfo)
+{
+ int shmid;
+ SynapticsPrivate *priv = pInfo->private;
+
+ if (priv->synshm)
+ return TRUE; /* Already allocated */
+
+ if (priv->shm_config) {
+ if ((shmid = shmget(SHM_SYNAPTICS, 0, 0)) != -1)
+ shmctl(shmid, IPC_RMID, NULL);
+ if ((shmid = shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM),
+ 0774 | IPC_CREAT)) == -1) {
+ xf86Msg(X_ERROR, "%s error shmget\n", pInfo->name);
+ return FALSE;
+ }
+ if ((priv->synshm = (SynapticsSHM*)shmat(shmid, NULL, 0)) == NULL) {
+ xf86Msg(X_ERROR, "%s error shmat\n", pInfo->name);
+ return FALSE;
+ }
+ } else {
+ priv->synshm = calloc(1, sizeof(SynapticsSHM));
+ if (!priv->synshm)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Free SynapticsParameters data previously allocated by alloc_shm_data().
+ */
+static void
+free_shm_data(SynapticsPrivate *priv)
+{
+ int shmid;
+
+ if (!priv->synshm)
+ return;
+
+ if (priv->shm_config) {
+ if ((shmid = shmget(SHM_SYNAPTICS, 0, 0)) != -1)
+ shmctl(shmid, IPC_RMID, NULL);
+ } else {
+ free(priv->synshm);
+ }
+
+ priv->synshm = NULL;
+}
+
+static void
+calculate_edge_widths(SynapticsPrivate *priv, int *l, int *r, int *t, int *b)
+{
+ int width, height;
+ int ewidth, eheight; /* edge width/height */
+
+ width = abs(priv->maxx - priv->minx);
+ height = abs(priv->maxy - priv->miny);
+
+ if (priv->model == MODEL_SYNAPTICS)
+ {
+ ewidth = width * .07;
+ eheight = height * .07;
+ } else if (priv->model == MODEL_ALPS)
+ {
+ ewidth = width * .15;
+ eheight = height * .15;
+ } else if (priv->model == MODEL_APPLETOUCH)
+ {
+ ewidth = width * .085;
+ eheight = height * .085;
+ } else
+ {
+ ewidth = width * .04;
+ eheight = height * .054;
+ }
+
+ *l = priv->minx + ewidth;
+ *r = priv->maxx - ewidth;
+ *t = priv->miny + eheight;
+ *b = priv->maxy - eheight;
+}
+
+/* Area options support both percent values and absolute values. This is
+ * awkward. The xf86Set* calls will print to the log, but they'll
+ * also print an error if we request a percent value but only have an
+ * int. So - check first for percent, then call xf86Set* again to get
+ * the log message.
+ */
+static int set_percent_option(pointer options, const char* optname,
+ const int range, const int offset,
+ const int default_value)
+{
+ int result;
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
+ double percent = xf86CheckPercentOption(options, optname, -1);
+
+ if (percent >= 0.0) {
+ percent = xf86SetPercentOption(options, optname, -1);
+ result = percent/100.0 * range + offset;
+ } else
+#endif
+ result = xf86SetIntOption(options, optname, default_value);
+
+ return result;
+}
+
+static void set_default_parameters(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = pInfo->private; /* read-only */
+ pointer opts = pInfo->options; /* read-only */
+ SynapticsParameters *pars = &priv->synpara; /* modified */
+
+ int horizScrollDelta, vertScrollDelta; /* pixels */
+ int tapMove; /* pixels */
+ int l, r, t, b; /* left, right, top, bottom */
+ int edgeMotionMinSpeed, edgeMotionMaxSpeed; /* pixels/second */
+ double accelFactor; /* 1/pixels */
+ int fingerLow, fingerHigh, fingerPress; /* pressure */
+ int emulateTwoFingerMinZ; /* pressure */
+ int emulateTwoFingerMinW; /* width */
+ int edgeMotionMinZ, edgeMotionMaxZ; /* pressure */
+ int pressureMotionMinZ, pressureMotionMaxZ; /* pressure */
+ int palmMinWidth, palmMinZ; /* pressure */
+ int tapButton1, tapButton2, tapButton3;
+ int clickFinger1, clickFinger2, clickFinger3;
+ Bool vertEdgeScroll, horizEdgeScroll;
+ Bool vertTwoFingerScroll, horizTwoFingerScroll;
+ int horizResolution = 1;
+ int vertResolution = 1;
+ int width, height, diag, range;
+ int horizHyst, vertHyst;
+
+ /* read the parameters */
+ if (priv->synshm)
+ priv->synshm->version = (PACKAGE_VERSION_MAJOR*10000+PACKAGE_VERSION_MINOR*100+PACKAGE_VERSION_PATCHLEVEL);
+
+ /* The synaptics specs specify typical edge widths of 4% on x, and 5.4% on
+ * y (page 7) [Synaptics TouchPad Interfacing Guide, 510-000080 - A
+ * Second Edition, http://www.synaptics.com/support/dev_support.cfm, 8 Sep
+ * 2008]. We use 7% for both instead for synaptics devices, and 15% for
+ * ALPS models.
+ * http://bugs.freedesktop.org/show_bug.cgi?id=21214
+ *
+ * If the range was autodetected, apply these edge widths to all four
+ * sides.
+ */
+ SynapticsDefaultDimensions(pInfo);
+
+ width = abs(priv->maxx - priv->minx);
+ height = abs(priv->maxy - priv->miny);
+ diag = sqrt(width * width + height * height);
+
+ calculate_edge_widths(priv, &l, &r, &t, &b);
+
+ /* Again, based on typical x/y range and defaults */
+ horizScrollDelta = diag * .020;
+ vertScrollDelta = diag * .020;
+ tapMove = diag * .044;
+ edgeMotionMinSpeed = 1;
+ edgeMotionMaxSpeed = diag * .080;
+ accelFactor = 200.0 / diag; /* trial-and-error */
+
+ /* hysteresis, assume >= 0 is a detected value (e.g. evdev fuzz) */
+ horizHyst = pars->hyst_x >= 0 ? pars->hyst_x : diag * 0.005;
+ vertHyst = pars->hyst_y >= 0 ? pars->hyst_y : diag * 0.005;
+
+ range = priv->maxp - priv->minp;
+
+ /* scaling based on defaults and a pressure of 256 */
+ fingerLow = priv->minp + range * (25.0/256);
+ fingerHigh = priv->minp + range * (30.0/256);
+ fingerPress = priv->minp + range * 1.000;
+ edgeMotionMinZ = priv->minp + range * (30.0/256);
+ edgeMotionMaxZ = priv->minp + range * (160.0/256);
+ pressureMotionMinZ = priv->minp + range * (30.0/256);
+ pressureMotionMaxZ = priv->minp + range * (160.0/256);
+ palmMinZ = priv->minp + range * (200.0/256);
+
+ /* Enable emulation when hw supports both pressure and width. */
+ if (!priv->has_double && priv->has_width)
+ emulateTwoFingerMinZ = fingerHigh;
+ else
+ emulateTwoFingerMinZ = priv->minp + range * (282.0/256);
+
+ range = priv->maxw - priv->minw;
+
+ /* scaling based on defaults below and a tool width of 16 */
+ palmMinWidth = priv->minw + range * (10.0/16);
+ emulateTwoFingerMinW = priv->minw + range * (7.0/16);
+
+ /* Enable tap if we don't have a phys left button */
+ tapButton1 = priv->has_left ? 0 : 1;
+ tapButton2 = priv->has_left ? 0 : 3;
+ tapButton3 = priv->has_left ? 0 : 2;
+
+ /* Enable multifinger-click if only have one physical button,
+ otherwise clickFinger is always button 1. */
+ clickFinger1 = 1;
+ clickFinger2 = (priv->has_right || priv->has_middle) ? 1 : 3;
+ clickFinger3 = (priv->has_right || priv->has_middle) ? 1 : 2;
+
+ /* Enable vert edge scroll if we can't detect doubletap */
+ vertEdgeScroll = priv->has_double ? FALSE : TRUE;
+ horizEdgeScroll = FALSE;
+
+ /* Enable twofinger scroll if we can detect doubletap */
+ vertTwoFingerScroll = priv->has_double ? TRUE : FALSE;
+ horizTwoFingerScroll = FALSE;
+
+ /* Use resolution reported by hardware if available */
+ if ((priv->resx > 0) && (priv->resy > 0)) {
+ horizResolution = priv->resx;
+ vertResolution = priv->resy;
+ }
+
+ /* set the parameters */
+ pars->left_edge = xf86SetIntOption(opts, "LeftEdge", l);
+ pars->right_edge = xf86SetIntOption(opts, "RightEdge", r);
+ pars->top_edge = xf86SetIntOption(opts, "TopEdge", t);
+ pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", b);
+
+ pars->area_top_edge = set_percent_option(opts, "AreaTopEdge", height, priv->miny, 0);
+ pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge", height, priv->miny, 0);
+ pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge", width, priv->minx, 0);
+ pars->area_right_edge = set_percent_option(opts, "AreaRightEdge", width, priv->minx, 0);
+
+ pars->hyst_x = set_percent_option(opts, "HorizHysteresis", width, 0, horizHyst);
+ pars->hyst_y = set_percent_option(opts, "VertHysteresis", height, 0, vertHyst);
+
+ pars->finger_low = xf86SetIntOption(opts, "FingerLow", fingerLow);
+ pars->finger_high = xf86SetIntOption(opts, "FingerHigh", fingerHigh);
+ pars->finger_press = xf86SetIntOption(opts, "FingerPress", fingerPress);
+ pars->tap_time = xf86SetIntOption(opts, "MaxTapTime", 180);
+ pars->tap_move = xf86SetIntOption(opts, "MaxTapMove", tapMove);
+ pars->tap_time_2 = xf86SetIntOption(opts, "MaxDoubleTapTime", 180);
+ pars->click_time = xf86SetIntOption(opts, "ClickTime", 100);
+ pars->fast_taps = xf86SetBoolOption(opts, "FastTaps", FALSE);
+ pars->emulate_mid_button_time = xf86SetIntOption(opts, "EmulateMidButtonTime", 75);
+ pars->emulate_twofinger_z = xf86SetIntOption(opts, "EmulateTwoFingerMinZ", emulateTwoFingerMinZ);
+ pars->emulate_twofinger_w = xf86SetIntOption(opts, "EmulateTwoFingerMinW", emulateTwoFingerMinW);
+ pars->scroll_dist_vert = xf86SetIntOption(opts, "VertScrollDelta", horizScrollDelta);
+ pars->scroll_dist_horiz = xf86SetIntOption(opts, "HorizScrollDelta", vertScrollDelta);
+ pars->scroll_edge_vert = xf86SetBoolOption(opts, "VertEdgeScroll", vertEdgeScroll);
+ pars->scroll_edge_horiz = xf86SetBoolOption(opts, "HorizEdgeScroll", horizEdgeScroll);
+ pars->scroll_edge_corner = xf86SetBoolOption(opts, "CornerCoasting", FALSE);
+ pars->scroll_twofinger_vert = xf86SetBoolOption(opts, "VertTwoFingerScroll", vertTwoFingerScroll);
+ pars->scroll_twofinger_horiz = xf86SetBoolOption(opts, "HorizTwoFingerScroll", horizTwoFingerScroll);
+ pars->edge_motion_min_z = xf86SetIntOption(opts, "EdgeMotionMinZ", edgeMotionMinZ);
+ pars->edge_motion_max_z = xf86SetIntOption(opts, "EdgeMotionMaxZ", edgeMotionMaxZ);
+ pars->edge_motion_min_speed = xf86SetIntOption(opts, "EdgeMotionMinSpeed", edgeMotionMinSpeed);
+ pars->edge_motion_max_speed = xf86SetIntOption(opts, "EdgeMotionMaxSpeed", edgeMotionMaxSpeed);
+ pars->edge_motion_use_always = xf86SetBoolOption(opts, "EdgeMotionUseAlways", FALSE);
+ if (priv->has_scrollbuttons) {
+ pars->updown_button_scrolling = xf86SetBoolOption(opts, "UpDownScrolling", TRUE);
+ pars->leftright_button_scrolling = xf86SetBoolOption(opts, "LeftRightScrolling", TRUE);
+ pars->updown_button_repeat = xf86SetBoolOption(opts, "UpDownScrollRepeat", TRUE);
+ pars->leftright_button_repeat = xf86SetBoolOption(opts, "LeftRightScrollRepeat", TRUE);
+ }
+ pars->scroll_button_repeat = xf86SetIntOption(opts,"ScrollButtonRepeat", 100);
+ pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", 0);
+ pars->locked_drags = xf86SetBoolOption(opts, "LockedDrags", FALSE);
+ pars->locked_drag_time = xf86SetIntOption(opts, "LockedDragTimeout", 5000);
+ pars->tap_action[RT_TAP] = xf86SetIntOption(opts, "RTCornerButton", 0);
+ pars->tap_action[RB_TAP] = xf86SetIntOption(opts, "RBCornerButton", 0);
+ pars->tap_action[LT_TAP] = xf86SetIntOption(opts, "LTCornerButton", 0);
+ pars->tap_action[LB_TAP] = xf86SetIntOption(opts, "LBCornerButton", 0);
+ pars->tap_action[F1_TAP] = xf86SetIntOption(opts, "TapButton1", tapButton1);
+ pars->tap_action[F2_TAP] = xf86SetIntOption(opts, "TapButton2", tapButton2);
+ pars->tap_action[F3_TAP] = xf86SetIntOption(opts, "TapButton3", tapButton3);
+ pars->click_action[F1_CLICK1] = xf86SetIntOption(opts, "ClickFinger1", clickFinger1);
+ pars->click_action[F2_CLICK1] = xf86SetIntOption(opts, "ClickFinger2", clickFinger2);
+ pars->click_action[F3_CLICK1] = xf86SetIntOption(opts, "ClickFinger3", clickFinger3);
+ pars->circular_scrolling = xf86SetBoolOption(opts, "CircularScrolling", FALSE);
+ pars->circular_trigger = xf86SetIntOption(opts, "CircScrollTrigger", 0);
+ pars->circular_pad = xf86SetBoolOption(opts, "CircularPad", FALSE);
+ pars->palm_detect = xf86SetBoolOption(opts, "PalmDetect", FALSE);
+ pars->palm_min_width = xf86SetIntOption(opts, "PalmMinWidth", palmMinWidth);
+ pars->palm_min_z = xf86SetIntOption(opts, "PalmMinZ", palmMinZ);
+ pars->single_tap_timeout = xf86SetIntOption(opts, "SingleTapTimeout", 180);
+ pars->press_motion_min_z = xf86SetIntOption(opts, "PressureMotionMinZ", pressureMotionMinZ);
+ pars->press_motion_max_z = xf86SetIntOption(opts, "PressureMotionMaxZ", pressureMotionMaxZ);
+
+ pars->min_speed = xf86SetRealOption(opts, "MinSpeed", 0.4);
+ pars->max_speed = xf86SetRealOption(opts, "MaxSpeed", 0.7);
+ pars->accl = xf86SetRealOption(opts, "AccelFactor", accelFactor);
+ pars->trackstick_speed = xf86SetRealOption(opts, "TrackstickSpeed", 40);
+ pars->scroll_dist_circ = xf86SetRealOption(opts, "CircScrollDelta", 0.1);
+ pars->coasting_speed = xf86SetRealOption(opts, "CoastingSpeed", 20.0);
+ pars->coasting_friction = xf86SetRealOption(opts, "CoastingFriction", 50);
+ pars->press_motion_min_factor = xf86SetRealOption(opts, "PressureMotionMinFactor", 1.0);
+ pars->press_motion_max_factor = xf86SetRealOption(opts, "PressureMotionMaxFactor", 1.0);
+ pars->grab_event_device = xf86SetBoolOption(opts, "GrabEventDevice", TRUE);
+ pars->tap_and_drag_gesture = xf86SetBoolOption(opts, "TapAndDragGesture", TRUE);
+ pars->resolution_horiz = xf86SetIntOption(opts, "HorizResolution", horizResolution);
+ pars->resolution_vert = xf86SetIntOption(opts, "VertResolution", vertResolution);
+
+ /* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
+ if (pars->top_edge > pars->bottom_edge) {
+ int tmp = pars->top_edge;
+ pars->top_edge = pars->bottom_edge;
+ pars->bottom_edge = tmp;
+ xf86Msg(X_WARNING, "%s: TopEdge is bigger than BottomEdge. Fixing.\n",
+ pInfo->name);
+ }
+}
+
+static float SynapticsAccelerationProfile(DeviceIntPtr dev,
+ DeviceVelocityPtr vel,
+ float velocity,
+ float thr,
+ float acc) {
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters* para = &priv->synpara;
+
+ double accelfct;
+
+ /*
+ * synaptics accel was originally base on device coordinate based
+ * velocity, which we recover this way so para->accl retains its scale.
+ */
+ velocity /= vel->const_acceleration;
+
+ /* speed up linear with finger velocity */
+ accelfct = velocity * para->accl;
+
+ /* clip acceleration factor */
+ if (accelfct > para->max_speed * acc)
+ accelfct = para->max_speed * acc;
+ else if (accelfct < para->min_speed)
+ accelfct = para->min_speed;
+
+ /* modify speed according to pressure */
+ if (priv->moving_state == MS_TOUCHPAD_RELATIVE) {
+ int minZ = para->press_motion_min_z;
+ int maxZ = para->press_motion_max_z;
+ double minFctr = para->press_motion_min_factor;
+ double maxFctr = para->press_motion_max_factor;
+ if (priv->hwState.z <= minZ) {
+ accelfct *= minFctr;
+ } else if (priv->hwState.z >= maxZ) {
+ accelfct *= maxFctr;
+ } else {
+ accelfct *= minFctr + (priv->hwState.z - minZ) * (maxFctr - minFctr) / (maxZ - minZ);
+ }
+ }
+
+ return accelfct;
+}
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12
+static int
+NewSynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+/*
+ * called by the module loader for initialization
+ */
+static InputInfoPtr
+SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr pInfo;
+
+ /* Allocate a new InputInfoRec and add it to the head xf86InputDevs. */
+ pInfo = xf86AllocateInput(drv, 0);
+ if (!pInfo) {
+ return NULL;
+ }
+
+ /* initialize the InputInfoRec */
+ pInfo->name = dev->identifier;
+ pInfo->reverse_conversion_proc = NULL;
+ pInfo->dev = NULL;
+ pInfo->private_flags = 0;
+ pInfo->flags = XI86_SEND_DRAG_EVENTS;
+ pInfo->conf_idev = dev;
+ pInfo->always_core_feedback = 0;
+
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+
+ if (NewSynapticsPreInit(drv, pInfo, flags) != Success)
+ return NULL;
+
+ pInfo->flags |= XI86_CONFIGURED;
+
+ return pInfo;
+}
+
+static int
+NewSynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+#else
+static int
+SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+#endif
+{
+ SynapticsPrivate *priv;
+
+ /* allocate memory for SynapticsPrivateRec */
+ priv = calloc(1, sizeof(SynapticsPrivate));
+ if (!priv)
+ return BadAlloc;
+
+ pInfo->type_name = XI_TOUCHPAD;
+ pInfo->device_control = DeviceControl;
+ pInfo->read_input = ReadInput;
+ pInfo->control_proc = ControlProc;
+ pInfo->switch_mode = SwitchMode;
+ pInfo->private = priv;
+
+ /* allocate now so we don't allocate in the signal handler */
+ priv->timer = TimerSet(NULL, 0, 0, NULL, NULL);
+ if (!priv->timer) {
+ free(priv);
+ return BadAlloc;
+ }
+
+ /* may change pInfo->options */
+ SetDeviceAndProtocol(pInfo);
+
+ /* open the touchpad device */
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1) {
+ xf86Msg(X_ERROR, "Synaptics driver unable to open device\n");
+ goto SetupProc_fail;
+ }
+ xf86ErrorFVerb(6, "port opened successfully\n");
+
+ /* initialize variables */
+ priv->repeatButtons = 0;
+ priv->nextRepeat = 0;
+ priv->count_packet_finger = 0;
+ priv->tap_state = TS_START;
+ priv->tap_button = 0;
+ priv->tap_button_state = TBS_BUTTON_UP;
+ priv->touch_on.millis = 0;
+ priv->synpara.hyst_x = -1;
+ priv->synpara.hyst_y = -1;
+
+ /* read hardware dimensions */
+ ReadDevDimensions(pInfo);
+
+ /* install shared memory or normal memory for parameters */
+ priv->shm_config = xf86SetBoolOption(pInfo->options, "SHMConfig", FALSE);
+
+ set_default_parameters(pInfo);
+
+ CalculateScalingCoeffs(priv);
+
+ if (!alloc_shm_data(pInfo))
+ goto SetupProc_fail;
+
+ priv->comm.buffer = XisbNew(pInfo->fd, INPUT_BUFFER_SIZE);
+
+ if (!QueryHardware(pInfo)) {
+ xf86Msg(X_ERROR, "%s Unable to query/initialize Synaptics hardware.\n", pInfo->name);
+ goto SetupProc_fail;
+ }
+
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ if (pInfo->fd != -1) {
+ if (priv->comm.buffer) {
+ XisbFree(priv->comm.buffer);
+ priv->comm.buffer = NULL;
+ }
+ xf86CloseSerial(pInfo->fd);
+ }
+ pInfo->fd = -1;
+
+ return Success;
+
+ SetupProc_fail:
+ if (pInfo->fd >= 0) {
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ }
+
+ if (priv->comm.buffer)
+ XisbFree(priv->comm.buffer);
+ free_shm_data(priv);
+ free(priv->proto_data);
+ free(priv->timer);
+ free(priv);
+ pInfo->private = NULL;
+ return BadAlloc;
+}
+
+
+/*
+ * Uninitialize the device.
+ */
+static void SynapticsUnInit(InputDriverPtr drv,
+ InputInfoPtr pInfo,
+ int flags)
+{
+ SynapticsPrivate *priv = ((SynapticsPrivate *)pInfo->private);
+ if (priv && priv->timer)
+ free(priv->timer);
+ if (priv && priv->proto_data)
+ free(priv->proto_data);
+ free(pInfo->private);
+ pInfo->private = NULL;
+ xf86DeleteInput(pInfo, 0);
+}
+
+
+/*
+ * Alter the control parameters for the mouse. Note that all special
+ * protocol values are handled by dix.
+ */
+static void
+SynapticsCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+}
+
+static Bool
+DeviceControl(DeviceIntPtr dev, int mode)
+{
+ Bool RetValue;
+
+ switch (mode) {
+ case DEVICE_INIT:
+ RetValue = DeviceInit(dev);
+ break;
+ case DEVICE_ON:
+ RetValue = DeviceOn(dev);
+ break;
+ case DEVICE_OFF:
+ RetValue = DeviceOff(dev);
+ break;
+ case DEVICE_CLOSE:
+ RetValue = DeviceClose(dev);
+ break;
+ default:
+ RetValue = BadValue;
+ }
+
+ return RetValue;
+}
+
+static Bool
+DeviceOn(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+
+ DBG(3, "Synaptics DeviceOn called\n");
+
+ SetDeviceAndProtocol(pInfo);
+ pInfo->fd = xf86OpenSerial(pInfo->options);
+ if (pInfo->fd == -1) {
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
+ return !Success;
+ }
+
+ if (priv->proto_ops->DeviceOnHook)
+ priv->proto_ops->DeviceOnHook(pInfo, &priv->synpara);
+
+ priv->comm.buffer = XisbNew(pInfo->fd, INPUT_BUFFER_SIZE);
+ if (!priv->comm.buffer) {
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ return !Success;
+ }
+
+ xf86FlushInput(pInfo->fd);
+
+ /* reinit the pad */
+ if (!QueryHardware(pInfo))
+ {
+ XisbFree(priv->comm.buffer);
+ priv->comm.buffer = NULL;
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ return !Success;
+ }
+
+ xf86AddEnabledDevice(pInfo);
+ dev->public.on = TRUE;
+
+ return Success;
+}
+
+static Bool
+DeviceOff(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+
+ DBG(3, "Synaptics DeviceOff called\n");
+
+ if (pInfo->fd != -1) {
+ TimerCancel(priv->timer);
+ xf86RemoveEnabledDevice(pInfo);
+ if (priv->proto_ops->DeviceOffHook)
+ priv->proto_ops->DeviceOffHook(pInfo);
+ if (priv->comm.buffer) {
+ XisbFree(priv->comm.buffer);
+ priv->comm.buffer = NULL;
+ }
+ xf86CloseSerial(pInfo->fd);
+ pInfo->fd = -1;
+ }
+ dev->public.on = FALSE;
+ return Success;
+}
+
+static Bool
+DeviceClose(DeviceIntPtr dev)
+{
+ Bool RetValue;
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+
+ RetValue = DeviceOff(dev);
+ TimerFree(priv->timer);
+ priv->timer = NULL;
+ free_shm_data(priv);
+ return RetValue;
+}
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+static void InitAxesLabels(Atom *labels, int nlabels)
+{
+ memset(labels, 0, nlabels * sizeof(Atom));
+ switch(nlabels)
+ {
+ default:
+ case 2:
+ labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+ case 1:
+ labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+ break;
+ }
+}
+
+static void InitButtonLabels(Atom *labels, int nlabels)
+{
+ memset(labels, 0, nlabels * sizeof(Atom));
+ switch(nlabels)
+ {
+ default:
+ case 7:
+ labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+ case 6:
+ labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+ case 5:
+ labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+ case 4:
+ labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+ case 3:
+ labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+ case 2:
+ labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+ case 1:
+ labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+ break;
+ }
+}
+#endif
+
+static Bool
+DeviceInit(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ Atom float_type, prop;
+ float tmpf;
+ unsigned char map[SYN_MAX_BUTTONS + 1];
+ int i;
+ int min, max;
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ Atom btn_labels[SYN_MAX_BUTTONS] = { 0 };
+ Atom axes_labels[2] = { 0 };
+ DeviceVelocityPtr pVel;
+
+ InitAxesLabels(axes_labels, 2);
+ InitButtonLabels(btn_labels, SYN_MAX_BUTTONS);
+#endif
+
+ DBG(3, "Synaptics DeviceInit called\n");
+
+ for (i = 0; i <= SYN_MAX_BUTTONS; i++)
+ map[i] = i;
+
+ dev->public.on = FALSE;
+
+ InitPointerDeviceStruct((DevicePtr)dev, map,
+ SYN_MAX_BUTTONS,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ btn_labels,
+#endif
+ SynapticsCtrl,
+ GetMotionHistorySize(), 2
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ , axes_labels
+#endif
+ );
+
+ /*
+ * setup dix acceleration to match legacy synaptics settings, and
+ * etablish a device-specific profile to do stuff like pressure-related
+ * acceleration.
+ */
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ if (NULL != (pVel = GetDevicePredictableAccelData(dev))) {
+ SetDeviceSpecificAccelerationProfile(pVel,
+ SynapticsAccelerationProfile);
+
+ /* float property type */
+ float_type = XIGetKnownProperty(XATOM_FLOAT);
+
+ /* translate MinAcc to constant deceleration.
+ * May be overridden in xf86InitValuatorDefaults */
+ tmpf = 1.0 / priv->synpara.min_speed;
+
+ xf86Msg(X_CONFIG, "%s: (accel) MinSpeed is now constant deceleration "
+ "%.1f\n", dev->name, tmpf);
+ prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
+ XIChangeDeviceProperty(dev, prop, float_type, 32,
+ PropModeReplace, 1, &tmpf, FALSE);
+
+ /* adjust accordingly */
+ priv->synpara.max_speed /= priv->synpara.min_speed;
+ priv->synpara.min_speed = 1.0;
+
+ /* synaptics seems to report 80 packet/s, but dix scales for
+ * 100 packet/s by default. */
+ pVel->corr_mul = 12.5f; /*1000[ms]/80[/s] = 12.5 */
+
+ xf86Msg(X_CONFIG, "%s: MaxSpeed is now %.2f\n",
+ dev->name, priv->synpara.max_speed);
+ xf86Msg(X_CONFIG, "%s: AccelFactor is now %.3f\n",
+ dev->name, priv->synpara.accl);
+
+ prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
+ i = AccelProfileDeviceSpecific;
+ XIChangeDeviceProperty(dev, prop, XA_INTEGER, 32,
+ PropModeReplace, 1, &i, FALSE);
+ }
+#endif
+
+ /* X valuator */
+ if (priv->minx < priv->maxx)
+ {
+ min = priv->minx;
+ max = priv->maxx;
+ } else
+ {
+ min = 0;
+ max = -1;
+ }
+
+ xf86InitValuatorAxisStruct(dev, 0,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ axes_labels[0],
+#endif
+ min, max, priv->resx * 1000, 0, priv->resx * 1000
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+ , Relative
+#endif
+ );
+ xf86InitValuatorDefaults(dev, 0);
+
+ /* Y valuator */
+ if (priv->miny < priv->maxy)
+ {
+ min = priv->miny;
+ max = priv->maxy;
+ } else
+ {
+ min = 0;
+ max = -1;
+ }
+
+ xf86InitValuatorAxisStruct(dev, 1,
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
+ axes_labels[1],
+#endif
+ min, max, priv->resy * 1000, 0, priv->resy * 1000
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
+ , Relative
+#endif
+ );
+ xf86InitValuatorDefaults(dev, 1);
+
+ if (!alloc_shm_data(pInfo))
+ return !Success;
+
+ InitDeviceProperties(pInfo);
+ XIRegisterPropertyHandler(pInfo->dev, SetProperty, NULL, NULL);
+
+ return Success;
+}
+
+
+/*
+ * Convert from absolute X/Y coordinates to a coordinate system where
+ * -1 corresponds to the left/upper edge and +1 corresponds to the
+ * right/lower edge.
+ */
+static void
+relative_coords(SynapticsPrivate *priv, int x, int y,
+ double *relX, double *relY)
+{
+ int minX = priv->synpara.left_edge;
+ int maxX = priv->synpara.right_edge;
+ int minY = priv->synpara.top_edge;
+ int maxY = priv->synpara.bottom_edge;
+ double xCenter = (minX + maxX) / 2.0;
+ double yCenter = (minY + maxY) / 2.0;
+
+ if ((maxX - xCenter > 0) && (maxY - yCenter > 0)) {
+ *relX = (x - xCenter) / (maxX - xCenter);
+ *relY = (y - yCenter) / (maxY - yCenter);
+ } else {
+ *relX = 0;
+ *relY = 0;
+ }
+}
+
+/* return angle of point relative to center */
+static double
+angle(SynapticsPrivate *priv, int x, int y)
+{
+ double xCenter = (priv->synpara.left_edge + priv->synpara.right_edge) / 2.0;
+ double yCenter = (priv->synpara.top_edge + priv->synpara.bottom_edge) / 2.0;
+
+ return atan2(-(y - yCenter), x - xCenter);
+}
+
+/* return angle difference */
+static double
+diffa(double a1, double a2)
+{
+ double da = fmod(a2 - a1, 2 * M_PI);
+ if (da < 0)
+ da += 2 * M_PI;
+ if (da > M_PI)
+ da -= 2 * M_PI;
+ return da;
+}
+
+static edge_type
+circular_edge_detection(SynapticsPrivate *priv, int x, int y)
+{
+ edge_type edge = 0;
+ double relX, relY, relR;
+
+ relative_coords(priv, x, y, &relX, &relY);
+ relR = SQR(relX) + SQR(relY);
+
+ if (relR > 1) {
+ /* we are outside the ellipse enclosed by the edge parameters */
+ if (relX > M_SQRT1_2)
+ edge |= RIGHT_EDGE;
+ else if (relX < -M_SQRT1_2)
+ edge |= LEFT_EDGE;
+
+ if (relY < -M_SQRT1_2)
+ edge |= TOP_EDGE;
+ else if (relY > M_SQRT1_2)
+ edge |= BOTTOM_EDGE;
+ }
+
+ return edge;
+}
+
+static edge_type
+edge_detection(SynapticsPrivate *priv, int x, int y)
+{
+ edge_type edge = NO_EDGE;
+
+ if (priv->synpara.circular_pad)
+ return circular_edge_detection(priv, x, y);
+
+ if (x > priv->synpara.right_edge)
+ edge |= RIGHT_EDGE;
+ else if (x < priv->synpara.left_edge)
+ edge |= LEFT_EDGE;
+
+ if (y < priv->synpara.top_edge)
+ edge |= TOP_EDGE;
+ else if (y > priv->synpara.bottom_edge)
+ edge |= BOTTOM_EDGE;
+
+ return edge;
+}
+
+/* Checks whether coordinates are in the Synaptics Area
+ * or not. If no Synaptics Area is defined (i.e. if
+ * priv->synpara.area_{left|right|top|bottom}_edge are
+ * all set to zero), the function returns TRUE.
+ */
+static Bool
+is_inside_active_area(SynapticsPrivate *priv, int x, int y)
+{
+ Bool inside_area = TRUE;
+
+ if ((priv->synpara.area_left_edge != 0) && (x < priv->synpara.area_left_edge))
+ inside_area = FALSE;
+ else if ((priv->synpara.area_right_edge != 0) && (x > priv->synpara.area_right_edge))
+ inside_area = FALSE;
+
+ if ((priv->synpara.area_top_edge != 0) && (y < priv->synpara.area_top_edge))
+ inside_area = FALSE;
+ else if ((priv->synpara.area_bottom_edge != 0) && (y > priv->synpara.area_bottom_edge))
+ inside_area = FALSE;
+
+ return inside_area;
+}
+
+static CARD32
+timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+ InputInfoPtr pInfo = arg;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ struct SynapticsHwState hw;
+ int delay;
+ int sigstate;
+ CARD32 wakeUpTime;
+
+ sigstate = xf86BlockSIGIO();
+
+ hw = priv->hwState;
+ hw.millis = now;
+ delay = HandleState(pInfo, &hw);
+
+ /*
+ * Workaround for wraparound bug in the TimerSet function. This bug is already
+ * fixed in CVS, but this driver needs to work with XFree86 versions 4.2.x and
+ * 4.3.x too.
+ */
+ wakeUpTime = now + delay;
+ if (wakeUpTime <= now)
+ wakeUpTime = 0xffffffffL;
+
+ priv->timer = TimerSet(priv->timer, TimerAbsolute, wakeUpTime, timerFunc, pInfo);
+
+ xf86UnblockSIGIO(sigstate);
+
+ return 0;
+}
+
+static int
+clamp(int val, int min, int max)
+{
+ if (val < min)
+ return min;
+ else if (val < max)
+ return val;
+ else
+ return max;
+}
+
+static Bool
+SynapticsGetHwState(InputInfoPtr pInfo, SynapticsPrivate *priv,
+ struct SynapticsHwState *hw)
+{
+ return priv->proto_ops->ReadHwState(pInfo, priv->proto_ops,
+ &priv->comm, hw);
+}
+
+/*
+ * called for each full received packet from the touchpad
+ */
+static void
+ReadInput(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ struct SynapticsHwState hw;
+ int delay = 0;
+ Bool newDelay = FALSE;
+
+ while (SynapticsGetHwState(pInfo, priv, &hw)) {
+ hw.millis = GetTimeInMillis();
+ priv->hwState = hw;
+ delay = HandleState(pInfo, &hw);
+ newDelay = TRUE;
+ }
+
+ if (newDelay)
+ priv->timer = TimerSet(priv->timer, 0, delay, timerFunc, pInfo);
+}
+
+static int
+HandleMidButtonEmulation(SynapticsPrivate *priv, struct SynapticsHwState *hw, int *delay)
+{
+ SynapticsParameters *para = &priv->synpara;
+ Bool done = FALSE;
+ int timeleft;
+ int mid = 0;
+
+ while (!done) {
+ switch (priv->mid_emu_state) {
+ case MBE_LEFT_CLICK:
+ case MBE_RIGHT_CLICK:
+ case MBE_OFF:
+ priv->button_delay_millis = hw->millis;
+ if (hw->left) {
+ priv->mid_emu_state = MBE_LEFT;
+ } else if (hw->right) {
+ priv->mid_emu_state = MBE_RIGHT;
+ } else {
+ done = TRUE;
+ }
+ break;
+ case MBE_LEFT:
+ timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time,
+ hw->millis);
+ if (timeleft > 0)
+ *delay = MIN(*delay, timeleft);
+
+ /* timeout, but within the same ReadInput cycle! */
+ if ((timeleft <= 0) && !hw->left) {
+ priv->mid_emu_state = MBE_LEFT_CLICK;
+ done = TRUE;
+ } else if ((!hw->left) || (timeleft <= 0)) {
+ hw->left = TRUE;
+ priv->mid_emu_state = MBE_TIMEOUT;
+ done = TRUE;
+ } else if (hw->right) {
+ priv->mid_emu_state = MBE_MID;
+ } else {
+ hw->left = FALSE;
+ done = TRUE;
+ }
+ break;
+ case MBE_RIGHT:
+ timeleft = TIME_DIFF(priv->button_delay_millis + para->emulate_mid_button_time,
+ hw->millis);
+ if (timeleft > 0)
+ *delay = MIN(*delay, timeleft);
+
+ /* timeout, but within the same ReadInput cycle! */
+ if ((timeleft <= 0) && !hw->right) {
+ priv->mid_emu_state = MBE_RIGHT_CLICK;
+ done = TRUE;
+ } else if (!hw->right || (timeleft <= 0)) {
+ hw->right = TRUE;
+ priv->mid_emu_state = MBE_TIMEOUT;
+ done = TRUE;
+ } else if (hw->left) {
+ priv->mid_emu_state = MBE_MID;
+ } else {
+ hw->right = FALSE;
+ done = TRUE;
+ }
+ break;
+ case MBE_MID:
+ if (!hw->left && !hw->right) {
+ priv->mid_emu_state = MBE_OFF;
+ } else {
+ mid = TRUE;
+ hw->left = hw->right = FALSE;
+ done = TRUE;
+ }
+ break;
+ case MBE_TIMEOUT:
+ if (!hw->left && !hw->right) {
+ priv->mid_emu_state = MBE_OFF;
+ } else {
+ done = TRUE;
+ }
+ }
+ }
+ return mid;
+}
+
+static enum FingerState
+SynapticsDetectFinger(SynapticsPrivate *priv, struct SynapticsHwState *hw)
+{
+ SynapticsParameters *para = &priv->synpara;
+ enum FingerState finger;
+
+ /* finger detection thru pressure and threshold */
+ if (hw->z > para->finger_press && priv->finger_state < FS_PRESSED)
+ finger = FS_PRESSED;
+ else if (hw->z > para->finger_high && priv->finger_state < FS_TOUCHED)
+ finger = FS_TOUCHED;
+ else if (hw->z < para->finger_low && priv->finger_state > FS_UNTOUCHED)
+ finger = FS_UNTOUCHED;
+ else
+ finger = priv->finger_state;
+
+ if (!para->palm_detect)
+ return finger;
+
+ /* palm detection */
+ if (finger) {
+ if ((hw->z > para->palm_min_z) && (hw->fingerWidth > para->palm_min_width))
+ priv->palm = TRUE;
+ } else {
+ priv->palm = FALSE;
+ }
+ if (hw->x == 0)
+ priv->avg_width = 0;
+ else
+ priv->avg_width += (hw->fingerWidth - priv->avg_width + 1) / 2;
+ if (finger && !priv->finger_state) {
+ int safe_width = MAX(hw->fingerWidth, priv->avg_width);
+
+ if (hw->numFingers > 1 || /* more than one finger -> not a palm */
+ ((safe_width < 6) && (priv->prev_z < para->finger_high)) || /* thin finger, distinct touch -> not a palm */
+ ((safe_width < 7) && (priv->prev_z < para->finger_high / 2)))/* thin finger, distinct touch -> not a palm */
+ {
+ /* leave finger value as is */
+ } else if (hw->z > priv->prev_z + 1) /* z not stable, may be a palm */
+ finger = FS_UNTOUCHED;
+ else if (hw->z < priv->prev_z - 5) /* z not stable, may be a palm */
+ finger = FS_UNTOUCHED;
+ else if (hw->fingerWidth > para->palm_min_width) /* finger width too large -> probably palm */
+ finger = FS_UNTOUCHED;
+ }
+ priv->prev_z = hw->z;
+
+ if (priv->palm)
+ finger = FS_UNTOUCHED;
+
+ return finger;
+}
+
+static void
+SelectTapButton(SynapticsPrivate *priv, edge_type edge)
+{
+ TapEvent tap;
+
+ if (priv->synpara.touchpad_off == 2) {
+ priv->tap_button = 0;
+ return;
+ }
+
+ switch (priv->tap_max_fingers) {
+ case 1:
+ default:
+ switch (edge) {
+ case RIGHT_TOP_EDGE:
+ DBG(7, "right top edge\n");
+ tap = RT_TAP;
+ break;
+ case RIGHT_BOTTOM_EDGE:
+ DBG(7, "right bottom edge\n");
+ tap = RB_TAP;
+ break;
+ case LEFT_TOP_EDGE:
+ DBG(7, "left top edge\n");
+ tap = LT_TAP;
+ break;
+ case LEFT_BOTTOM_EDGE:
+ DBG(7, "left bottom edge\n");
+ tap = LB_TAP;
+ break;
+ default:
+ DBG(7, "no edge\n");
+ tap = F1_TAP;
+ break;
+ }
+ break;
+ case 2:
+ DBG(7, "two finger tap\n");
+ tap = F2_TAP;
+ break;
+ case 3:
+ DBG(7, "three finger tap\n");
+ tap = F3_TAP;
+ break;
+ }
+
+ priv->tap_button = priv->synpara.tap_action[tap];
+ priv->tap_button = clamp(priv->tap_button, 0, SYN_MAX_BUTTONS);
+}
+
+static void
+SetTapState(SynapticsPrivate *priv, enum TapState tap_state, int millis)
+{
+ SynapticsParameters *para = &priv->synpara;
+ DBG(7, "SetTapState - %d -> %d (millis:%d)\n", priv->tap_state, tap_state, millis);
+ switch (tap_state) {
+ case TS_START:
+ priv->tap_button_state = TBS_BUTTON_UP;
+ priv->tap_max_fingers = 0;
+ break;
+ case TS_1:
+ priv->tap_button_state = TBS_BUTTON_UP;
+ break;
+ case TS_2A:
+ if (para->fast_taps)
+ priv->tap_button_state = TBS_BUTTON_DOWN;
+ else
+ priv->tap_button_state = TBS_BUTTON_UP;
+ break;
+ case TS_2B:
+ priv->tap_button_state = TBS_BUTTON_UP;
+ break;
+ case TS_3:
+ if (para->tap_and_drag_gesture)
+ priv->tap_button_state = TBS_BUTTON_DOWN;
+ else
+ priv->tap_button_state = TBS_BUTTON_UP;
+ break;
+ case TS_SINGLETAP:
+ if (para->fast_taps)
+ priv->tap_button_state = TBS_BUTTON_UP;
+ else
+ priv->tap_button_state = TBS_BUTTON_DOWN;
+ priv->touch_on.millis = millis;
+ break;
+ default:
+ break;
+ }
+ priv->tap_state = tap_state;
+}
+
+static void
+SetMovingState(SynapticsPrivate *priv, enum MovingState moving_state, int millis)
+{
+ DBG(7, "SetMovingState - %d -> %d center at %d/%d (millis:%d)\n", priv->moving_state,
+ moving_state,priv->hwState.x, priv->hwState.y, millis);
+
+ if (moving_state == MS_TRACKSTICK) {
+ priv->trackstick_neutral_x = priv->hwState.x;
+ priv->trackstick_neutral_y = priv->hwState.y;
+ }
+ priv->moving_state = moving_state;
+}
+
+static int
+GetTimeOut(SynapticsPrivate *priv)
+{
+ SynapticsParameters *para = &priv->synpara;
+
+ switch (priv->tap_state) {
+ case TS_1:
+ case TS_3:
+ case TS_5:
+ return para->tap_time;
+ case TS_SINGLETAP:
+ return para->click_time;
+ case TS_2A:
+ return para->single_tap_timeout;
+ case TS_2B:
+ return para->tap_time_2;
+ case TS_4:
+ return para->locked_drag_time;
+ default:
+ return -1; /* No timeout */
+ }
+}
+
+static int
+HandleTapProcessing(SynapticsPrivate *priv, struct SynapticsHwState *hw,
+ enum FingerState finger, Bool inside_active_area)
+{
+ SynapticsParameters *para = &priv->synpara;
+ Bool touch, release, is_timeout, move;
+ int timeleft, timeout;
+ edge_type edge;
+ int delay = 1000000000;
+
+ if (priv->palm)
+ return delay;
+
+ touch = finger && !priv->finger_state;
+ release = !finger && priv->finger_state;
+ move = (finger &&
+ (priv->tap_max_fingers <= ((priv->horiz_scroll_twofinger_on || priv->vert_scroll_twofinger_on)? 2 : 1)) &&
+ ((abs(hw->x - priv->touch_on.x) >= para->tap_move) ||
+ (abs(hw->y - priv->touch_on.y) >= para->tap_move)));
+
+ if (touch) {
+ priv->touch_on.x = hw->x;
+ priv->touch_on.y = hw->y;
+ priv->touch_on.millis = hw->millis;
+ } else if (release) {
+ priv->touch_on.millis = hw->millis;
+ }
+ if (hw->z > para->finger_high)
+ if (priv->tap_max_fingers < hw->numFingers)
+ priv->tap_max_fingers = hw->numFingers;
+ timeout = GetTimeOut(priv);
+ timeleft = TIME_DIFF(priv->touch_on.millis + timeout, hw->millis);
+ is_timeout = timeleft <= 0;
+
+ restart:
+ switch (priv->tap_state) {
+ case TS_START:
+ if (touch)
+ SetTapState(priv, TS_1, hw->millis);
+ break;
+ case TS_1:
+ if (move) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ SetTapState(priv, TS_MOVE, hw->millis);
+ goto restart;
+ } else if (is_timeout) {
+ if (finger == FS_TOUCHED) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ } else if (finger == FS_PRESSED) {
+ SetMovingState(priv, MS_TRACKSTICK, hw->millis);
+ }
+ SetTapState(priv, TS_MOVE, hw->millis);
+ goto restart;
+ } else if (release) {
+ edge = edge_detection(priv, priv->touch_on.x, priv->touch_on.y);
+ SelectTapButton(priv, edge);
+ /* Disable taps outside of the active area */
+ if (!inside_active_area) {
+ priv->tap_button = 0;
+ }
+ SetTapState(priv, TS_2A, hw->millis);
+ }
+ break;
+ case TS_MOVE:
+ if (move && priv->moving_state == MS_TRACKSTICK) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ }
+ if (release) {
+ SetMovingState(priv, MS_FALSE, hw->millis);
+ SetTapState(priv, TS_START, hw->millis);
+ }
+ break;
+ case TS_2A:
+ if (touch)
+ SetTapState(priv, TS_3, hw->millis);
+ else if (is_timeout)
+ SetTapState(priv, TS_SINGLETAP, hw->millis);
+ break;
+ case TS_2B:
+ if (touch) {
+ SetTapState(priv, TS_3, hw->millis);
+ } else if (is_timeout) {
+ SetTapState(priv, TS_START, hw->millis);
+ priv->tap_button_state = TBS_BUTTON_DOWN_UP;
+ }
+ break;
+ case TS_SINGLETAP:
+ if (touch)
+ SetTapState(priv, TS_1, hw->millis);
+ else if (is_timeout)
+ SetTapState(priv, TS_START, hw->millis);
+ break;
+ case TS_3:
+ if (move) {
+ if (para->tap_and_drag_gesture) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ SetTapState(priv, TS_DRAG, hw->millis);
+ } else {
+ SetTapState(priv, TS_1, hw->millis);
+ }
+ goto restart;
+ } else if (is_timeout) {
+ if (para->tap_and_drag_gesture) {
+ if (finger == FS_TOUCHED) {
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ } else if (finger == FS_PRESSED) {
+ SetMovingState(priv, MS_TRACKSTICK, hw->millis);
+ }
+ SetTapState(priv, TS_DRAG, hw->millis);
+ } else {
+ SetTapState(priv, TS_1, hw->millis);
+ }
+ goto restart;
+ } else if (release) {
+ SetTapState(priv, TS_2B, hw->millis);
+ }
+ break;
+ case TS_DRAG:
+ if (move)
+ SetMovingState(priv, MS_TOUCHPAD_RELATIVE, hw->millis);
+ if (release) {
+ SetMovingState(priv, MS_FALSE, hw->millis);
+ if (para->locked_drags) {
+ SetTapState(priv, TS_4, hw->millis);
+ } else {
+ SetTapState(priv, TS_START, hw->millis);
+ }
+ }
+ break;
+ case TS_4:
+ if (is_timeout) {
+ SetTapState(priv, TS_START, hw->millis);
+ goto restart;
+ }
+ if (touch)
+ SetTapState(priv, TS_5, hw->millis);
+ break;
+ case TS_5:
+ if (is_timeout || move) {
+ SetTapState(priv, TS_DRAG, hw->millis);
+ goto restart;
+ } else if (release) {
+ SetMovingState(priv, MS_FALSE, hw->millis);
+ SetTapState(priv, TS_START, hw->millis);
+ }
+ break;
+ }
+
+ timeout = GetTimeOut(priv);
+ if (timeout >= 0) {
+ timeleft = TIME_DIFF(priv->touch_on.millis + timeout, hw->millis);
+ delay = clamp(timeleft, 1, delay);
+ }
+ return delay;
+}
+
+#define HIST(a) (priv->move_hist[((priv->hist_index - (a) + SYNAPTICS_MOVE_HISTORY) % SYNAPTICS_MOVE_HISTORY)])
+
+static void
+store_history(SynapticsPrivate *priv, int x, int y, unsigned int millis)
+{
+ int idx = (priv->hist_index + 1) % SYNAPTICS_MOVE_HISTORY;
+ priv->move_hist[idx].x = x;
+ priv->move_hist[idx].y = y;
+ priv->move_hist[idx].millis = millis;
+ priv->hist_index = idx;
+}
+
+/*
+ * Estimate the slope for the data sequence [x3, x2, x1, x0] by using
+ * linear regression to fit a line to the data and use the slope of the
+ * line.
+ */
+static double
+estimate_delta(double x0, double x1, double x2, double x3)
+{
+ return x0 * 0.3 + x1 * 0.1 - x2 * 0.1 - x3 * 0.3;
+}
+
+/**
+ * Applies hysteresis. center is shifted such that it is in range with
+ * in by the margin again. The new center is returned.
+ * @param in the current value
+ * @param center the current center
+ * @param margin the margin to center in which no change is applied
+ * @return the new center (which might coincide with the previous)
+ */
+static int hysteresis(int in, int center, int margin) {
+ int diff = in - center;
+ if (abs(diff) <= margin) {
+ diff = 0;
+ } else if (diff > margin) {
+ diff -= margin;
+ } else if (diff < -margin) {
+ diff += margin;
+ }
+ return center + diff;
+}
+
+static void
+get_delta_for_trackstick(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
+ double *dx, double *dy)
+{
+ SynapticsParameters *para = &priv->synpara;
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+
+ *dx = (hw->x - priv->trackstick_neutral_x);
+ *dy = (hw->y - priv->trackstick_neutral_y);
+
+ *dx = *dx * dtime * para->trackstick_speed;
+ *dy = *dy * dtime * para->trackstick_speed;
+}
+
+static void
+get_edge_speed(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
+ edge_type edge, int *x_edge_speed, int *y_edge_speed)
+{
+ SynapticsParameters *para = &priv->synpara;
+
+ int minZ = para->edge_motion_min_z;
+ int maxZ = para->edge_motion_max_z;
+ int minSpd = para->edge_motion_min_speed;
+ int maxSpd = para->edge_motion_max_speed;
+ int edge_speed;
+
+ if (hw->z <= minZ) {
+ edge_speed = minSpd;
+ } else if (hw->z >= maxZ) {
+ edge_speed = maxSpd;
+ } else {
+ edge_speed = minSpd + (hw->z - minZ) * (maxSpd - minSpd) / (maxZ - minZ);
+ }
+ if (!priv->synpara.circular_pad) {
+ /* on rectangular pad */
+ if (edge & RIGHT_EDGE) {
+ *x_edge_speed = edge_speed;
+ } else if (edge & LEFT_EDGE) {
+ *x_edge_speed = -edge_speed;
+ }
+ if (edge & TOP_EDGE) {
+ *y_edge_speed = -edge_speed;
+ } else if (edge & BOTTOM_EDGE) {
+ *y_edge_speed = edge_speed;
+ }
+ } else if (edge) {
+ /* at edge of circular pad */
+ double relX, relY;
+
+ relative_coords(priv, hw->x, hw->y, &relX, &relY);
+ *x_edge_speed = (int)(edge_speed * relX);
+ *y_edge_speed = (int)(edge_speed * relY);
+ }
+}
+
+static void
+get_delta(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
+ edge_type edge, double *dx, double *dy)
+{
+ SynapticsParameters *para = &priv->synpara;
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+ double integral;
+ double tmpf;
+ int x_edge_speed = 0;
+ int y_edge_speed = 0;
+
+ /* HIST is full enough: priv->count_packet_finger > 3 */
+ *dx = estimate_delta(hw->x, HIST(0).x, HIST(1).x, HIST(2).x);
+ *dy = estimate_delta(hw->y, HIST(0).y, HIST(1).y, HIST(2).y);
+
+ if ((priv->tap_state == TS_DRAG) || para->edge_motion_use_always)
+ get_edge_speed(priv, hw, edge, &x_edge_speed, &y_edge_speed);
+
+ /* report edge speed as synthetic motion. Of course, it would be
+ * cooler to report floats than to buffer, but anyway. */
+ tmpf = *dx + x_edge_speed * dtime + priv->frac_x;
+ priv->frac_x = modf(tmpf, &integral);
+ *dx = integral;
+ tmpf = *dy + y_edge_speed * dtime + priv->frac_y;
+ priv->frac_y = modf(tmpf, &integral);
+ *dy = integral;
+}
+
+/**
+ * Compute relative motion ('deltas') including edge motion xor trackstick.
+ */
+static int
+ComputeDeltas(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
+ edge_type edge, int *dxP, int *dyP, Bool inside_area)
+{
+ enum MovingState moving_state;
+ double dx, dy;
+ int delay = 1000000000;
+
+ dx = dy = 0;
+
+ moving_state = priv->moving_state;
+ if (moving_state == MS_FALSE) {
+ switch (priv->tap_state) {
+ case TS_MOVE:
+ case TS_DRAG:
+ moving_state = MS_TOUCHPAD_RELATIVE;
+ break;
+ case TS_1:
+ case TS_3:
+ case TS_5:
+ if (hw->numFingers == 1)
+ moving_state = MS_TOUCHPAD_RELATIVE;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!inside_area || !moving_state || priv->palm ||
+ priv->vert_scroll_edge_on || priv->horiz_scroll_edge_on ||
+ priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
+ priv->circ_scroll_on || priv->prevFingers != hw->numFingers)
+ {
+ /* reset packet counter. */
+ priv->count_packet_finger = 0;
+ goto out;
+ }
+
+ /* to create fluid edge motion, call back 'soon'
+ * even in the absence of new hardware events */
+ delay = MIN(delay, 13);
+
+ if (priv->count_packet_finger <= 3) /* min. 3 packets, see get_delta() */
+ goto skip; /* skip the lot */
+
+ if (priv->moving_state == MS_TRACKSTICK)
+ get_delta_for_trackstick(priv, hw, &dx, &dy);
+ else if (moving_state == MS_TOUCHPAD_RELATIVE)
+ get_delta(priv, hw, edge, &dx, &dy);
+
+skip:
+ priv->count_packet_finger++;
+out:
+ priv->prevFingers = hw->numFingers;
+
+ *dxP = dx;
+ *dyP = dy;
+
+ return delay;
+}
+
+struct ScrollData {
+ int left, right, up, down;
+};
+
+static void
+start_coasting(SynapticsPrivate *priv, struct SynapticsHwState *hw, edge_type edge,
+ Bool vertical)
+{
+ SynapticsParameters *para = &priv->synpara;
+
+ priv->autoscroll_y = 0.0;
+ priv->autoscroll_x = 0.0;
+
+ if ((priv->scroll_packet_count > 3) && (para->coasting_speed > 0.0)) {
+ double pkt_time = (HIST(0).millis - HIST(3).millis) / 1000.0;
+ if (para->scroll_twofinger_vert || vertical) {
+ double dy = estimate_delta(HIST(0).y, HIST(1).y, HIST(2).y, HIST(3).y);
+ int sdelta = para->scroll_dist_vert;
+ if ((para->scroll_twofinger_vert || (edge & RIGHT_EDGE)) && pkt_time > 0 && sdelta > 0) {
+ double scrolls_per_sec = dy / pkt_time / sdelta;
+ if (fabs(scrolls_per_sec) >= para->coasting_speed) {
+ priv->autoscroll_yspd = scrolls_per_sec;
+ priv->autoscroll_y = (hw->y - priv->scroll_y) / (double)sdelta;
+ }
+ }
+ }
+ if (para->scroll_twofinger_horiz || !vertical){
+ double dx = estimate_delta(HIST(0).x, HIST(1).x, HIST(2).x, HIST(3).x);
+ int sdelta = para->scroll_dist_horiz;
+ if ((para->scroll_twofinger_horiz || (edge & BOTTOM_EDGE)) && pkt_time > 0 && sdelta > 0) {
+ double scrolls_per_sec = dx / pkt_time / sdelta;
+ if (fabs(scrolls_per_sec) >= para->coasting_speed) {
+ priv->autoscroll_xspd = scrolls_per_sec;
+ priv->autoscroll_x = (hw->x - priv->scroll_x) / (double)sdelta;
+ }
+ }
+ }
+ }
+ priv->scroll_packet_count = 0;
+}
+
+static void
+stop_coasting(SynapticsPrivate *priv)
+{
+ priv->autoscroll_xspd = 0;
+ priv->autoscroll_yspd = 0;
+ priv->scroll_packet_count = 0;
+}
+
+static int
+HandleScrolling(SynapticsPrivate *priv, struct SynapticsHwState *hw,
+ edge_type edge, Bool finger, struct ScrollData *sd)
+{
+ SynapticsParameters *para = &priv->synpara;
+ int delay = 1000000000;
+
+ sd->left = sd->right = sd->up = sd->down = 0;
+
+ if (priv->synpara.touchpad_off == 2) {
+ stop_coasting(priv);
+ priv->circ_scroll_on = FALSE;
+ priv->vert_scroll_edge_on = FALSE;
+ priv->horiz_scroll_edge_on = FALSE;
+ priv->vert_scroll_twofinger_on = FALSE;
+ priv->horiz_scroll_twofinger_on = FALSE;
+ return delay;
+ }
+
+ /* scroll detection */
+ if (finger && !priv->finger_state) {
+ stop_coasting(priv);
+ if (para->circular_scrolling) {
+ if ((para->circular_trigger == 0 && edge) ||
+ (para->circular_trigger == 1 && edge & TOP_EDGE) ||
+ (para->circular_trigger == 2 && edge & TOP_EDGE && edge & RIGHT_EDGE) ||
+ (para->circular_trigger == 3 && edge & RIGHT_EDGE) ||
+ (para->circular_trigger == 4 && edge & RIGHT_EDGE && edge & BOTTOM_EDGE) ||
+ (para->circular_trigger == 5 && edge & BOTTOM_EDGE) ||
+ (para->circular_trigger == 6 && edge & BOTTOM_EDGE && edge & LEFT_EDGE) ||
+ (para->circular_trigger == 7 && edge & LEFT_EDGE) ||
+ (para->circular_trigger == 8 && edge & LEFT_EDGE && edge & TOP_EDGE)) {
+ priv->circ_scroll_on = TRUE;
+ priv->circ_scroll_vert = TRUE;
+ priv->scroll_a = angle(priv, hw->x, hw->y);
+ DBG(7, "circular scroll detected on edge\n");
+ }
+ }
+ }
+ if (!priv->circ_scroll_on) {
+ if (finger) {
+ if (hw->numFingers == 2) {
+ if (!priv->vert_scroll_twofinger_on &&
+ (para->scroll_twofinger_vert) && (para->scroll_dist_vert != 0)) {
+ priv->vert_scroll_twofinger_on = TRUE;
+ priv->vert_scroll_edge_on = FALSE;
+ priv->scroll_y = hw->y;
+ DBG(7, "vert two-finger scroll detected\n");
+ }
+ if (!priv->horiz_scroll_twofinger_on &&
+ (para->scroll_twofinger_horiz) && (para->scroll_dist_horiz != 0)) {
+ priv->horiz_scroll_twofinger_on = TRUE;
+ priv->horiz_scroll_edge_on = FALSE;
+ priv->scroll_x = hw->x;
+ DBG(7, "horiz two-finger scroll detected\n");
+ }
+ }
+ }
+ if (finger && !priv->finger_state) {
+ if (!priv->vert_scroll_twofinger_on && !priv->horiz_scroll_twofinger_on) {
+ if ((para->scroll_edge_vert) && (para->scroll_dist_vert != 0) &&
+ (edge & RIGHT_EDGE)) {
+ priv->vert_scroll_edge_on = TRUE;
+ priv->scroll_y = hw->y;
+ DBG(7, "vert edge scroll detected on right edge\n");
+ }
+ if ((para->scroll_edge_horiz) && (para->scroll_dist_horiz != 0) &&
+ (edge & BOTTOM_EDGE)) {
+ priv->horiz_scroll_edge_on = TRUE;
+ priv->scroll_x = hw->x;
+ DBG(7, "horiz edge scroll detected on bottom edge\n");
+ }
+ }
+ }
+ }
+ {
+ Bool oldv = priv->vert_scroll_twofinger_on || priv->vert_scroll_edge_on ||
+ (priv->circ_scroll_on && priv->circ_scroll_vert);
+ Bool oldh = priv->horiz_scroll_twofinger_on || priv->horiz_scroll_edge_on ||
+ (priv->circ_scroll_on && !priv->circ_scroll_vert);
+ if (priv->circ_scroll_on && !finger) {
+ /* circular scroll locks in until finger is raised */
+ DBG(7, "cicular scroll off\n");
+ priv->circ_scroll_on = FALSE;
+ }
+
+ if (!finger || hw->numFingers != 2) {
+ if (priv->vert_scroll_twofinger_on) {
+ DBG(7, "vert two-finger scroll off\n");
+ priv->vert_scroll_twofinger_on = FALSE;
+ }
+ if (priv->horiz_scroll_twofinger_on) {
+ DBG(7, "horiz two-finger scroll off\n");
+ priv->horiz_scroll_twofinger_on = FALSE;
+ }
+ }
+
+ if (priv->vert_scroll_edge_on && (!(edge & RIGHT_EDGE) || !finger)) {
+ DBG(7, "vert edge scroll off\n");
+ priv->vert_scroll_edge_on = FALSE;
+ }
+ if (priv->horiz_scroll_edge_on && (!(edge & BOTTOM_EDGE) || !finger)) {
+ DBG(7, "horiz edge scroll off\n");
+ priv->horiz_scroll_edge_on = FALSE;
+ }
+ /* If we were corner edge scrolling (coasting),
+ * but no longer in corner or raised a finger, then stop coasting. */
+ if (para->scroll_edge_corner && (priv->autoscroll_xspd || priv->autoscroll_yspd)) {
+ Bool is_in_corner =
+ ((edge & RIGHT_EDGE) && (edge & (TOP_EDGE | BOTTOM_EDGE))) ||
+ ((edge & BOTTOM_EDGE) && (edge & (LEFT_EDGE | RIGHT_EDGE))) ;
+ if (!is_in_corner || !finger) {
+ DBG(7, "corner edge scroll off\n");
+ stop_coasting(priv);
+ }
+ }
+ /* if we were scrolling, but couldn't corner edge scroll,
+ * and are no longer scrolling, then start coasting */
+ if ((oldv || oldh) && !para->scroll_edge_corner &&
+ !(priv->circ_scroll_on || priv->vert_scroll_edge_on ||
+ priv->horiz_scroll_edge_on || priv->horiz_scroll_twofinger_on ||
+ priv->vert_scroll_twofinger_on)) {
+ start_coasting(priv, hw, edge, oldv);
+ }
+ }
+
+ /* if hitting a corner (top right or bottom right) while vertical
+ * scrolling is active, consider starting corner edge scrolling or
+ * switching over to circular scrolling smoothly */
+ if (priv->vert_scroll_edge_on && !priv->horiz_scroll_edge_on &&
+ (edge & RIGHT_EDGE) && (edge & (TOP_EDGE | BOTTOM_EDGE))) {
+ if (para->scroll_edge_corner) {
+ if (priv->autoscroll_yspd == 0) {
+ /* FYI: We can generate multiple start_coasting requests if
+ * we're in the corner, but we were moving so slowly when we
+ * got here that we didn't actually start coasting. */
+ DBG(7, "corner edge scroll on\n");
+ start_coasting(priv, hw, edge, TRUE);
+ }
+ } else if (para->circular_scrolling) {
+ priv->vert_scroll_edge_on = FALSE;
+ priv->circ_scroll_on = TRUE;
+ priv->circ_scroll_vert = TRUE;
+ priv->scroll_a = angle(priv, hw->x, hw->y);
+ DBG(7, "switching to circular scrolling\n");
+ }
+ }
+ /* Same treatment for horizontal scrolling */
+ if (priv->horiz_scroll_edge_on && !priv->vert_scroll_edge_on &&
+ (edge & BOTTOM_EDGE) && (edge & (LEFT_EDGE | RIGHT_EDGE))) {
+ if (para->scroll_edge_corner) {
+ if (priv->autoscroll_xspd == 0) {
+ /* FYI: We can generate multiple start_coasting requests if
+ * we're in the corner, but we were moving so slowly when we
+ * got here that we didn't actually start coasting. */
+ DBG(7, "corner edge scroll on\n");
+ start_coasting(priv, hw, edge, FALSE);
+ }
+ } else if (para->circular_scrolling) {
+ priv->horiz_scroll_edge_on = FALSE;
+ priv->circ_scroll_on = TRUE;
+ priv->circ_scroll_vert = FALSE;
+ priv->scroll_a = angle(priv, hw->x, hw->y);
+ DBG(7, "switching to circular scrolling\n");
+ }
+ }
+
+ if (priv->vert_scroll_edge_on || priv->horiz_scroll_edge_on ||
+ priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
+ priv->circ_scroll_on) {
+ priv->scroll_packet_count++;
+ }
+
+ if (priv->vert_scroll_edge_on || priv->vert_scroll_twofinger_on) {
+ /* + = down, - = up */
+ int delta = para->scroll_dist_vert;
+ if (delta > 0) {
+ while (hw->y - priv->scroll_y > delta) {
+ sd->down++;
+ priv->scroll_y += delta;
+ }
+ while (hw->y - priv->scroll_y < -delta) {
+ sd->up++;
+ priv->scroll_y -= delta;
+ }
+ }
+ }
+ if (priv->horiz_scroll_edge_on || priv->horiz_scroll_twofinger_on) {
+ /* + = right, - = left */
+ int delta = para->scroll_dist_horiz;
+ if (delta > 0) {
+ while (hw->x - priv->scroll_x > delta) {
+ sd->right++;
+ priv->scroll_x += delta;
+ }
+ while (hw->x - priv->scroll_x < -delta) {
+ sd->left++;
+ priv->scroll_x -= delta;
+ }
+ }
+ }
+ if (priv->circ_scroll_on) {
+ /* + = counter clockwise, - = clockwise */
+ double delta = para->scroll_dist_circ;
+ if (delta >= 0.005) {
+ while (diffa(priv->scroll_a, angle(priv, hw->x, hw->y)) > delta) {
+ if (priv->circ_scroll_vert)
+ sd->up++;
+ else
+ sd->right++;
+ priv->scroll_a += delta;
+ if (priv->scroll_a > M_PI)
+ priv->scroll_a -= 2 * M_PI;
+ }
+ while (diffa(priv->scroll_a, angle(priv, hw->x, hw->y)) < -delta) {
+ if (priv->circ_scroll_vert)
+ sd->down++;
+ else
+ sd->left++;
+ priv->scroll_a -= delta;
+ if (priv->scroll_a < -M_PI)
+ priv->scroll_a += 2 * M_PI;
+ }
+ }
+ }
+
+ if (priv->autoscroll_yspd) {
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+ double ddy = para->coasting_friction * dtime;
+ priv->autoscroll_y += priv->autoscroll_yspd * dtime;
+ delay = MIN(delay, 20);
+ while (priv->autoscroll_y > 1.0) {
+ sd->down++;
+ priv->autoscroll_y -= 1.0;
+ }
+ while (priv->autoscroll_y < -1.0) {
+ sd->up++;
+ priv->autoscroll_y += 1.0;
+ }
+ if (abs(priv->autoscroll_yspd) < ddy) {
+ priv->autoscroll_yspd = 0;
+ priv->scroll_packet_count = 0;
+ } else {
+ priv->autoscroll_yspd += (priv->autoscroll_yspd < 0 ? ddy : -1*ddy);
+ }
+ }
+
+ if (priv->autoscroll_xspd) {
+ double dtime = (hw->millis - HIST(0).millis) / 1000.0;
+ double ddx = para->coasting_friction * dtime;
+ priv->autoscroll_x += priv->autoscroll_xspd * dtime;
+ delay = MIN(delay, 20);
+ while (priv->autoscroll_x > 1.0) {
+ sd->right++;
+ priv->autoscroll_x -= 1.0;
+ }
+ while (priv->autoscroll_x < -1.0) {
+ sd->left++;
+ priv->autoscroll_x += 1.0;
+ }
+ if (abs(priv->autoscroll_xspd) < ddx) {
+ priv->autoscroll_xspd = 0;
+ priv->scroll_packet_count = 0;
+ } else {
+ priv->autoscroll_xspd += (priv->autoscroll_xspd < 0 ? ddx : -1*ddx);
+ }
+ }
+
+ return delay;
+}
+
+static void
+handle_clickfinger(SynapticsParameters *para, struct SynapticsHwState *hw)
+{
+ int action = 0;
+ switch(hw->numFingers){
+ case 1:
+ action = para->click_action[F1_CLICK1];
+ break;
+ case 2:
+ action = para->click_action[F2_CLICK1];
+ break;
+ case 3:
+ action = para->click_action[F3_CLICK1];
+ break;
+ }
+ switch(action){
+ case 1:
+ hw->left = 1;
+ break;
+ case 2:
+ hw->left = 0;
+ hw->middle = 1;
+ break;
+ case 3:
+ hw->left = 0;
+ hw->right = 1;
+ break;
+ }
+}
+
+
+/* Update the hardware state in shared memory. This is read-only these days,
+ * nothing in the driver reads back from SHM. SHM configuration is a thing of the past.
+ */
+static void
+update_shm(const InputInfoPtr pInfo, const struct SynapticsHwState *hw)
+{
+ int i;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsSHM *shm = priv->synshm;
+
+ if (!shm)
+ return;
+
+ shm->x = hw->x;
+ shm->y = hw->y;
+ shm->z = hw->z;
+ shm->numFingers = hw->numFingers;
+ shm->fingerWidth = hw->fingerWidth;
+ shm->left = hw->left;
+ shm->right = hw->right;
+ shm->up = hw->up;
+ shm->down = hw->down;
+ for (i = 0; i < 8; i++)
+ shm->multi[i] = hw->multi[i];
+ shm->middle = hw->middle;
+}
+
+/* Adjust the hardware state according to the extra buttons (if the touchpad
+ * has any and not many touchpads do these days). These buttons are up/down
+ * tilt buttons and/or left/right buttons that then map into a specific
+ * function (or scrolling into).
+ */
+static Bool
+adjust_state_from_scrollbuttons(const InputInfoPtr pInfo, struct SynapticsHwState *hw)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+ Bool double_click = FALSE;
+
+ if (!para->updown_button_scrolling) {
+ if (hw->down) { /* map down button to middle button */
+ hw->middle = TRUE;
+ }
+
+ if (hw->up) { /* up button generates double click */
+ if (!priv->prev_up)
+ double_click = TRUE;
+ }
+ priv->prev_up = hw->up;
+
+ /* reset up/down button events */
+ hw->up = hw->down = FALSE;
+ }
+
+ /* Left/right button scrolling, or middle clicks */
+ if (!para->leftright_button_scrolling) {
+ if (hw->multi[2] || hw->multi[3])
+ hw->middle = TRUE;
+
+ /* reset left/right button events */
+ hw->multi[2] = hw->multi[3] = FALSE;
+ }
+
+ return double_click;
+}
+
+static void
+update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw, int *delay)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+
+ /* Treat the first two multi buttons as up/down for now. */
+ hw->up |= hw->multi[0];
+ hw->down |= hw->multi[1];
+
+ /* 3rd button emulation */
+ hw->middle |= HandleMidButtonEmulation(priv, hw, delay);
+
+ /* Fingers emulate other buttons */
+ if(hw->left && hw->numFingers >= 1){
+ handle_clickfinger(para, hw);
+ }
+
+ /* Two finger emulation */
+ if (hw->numFingers == 1 && hw->z >= para->emulate_twofinger_z &&
+ hw->fingerWidth >= para->emulate_twofinger_w) {
+ hw->numFingers = 2;
+ }
+}
+
+static void
+post_button_click(const InputInfoPtr pInfo, const int button)
+{
+ xf86PostButtonEvent(pInfo->dev, FALSE, button, TRUE, 0, 0);
+ xf86PostButtonEvent(pInfo->dev, FALSE, button, FALSE, 0, 0);
+}
+
+
+static void
+post_scroll_events(const InputInfoPtr pInfo, struct ScrollData scroll)
+{
+ while (scroll.up-- > 0)
+ post_button_click(pInfo, 4);
+
+ while (scroll.down-- > 0)
+ post_button_click(pInfo, 5);
+
+ while (scroll.left-- > 0)
+ post_button_click(pInfo, 6);
+
+ while (scroll.right-- > 0)
+ post_button_click(pInfo, 7);
+}
+
+static inline int
+repeat_scrollbuttons(const InputInfoPtr pInfo,
+ const struct SynapticsHwState *hw,
+ int buttons, int delay)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+ int repeat_delay, timeleft;
+ int rep_buttons = ((para->updown_button_repeat ? 0x18 : 0) |
+ (para->leftright_button_repeat ? 0x60 : 0));
+
+ /* Handle auto repeat buttons */
+ repeat_delay = clamp(para->scroll_button_repeat, SBR_MIN, SBR_MAX);
+ if (((hw->up || hw->down) && para->updown_button_repeat &&
+ para->updown_button_scrolling) ||
+ ((hw->multi[2] || hw->multi[3]) && para->leftright_button_repeat &&
+ para->leftright_button_scrolling)) {
+ priv->repeatButtons = buttons & rep_buttons;
+ if (!priv->nextRepeat) {
+ priv->nextRepeat = hw->millis + repeat_delay * 2;
+ }
+ } else {
+ priv->repeatButtons = 0;
+ priv->nextRepeat = 0;
+ }
+
+ if (priv->repeatButtons) {
+ timeleft = TIME_DIFF(priv->nextRepeat, hw->millis);
+ if (timeleft > 0)
+ delay = MIN(delay, timeleft);
+ if (timeleft <= 0) {
+ int change, id;
+ change = priv->repeatButtons;
+ while (change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(pInfo->dev, FALSE, id, FALSE, 0, 0);
+ xf86PostButtonEvent(pInfo->dev, FALSE, id, TRUE, 0, 0);
+ }
+
+ priv->nextRepeat = hw->millis + repeat_delay;
+ delay = MIN(delay, repeat_delay);
+ }
+ }
+
+ return delay;
+}
+
+/*
+ * React on changes in the hardware state. This function is called every time
+ * the hardware state changes. The return value is used to specify how many
+ * milliseconds to wait before calling the function again if no state change
+ * occurs.
+ */
+static int
+HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+ SynapticsParameters *para = &priv->synpara;
+ int finger;
+ int dx, dy, buttons, id;
+ edge_type edge = NO_EDGE;
+ int change;
+ struct ScrollData scroll;
+ int double_click = FALSE;
+ int delay = 1000000000;
+ int timeleft;
+ Bool inside_active_area;
+
+ update_shm(pInfo, hw);
+
+ /* If touchpad is switched off, we skip the whole thing and return delay */
+ if (para->touchpad_off == 1)
+ return delay;
+
+ /* apply hysteresis before doing anything serious. This cancels
+ * out a lot of noise which might surface in strange phenomena
+ * like flicker in scrolling or noise motion. */
+ priv->hyst_center_x = hysteresis(hw->x, priv->hyst_center_x, para->hyst_x);
+ priv->hyst_center_y = hysteresis(hw->y, priv->hyst_center_y, para->hyst_y);
+ hw->x = priv->hyst_center_x;
+ hw->y = priv->hyst_center_y;
+
+ inside_active_area = is_inside_active_area(priv, hw->x, hw->y);
+
+ /* now we know that these _coordinates_ aren't in the area.
+ invalid are: x, y, z, numFingers, fingerWidth
+ valid are: millis, left/right/middle/up/down/etc.
+ */
+ if (!inside_active_area)
+ {
+ hw->x = 0;
+ hw->y = 0;
+ hw->z = 0;
+ hw->numFingers = 0;
+ hw->fingerWidth = 0;
+
+ /* FIXME: if finger accidentally moves into the area and doesn't
+ * really release, the finger should remain down. */
+ finger = FS_UNTOUCHED;
+ edge = NO_EDGE;
+
+ dx = dy = 0;
+ }
+
+ /* these two just update hw->left, right, etc. */
+ update_hw_button_state(pInfo, hw, &delay);
+ if (priv->has_scrollbuttons)
+ double_click = adjust_state_from_scrollbuttons(pInfo, hw);
+
+ /* no edge or finger detection outside of area */
+ if (inside_active_area) {
+ edge = edge_detection(priv, hw->x, hw->y);
+ finger = SynapticsDetectFinger(priv, hw);
+ }
+
+ /* tap and drag detection. Needs to be performed even if the finger is in
+ * the dead area to reset the state. */
+ timeleft = HandleTapProcessing(priv, hw, finger, inside_active_area);
+ if (timeleft > 0)
+ delay = MIN(delay, timeleft);
+
+ if (inside_active_area)
+ {
+ /* Don't bother about scrolling in the dead area of the touchpad. */
+ timeleft = HandleScrolling(priv, hw, edge, finger, &scroll);
+ if (timeleft > 0)
+ delay = MIN(delay, timeleft);
+
+ /*
+ * Compensate for unequal x/y resolution. This needs to be done after
+ * calculations that require unadjusted coordinates, for example edge
+ * detection.
+ */
+ ScaleCoordinates(priv, hw);
+ }
+
+ dx = dy = 0;
+
+ if (!priv->absolute_events) {
+ timeleft = ComputeDeltas(priv, hw, edge, &dx, &dy, inside_active_area);
+ delay = MIN(delay, timeleft);
+ }
+
+
+ buttons = ((hw->left ? 0x01 : 0) |
+ (hw->middle ? 0x02 : 0) |
+ (hw->right ? 0x04 : 0) |
+ (hw->up ? 0x08 : 0) |
+ (hw->down ? 0x10 : 0) |
+ (hw->multi[2] ? 0x20 : 0) |
+ (hw->multi[3] ? 0x40 : 0));
+
+ if (priv->tap_button > 0) {
+ int tap_mask = 1 << (priv->tap_button - 1);
+ if (priv->tap_button_state == TBS_BUTTON_DOWN_UP) {
+ if (tap_mask != (priv->lastButtons & tap_mask)) {
+ xf86PostButtonEvent(pInfo->dev, FALSE, priv->tap_button, TRUE, 0, 0);
+ priv->lastButtons |= tap_mask;
+ }
+ priv->tap_button_state = TBS_BUTTON_UP;
+ }
+ if (priv->tap_button_state == TBS_BUTTON_DOWN)
+ buttons |= tap_mask;
+ }
+
+ /* Post events */
+ if (finger > FS_UNTOUCHED) {
+ if (priv->absolute_events && inside_active_area) {
+ xf86PostMotionEvent(pInfo->dev, 1, 0, 2, hw->x, hw->y);
+ } else if (dx || dy) {
+ xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
+ }
+ }
+
+ if (priv->mid_emu_state == MBE_LEFT_CLICK)
+ {
+ post_button_click(pInfo, 1);
+ priv->mid_emu_state = MBE_OFF;
+ } else if (priv->mid_emu_state == MBE_RIGHT_CLICK)
+ {
+ post_button_click(pInfo, 3);
+ priv->mid_emu_state = MBE_OFF;
+ }
+
+ change = buttons ^ priv->lastButtons;
+ while (change) {
+ id = ffs(change); /* number of first set bit 1..32 is returned */
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(pInfo->dev, FALSE, id, (buttons & (1 << (id - 1))), 0, 0);
+ }
+
+ /* Process scroll events only if coordinates are
+ * in the Synaptics Area
+ */
+ if (inside_active_area)
+ post_scroll_events(pInfo, scroll);
+
+ if (double_click) {
+ post_button_click(pInfo, 1);
+ post_button_click(pInfo, 1);
+ }
+
+ if (priv->has_scrollbuttons)
+ delay = repeat_scrollbuttons(pInfo, hw, buttons, delay);
+
+ /* Save old values of some state variables */
+ priv->finger_state = finger;
+ priv->lastButtons = buttons;
+
+ /* generate a history of the absolute positions */
+ if (inside_active_area)
+ store_history(priv, hw->x, hw->y, hw->millis);
+
+ return delay;
+}
+
+static int
+ControlProc(InputInfoPtr pInfo, xDeviceCtl * control)
+{
+ DBG(3, "Control Proc called\n");
+ return Success;
+}
+
+
+static int
+SwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
+{
+ InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
+ SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+
+ DBG(3, "SwitchMode called\n");
+
+ switch (mode) {
+ case Absolute:
+ priv->absolute_events = TRUE;
+ break;
+
+ case Relative:
+ priv->absolute_events = FALSE;
+ break;
+
+ default:
+ return XI_BadMode;
+ }
+
+ return Success;
+}
+
+static void
+ReadDevDimensions(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+
+ if (priv->proto_ops->ReadDevDimensions)
+ priv->proto_ops->ReadDevDimensions(pInfo);
+}
+
+static Bool
+QueryHardware(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+
+ priv->comm.protoBufTail = 0;
+
+ if (!priv->proto_ops->QueryHardware(pInfo)) {
+ xf86Msg(X_PROBED, "%s: no supported touchpad found\n", pInfo->name);
+ if (priv->proto_ops->DeviceOffHook)
+ priv->proto_ops->DeviceOffHook(pInfo);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ScaleCoordinates(SynapticsPrivate *priv, struct SynapticsHwState *hw)
+{
+ int xCenter = (priv->synpara.left_edge + priv->synpara.right_edge) / 2;
+ int yCenter = (priv->synpara.top_edge + priv->synpara.bottom_edge) / 2;
+
+ hw->x = (hw->x - xCenter) * priv->horiz_coeff + xCenter;
+ hw->y = (hw->y - yCenter) * priv->vert_coeff + yCenter;
+}
+
+void
+CalculateScalingCoeffs(SynapticsPrivate *priv)
+{
+ int vertRes = priv->synpara.resolution_vert;
+ int horizRes = priv->synpara.resolution_horiz;
+
+ if ((horizRes > vertRes) && (horizRes > 0)) {
+ priv->horiz_coeff = vertRes / (double)horizRes;
+ priv->vert_coeff = 1;
+ } else if ((horizRes < vertRes) && (vertRes > 0)) {
+ priv->horiz_coeff = 1;
+ priv->vert_coeff = horizRes / (double)vertRes;
+ } else {
+ priv->horiz_coeff = 1;
+ priv->vert_coeff = 1;
+ }
+}
diff --git a/driver/xf86-input-synaptics/src/synapticsstr.h b/driver/xf86-input-synaptics/src/synapticsstr.h
new file mode 100644
index 000000000..066b3f379
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/synapticsstr.h
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYNAPTICSSTR_H_
+#define _SYNAPTICSSTR_H_
+
+#include "synproto.h"
+
+#ifdef DBG
+# undef DBG
+#endif
+
+#ifdef DEBUG
+#define DBG(verb, ...) \
+ xf86MsgVerb(X_INFO, verb, __VA_ARGS__)
+#else
+#define DBG(verb, msg, ...) /* */
+#endif
+
+/******************************************************************************
+ * Definitions
+ * structs, typedefs, #defines, enums
+ *****************************************************************************/
+#define SYNAPTICS_MOVE_HISTORY 5
+
+typedef struct _SynapticsMoveHist
+{
+ int x, y;
+ int millis;
+} SynapticsMoveHistRec;
+
+enum FingerState { /* Note! The order matters. Compared with < operator. */
+ FS_UNTOUCHED,
+ FS_TOUCHED,
+ FS_PRESSED
+};
+
+enum MovingState {
+ MS_FALSE,
+ MS_TOUCHPAD_RELATIVE,
+ MS_TRACKSTICK /* trackstick is always relative */
+};
+
+enum MidButtonEmulation {
+ MBE_OFF, /* No button pressed */
+ MBE_LEFT, /* Left button pressed, waiting for right button or timeout */
+ MBE_RIGHT, /* Right button pressed, waiting for left button or timeout */
+ MBE_MID, /* Left and right buttons pressed, waiting for both buttons
+ to be released */
+ MBE_TIMEOUT, /* Waiting for both buttons to be released. */
+ MBE_LEFT_CLICK, /* Emulate left button click. */
+ MBE_RIGHT_CLICK, /* Emulate right button click. */
+};
+
+/* See docs/tapndrag.dia for a state machine diagram */
+enum TapState {
+ TS_START, /* No tap/drag in progress */
+ TS_1, /* After first touch */
+ TS_MOVE, /* Pointer movement enabled */
+ TS_2A, /* After first release */
+ TS_2B, /* After second/third/... release */
+ TS_SINGLETAP, /* After timeout after first release */
+ TS_3, /* After second touch */
+ TS_DRAG, /* Pointer drag enabled */
+ TS_4, /* After release when "locked drags" enabled */
+ TS_5 /* After touch when "locked drags" enabled */
+};
+
+enum TapButtonState {
+ TBS_BUTTON_UP, /* "Virtual tap button" is up */
+ TBS_BUTTON_DOWN, /* "Virtual tap button" is down */
+ TBS_BUTTON_DOWN_UP /* Send button down event + set up state */
+};
+
+enum TouchpadModel {
+ MODEL_UNKNOWN = 0,
+ MODEL_SYNAPTICS,
+ MODEL_ALPS,
+ MODEL_APPLETOUCH
+};
+
+typedef struct _SynapticsParameters
+{
+ /* Parameter data */
+ int left_edge, right_edge, top_edge, bottom_edge; /* edge coordinates absolute */
+ int finger_low, finger_high, finger_press; /* finger detection values in Z-values */
+ int tap_time;
+ int tap_move; /* max. tapping time and movement in packets and coord. */
+ int single_tap_timeout; /* timeout to recognize a single tap */
+ int tap_time_2; /* max. tapping time for double taps */
+ int click_time; /* The duration of a single click */
+ Bool fast_taps; /* Faster reaction to single taps */
+ int emulate_mid_button_time; /* Max time between left and right button presses to
+ emulate a middle button press. */
+ int emulate_twofinger_z; /* pressure threshold to emulate two finger touch (for Alps) */
+ int emulate_twofinger_w; /* Finger width threshold to emulate two finger touch */
+ int scroll_dist_vert; /* Scrolling distance in absolute coordinates */
+ int scroll_dist_horiz; /* Scrolling distance in absolute coordinates */
+ Bool scroll_edge_vert; /* Enable/disable vertical scrolling on right edge */
+ Bool scroll_edge_horiz; /* Enable/disable horizontal scrolling on left edge */
+ Bool scroll_edge_corner; /* Enable/disable continuous edge scrolling when in the corner */
+ Bool scroll_twofinger_vert; /* Enable/disable vertical two-finger scrolling */
+ Bool scroll_twofinger_horiz; /* Enable/disable horizontal two-finger scrolling */
+ double min_speed, max_speed, accl; /* movement parameters */
+ double trackstick_speed; /* trackstick mode speed */
+ int edge_motion_min_z; /* finger pressure at which minimum edge motion speed is set */
+ int edge_motion_max_z; /* finger pressure at which maximum edge motion speed is set */
+ int edge_motion_min_speed; /* slowest setting for edge motion speed */
+ int edge_motion_max_speed; /* fastest setting for edge motion speed */
+ Bool edge_motion_use_always; /* If false, egde motion is used only when dragging */
+
+ Bool updown_button_scrolling; /* Up/Down-Button scrolling or middle/double-click */
+ Bool leftright_button_scrolling; /* Left/right-button scrolling, or two lots of middle button */
+ Bool updown_button_repeat; /* If up/down button being used to scroll, auto-repeat?*/
+ Bool leftright_button_repeat; /* If left/right button being used to scroll, auto-repeat? */
+ int scroll_button_repeat; /* time, in milliseconds, between scroll events being
+ * sent when holding down scroll buttons */
+ int touchpad_off; /* Switches the touchpad off
+ * 0 : Not off
+ * 1 : Off
+ * 2 : Only tapping and scrolling off
+ */
+ Bool locked_drags; /* Enable locked drags */
+ int locked_drag_time; /* timeout for locked drags */
+ int tap_action[MAX_TAP]; /* Button to report on tap events */
+ int click_action[MAX_CLICK]; /* Button to report on click with fingers */
+ Bool circular_scrolling; /* Enable circular scrolling */
+ double scroll_dist_circ; /* Scrolling angle radians */
+ int circular_trigger; /* Trigger area for circular scrolling */
+ Bool circular_pad; /* Edge has an oval or circular shape */
+ Bool palm_detect; /* Enable Palm Detection */
+ int palm_min_width; /* Palm detection width */
+ int palm_min_z; /* Palm detection depth */
+ double coasting_speed; /* Coasting threshold scrolling speed */
+ double coasting_friction; /* Number of scrolls per second per second to change coasting speed */
+ int press_motion_min_z; /* finger pressure at which minimum pressure motion factor is applied */
+ int press_motion_max_z; /* finger pressure at which maximum pressure motion factor is applied */
+ double press_motion_min_factor; /* factor applied on speed when finger pressure is at minimum */
+ double press_motion_max_factor; /* factor applied on speed when finger pressure is at minimum */
+ Bool grab_event_device; /* grab event device for exclusive use? */
+ Bool tap_and_drag_gesture; /* Switches the tap-and-drag gesture on/off */
+ unsigned int resolution_horiz; /* horizontal resolution of touchpad in units/mm */
+ unsigned int resolution_vert; /* vertical resolution of touchpad in units/mm */
+ int area_left_edge, area_right_edge, area_top_edge, area_bottom_edge; /* area coordinates absolute */
+ int hyst_x, hyst_y; /* x and y width of hysteresis box */
+} SynapticsParameters;
+
+
+typedef struct _SynapticsPrivateRec
+{
+ SynapticsParameters synpara; /* Default parameter settings, read from
+ the X config file */
+ SynapticsSHM *synshm; /* Current parameter settings. Will point to
+ shared memory if shm_config is true */
+ struct SynapticsProtocolOperations* proto_ops;
+ void *proto_data; /* protocol-specific data */
+
+ struct SynapticsHwState hwState;
+
+ Bool shm_config; /* True when shared memory area allocated */
+
+ OsTimerPtr timer; /* for up/down-button repeat, tap processing, etc */
+
+ struct CommData comm;
+
+ Bool absolute_events; /* post absolute motion events instead of relative */
+ SynapticsMoveHistRec move_hist[SYNAPTICS_MOVE_HISTORY]; /* movement history */
+ int hist_index; /* Last added entry in move_hist[] */
+ int hyst_center_x; /* center x of hysteresis*/
+ int hyst_center_y; /* center y of hysteresis*/
+ int scroll_y; /* last y-scroll position */
+ int scroll_x; /* last x-scroll position */
+ double scroll_a; /* last angle-scroll position */
+ int count_packet_finger; /* packet counter with finger on the touchpad */
+ int button_delay_millis; /* button delay for 3rd button emulation */
+ Bool prev_up; /* Previous up button value, for double click emulation */
+ enum FingerState finger_state; /* previous finger state */
+
+ enum TapState tap_state; /* State of tap processing */
+ int tap_max_fingers; /* Max number of fingers seen since entering start state */
+ int tap_button; /* Which button started the tap processing */
+ enum TapButtonState tap_button_state; /* Current tap action */
+ SynapticsMoveHistRec touch_on; /* data when the touchpad is touched/released */
+
+ enum MovingState moving_state; /* previous moving state */
+ Bool vert_scroll_edge_on; /* Keeps track of currently active scroll modes */
+ Bool horiz_scroll_edge_on; /* Keeps track of currently active scroll modes */
+ Bool vert_scroll_twofinger_on; /* Keeps track of currently active scroll modes */
+ Bool horiz_scroll_twofinger_on; /* Keeps track of currently active scroll modes */
+ Bool circ_scroll_on; /* Keeps track of currently active scroll modes */
+ Bool circ_scroll_vert; /* True: Generate vertical scroll events
+ False: Generate horizontal events */
+ int trackstick_neutral_x; /* neutral x position for trackstick mode */
+ int trackstick_neutral_y; /* neutral y position for trackstick mode */
+ double autoscroll_xspd; /* Horizontal coasting speed */
+ double autoscroll_yspd; /* Vertical coasting speed */
+ double autoscroll_x; /* Accumulated horizontal coasting scroll */
+ double autoscroll_y; /* Accumulated vertical coasting scroll */
+ int scroll_packet_count; /* Scroll duration */
+ double frac_x, frac_y; /* absolute -> relative fraction */
+ enum MidButtonEmulation mid_emu_state; /* emulated 3rd button */
+ int repeatButtons; /* buttons for repeat */
+ int nextRepeat; /* Time when to trigger next auto repeat event */
+ int lastButtons; /* last state of the buttons */
+ int palm; /* Set to true when palm detected, reset to false when
+ palm/finger contact disappears */
+ int prev_z; /* previous z value, for palm detection */
+ int prevFingers; /* previous numFingers, for transition detection */
+ int avg_width; /* weighted average of previous fingerWidth values */
+ double horiz_coeff; /* normalization factor for x coordintes */
+ double vert_coeff; /* normalization factor for y coordintes */
+
+ int minx, maxx, miny, maxy; /* min/max dimensions as detected */
+ int minp, maxp, minw, maxw; /* min/max pressure and finger width as detected */
+ int resx, resy; /* resolution of coordinates as detected in units/mm */
+ Bool has_left; /* left button detected for this device */
+ Bool has_right; /* right button detected for this device */
+ Bool has_middle; /* middle button detected for this device */
+ Bool has_double; /* double click detected for this device */
+ Bool has_triple; /* triple click detected for this device */
+ Bool has_pressure; /* device reports pressure */
+ Bool has_width; /* device reports finger width */
+ Bool has_scrollbuttons; /* device has physical scrollbuttons */
+
+ enum TouchpadModel model; /* The detected model */
+} SynapticsPrivate;
+
+
+extern void SynapticsDefaultDimensions(InputInfoPtr pInfo);
+
+#endif /* _SYNAPTICSSTR_H_ */
diff --git a/driver/xf86-input-synaptics/src/synproto.h b/driver/xf86-input-synaptics/src/synproto.h
new file mode 100644
index 000000000..96ddf3e92
--- /dev/null
+++ b/driver/xf86-input-synaptics/src/synproto.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2004 Peter Osterlund
+ *
+ * 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 Osterlund (petero2@telia.com)
+ */
+
+#ifndef _SYNPROTO_H_
+#define _SYNPROTO_H_
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <xf86Xinput.h>
+#include <xisb.h>
+
+/*
+ * A structure to describe the state of the touchpad hardware (buttons and pad)
+ */
+struct SynapticsHwState {
+ int millis; /* Timestamp in milliseconds */
+ int x; /* X position of finger */
+ int y; /* Y position of finger */
+ int z; /* Finger pressure */
+ int numFingers;
+ int fingerWidth;
+
+ Bool left;
+ Bool right;
+ Bool up;
+ Bool down;
+
+ Bool multi[8];
+ Bool middle; /* Some ALPS touchpads have a middle button */
+};
+
+struct CommData {
+ XISBuffer *buffer;
+ unsigned char protoBuf[6]; /* Buffer for Packet */
+ unsigned char lastByte; /* Last read byte. Use for reset sequence detection. */
+ int outOfSync; /* How many consecutive incorrect packets we
+ have received */
+ int protoBufTail;
+
+ /* Used for keeping track of partial HwState updates. */
+ struct SynapticsHwState hwState;
+ Bool oneFinger;
+ Bool twoFingers;
+ Bool threeFingers;
+};
+
+enum SynapticsProtocol {
+ SYN_PROTO_PSAUX, /* Raw psaux device */
+#ifdef BUILD_EVENTCOMM
+ SYN_PROTO_EVENT, /* Linux kernel event interface */
+#endif /* BUILD_EVENTCOMM */
+#ifdef BUILD_PSMCOMM
+ SYN_PROTO_PSM, /* FreeBSD psm driver */
+#endif /* BUILD_PSMCOMM */
+ SYN_PROTO_ALPS /* ALPS touchpad protocol */
+};
+
+struct _SynapticsParameters;
+struct SynapticsHwInfo;
+struct CommData;
+
+struct SynapticsProtocolOperations {
+ void (*DeviceOnHook)(InputInfoPtr pInfo, struct _SynapticsParameters *para);
+ void (*DeviceOffHook)(InputInfoPtr pInfo);
+ Bool (*QueryHardware)(InputInfoPtr pInfo);
+ Bool (*ReadHwState)(InputInfoPtr pInfo,
+ struct SynapticsProtocolOperations *proto_ops,
+ struct CommData *comm, struct SynapticsHwState *hwRet);
+ Bool (*AutoDevProbe)(InputInfoPtr pInfo);
+ void (*ReadDevDimensions)(InputInfoPtr pInfo);
+};
+
+extern struct SynapticsProtocolOperations psaux_proto_operations;
+#ifdef BUILD_EVENTCOMM
+extern struct SynapticsProtocolOperations event_proto_operations;
+#endif /* BUILD_EVENTCOMM */
+#ifdef BUILD_PSMCOMM
+extern struct SynapticsProtocolOperations psm_proto_operations;
+#endif /* BUILD_PSMCOMM */
+extern struct SynapticsProtocolOperations alps_proto_operations;
+
+
+#endif /* _SYNPROTO_H_ */