All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Chase Douglas <chase.douglas@canonical.com>
Cc: linux-input@vger.kernel.org, xorg-devel@lists.x.org,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	Chris Bagwell <chris@cnpbagwell.com>,
	Andy Whitcroft <apw@canonical.com>,
	Henrik Rydberg <rydberg@euromail.se>,
	linux-kernel@vger.kernel.org,
	Peter Hutterer <peter.hutterer@who-t.net>,
	Duncan McGreggor <duncan.mcgreggor@canonical.com>
Subject: Re: [PATCH 0/3] Input: synaptics - multitouch and multifinger support
Date: Fri, 08 Oct 2010 18:37:22 +0200	[thread overview]
Message-ID: <s5hfwwg4p4t.wl%tiwai@suse.de> (raw)
In-Reply-To: <1286549880-32580-1-git-send-email-chase.douglas@canonical.com>

At Fri,  8 Oct 2010 10:57:57 -0400,
Chase Douglas wrote:
> 
> Tobyn Bertram reverse engineered the multitouch protocol for Synaptics devices.
> I've been able to take his work and produce a series of commits to enable MT
> and multifinger (MF) support.
> 
> Unfortunately, there's a tricky issue with some Synaptics touchpads that have
> integrated buttons. For example, the left and right buttons on the touchpad of
> my Dell Mini 1012 consist of the lower ~20% of the touchpad surface. The
> touchpad physically clicks under these areas.
> 
> The X synaptics input module now has a parameter to disable touches occuring
> over the button area, but this solution still doesn't work perfectly. If you
> click a button and drag with another finger near the clicking finger, the
> touchpad gets confused.
> 
> Now that we have full MT support, we can try to handle this scenario better.
> What I've found to work best is to make touches vanish if they occur over the
> button area of the trackpad while any button is held. This works in conjunction
> with the X synaptics driver to disable single touch control over the button
> area. With full MT support, the touchpad doesn't seem to get confused when a
> click and drag occurs with two fingers close to each other, and it enables MT
> gestures and MF support across the entire trackpad when no buttons are held.
> 
> The first question is whether this seems appropriate to others, or if some
> other method would work better. Secondarily, should the solution occur in the
> kernel, like I have in the third patch of this series, or should it occur in
> the X input module? Although we don't have this information today, we may be
> able to query the touchpad in the future to know the area of the integrated
> buttons. If that were possible, would the recommended location for the hack
> change?

Great!  Finally someone found it out!
I found this and made a series of patches in 4 months ago.  Since
then, Novell legal prohibited me to send the patches to the upstream
due to "possible patent infringing".  Now you cracked out.  Yay.

FWIW, my corresponding patch is below.  It really looks similar in the
end ;)  I added a kconfig just to be safer.

Regarding the "clickpad" support: in my case, I implemented almost
everything about it in xorg driver.  I'm going to submit xorg
patches.


thanks,

Takashi

---
>From 4c88fb69bdfb20a6ad030c7a19eed1e76beb0442 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Mon, 14 Jun 2010 12:46:48 +0200
Subject: [PATCH] input: Add multi-touch protocol support to Synaptics

This patch adds the experimental support of the multi-touch protocol
for recent Synaptics devices.  Note that the protocol was analyzed just
by a pure guess work by watching device outputs, so it might be incorrect.
Also, the check of the multi-touch capability based on the 0x0c caps
might be also wrong.

In the multi-touch mode, the driver gives MT_POSITION_X, MT_POSITION_Y
and MT_PRESSURE abs events to follow the type A in
Documentation/input/multi-touch-protocol.txt.
The device supports up to two finger points, as far as I've tested.

As the driver now gives the MT_* events, this extension might result in
the incompatible event outputs.  Thus make sure that the user-space side
(e.g. X11 synaptics driver) is also updated to support MT_* events.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/input/mouse/Kconfig     |   11 ++++
 drivers/input/mouse/synaptics.c |  113 +++++++++++++++++++++++++++++++++-----
 drivers/input/mouse/synaptics.h |    1 +
 3 files changed, 110 insertions(+), 15 deletions(-)

diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 91d3517..6dd0d29 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -76,6 +76,17 @@ config MOUSE_PS2_SYNAPTICS_LED
 	  Say Y here if you have a Synaptics device with an embedded LED.
 	  This will enable LED class driver to control the LED device.
 
+config MOUSE_PS2_SYNAPTICS_MULTI_TOUCH
+	bool "Support multi-touch protocol of Synaptics devices"
+	depends on MOUSE_PS2_SYNAPTICS
+	help
+	  Say Y here for enabling the multi-touch protocol of recent
+	  Syanptics devices.  This may result in incompatible input
+	  events, thus make sure that you update X11 synaptics driver
+	  beforehand with the multi-protocol touch.
+
+	  If unsure, say N.
+
 config MOUSE_PS2_LIFEBOOK
 	bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
 	default y
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 00799bc..79d9463 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -181,6 +181,12 @@ static int synaptics_capability(struct psmouse *psmouse)
 		}
 	}
 
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_MULTI_TOUCH
+	/* FIXME: is this the right guess? */
+	if (priv->ext_cap_0c & (0x08 << 16))
+		priv->can_multi_touch = 1;
+#endif
+
 	return 0;
 }
 
