[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-input-synaptics: Changes to 'ubuntu'



 debian/changelog                  |    9 
 debian/control                    |   11 
 debian/patches/200_xi2.1.patch    |  562 ++++++++++++++++++++++++
 debian/patches/201_gestures.patch |  863 ++++++++++++++++++++++++++++++++++++++
 debian/patches/series             |    2 
 5 files changed, 1444 insertions(+), 3 deletions(-)

New commits:
commit 00bcf73793ca7b6d27f42659cb3a72b2ee075df2
Author: Chase Douglas <chase.douglas@canonical.com>
Date:   Mon Feb 7 14:27:11 2011 -0500

    Add in xi 2.1 support and uTouch gesture support
    
    * Add in xi 2.1 support and uTouch gesture support
      - Added 200_xi2.1.patch
      - Added 201_gestures.patch
      - Add depends on libmtdev and libutouch-grail

diff --git a/debian/changelog b/debian/changelog
index f51b938..b941536 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+xserver-xorg-input-synaptics (1.3.99+git20110116.0e27ce3a-0ubuntu4) UNRELEASED; urgency=low
+
+  * Add in xi 2.1 support and uTouch gesture support
+    - Added 200_xi2.1.patch
+    - Added 201_gestures.patch
+    - Add depends on libmtdev and libutouch-grail
+
+ -- Chase Douglas <chase.douglas@ubuntu.com>  Sun, 20 Feb 2011 19:23:11 -0500
+
 xserver-xorg-input-synaptics (1.3.99+git20110116.0e27ce3a-0ubuntu3) natty; urgency=low
 
   * debian/control: Bump build-depend on xserver-xorg-dev to really, really
diff --git a/debian/control b/debian/control
index bbeb86f..26cd301 100644
--- a/debian/control
+++ b/debian/control
@@ -11,12 +11,15 @@ Build-Depends:
  libxi-dev (>= 2:1.2.0),
  libxtst-dev,
  x11proto-core-dev,
- xserver-xorg-dev (>= 2:1.9.99.901+git20110131),
+ xserver-xorg-dev (>= 2:1.9.99.902-2ubuntu1),
  pkg-config,
  quilt,
  automake,
  libtool,
- xutils-dev (>= 1:7.5+4)
+ xutils-dev (>= 1:7.5+4),
+ x11proto-input-dev (>= 2.0.1-1ubuntu1),
+ libmtdev-dev,
+ libutouch-grail-dev
 Standards-Version: 3.8.4
 Vcs-Git: git://git.debian.org/git/pkg-xorg/driver/xserver-xorg-input-synaptics
 Vcs-Browser: http://git.debian.org/?p=pkg-xorg/driver/xserver-xorg-input-synaptics.git
@@ -27,7 +30,9 @@ Depends:
  udev [linux-any],
  ${shlibs:Depends},
  ${xinpdriver:Depends},
- ${misc:Depends}
+ ${misc:Depends},
+ libutouch-grail1 (>= 1.0.19),
+ xserver-xorg-core (>= 2:1.9.99.902-2ubuntu1)
 Conflicts: xfree86-driver-synaptics (<< 0.14.4-2), xorg-driver-synaptics
 Replaces: xfree86-driver-synaptics (<< 0.14.4-2), xorg-driver-synaptics
 Provides: ${xinpdriver:Provides}, xfree86-driver-synaptics, xorg-driver-synaptics
diff --git a/debian/patches/200_xi2.1.patch b/debian/patches/200_xi2.1.patch
new file mode 100644
index 0000000..b59e29f
--- /dev/null
+++ b/debian/patches/200_xi2.1.patch
@@ -0,0 +1,562 @@
+diff --git a/configure.ac b/configure.ac
+index 155c6dc..537b4c0 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -101,6 +101,9 @@ case "${host}" in
+ 	AC_MSG_RESULT([eventcomm])
+ 	BUILD_EVENTCOMM="yes"
+ 	AC_DEFINE(BUILD_EVENTCOMM, 1, [Optional backend eventcomm enabled])
++
++	# Obtain compiler/linker options for mtdev
++	PKG_CHECK_MODULES(MTDEV, mtdev)
+ 	;;
+ *freebsd* | *openbsd* | *netbsd* | *dragonfly*)
+ 	AC_MSG_RESULT([psmcomm])
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 980ab5e..2150292 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -40,6 +40,7 @@ AM_CFLAGS = $(XORG_CFLAGS)
+ if BUILD_EVENTCOMM
+ @DRIVER_NAME@_drv_la_SOURCES += \
+ 	eventcomm.c eventcomm.h
++@DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS)
+ endif
+ 
+ if BUILD_PSMCOMM
+diff --git a/src/alpscomm.c b/src/alpscomm.c
+index 84d2136..94cdc58 100644
+--- a/src/alpscomm.c
++++ b/src/alpscomm.c
+@@ -230,6 +230,9 @@ ALPSAutoDevProbe(InputInfoPtr pInfo)
+ struct SynapticsProtocolOperations alps_proto_operations = {
+     NULL,
+     NULL,
++    NULL,
++    NULL,
++    NULL,
+     ALPSQueryHardware,
+     ALPSReadHwState,
+     ALPSAutoDevProbe,
+diff --git a/src/eventcomm.c b/src/eventcomm.c
+index 4593bba..86e8192 100644
+--- a/src/eventcomm.c
++++ b/src/eventcomm.c
+@@ -41,6 +41,8 @@
+ #include "synaptics.h"
+ #include "synapticsstr.h"
+ #include <xf86.h>
++#include <xorg/xserver-properties.h>
++#include <mtdev.h>
+ 
+ 
+ #define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
+@@ -55,16 +57,115 @@
+  *	Function Definitions
+  ****************************************************************************/
+ 
+-static void
+-EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
++static int
++EventDevicePreInitHook(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+ {
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+-    BOOL *need_grab;
++    EventcommPrivate *ecpriv;
++    struct input_absinfo abs;
++    int rc;
+ 
++    priv->proto_data = calloc(1, sizeof(EventcommPrivate));
+     if (!priv->proto_data)
+-        priv->proto_data = calloc(1, sizeof(BOOL));
++        return !Success;
++
++    ecpriv = priv->proto_data;
++    ecpriv->need_grab = TRUE;
++    ecpriv->num_touches = 10;
++
++    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_MT_SLOT), &abs));
++    if (rc >= 0 && abs.maximum > 0)
++        ecpriv->num_touches = abs.maximum + 1;
++    else {
++        SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_MT_TRACKING_ID), &abs));
++        if (rc >= 0 && abs.maximum > 0)
++            ecpriv->num_touches = abs.maximum + 1;
++    }
++        
++    return Success;
++}
++
++static Bool
++EventDeviceInitHook(DeviceIntPtr dev)
++{
++    InputInfoPtr pInfo = dev->public.devicePrivate;
++    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++    int i;
++
++    if (!priv->has_touch)
++        return Success;
++
++    ecpriv->mt_slot_map = malloc(ecpriv->num_touches * sizeof(int));
++    if (!ecpriv->mt_slot_map)
++        goto err;
++
++    for (i = 0; i < ecpriv->num_touches; i++)
++        ecpriv->mt_slot_map[i] = -1;
++
++    ecpriv->touch_mask = valuator_mask_new(ecpriv->num_mt_axes);
++    ecpriv->cur_vals = valuator_mask_new(ecpriv->num_mt_axes);
++    if (!ecpriv->touch_mask || !ecpriv->cur_vals)
++        goto err;
++
++    if (!InitTouchClassDeviceStruct(pInfo->dev, ecpriv->num_touches,
++                                    XIDependentTouch, ecpriv->num_mt_axes))
++        goto err;
++
++    for (i = ABS_MT_TOUCH_MAJOR; i <= ABS_MT_DISTANCE; i++) {
++        int axnum, resolution = 10000;
++        char *name;
++        Atom atom;
++        static char * const names[] = {
++            AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR,
++            AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR,
++            AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR,
++            AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR,
++            AXIS_LABEL_PROP_ABS_MT_ORIENTATION,
++            AXIS_LABEL_PROP_ABS_MT_POSITION_X,
++            AXIS_LABEL_PROP_ABS_MT_POSITION_Y,
++            AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE,
++            AXIS_LABEL_PROP_ABS_MT_BLOB_ID,
++            AXIS_LABEL_PROP_ABS_MT_TRACKING_ID,
++            AXIS_LABEL_PROP_ABS_MT_PRESSURE,
++        };
++
++        if (!BitIsOn(ecpriv->absbits, i))
++            continue;
++
++        axnum = ecpriv->mt_axis_map[i - ABS_MT_TOUCH_MAJOR];
++        name = names[i - ABS_MT_TOUCH_MAJOR];
++
++        if (ecpriv->absinfo[i].resolution)
++            resolution = ecpriv->absinfo[i].resolution * 1000;
++
++        atom = MakeAtom(name, strlen(name), TRUE);
++
++        xf86InitTouchValuatorAxisStruct(pInfo->dev, axnum, atom,
++                                        ecpriv->absinfo[i].minimum,
++                                        ecpriv->absinfo[i].maximum,
++                                        ecpriv->absinfo[i].resolution);
++    }
++
++    return Success;
++
++err:
++    free(ecpriv->mt_slot_map);
++    ecpriv->mt_slot_map = NULL;
++    free(ecpriv->cur_vals);
++    ecpriv->cur_vals = NULL;
++    free(ecpriv->touch_mask);
++    ecpriv->touch_mask = NULL;
++    return !Success;
++}
+ 
+-    need_grab = (BOOL*)priv->proto_data;
++static void
++EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
++{
++    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++    struct input_absinfo abs;
++    int rc;
+ 
+     if (para->grab_event_device) {
+ 	/* Try to grab the event device so that data don't leak to /dev/input/mice */
+@@ -76,7 +177,48 @@ EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
+ 	}
+     }
+ 
+-    *need_grab = FALSE;
++    ecpriv->need_grab = FALSE;
++
++    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_MT_SLOT), &abs));
++    if (rc >= 0)
++        ecpriv->cur_slot = abs.value;
++
++    ecpriv->mtdev = malloc(sizeof(struct mtdev));
++    if (!ecpriv->mtdev)
++        return;
++
++    if (mtdev_open(ecpriv->mtdev, pInfo->fd)) {
++        free(ecpriv->mtdev);
++        ecpriv->mtdev = NULL;
++        return;
++    }
++}
++
++static void
++EventDeviceOffHook(InputInfoPtr pInfo)
++{
++    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++
++    if (ecpriv->mtdev) {
++        mtdev_close(ecpriv->mtdev);
++        free(ecpriv->mtdev);
++        ecpriv->mtdev = NULL;
++    }
++}
++
++static void
++EventDeviceCloseHook(DeviceIntPtr dev)
++{
++    InputInfoPtr pInfo = dev->public.devicePrivate;
++    SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++
++    free(ecpriv->mt_slot_map);
++    free(ecpriv->cur_vals);
++    free(ecpriv->touch_mask);
++    free(ecpriv);
++    priv->proto_data = NULL;
+ }
+ 
+ static Bool
+@@ -171,11 +313,13 @@ static void
+ event_query_axis_ranges(InputInfoPtr pInfo)
+ {
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+     struct input_absinfo abs = {0};
+-    unsigned long absbits[NBITS(ABS_MAX)] = {0};
+     unsigned long keybits[NBITS(KEY_MAX)] = {0};
+     char buf[256];
+-    int rc;
++    int i, rc;
++
++    memset(ecpriv->absbits, 0, sizeof(ecpriv->absbits));
+ 
+     SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(ABS_X), &abs));
+     if (rc >= 0)
+@@ -207,11 +351,12 @@ event_query_axis_ranges(InputInfoPtr pInfo)
+ 
+     priv->has_pressure = FALSE;
+     priv->has_width = FALSE;
+-    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
++    SYSCALL(rc = ioctl(pInfo->fd, EVIOCGBIT(EV_ABS, sizeof(ecpriv->absbits)),
++                       ecpriv->absbits));
+     if (rc >= 0)
+     {
+-	priv->has_pressure = (TEST_BIT(ABS_PRESSURE, absbits) != 0);
+-	priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, absbits) != 0);
++	priv->has_pressure = (TEST_BIT(ABS_PRESSURE, ecpriv->absbits) != 0);
++	priv->has_width = (TEST_BIT(ABS_TOOL_WIDTH, ecpriv->absbits) != 0);
+     }
+     else
+ 	xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", pInfo->name,
+@@ -270,15 +415,29 @@ event_query_axis_ranges(InputInfoPtr pInfo)
+ 
+ 	xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->name, buf);
+     }
++
++    for (i = ABS_MT_TOUCH_MAJOR; i <= ABS_MT_PRESSURE; i++) {
++	if (!BitIsOn(ecpriv->absbits, i))
++            continue;
++
++        SYSCALL(rc = ioctl(pInfo->fd, EVIOCGABS(i), &ecpriv->absinfo[i]));
++        if (rc < 0) {
++            ClearBit(ecpriv->absbits, i);
++            continue;
++        }
++
++        ecpriv->mt_axis_map[i - ABS_MT_TOUCH_MAJOR] = ecpriv->num_mt_axes++;
++        priv->has_touch = TRUE;
++    }
+ }
+ 
+ static Bool
+ EventQueryHardware(InputInfoPtr pInfo)
+ {
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+-    BOOL *need_grab = (BOOL*)priv->proto_data;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+ 
+-    if (!event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
++    if (!event_query_is_touchpad(pInfo->fd, ecpriv->need_grab))
+ 	return FALSE;
+ 
+     xf86Msg(X_PROBED, "%s: touchpad found\n", pInfo->name);
+@@ -286,13 +445,49 @@ EventQueryHardware(InputInfoPtr pInfo)
+     return TRUE;
+ }
+ 
++static void
++ProcessTouch(InputInfoPtr pInfo, SynapticsPrivate *priv)
++{
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++
++    if (!priv->has_touch || ecpriv->cur_slot < 0 ||
++        ecpriv->mt_slot_map[ecpriv->cur_slot] == (uint32_t)-1)
++        return;
++
++    if (ecpriv->close_slot)
++    {  
++        xf86PostTouchEvent(pInfo->dev,
++                           ecpriv->mt_slot_map[ecpriv->cur_slot],
++                           XI_TouchEnd, 0, ecpriv->touch_mask);
++        ecpriv->mt_slot_map[ecpriv->cur_slot] = -1;
++        ecpriv->close_slot = FALSE;
++    }
++    else
++    {
++        uint16_t type = ecpriv->new_touch ? XI_TouchBegin : XI_TouchUpdate;
++
++        xf86PostTouchEvent(pInfo->dev, ecpriv->mt_slot_map[ecpriv->cur_slot],
++                           type, 0, ecpriv->touch_mask);
++        ecpriv->new_touch = FALSE;
++    }
++
++    valuator_mask_zero(ecpriv->touch_mask);
++}
++
+ static Bool
+ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
+ {
++    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+     int rc = TRUE;
+     ssize_t len;
+ 
+-    len = read(pInfo->fd, ev, sizeof(*ev));
++    if (ecpriv->mtdev)
++        len = mtdev_get(ecpriv->mtdev, pInfo->fd, ev, 1) *
++            sizeof(struct input_event);
++    else
++        len = read(pInfo->fd, ev, sizeof(*ev));
++
+     if (len <= 0)
+     {
+         /* We use X_NONE here because it doesn't alloc */
+@@ -316,6 +511,7 @@ EventReadHwState(InputInfoPtr pInfo,
+     struct SynapticsHwState *hw = &(comm->hwState);
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+     SynapticsParameters *para = &priv->synpara;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+ 
+     while (SynapticsReadEvent(pInfo, &ev)) {
+ 	switch (ev.type) {
+@@ -331,6 +527,7 @@ EventReadHwState(InputInfoPtr pInfo,
+ 		else
+ 		    hw->numFingers = 0;
+ 		*hwRet = *hw;
++                ProcessTouch(pInfo, priv);
+ 		return TRUE;
+ 	    }
+ 	case EV_KEY:
+@@ -404,6 +601,52 @@ EventReadHwState(InputInfoPtr pInfo,
+ 	    case ABS_TOOL_WIDTH:
+ 		hw->fingerWidth = ev.value;
+ 		break;
++            case ABS_MT_SLOT:
++                ProcessTouch(pInfo, priv);
++                ecpriv->cur_slot = ev.value;
++                break;
++            case ABS_MT_TRACKING_ID:
++                if (ecpriv->cur_slot < 0)
++                    break;
++                if (ev.value >= 0)
++                {
++                    if (ecpriv->mt_slot_map[ecpriv->cur_slot] != (uint32_t)-1)
++                    {
++                        xf86Msg(X_WARNING, "%s: Ignoring new tracking ID for "
++                                "existing touch.\n", pInfo->dev->name);
++                    }
++                    else
++                    {
++                        ecpriv->mt_slot_map[ecpriv->cur_slot] =
++                            ecpriv->next_touch_id++;
++                        ecpriv->new_touch = TRUE;
++                        valuator_mask_copy(ecpriv->touch_mask,
++                                           ecpriv->cur_vals);
++                    }
++                }
++                else
++                    ecpriv->close_slot = TRUE;
++                break;
++            case ABS_MT_TOUCH_MAJOR:
++            case ABS_MT_TOUCH_MINOR:
++            case ABS_MT_WIDTH_MAJOR:
++            case ABS_MT_WIDTH_MINOR:
++            case ABS_MT_ORIENTATION:
++            case ABS_MT_POSITION_X:
++            case ABS_MT_POSITION_Y:
++            case ABS_MT_TOOL_TYPE:
++            case ABS_MT_BLOB_ID:
++            case ABS_MT_PRESSURE:
++                if (ecpriv->cur_slot >= 0)
++                {
++                    valuator_mask_set(ecpriv->touch_mask,
++                                      ecpriv->mt_axis_map[ev.code - ABS_MT_TOUCH_MAJOR],
++                                      ev.value);
++                    valuator_mask_set(ecpriv->cur_vals,
++                                      ecpriv->mt_axis_map[ev.code - ABS_MT_TOUCH_MAJOR],
++                                      ev.value);
++                }
++                break;
+ 	    }
+ 	    break;
+ 	}
+@@ -423,9 +666,9 @@ static void
+ EventReadDevDimensions(InputInfoPtr pInfo)
+ {
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+-    BOOL *need_grab = (BOOL*)priv->proto_data;
++    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+ 
+-    if (event_query_is_touchpad(pInfo->fd, (need_grab) ? *need_grab : TRUE))
++    if (event_query_is_touchpad(pInfo->fd, ecpriv->need_grab))
+ 	event_query_axis_ranges(pInfo);
+     event_query_info(pInfo);
+ }
+@@ -482,8 +725,11 @@ EventAutoDevProbe(InputInfoPtr pInfo)
+ }
+ 
+ struct SynapticsProtocolOperations event_proto_operations = {
++    EventDevicePreInitHook,
++    EventDeviceInitHook,
+     EventDeviceOnHook,
+-    NULL,
++    EventDeviceOffHook,
++    EventDeviceCloseHook,
+     EventQueryHardware,
+     EventReadHwState,
+     EventAutoDevProbe,
+diff --git a/src/eventcomm.h b/src/eventcomm.h
+index 8fd7bcb..f3d94ba 100644
+--- a/src/eventcomm.h
++++ b/src/eventcomm.h
+@@ -29,9 +29,31 @@
+ 
+ #include <linux/input.h>
+ #include <linux/version.h>
++#include <X11/Xdefs.h>
++#include <xorg/input.h>
++#include <stdint.h>
+ 
+ /* for auto-dev: */
+ #define DEV_INPUT_EVENT "/dev/input"
+ #define EVENT_DEV_NAME "event"
+ 
++struct mtdev;
++
++typedef struct {
++    BOOL need_grab;
++    unsigned long absbits[ABS_CNT];
++    struct input_absinfo absinfo[ABS_CNT];
++    int mt_axis_map[ABS_MT_DISTANCE - ABS_MT_TOUCH_MAJOR];
++    int cur_slot;
++    uint32_t *mt_slot_map;
++    Bool close_slot;
++    uint32_t next_touch_id;
++    ValuatorMask *touch_mask;
++    ValuatorMask *cur_vals;
++    Bool new_touch;
++    int num_mt_axes;
++    int num_touches;
++    struct mtdev *mtdev;
++} EventcommPrivate;
++
+ #endif /* _EVENTCOMM_H_ */
+diff --git a/src/ps2comm.c b/src/ps2comm.c
+index 4e372b3..0878f7c 100644
+--- a/src/ps2comm.c
++++ b/src/ps2comm.c
+@@ -668,7 +668,10 @@ PS2AutoDevProbe(InputInfoPtr pInfo)
+ 
+ struct SynapticsProtocolOperations psaux_proto_operations = {
+     NULL,
++    NULL,
++    NULL,
+     PS2DeviceOffHook,
++    NULL,
+     PS2QueryHardware,
+     PS2ReadHwState,
+     PS2AutoDevProbe,
+diff --git a/src/synaptics.c b/src/synaptics.c
+index 88bd024..b6e3c47 100644
+--- a/src/synaptics.c
++++ b/src/synaptics.c
+@@ -723,6 +723,10 @@ SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+     priv->tap_button_state = TBS_BUTTON_UP;
+     priv->touch_on.millis = 0;
+ 
++    if (priv->proto_ops->DevicePreInitHook)
++        if (priv->proto_ops->DevicePreInitHook(drv, pInfo, flags) != Success)
++            goto SetupProc_fail;
++
+     /* read hardware dimensions */
+     ReadDevDimensions(pInfo);
+ 
+@@ -899,6 +903,9 @@ DeviceClose(DeviceIntPtr dev)
+     InputInfoPtr pInfo = dev->public.devicePrivate;
+     SynapticsPrivate *priv = (SynapticsPrivate *) pInfo->private;
+ 
++    if (priv->proto_ops->DeviceCloseHook)
++        priv->proto_ops->DeviceCloseHook(dev);
++
+     RetValue = DeviceOff(dev);
+     TimerFree(priv->timer);
+     priv->timer = NULL;
+@@ -1077,6 +1084,9 @@ DeviceInit(DeviceIntPtr dev)
+     InitDeviceProperties(pInfo);
+     XIRegisterPropertyHandler(pInfo->dev, SetProperty, NULL, NULL);
+ 
++    if (priv->proto_ops->DeviceInitHook)
++        return priv->proto_ops->DeviceInitHook(dev);
++
+     return Success;
+ }
+ 
+diff --git a/src/synapticsstr.h b/src/synapticsstr.h
+index 9ad8638..e8113ac 100644
+--- a/src/synapticsstr.h
++++ b/src/synapticsstr.h
+@@ -22,6 +22,8 @@
+ #ifndef	_SYNAPTICSSTR_H_
+ #define _SYNAPTICSSTR_H_
+ 
++#include <linux/input.h>
++
+ #include "synproto.h"
+ 
+ #ifdef DBG
+@@ -236,6 +238,7 @@ typedef struct _SynapticsPrivateRec
+     Bool has_pressure;			/* device reports pressure */
+     Bool has_width;			/* device reports finger width */
+     Bool has_scrollbuttons;		/* device has physical scrollbuttons */
++    Bool has_touch;                     /* device has multitouch */
+ 
+     enum TouchpadModel model;          /* The detected model */
+ } SynapticsPrivate;
+diff --git a/src/synproto.h b/src/synproto.h
+index 96ddf3e..4d5f510 100644
+--- a/src/synproto.h
++++ b/src/synproto.h
+@@ -83,8 +83,11 @@ struct SynapticsHwInfo;
+ struct CommData;
+ 
+ struct SynapticsProtocolOperations {
++    int (*DevicePreInitHook)(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
++    Bool (*DeviceInitHook)(DeviceIntPtr dev);
+     void (*DeviceOnHook)(InputInfoPtr pInfo, struct _SynapticsParameters *para);
+     void (*DeviceOffHook)(InputInfoPtr pInfo);
++    void (*DeviceCloseHook)(DeviceIntPtr dev);
+     Bool (*QueryHardware)(InputInfoPtr pInfo);
+     Bool (*ReadHwState)(InputInfoPtr pInfo,
+ 			struct SynapticsProtocolOperations *proto_ops,
+@@ -102,5 +105,4 @@ extern struct SynapticsProtocolOperations psm_proto_operations;
+ #endif /* BUILD_PSMCOMM */
+ extern struct SynapticsProtocolOperations alps_proto_operations;
+ 
+-
+ #endif /* _SYNPROTO_H_ */
diff --git a/debian/patches/201_gestures.patch b/debian/patches/201_gestures.patch
new file mode 100644
index 0000000..2007057
--- /dev/null
+++ b/debian/patches/201_gestures.patch
@@ -0,0 +1,863 @@
+diff --git a/configure.ac b/configure.ac
+index 537b4c0..33a8668 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -104,6 +104,10 @@ case "${host}" in
+ 
+ 	# Obtain compiler/linker options for mtdev
+ 	PKG_CHECK_MODULES(MTDEV, mtdev)
++
++	# Obtain compiler/linker options for grail
++	PKG_CHECK_MODULES(GRAIL, utouch-grail)
++	AC_DEFINE(GESTURES, 1, Needed to interpret xorg headers properly)
+ 	;;
+ *freebsd* | *openbsd* | *netbsd* | *dragonfly*)
+ 	AC_MSG_RESULT([psmcomm])
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 2150292..8def136 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -39,8 +39,8 @@ AM_CFLAGS = $(XORG_CFLAGS)
+ 
+ if BUILD_EVENTCOMM
+ @DRIVER_NAME@_drv_la_SOURCES += \
+-	eventcomm.c eventcomm.h
+-@DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS)
++	eventcomm.c eventcomm.h grail.c
++@DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS) $(GRAIL_LIBS)
+ endif
+ 
+ if BUILD_PSMCOMM
+diff --git a/src/eventcomm.c b/src/eventcomm.c
+index 86e8192..1fe02f4 100644
+--- a/src/eventcomm.c
++++ b/src/eventcomm.c
+@@ -43,6 +43,7 @@
+ #include <xf86.h>
+ #include <xorg/xserver-properties.h>
+ #include <mtdev.h>
++#include <grail.h>
+ 
+ 
+ #define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
+@@ -183,28 +184,13 @@ EventDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para)
+     if (rc >= 0)
+         ecpriv->cur_slot = abs.value;
+ 
+-    ecpriv->mtdev = malloc(sizeof(struct mtdev));
+-    if (!ecpriv->mtdev)
+-        return;
+-
+-    if (mtdev_open(ecpriv->mtdev, pInfo->fd)) {
+-        free(ecpriv->mtdev);
+-        ecpriv->mtdev = NULL;
+-        return;
+-    }
++    GrailOpen(pInfo);
+ }
+ 
+ static void
+ EventDeviceOffHook(InputInfoPtr pInfo)
+ {
+-    SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+-    EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
+-
+-    if (ecpriv->mtdev) {
+-        mtdev_close(ecpriv->mtdev);
+-        free(ecpriv->mtdev);
+-        ecpriv->mtdev = NULL;
+-    }
++    GrailClose(pInfo);
+ }
+ 
+ static void
+@@ -482,9 +468,8 @@ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
+     int rc = TRUE;
+     ssize_t len;
+ 
+-    if (ecpriv->mtdev)
+-        len = mtdev_get(ecpriv->mtdev, pInfo->fd, ev, 1) *
+-            sizeof(struct input_event);
++    if (ecpriv->grail)
++        len = grail_pull(ecpriv->grail, pInfo->fd);
+     else
+         len = read(pInfo->fd, ev, sizeof(*ev));
+ 
+@@ -494,163 +479,179 @@ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
+         if (errno != EAGAIN)
+             xf86MsgVerb(X_NONE, 0, "%s: Read error %s\n", pInfo->name, strerror(errno));
+         rc = FALSE;
+-    } else if (len % sizeof(*ev)) {
++    } else if (ecpriv->grail)
++        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)
++Bool
++EventProcessEvent(InputInfoPtr pInfo, struct CommData *comm,
++                  struct SynapticsHwState *hwRet, const struct input_event *ev)
+ {
+-    struct input_event ev;
+-    Bool v;
+-    struct SynapticsHwState *hw = &(comm->hwState);
+     SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+-    SynapticsParameters *para = &priv->synpara;
+     EventcommPrivate *ecpriv = (EventcommPrivate *)priv->proto_data;
++    SynapticsParameters *para = &priv->synpara;
++    struct SynapticsHwState *hw = &(comm->hwState);
++    Bool v;
+ 
+-    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;
+-                ProcessTouch(pInfo, priv);
+-		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;
+-            case ABS_MT_SLOT:
+-                ProcessTouch(pInfo, priv);
+-                ecpriv->cur_slot = ev.value;
++    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;
++            ProcessTouch(pInfo, priv);
++            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;
++        case ABS_MT_SLOT:
++            ProcessTouch(pInfo, priv);
++            ecpriv->cur_slot = ev->value;
++            break;
++        case ABS_MT_TRACKING_ID:
++            if (ecpriv->cur_slot < 0)
+                 break;
+-            case ABS_MT_TRACKING_ID:
+-                if (ecpriv->cur_slot < 0)
+-                    break;
+-                if (ev.value >= 0)
++            if (ev->value >= 0)
++            {
++                if (ecpriv->mt_slot_map[ecpriv->cur_slot] != (uint32_t)-1)
+                 {
+-                    if (ecpriv->mt_slot_map[ecpriv->cur_slot] != (uint32_t)-1)
+-                    {
+-                        xf86Msg(X_WARNING, "%s: Ignoring new tracking ID for "
+-                                "existing touch.\n", pInfo->dev->name);
+-                    }
+-                    else
+-                    {
+-                        ecpriv->mt_slot_map[ecpriv->cur_slot] =
+-                            ecpriv->next_touch_id++;
+-                        ecpriv->new_touch = TRUE;
+-                        valuator_mask_copy(ecpriv->touch_mask,
+-                                           ecpriv->cur_vals);
+-                    }
++                    xf86Msg(X_WARNING, "%s: Ignoring new tracking ID for "
++                            "existing touch.\n", pInfo->dev->name);
+                 }
+                 else
+-                    ecpriv->close_slot = TRUE;
+-                break;
+-            case ABS_MT_TOUCH_MAJOR:
+-            case ABS_MT_TOUCH_MINOR:
+-            case ABS_MT_WIDTH_MAJOR:
+-            case ABS_MT_WIDTH_MINOR:
+-            case ABS_MT_ORIENTATION:
+-            case ABS_MT_POSITION_X:
+-            case ABS_MT_POSITION_Y:
+-            case ABS_MT_TOOL_TYPE:
+-            case ABS_MT_BLOB_ID:
+-            case ABS_MT_PRESSURE:
+-                if (ecpriv->cur_slot >= 0)
+                 {
+-                    valuator_mask_set(ecpriv->touch_mask,
+-                                      ecpriv->mt_axis_map[ev.code - ABS_MT_TOUCH_MAJOR],
+-                                      ev.value);
+-                    valuator_mask_set(ecpriv->cur_vals,
+-                                      ecpriv->mt_axis_map[ev.code - ABS_MT_TOUCH_MAJOR],
+-                                      ev.value);
++                    ecpriv->mt_slot_map[ecpriv->cur_slot] =
++                        ecpriv->next_touch_id++;
++                    ecpriv->new_touch = TRUE;
++                    valuator_mask_copy(ecpriv->touch_mask,
++                                       ecpriv->cur_vals);
+                 }
+-                break;
+-	    }
+-	    break;
+-	}


Reply to: