linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: djkurtz@chromium.org
To: dmitry.torokhov@gmail.com, rydberg@euromail.se,
	chase.douglas@canonical.com, rubini@cvml.unipv.it
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
	derek.foreman@collabora.co.uk, daniel.stone@collabora.co.uk,
	olofj@chromium.org, Daniel Kurtz <djkurtz@chromium.org>
Subject: [PATCH 09/12] Input: synaptics - add image sensor support
Date: Wed, 29 Jun 2011 13:07:19 +0800	[thread overview]
Message-ID: <1309324042-22943-10-git-send-email-djkurtz@chromium.org> (raw)
In-Reply-To: <1309324042-22943-1-git-send-email-djkurtz@chromium.org>

From: Daniel Kurtz <djkurtz@chromium.org>

Synaptics makes (at least) two kinds of touchpad sensors:
 * Older pads use a profile sensor that could only infer the location
   of individual fingers based on the projection of their profiles
   onto row and column sensors.
 * Newer pads use an image sensor that can track true finger position
   using a two-dimensional sensor grid.

Both sensor types support an "Advanced Gesture Mode":
 When multiple fingers are detected, the touchpad sends alternating
 "Advanced Gesture Mode" (AGM) and "Simple Gesture Mode" (SGM)
 packets.
 The AGM packets have w=2, and contain reduced resolution finger data
 The SGM packets have w={0,1} and contain full resolution finger data

Profile sensors try to report the "upper" (larger y value) finger in
 the SGM packet, and the lower (smaller y value) in the AGM packet.
 However, due to the nature of the profile sensor, they easily get
 confused when fingers cross, and can start reporting the x-coordinate
 of one with the y-coordinate of the other.  Thus, for profile
 sensors, "semi-mt" was created, which reports a "bounding box"
 created by pairing min and max coordinates of the two pairs of
 reported fingers.

Image sensors can report the actual coordinates of two of the fingers
 present.  This patch detects if the touchpad is an image sensor and
 reports finger data using the MT-B protocol.

NOTE: This patch only adds partial support for 2-finger gestures.
      The proper interpretation of the slot contents when more than
      two fingers are present is left to later patches.  Also,
      handling of 'number of fingers' transitions is incomplete.

Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
---
 drivers/input/mouse/synaptics.c |  116 ++++++++++++++++++++++++++++++++++++++-
 drivers/input/mouse/synaptics.h |   13 ++++
 2 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 0a51b0ba..2d7ac0a 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -286,7 +286,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
 	static unsigned char param = 0xc8;
 	struct synaptics_data *priv = psmouse->private;
 
-	if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
+	if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
+			SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
 		return 0;
 
 	if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
@@ -434,7 +435,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
 			hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
 		}
 