@@ -458,6 +464,32 @@ static void synaptics_free_led(struct psmouse *psmouse)
 #define synaptics_sync_led(ps)	do {} while (0)
 #endif
 
+/* change to the multi-touch mode;
+ * this is done by sending SYN_QUE_MODEL cmd but setting a parameter
+ * by SETRATE instead of querying via GETINFO.
+ * 0xc8 seems to be the multi-touch mode.
+ */
+static int synaptics_init_multi_touch(struct psmouse *psmouse)
+{
+	unsigned char param[1];
+
+	if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
+		return -1;
+	param[0] = 0xc8;
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
+		return -1;
+	return 0;
+}
+
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_MULTI_TOUCH
+#define is_multi_touch(priv)	(priv)->can_multi_touch
+#else
+#define is_multi_touch(priv)	0
+#endif
+/* the multi-touch packet contains w=2 (like pen) */
+#define is_multi_touch_packet(priv, hw) \
+	(is_multi_touch(priv) && (hw)->w == 2)
+
 /*****************************************************************************
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
@@ -467,17 +499,27 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
 	memset(hw, 0, sizeof(struct synaptics_hw_state));
 
 	if (SYN_MODEL_NEWABS(priv->model_id)) {
-		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];
 		hw->w = (((buf[0] & 0x30) >> 2) |
 			 ((buf[0] & 0x04) >> 1) |
 			 ((buf[3] & 0x04) >> 2));
+		if (is_multi_touch_packet(priv, hw)) {
+			/* a multi-touch packet is encoded differently;
+			 * it appears to have half-resolutions.  I might
+			 * have missed the lowest bits, but it's hard
+			 * to recognize.
+			 */
+			hw->x = ((buf[4] & 0x0f) << 8 | buf[1]) << 1;
+			hw->y = ((buf[4] & 0xf0) << 4 | buf[2]) << 1;
+			hw->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
+		} else {
+			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];
+		}
 
 		hw->left  = (buf[0] & 0x01) ? 1 : 0;
 		hw->right = (buf[0] & 0x02) ? 1 : 0;
@@ -492,7 +534,7 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
 
 		} else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
 			hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
-			if (hw->w == 2)
+			if (!is_multi_touch(priv) && hw->w == 2)
 				hw->scroll = (signed char)(buf[1]);
 		}
 
@@ -550,6 +592,18 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 
 	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
+	if (is_multi_touch_packet(priv, &hw)) {
+		/* multi-touching */
+		if (hw.z > 0) {
+			input_report_abs(dev, ABS_MT_POSITION_X, hw.x);
+			input_report_abs(dev, ABS_MT_POSITION_Y,
+					 YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
+		}
+		input_report_abs(dev, ABS_MT_PRESSURE, hw.z);
+		input_mt_sync(dev);
+		return;
+	}
+
 	if (hw.scroll) {
 		priv->scroll += hw.scroll;
 
@@ -576,7 +630,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 		if (SYN_CAP_EXTENDED(priv->capabilities)) {
 			switch (hw.w) {
 			case 0 ... 1:
-				if (SYN_CAP_MULTIFINGER(priv->capabilities))
+				if (SYN_CAP_MULTIFINGER(priv->capabilities) ||
+				    is_multi_touch(priv))
 					num_fingers = hw.w + 2;
 				break;
 			case 2:
@@ -602,10 +657,15 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 	if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
 
 	if (hw.z > 0) {
-		input_report_abs(dev, ABS_X, hw.x);
-		input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
+		int key;
+		key = is_multi_touch(priv) ? ABS_MT_POSITION_X : ABS_X;
+		input_report_abs(dev, key, hw.x);
+		key = is_multi_touch(priv) ? ABS_MT_POSITION_Y : ABS_Y;
+		input_report_abs(dev, key, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
 	}
-	input_report_abs(dev, ABS_PRESSURE, hw.z);
+	input_report_abs(dev,
+			 is_multi_touch(priv) ? ABS_MT_PRESSURE : ABS_PRESSURE,
+			 hw.z);
 
 	if (SYN_CAP_PALMDETECT(priv->capabilities))
 		input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
@@ -614,7 +674,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 	input_report_key(dev, BTN_LEFT, hw.left);
 	input_report_key(dev, BTN_RIGHT, hw.right);
 
-	if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
+	if (SYN_CAP_MULTIFINGER(priv->capabilities) || is_multi_touch(priv)) {
 		input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
 		input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
 	}
@@ -630,6 +690,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 	for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
 		input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
 
+	if (is_multi_touch(priv))
+		input_mt_sync(dev);
 	input_sync(dev);
 }
 
@@ -719,7 +781,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 	__set_bit(BTN_LEFT, dev->keybit);
 	__set_bit(BTN_RIGHT, dev->keybit);
 
-	if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
+	if (SYN_CAP_MULTIFINGER(priv->capabilities) || is_multi_touch(priv)) {
 		__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
 		__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
 	}
@@ -748,6 +810,16 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 		__clear_bit(BTN_RIGHT, dev->keybit);
 		__clear_bit(BTN_MIDDLE, dev->keybit);
 	}
+
+	if (is_multi_touch(priv)) {
+		input_set_abs_params(dev, ABS_MT_POSITION_X,
+				     XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_Y,
+				     YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
+		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+		input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res);
+		input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res);
+	}
 }
 
 static void synaptics_disconnect(struct psmouse *psmouse)
@@ -785,6 +857,8 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 	}
 
 	synaptics_sync_led(psmouse);
