From e309fbac1531fc2e38beac7af76a1a80db9e1154 Mon Sep 17 00:00:00 2001
From: Chris Bagwell <chris@cnpbagwell.com>
Date: Tue, 9 Mar 2010 19:40:11 -0600
Subject: [PATCH] optionally support multi-touch input interface

The wacom kernel driver will eventually move to use
the linux input multi-touch interface to return
multi-touch finger data to wacom X driver.

If multi-touch events are received, this patch disables
old way of splitting up finger data based on BTN_TOOL_DOUBLETAP
and BTN_TOOL_TRIPLETAP and processes both fingers data with a
single event.

If no multi-touch packets recieved then previous logic will
be used and expects a EV_SYNC event in between multiple finger data.

Signed-off-by: Chris Bagwell <chris@cnpbagwell.com>
---
 src/wcmUSB.c        |   64 +++++++++++++++++++++++++++++++++++++++++++++++----
 src/xf86WacomDefs.h |    1 +
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/src/wcmUSB.c b/src/wcmUSB.c
index 997b843..357138c 100644
--- a/src/wcmUSB.c
+++ b/src/wcmUSB.c
@@ -887,9 +887,9 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 		/* absolute events */
 		if (event->type == EV_ABS)
 		{
-			if (event->code == ABS_X)
+			if (event->code == ABS_X && !common->wcmMTChan)
 				ds->x = event->value;
-			else if (event->code == ABS_Y)
+			else if (event->code == ABS_Y && !common->wcmMTChan)
 				ds->y = event->value;
 			else if (event->code == ABS_RX)
 				ds->stripx = event->value; 
@@ -901,7 +901,8 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 				ds->tiltx = event->value - common->wcmMaxtiltX/2;
 			else if (event->code ==  ABS_TILT_Y)
 				ds->tilty = event->value - common->wcmMaxtiltY/2;
-			else if (event->code == ABS_PRESSURE) {
+			else if (event->code == ABS_PRESSURE && 
+				 !common->wcmMTChan) {
 				if (ds->device_type == TOUCH_ID)
 					ds->capacity = event->value;
 				else
@@ -915,6 +916,12 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 				ds->throttle = event->value;
 			else if (event->code == ABS_MISC && event->value)
 				ds->device_id = event->value;
+			else if (event->code == ABS_MT_POSITION_X)
+				common->wcmChannel[common->wcmMTChan].work.x = event->value;
+			else if (event->code == ABS_MT_POSITION_Y)
+				common->wcmChannel[common->wcmMTChan].work.y = event->value;
+			else if (event->code == ABS_MT_TOUCH_MAJOR)
+				common->wcmChannel[common->wcmMTChan].work.proximity = (event->value != 0);
 		}
 		else if (event->type == EV_REL)
 		{
@@ -975,7 +982,7 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 				ds->device_id = PAD_DEVICE_ID;
 				ds->proximity = (event->value != 0);
 			}
-			else if (event->code == BTN_TOOL_DOUBLETAP)
+			else if (event->code == BTN_TOOL_DOUBLETAP && !common->wcmMTChan)
 			{
 				WacomChannelPtr pChannel = common->wcmChannel + channel;
 				WacomDeviceState dslast = pChannel->valid.state;
@@ -997,7 +1004,7 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 				if (common->wcmCapacityDefault < 0)
 					MOD_BUTTONS (0, event->value);
 			}
-			else if (event->code == BTN_TOOL_TRIPLETAP)
+			else if (event->code == BTN_TOOL_TRIPLETAP && !common->wcmMTChan)
 			{
 				WacomChannelPtr pChannel = common->wcmChannel + channel;
 				WacomDeviceState dslast = pChannel->valid.state;
@@ -1040,6 +1047,44 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 					}
 			}
 		}
+		else if (event->type == EV_SYN && event->code == SYN_MT_REPORT)
+		{
+			/* Kernel driver used to use
+			 * BTN_TOOL_DOUBLETAP and TRIPLETAP when
+			 * SYN_MT_REPORT wasn't supported by kernel.
+			 * The old way is still supported to be
+			 * backwards compatible.
+			 */
+			WacomChannelPtr pChannel = common->wcmChannel + channel;
+			WacomDeviceState dslast = pChannel->valid.state;
+
+			common->wcmChannel[common->wcmMTChan].work.device_type = TOUCH_ID;
+			common->wcmChannel[common->wcmMTChan].work.device_id = TOUCH_DEVICE_ID;
+			if ((ds->proximity && !dslast.proximity) ||
+			    (!ds->proximity && dslast.proximity))
+				ds->sample = (int)GetTimeInMillis();
+
+			/* FIXME: This conflicts with gesture logic
+			 * in wcmEvent().  It should be centralized
+			 * there.  Also, touchpads should not be
+			 * calling this.   We do not have the
+			 * correct priv pointer handy to check
+			 * for ABSOLUTE mode so doing it the easy
+			 * way until gestuer logic is centralized.
+			 */
+			if (!(common->tablet_id >= 0xd0 && common->tablet_id <= 0xd3))
+				MOD_BUTTONS (0, event->value);
+
+			if (common->wcmMTChan < MAX_FINGERS-1)
+			{
+
+				common->wcmMTChan++;
+
+				/* Do any initialization that we are bypassing */
+				common->wcmChannel[common->wcmMTChan].work.relwheel = 0;
+				common->wcmChannel[common->wcmMTChan].work.serial_num = common->wcmMTChan;
+			}
+		}
 	} /* next event */
 
 	/* don't send touch event when touch isn't enabled */
@@ -1057,6 +1102,15 @@ static void usbParseChannel(LocalDevicePtr local, int channel)
 
 	/* dispatch event */
 	wcmEvent(common, channel, ds);
+	
+	if (common->wcmMTChan)
+	{
+		int mtc;
+
+		for (mtc = 1; mtc <= common->wcmMTChan; mtc++)
+			wcmEvent(common, mtc, &common->wcmChannel[mtc].work);
+		common->wcmMTChan = 0;
+	}
 }
 
 /**
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index f9d4b5e..6f82b76 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -423,6 +423,7 @@ struct _WacomCommonRec
 	int wcmLastToolSerial;
 	int wcmEventCnt;
 	struct input_event wcmEvents[MAX_USB_EVENTS];  /* events for current change */
+	int wcmMTChan;		     /* Current multi-touch channel */
 
 	WacomToolPtr wcmTool; /* List of unique tools */
 };
-- 
1.6.6.1