-		if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
+		if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)
+				|| SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))
+				&& hw->w == 2) {
 			/* Gesture packet: (x, y, z) at half resolution */
 			priv->agm.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
 			priv->agm.y = INVERT_Y((((buf[4] & 0xf0) << 4)
@@ -519,6 +522,92 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
 	}
 }
 
+static void synaptics_report_mt_slot(struct input_dev *dev, int slot, int state,
+				     const struct synaptics_hw_state *sgm,
+				     const struct synaptics_hw_state *agm)
+{
+	input_mt_slot(dev, slot);
+	switch (state) {
+	case SYN_SLOT_EMPTY:
+		input_mt_report_slot_state(dev, MT_TOOL_FINGER, false);
+		break;
+	case SYN_SLOT_SGM:
+		input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
+		input_report_abs(dev, ABS_MT_POSITION_X, sgm->x);
+		input_report_abs(dev, ABS_MT_POSITION_Y, sgm->y);
+		input_report_abs(dev, ABS_MT_PRESSURE, sgm->z);
+		if (sgm->w >= 4)
+			input_report_abs(dev, ABS_MT_TOUCH_MAJOR, sgm->w);
+		break;
+	case SYN_SLOT_AGM:
+		input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
+		input_report_abs(dev, ABS_MT_POSITION_X, agm->x);
+		input_report_abs(dev, ABS_MT_POSITION_Y, agm->y);
+		input_report_abs(dev, ABS_MT_PRESSURE, agm->z);
+		break;
+	}
+}
+
+static void synaptics_update_slots(struct synaptics_data *priv, int count,
+				   int sgm, int agm)
+{
+	int i;
+
+	/* First, clear previous slots. */
+	for (i = 0; i < SYN_TRACK_SLOT_COUNT; i++)
+		priv->slot[i] = SYN_SLOT_EMPTY;
+
+	if (count < 1)
+		return;
+	priv->slot[sgm] = SYN_SLOT_SGM;
+
+	if (count < 2)
+		return;
+	priv->slot[agm] = SYN_SLOT_AGM;
+}
+
+static void synaptics_process_hw_state(struct synaptics_data *priv,
+				       struct synaptics_hw_state *sgm)
+{
+	int new_num_fingers;
+
+	if (sgm->z == 0)
+		new_num_fingers = 0;
+	else if (sgm->w >= 4)
+		new_num_fingers = 1;
+	else if (sgm->w == 0)
+		new_num_fingers = 2;
+	else if (sgm->w == 1)
+		new_num_fingers = 3;
+
+	switch (new_num_fingers) {
+	case 0:
+		synaptics_update_slots(priv, 0, 0, 0);
+		break;
+	case 1:
+		synaptics_update_slots(priv, 1, 0, 0);
+		break;
+	case 2:
+	case 3: /* Fall-through case */
+		synaptics_update_slots(priv, 2, 0, 1);
+		break;
+	}
+
+	priv->num_fingers = new_num_fingers;
+}
+
+static void synaptics_report_mt_data(struct psmouse *psmouse,
+				     struct synaptics_hw_state *sgm)
+{
+	struct input_dev *dev = psmouse->dev;
+	struct synaptics_data *priv = psmouse->private;
+	struct synaptics_hw_state *agm = &priv->agm;
+	int i;
+
+	for (i = 0; i < SYN_TRACK_SLOT_COUNT; i++)
+		synaptics_report_mt_slot(dev, i, priv->slot[i], sgm, agm);
+}
+
 /*
  *  called for each full received packet from the touchpad
  */
@@ -534,6 +623,15 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 	if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
 		return;
 
+	if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
+		synaptics_process_hw_state(priv, &hw);
+		synaptics_report_mt_data(psmouse, &hw);
+		input_mt_report_pointer_emulation(dev, true);
+		input_report_key(dev, BTN_LEFT, hw.left);
+		input_sync(dev);
+		return;
+	}
+
 	if (hw.scroll) {
 		priv->scroll += hw.scroll;
 
@@ -705,7 +803,19 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 			     priv->y_max ?: YMAX_NOMINAL, fuzz, 0);
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
-	if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
+	if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
+		input_mt_init_slots(dev, SYN_TRACK_SLOT_COUNT);
+		input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
+				     priv->x_max ?: XMAX_NOMINAL, fuzz, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
+				     priv->y_max ?: YMAX_NOMINAL, fuzz, 0);
+		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+		input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 4, 15, 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);
+
+	} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
 		input_mt_init_slots(dev, 2);
 		input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index e367239..1de2256 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -73,6 +73,8 @@
  * 2	0x04	reduced filtering	firmware does less filtering on
  *					position data, driver should watch
  *					for noise.
+ * 2	0x08	image sensor		image sensor tracks 5 fingers, but only
+ *					reports 2.
  */
 #define SYN_CAP_ADJ_THRESHOLD(ex0c)	((ex0c) & 0x010000)
 #define SYN_CAP_MAX_DIMENSIONS(ex0c)	((ex0c) & 0x020000)
@@ -84,6 +86,7 @@
 #define SYN_CAP_CLICKPAD2BTN(ex0c)	((ex0c) & 0x000100) /* 2-button ClickPad */
 #define SYN_CAP_DELUXE_LED(ex0c)	((ex0c) & 0x000200)
 #define SYN_CAP_REDUCED_FILTERING(ex0c)	((ex0c) & 0x000400)
+#define SYN_CAP_IMAGE_SENSOR(ex0c)	((ex0c) & 0x000800)
 
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
@@ -113,6 +116,14 @@
 /* amount to fuzz position data when touchpad reports reduced filtering */
 #define SYN_REDUCED_FILTER_FUZZ		8
 
+/* synaptics tracking slot states */
+#define SYN_SLOT_EMPTY			0
+#define SYN_SLOT_SGM			1
+#define SYN_SLOT_AGM			2
+
+/* number of tracking slots for Image Sensor firmware */
+#define SYN_TRACK_SLOT_COUNT		2
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -148,6 +159,8 @@ struct synaptics_data {
 	struct serio *pt_port;			/* Pass-through serio port */
 
 	struct synaptics_hw_state agm;		/* last AGM packet */
+	int num_fingers;			/* current finger count */
+	int slot[SYN_TRACK_SLOT_COUNT];		/* finger slot state */
 };
 
 void synaptics_module_init(void);