+	if (is_multi_touch(priv))
+		synaptics_init_multi_touch(psmouse);
 
 	return 0;
 }
@@ -863,6 +937,15 @@ int synaptics_init(struct psmouse *psmouse)
 	if (synaptics_init_led(psmouse) < 0)
 		goto init_fail;
 
+	if (priv->can_multi_touch) {
+		if (synaptics_init_multi_touch(psmouse)) {
+			printk(KERN_WARNING "Synaptics: "
+			       "unable to initialize multi-touch\n");
+			priv->can_multi_touch = 0;
+		} else
+			printk(KERN_INFO "Synaptics: multi-touch enabled\n");
+	}
+
 	set_input_params(psmouse->dev, priv);
 
 	/*
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index e1a9033..b586087 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -111,6 +111,7 @@ struct synaptics_data {
 
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
+	unsigned char can_multi_touch;		/* multi-touch support */
 	int scroll;
 	struct synaptics_led *led;
 };
-- 
1.7.2.1


  parent reply	other threads:[~2010-10-08 16:37 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-10-08 14:57 [PATCH 0/3] Input: synaptics - multitouch and multifinger support Chase Douglas
2010-10-08 14:57 ` [PATCH 1/3] Input: synaptics - add multitouch support Chase Douglas
2010-10-08 14:57   ` [PATCH 2/3] Input: synaptics - add multitouch multifinger support Chase Douglas
2010-10-08 14:58     ` [PATCH 3/3] Input: synaptics - remove touches over button click area Chase Douglas
2010-10-10 15:58       ` Chris Bagwell
2010-10-11 16:24       ` Chris Bagwell
2010-10-11 16:24         ` Chris Bagwell
2010-10-11 17:10         ` Takashi Iwai
2010-10-11 17:10           ` Takashi Iwai
2010-10-11 17:30           ` Dmitry Torokhov
2010-10-11 17:30             ` Dmitry Torokhov
2010-10-11 17:40             ` Takashi Iwai
2010-10-11 17:46           ` Chris Bagwell
2010-10-11 17:46             ` Chris Bagwell
2010-10-11 17:54             ` Henrik Rydberg
2010-10-11 18:29             ` Takashi Iwai
2010-10-11 18:29               ` Takashi Iwai
2010-10-10 15:44     ` [PATCH 2/3] Input: synaptics - add multitouch multifinger support Chris Bagwell
2010-10-10 15:37   ` [PATCH 1/3] Input: synaptics - add multitouch support Chris Bagwell
2010-10-10 15:41   ` Chris Bagwell
2010-10-08 16:37 ` Takashi Iwai [this message]
2010-10-08 16:38   ` [PATCH 0/3] Input: synaptics - multitouch and multifinger support Takashi Iwai
2010-10-08 17:48     ` Takashi Iwai
2010-10-08 17:15   ` Chase Douglas
2010-10-08 17:46     ` Takashi Iwai
2010-10-08 18:04     ` Dmitry Torokhov
2010-10-08 19:31       ` Takashi Iwai
2010-10-10 21:04         ` Dmitry Torokhov
2010-10-11  7:35           ` Takashi Iwai
2010-10-11  7:48             ` Henrik Rydberg
2010-10-11  7:59               ` Takashi Iwai
2010-10-11 13:41               ` Chris Bagwell
2010-10-11 13:41                 ` Chris Bagwell
2010-10-11 14:01                 ` Takashi Iwai
2010-10-11 14:01                   ` Takashi Iwai
2010-10-11 14:24                   ` Henrik Rydberg
2010-10-11 14:49                     ` Takashi Iwai
2010-10-11 15:31                       ` Henrik Rydberg
2010-10-11 15:58                         ` Takashi Iwai
2010-10-10  7:49   ` Henrik Rydberg
2010-10-10 20:59     ` Dmitry Torokhov
2010-10-11  7:28       ` Takashi Iwai
2010-10-11  7:40         ` Henrik Rydberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=s5hfwwg4p4t.wl%tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=apw@canonical.com \
    --cc=chase.douglas@canonical.com \
    --cc=chris@cnpbagwell.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=duncan.mcgreggor@canonical.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peter.hutterer@who-t.net \
    --cc=rydberg@euromail.se \
    --cc=xorg-devel@lists.x.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.