-- 
1.7.3.1


  parent reply	other threads:[~2011-06-29  5:09 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-29  5:07 [PATCH 00/12] Synaptics image sensor support djkurtz
2011-06-29  5:07 ` [PATCH 01/12] Input: synaptics - cleanup 0x0c query documentation djkurtz
2011-07-05 17:33   ` Chase Douglas
2011-07-06 13:50     ` Daniel Kurtz
2011-07-07  6:30   ` Dmitry Torokhov
2011-06-29  5:07 ` [PATCH 02/12] Input: synaptics - do not invert y if 0 djkurtz
2011-07-04 21:08   ` Henrik Rydberg
2011-07-05  4:29     ` Daniel Kurtz
2011-07-05 18:07       ` Henrik Rydberg
2011-07-05 18:39         ` Chris Bagwell
2011-07-05 23:02         ` Daniel Kurtz
2011-07-05 17:42   ` Chase Douglas
2011-07-05 22:50     ` Daniel Kurtz
2011-07-05 23:06       ` Chase Douglas
2011-07-05 23:15         ` Daniel Kurtz
2011-07-05 23:25           ` Dmitry Torokhov
2011-06-29  5:07 ` [PATCH 03/12] Input: synaptics - fix minimum reported ABS_TOOL_WIDTH djkurtz
2011-06-29 13:28   ` Chris Bagwell
2011-06-29 16:48     ` Daniel Kurtz
2011-06-29 19:46       ` Chris Bagwell
2011-07-04 21:14         ` Henrik Rydberg
2011-07-09  6:24   ` Jeffrey Brown
2011-06-29  5:07 ` [PATCH 04/12] Input: synaptics - set resolution for MT_POSITION_X/Y axes djkurtz
2011-07-05 17:44   ` Chase Douglas
2011-07-07  6:23     ` Dmitry Torokhov
2011-06-29  5:07 ` [PATCH 05/12] Input: synaptics - process button bits in AGM packets djkurtz
2011-07-04 21:24   ` Henrik Rydberg
2011-07-05  4:38     ` Daniel Kurtz
2011-07-05 18:18       ` Henrik Rydberg
2011-07-05 18:19         ` Chase Douglas
2011-07-05 17:47   ` Chase Douglas
2011-07-07  6:24     ` Dmitry Torokhov
2011-06-29  5:07 ` [PATCH 06/12] Input: synaptics - fuzz position if touchpad reports reduced filtering djkurtz
2011-07-05 17:49   ` Chase Douglas
2011-07-07  6:25     ` Dmitry Torokhov
2011-06-29  5:07 ` [PATCH 07/12] Input: synaptics - rename synaptics_data.mt to agm djkurtz
2011-07-04 21:26   ` Henrik Rydberg
2011-07-05  4:39     ` Daniel Kurtz
2011-07-05 18:20       ` Henrik Rydberg
2011-07-05 17:53   ` Chase Douglas
2011-06-29  5:07 ` [PATCH 08/12] Input: synaptics - rename set_slot to be more descriptive djkurtz
2011-07-05 17:54   ` Chase Douglas
2011-07-07  6:27     ` Dmitry Torokhov
2011-06-29  5:07 ` djkurtz [this message]
2011-07-04 21:42   ` [PATCH 09/12] Input: synaptics - add image sensor support Henrik Rydberg
2011-07-05  5:08     ` Daniel Kurtz
2011-07-05 19:27       ` Henrik Rydberg
2011-07-06 16:41         ` Daniel Kurtz
2011-07-06 17:08           ` Chase Douglas
2011-07-06 17:45           ` Dmitry Torokhov
2011-07-06 18:47             ` Henrik Rydberg
2011-07-06 18:58               ` Dmitry Torokhov
2011-07-06 19:31                 ` Henrik Rydberg
2011-07-06 20:00                   ` Dmitry Torokhov
2011-07-06 20:20                     ` Henrik Rydberg
2011-07-06 21:22                       ` Chase Douglas
2011-07-06 21:36                         ` Dmitry Torokhov
2011-07-06 22:16                           ` Chase Douglas
2011-07-06 22:35                             ` Henrik Rydberg
2011-07-06 23:30                               ` Chase Douglas
2011-06-29  5:07 ` [PATCH 10/12] Input: synaptics - decode AGM packet types djkurtz
2011-06-29 10:02   ` Chase Douglas
2011-06-29 10:07     ` Daniel Stone
2011-06-29 10:32       ` Chase Douglas
2011-06-29 11:26         ` Daniel Kurtz
2011-06-29 11:04     ` Daniel Kurtz
2011-07-05 18:17   ` Chase Douglas
2011-07-05 18:55     ` Chris Bagwell
2011-07-06 16:53       ` Daniel Kurtz
2011-06-29  5:07 ` [PATCH 11/12] Input: synaptics - process finger (<=3) transitions djkurtz
2011-06-29  5:07 ` [PATCH 12/12] Input: synaptics - process finger (<=5) transitions djkurtz

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=1309324042-22943-10-git-send-email-djkurtz@chromium.org \
    --to=djkurtz@chromium.org \
    --cc=chase.douglas@canonical.com \
    --cc=daniel.stone@collabora.co.uk \
    --cc=derek.foreman@collabora.co.uk \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=olofj@chromium.org \
    --cc=rubini@cvml.unipv.it \
    --cc=rydberg@euromail.se \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).