[kernel/f16] Add commits queued for 3.2 for elantech driver (rhbz 728607)
Josh Boyer
jwboyer at fedoraproject.org
Thu Nov 3 13:42:12 UTC 2011
commit 436da03d79647ec0e9887f553d190c4b137c8d12
Author: Josh Boyer <jwboyer at redhat.com>
Date: Thu Nov 3 09:39:46 2011 -0400
Add commits queued for 3.2 for elantech driver (rhbz 728607)
elantech.patch | 2116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
kernel.spec | 11 +-
2 files changed, 2126 insertions(+), 1 deletions(-)
---
diff --git a/elantech.patch b/elantech.patch
new file mode 100644
index 0000000..255efd2
--- /dev/null
+++ b/elantech.patch
@@ -0,0 +1,2116 @@
+From 13ac768d9a8731c8b3bab7d6c86520f290272fe7 Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:22:19 -0700
+Subject: Input: elantech - correct x, y value range for v2 hardware
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+x, y values are actually 12-bit long. Also update protocol document to
+reflect the change.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ Documentation/input/elantech.txt | 8 ++++----
+ drivers/input/mouse/elantech.c | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
+index db798af..bce9941 100644
+--- a/Documentation/input/elantech.txt
++++ b/Documentation/input/elantech.txt
+@@ -389,14 +389,14 @@ byte 0:
+ byte 1:
+
+ bit 7 6 5 4 3 2 1 0
+- p7 p6 p5 p4 . x10 x9 x8
++ p7 p6 p5 p4 x11 x10 x9 x8
+
+ byte 2:
+
+ bit 7 6 5 4 3 2 1 0
+ x7 x6 x5 x4 x3 x2 x1 x0
+
+- x10..x0 = absolute x value (horizontal)
++ x11..x0 = absolute x value (horizontal)
+
+ byte 3:
+
+@@ -420,7 +420,7 @@ byte 3:
+ byte 4:
+
+ bit 7 6 5 4 3 2 1 0
+- p3 p1 p2 p0 . . y9 y8
++ p3 p1 p2 p0 y11 y10 y9 y8
+
+ p7..p0 = pressure (not EF113)
+
+@@ -429,7 +429,7 @@ byte 5:
+ bit 7 6 5 4 3 2 1 0
+ y7 y6 y5 y4 y3 y2 y1 y0
+
+- y9..y0 = absolute y value (vertical)
++ y11..y0 = absolute y value (vertical)
+
+
+ 4.2.2 Two finger touch
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index 3250356..da161da 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -290,15 +290,15 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ /* pass through... */
+ case 1:
+ /*
+- * byte 1: . . . . . x10 x9 x8
++ * byte 1: . . . . x11 x10 x9 x8
+ * byte 2: x7 x6 x5 x4 x4 x2 x1 x0
+ */
+- x1 = ((packet[1] & 0x07) << 8) | packet[2];
++ x1 = ((packet[1] & 0x0f) << 8) | packet[2];
+ /*
+- * byte 4: . . . . . . y9 y8
++ * byte 4: . . . . y11 y10 y9 y8
+ * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
+ */
+- y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]);
++ y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]);
+
+ input_report_abs(dev, ABS_X, x1);
+ input_report_abs(dev, ABS_Y, y1);
+--
+1.7.6.4
+
+
+From c47c9334b4ebb6ecb565d9bf834df170fcd09484 Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:22:58 -0700
+Subject: Input: elantech - get rid of ETP_2FT_* in elantech.h
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For two finger touches the coordinate of each finger gets reported
+separately but with reduced resolution.
+
+With this change, we now have the same range for ST and MT data and
+scale MT data because it has lower resolution to match ST.
+
+Suggested-by: Dmitry Torokhov <dmitry.torokhov at gmail.com>
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 28 +++++++++++++---------------
+ drivers/input/mouse/elantech.h | 11 -----------
+ 2 files changed, 13 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index da161da..cd8e2e5 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -273,11 +273,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ struct elantech_data *etd = psmouse->private;
+ struct input_dev *dev = psmouse->dev;
+ unsigned char *packet = psmouse->packet;
+- unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0;
++ unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
++ unsigned int width = 0, pres = 0;
+
+ /* byte 0: n1 n0 . . . . R L */
+ fingers = (packet[0] & 0xc0) >> 6;
+- input_report_key(dev, BTN_TOUCH, fingers != 0);
+
+ switch (fingers) {
+ case 3:
+@@ -300,9 +300,6 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ */
+ y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]);
+
+- input_report_abs(dev, ABS_X, x1);
+- input_report_abs(dev, ABS_Y, y1);
+-
+ pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+ width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
+ break;
+@@ -314,22 +311,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ * byte 0: . . ay8 ax8 . . . .
+ * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
+ */
+- x1 = ((packet[0] & 0x10) << 4) | packet[1];
++ x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2;
+ /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
+- y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]);
++ y1 = ETP_YMAX_V2 -
++ ((((packet[0] & 0x20) << 3) | packet[2]) << 2);
+ /*
+ * byte 3: . . by8 bx8 . . . .
+ * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
+ */
+- x2 = ((packet[3] & 0x10) << 4) | packet[4];
++ x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2;
+ /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */
+- y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]);
+- /*
+- * For compatibility with the X Synaptics driver scale up
+- * one coordinate and report as ordinary mouse movent
+- */
+- input_report_abs(dev, ABS_X, x1 << 2);
+- input_report_abs(dev, ABS_Y, y1 << 2);
++ y2 = ETP_YMAX_V2 -
++ ((((packet[3] & 0x20) << 3) | packet[5]) << 2);
+
+ /* Unknown so just report sensible values */
+ pres = 127;
+@@ -337,6 +330,11 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ break;
+ }
+
++ input_report_key(dev, BTN_TOUCH, fingers != 0);
++ if (fingers != 0) {
++ input_report_abs(dev, ABS_X, x1);
++ input_report_abs(dev, ABS_Y, y1);
++ }
+ elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index fabb2b9..1c5894e 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -82,17 +82,6 @@
+ #define ETP_WMIN_V2 0
+ #define ETP_WMAX_V2 15
+
+-/*
+- * For two finger touches the coordinate of each finger gets reported
+- * separately but with reduced resolution.
+- */
+-#define ETP_2FT_FUZZ 4
+-
+-#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ)
+-#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ)
+-#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ)
+-#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ)
+-
+ struct elantech_data {
+ unsigned char reg_10;
+ unsigned char reg_11;
+--
+1.7.6.4
+
+
+From aa719e391c1769c93ec42a30daffa4ffa2a8503c Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:26:16 -0700
+Subject: Input: elantech - use firmware provided x, y ranges
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+With newer hardware, the touchpad provides range info.
+Let's use it.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 71 +++++++++++++++++++++++++++++++--------
+ drivers/input/mouse/elantech.h | 3 +-
+ 2 files changed, 58 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index cd8e2e5..296b6a6 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -223,7 +223,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
+ input_report_abs(dev, ABS_X,
+ ((packet[1] & 0x0c) << 6) | packet[2]);
+ input_report_abs(dev, ABS_Y,
+- ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3]));
++ etd->y_max - (((packet[1] & 0x03) << 8) | packet[3]));
+ }
+
+ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
+@@ -233,7 +233,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+
+ if (etd->fw_version < 0x020000 &&
+- (etd->capabilities & ETP_CAP_HAS_ROCKER)) {
++ (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
+ /* rocker up */
+ input_report_key(dev, BTN_FORWARD, packet[0] & 0x40);
+ /* rocker down */
+@@ -298,7 +298,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ * byte 4: . . . . y11 y10 y9 y8
+ * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
+ */
+- y1 = ETP_YMAX_V2 - (((packet[4] & 0x0f) << 8) | packet[5]);
++ y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
+
+ pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+ width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
+@@ -313,7 +313,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ */
+ x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2;
+ /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
+- y1 = ETP_YMAX_V2 -
++ y1 = etd->y_max -
+ ((((packet[0] & 0x20) << 3) | packet[2]) << 2);
+ /*
+ * byte 3: . . by8 bx8 . . . .
+@@ -321,7 +321,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ */
+ x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2;
+ /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */
+- y2 = ETP_YMAX_V2 -
++ y2 = etd->y_max -
+ ((((packet[3] & 0x20) << 3) | packet[5]) << 2);
+
+ /* Unknown so just report sensible values */
+@@ -468,6 +468,41 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+ return rc;
+ }
+
++static void elantech_set_range(struct psmouse *psmouse,
++ unsigned int *x_min, unsigned int *y_min,
++ unsigned int *x_max, unsigned int *y_max)
++{
++ struct elantech_data *etd = psmouse->private;
++ int i;
++
++ switch (etd->hw_version) {
++ case 1:
++ *x_min = ETP_XMIN_V1;
++ *y_min = ETP_YMIN_V1;
++ *x_max = ETP_XMAX_V1;
++ *y_max = ETP_YMAX_V1;
++ break;
++
++ case 2:
++ if (etd->fw_version == 0x020800 ||
++ etd->fw_version == 0x020b00 ||
++ etd->fw_version == 0x020030) {
++ *x_min = ETP_XMIN_V2;
++ *y_min = ETP_YMIN_V2;
++ *x_max = ETP_XMAX_V2;
++ *y_max = ETP_YMAX_V2;
++ } else {
++ i = (etd->fw_version > 0x020800 &&
++ etd->fw_version < 0x020900) ? 1 : 2;
++ *x_min = 0;
++ *y_min = 0;
++ *x_max = (etd->capabilities[1] - i) * 64;
++ *y_max = (etd->capabilities[2] - i) * 64;
++ }
++ break;
++ }
++}
++
+ /*
+ * Set the appropriate event bits for the input subsystem
+ */
+@@ -475,6 +510,9 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+ {
+ struct input_dev *dev = psmouse->dev;
+ struct elantech_data *etd = psmouse->private;
++ unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0;
++
++ elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max);
+
+ __set_bit(EV_KEY, dev->evbit);
+ __set_bit(EV_ABS, dev->evbit);
+@@ -492,18 +530,18 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+ case 1:
+ /* Rocker button */
+ if (etd->fw_version < 0x020000 &&
+- (etd->capabilities & ETP_CAP_HAS_ROCKER)) {
++ (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) {
+ __set_bit(BTN_FORWARD, dev->keybit);
+ __set_bit(BTN_BACK, dev->keybit);
+ }
+- input_set_abs_params(dev, ABS_X, ETP_XMIN_V1, ETP_XMAX_V1, 0, 0);
+- input_set_abs_params(dev, ABS_Y, ETP_YMIN_V1, ETP_YMAX_V1, 0, 0);
++ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
++ input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
+ break;
+
+ case 2:
+ __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
+- input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
+- input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
++ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
++ input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
+ if (etd->reports_pressure) {
+ input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
+ ETP_PMAX_V2, 0, 0);
+@@ -512,10 +550,12 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+ }
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+ input_mt_init_slots(dev, 2);
+- input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
+- input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
++ input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
++ input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
+ break;
+ }
++
++ etd->y_max = y_max;
+ }
+
+ struct elantech_attr_data {
+@@ -769,13 +809,14 @@ int elantech_init(struct psmouse *psmouse)
+ pr_info("assuming hardware version %d, firmware version %d.%d.%d\n",
+ etd->hw_version, param[0], param[1], param[2]);
+
+- if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) {
++ if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
++ etd->capabilities)) {
+ pr_err("failed to query capabilities.\n");
+ goto init_fail;
+ }
+ pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
+- param[0], param[1], param[2]);
+- etd->capabilities = param[0];
++ etd->capabilities[0], etd->capabilities[1],
++ etd->capabilities[2]);
+
+ /*
+ * This firmware suffers from misreporting coordinates when
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index 1c5894e..b54ea27 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -93,13 +93,14 @@ struct elantech_data {
+ unsigned char reg_25;
+ unsigned char reg_26;
+ unsigned char debug;
+- unsigned char capabilities;
++ unsigned char capabilities[3];
+ bool paritycheck;
+ bool jumpy_cursor;
+ bool reports_pressure;
+ unsigned char hw_version;
+ unsigned int fw_version;
+ unsigned int single_finger_reports;
++ unsigned int y_max;
+ unsigned char parity[256];
+ };
+
+--
+1.7.6.4
+
+
+From 91f395e84dc83707b01c69e297894dbf992a566e Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:27:42 -0700
+Subject: Input: elantech - remove ETP_EDGE_FUZZ_V2
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Don't try to be too clever and remove ETP_EDGE_FUZZ_V2. X, Y ranges
+should be just the raw resolution of the device. Otherwise, they can
+cause underflow on the Y axis.
+
+Suggested-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.h | 15 ++++++---------
+ 1 files changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index b54ea27..d9e6144 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -66,16 +66,13 @@
+ #define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1)
+
+ /*
+- * It seems the resolution for hardware version 2 doubled.
+- * Hence the X and Y ranges are doubled too.
+- * The bezel around the pad also appears to be smaller
++ * The resolution for older v2 hardware doubled.
++ * (newer v2's firmware provides command so we can query)
+ */
+-#define ETP_EDGE_FUZZ_V2 8
+-
+-#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
+-#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2)
+-#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
+-#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2)
++#define ETP_XMIN_V2 0
++#define ETP_XMAX_V2 1152
++#define ETP_YMIN_V2 0
++#define ETP_YMAX_V2 768
+
+ #define ETP_PMIN_V2 0
+ #define ETP_PMAX_V2 255
+--
+1.7.6.4
+
+
+From cc66bde05d267cce5a6f64d877e63036505cc31e Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:28:04 -0700
+Subject: Input: elantech - packet checking for v2 hardware
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For v2 hardware, there is no real parity check, but we can still check
+some constant bits for data integrity.
+
+Also rename elantech_check_parity_v1 to elantech_packet_check_v1 to make
+these packet checking function names consistent.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 39 ++++++++++++++++++++++++++++++++++-----
+ 1 files changed, 34 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index 296b6a6..f2e3a2b 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -350,7 +350,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ input_sync(dev);
+ }
+
+-static int elantech_check_parity_v1(struct psmouse *psmouse)
++static int elantech_packet_check_v1(struct psmouse *psmouse)
+ {
+ struct elantech_data *etd = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+@@ -374,6 +374,34 @@ static int elantech_check_parity_v1(struct psmouse *psmouse)
+ etd->parity[packet[3]] == p3;
+ }
+
++static int elantech_packet_check_v2(struct psmouse *psmouse)
++{
++ struct elantech_data *etd = psmouse->private;
++ unsigned char *packet = psmouse->packet;
++
++ /*
++ * V2 hardware has two flavors. Older ones that do not report pressure,
++ * and newer ones that reports pressure and width. With newer ones, all
++ * packets (1, 2, 3 finger touch) have the same constant bits. With
++ * older ones, 1/3 finger touch packets and 2 finger touch packets
++ * have different constant bits.
++ * With all three cases, if the constant bits are not exactly what I
++ * expected, I consider them invalid.
++ */
++ if (etd->reports_pressure)
++ return (packet[0] & 0x0c) == 0x04 &&
++ (packet[3] & 0x0f) == 0x02;
++
++ if ((packet[0] & 0xc0) == 0x80)
++ return (packet[0] & 0x0c) == 0x0c &&
++ (packet[3] & 0x0e) == 0x08;
++
++ return (packet[0] & 0x3c) == 0x3c &&
++ (packet[1] & 0xf0) == 0x00 &&
++ (packet[3] & 0x3e) == 0x38 &&
++ (packet[4] & 0xf0) == 0x00;
++}
++
+ /*
+ * Process byte stream from mouse and handle complete packets
+ */
+@@ -389,14 +417,16 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+
+ switch (etd->hw_version) {
+ case 1:
+- if (etd->paritycheck && !elantech_check_parity_v1(psmouse))
++ if (etd->paritycheck && !elantech_packet_check_v1(psmouse))
+ return PSMOUSE_BAD_DATA;
+
+ elantech_report_absolute_v1(psmouse);
+ break;
+
+ case 2:
+- /* We don't know how to check parity in protocol v2 */
++ if (etd->paritycheck && !elantech_packet_check_v2(psmouse))
++ return PSMOUSE_BAD_DATA;
++
+ elantech_report_absolute_v2(psmouse);
+ break;
+ }
+@@ -795,8 +825,7 @@ int elantech_init(struct psmouse *psmouse)
+ etd->hw_version = 2;
+ /* For now show extra debug information */
+ etd->debug = 1;
+- /* Don't know how to do parity checking for version 2 */
+- etd->paritycheck = 0;
++ etd->paritycheck = 1;
+
+ if (etd->fw_version >= 0x020800)
+ etd->reports_pressure = true;
+--
+1.7.6.4
+
+
+From 7e1abba14d70426b251ee58451ab1671af425409 Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:28:19 -0700
+Subject: Input: elantech - clean up elantech_init
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Group property setting code into elantech_set_properties.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 69 ++++++++++++++++++++++-----------------
+ 1 files changed, 39 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index f2e3a2b..1ab1c14 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -791,6 +791,42 @@ static int elantech_reconnect(struct psmouse *psmouse)
+ }
+
+ /*
++ * determine hardware version and set some properties according to it.
++ */
++static void elantech_set_properties(struct elantech_data *etd)
++{
++ /*
++ * Assume every version greater than 0x020030 is new EeePC style
++ * hardware with 6 byte packets, except 0x020600
++ */
++ if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
++ etd->hw_version = 1;
++ else
++ etd->hw_version = 2;
++
++ /*
++ * Turn on packet checking by default.
++ */
++ etd->paritycheck = 1;
++
++ /*
++ * This firmware suffers from misreporting coordinates when
++ * a touch action starts causing the mouse cursor or scrolled page
++ * to jump. Enable a workaround.
++ */
++ etd->jumpy_cursor =
++ (etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
++
++ if (etd->hw_version == 2) {
++ /* For now show extra debug information */
++ etd->debug = 1;
++
++ if (etd->fw_version >= 0x020800)
++ etd->reports_pressure = true;
++ }
++}
++
++/*
+ * Initialize the touchpad and create sysfs entries
+ */
+ int elantech_init(struct psmouse *psmouse)
+@@ -816,26 +852,9 @@ int elantech_init(struct psmouse *psmouse)
+ }
+
+ etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
+-
+- /*
+- * Assume every version greater than this is new EeePC style
+- * hardware with 6 byte packets
+- */
+- if (etd->fw_version >= 0x020030) {
+- etd->hw_version = 2;
+- /* For now show extra debug information */
+- etd->debug = 1;
+- etd->paritycheck = 1;
+-
+- if (etd->fw_version >= 0x020800)
+- etd->reports_pressure = true;
+-
+- } else {
+- etd->hw_version = 1;
+- etd->paritycheck = 1;
+- }
+-
+- pr_info("assuming hardware version %d, firmware version %d.%d.%d\n",
++ elantech_set_properties(etd);
++ pr_info("assuming hardware version %d "
++ "(with firmware version 0x%02x%02x%02x)\n",
+ etd->hw_version, param[0], param[1], param[2]);
+
+ if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
+@@ -847,16 +866,6 @@ int elantech_init(struct psmouse *psmouse)
+ etd->capabilities[0], etd->capabilities[1],
+ etd->capabilities[2]);
+
+- /*
+- * This firmware suffers from misreporting coordinates when
+- * a touch action starts causing the mouse cursor or scrolled page
+- * to jump. Enable a workaround.
+- */
+- if (etd->fw_version == 0x020022 || etd->fw_version == 0x020600) {
+- pr_info("firmware version 2.0.34/2.6.0 detected, enabling jumpy cursor workaround\n");
+- etd->jumpy_cursor = true;
+- }
+-
+ if (elantech_set_absolute_mode(psmouse)) {
+ pr_err("failed to put touchpad into absolute mode.\n");
+ goto init_fail;
+--
+1.7.6.4
+
+
+From 709d9ebd2853032df0599c30d5ac61c8397679f3 Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:30:31 -0700
+Subject: Input: elantech - add v3 hardware support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+v3 hardware's packet format is almost identical to v2 (one/three finger touch),
+except when sensing two finger touch, the hardware sends 12 bytes of data.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Acked-by: Daniel Kurtz <djkurtz at chromium.org>
+Acked-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ Documentation/input/elantech.txt | 117 +++++++++++++++++++--
+ drivers/input/mouse/elantech.c | 208 ++++++++++++++++++++++++++++++++++----
+ drivers/input/mouse/elantech.h | 12 ++
+ 3 files changed, 306 insertions(+), 31 deletions(-)
+
+diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
+index bce9941..cee08ee 100644
+--- a/Documentation/input/elantech.txt
++++ b/Documentation/input/elantech.txt
+@@ -16,15 +16,22 @@ Contents
+
+ 1. Introduction
+ 2. Extra knobs
+- 3. Hardware version 1
+- 3.1 Registers
+- 3.2 Native relative mode 4 byte packet format
+- 3.3 Native absolute mode 4 byte packet format
+- 4. Hardware version 2
++ 3. Differentiating hardware versions
++ 4. Hardware version 1
+ 4.1 Registers
+- 4.2 Native absolute mode 6 byte packet format
+- 4.2.1 One finger touch
+- 4.2.2 Two finger touch
++ 4.2 Native relative mode 4 byte packet format
++ 4.3 Native absolute mode 4 byte packet format
++ 5. Hardware version 2
++ 5.1 Registers
++ 5.2 Native absolute mode 6 byte packet format
++ 5.2.1 Parity checking and packet re-synchronization
++ 5.2.2 One/Three finger touch
++ 5.2.3 Two finger touch
++ 6. Hardware version 3
++ 6.1 Registers
++ 6.2 Native absolute mode 6 byte packet format
++ 6.2.1 One/Three finger touch
++ 6.2.2 Two finger touch
+
+
+
+@@ -375,7 +382,7 @@ For all the other ones, there are just a few constant bits:
+
+ In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
+
+-5.2.1 One/Three finger touch
++5.2.2 One/Three finger touch
+ ~~~~~~~~~~~~~~~~
+
+ byte 0:
+@@ -384,7 +391,7 @@ byte 0:
+ n1 n0 w3 w2 . . R L
+
+ L, R = 1 when Left, Right mouse button pressed
+- n1..n0 = numbers of fingers on touchpad
++ n1..n0 = number of fingers on touchpad
+
+ byte 1:
+
+@@ -432,7 +439,7 @@ byte 5:
+ y11..y0 = absolute y value (vertical)
+
+
+-4.2.2 Two finger touch
++5.2.3 Two finger touch
+ ~~~~~~~~~~~~~~~~
+
+ Note that the two pairs of coordinates are not exactly the coordinates of the
+@@ -446,7 +453,7 @@ byte 0:
+ n1 n0 ay8 ax8 . . R L
+
+ L, R = 1 when Left, Right mouse button pressed
+- n1..n0 = numbers of fingers on touchpad
++ n1..n0 = number of fingers on touchpad
+
+ byte 1:
+
+@@ -480,3 +487,89 @@ byte 5:
+ by7 by8 by5 by4 by3 by2 by1 by0
+
+ by8..by0 = upper-right finger absolute y value
++
++/////////////////////////////////////////////////////////////////////////////
++
++6. Hardware version 3
++ ==================
++
++6.1 Registers
++ ~~~~~~~~~
++* reg_10
++
++ bit 7 6 5 4 3 2 1 0
++ 0 0 0 0 0 0 0 A
++
++ A: 1 = enable absolute tracking
++
++6.2 Native absolute mode 6 byte packet format
++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++1 and 3 finger touch shares the same 6-byte packet format, except that
++3 finger touch only reports the position of the center of all three fingers.
++
++Firmware would send 12 bytes of data for 2 finger touch.
++
++Note on debounce:
++In case the box has unstable power supply or other electricity issues, or
++when number of finger changes, F/W would send "debounce packet" to inform
++driver that the hardware is in debounce status.
++The debouce packet has the following signature:
++ byte 0: 0xc4
++ byte 1: 0xff
++ byte 2: 0xff
++ byte 3: 0x02
++ byte 4: 0xff
++ byte 5: 0xff
++When we encounter this kind of packet, we just ignore it.
++
++6.2.1 One/Three finger touch
++ ~~~~~~~~~~~~~~~~~~~~~~
++
++byte 0:
++
++ bit 7 6 5 4 3 2 1 0
++ n1 n0 w3 w2 0 1 R L
++
++ L, R = 1 when Left, Right mouse button pressed
++ n1..n0 = number of fingers on touchpad
++
++byte 1:
++
++ bit 7 6 5 4 3 2 1 0
++ p7 p6 p5 p4 x11 x10 x9 x8
++
++byte 2:
++
++ bit 7 6 5 4 3 2 1 0
++ x7 x6 x5 x4 x3 x2 x1 x0
++
++ x11..x0 = absolute x value (horizontal)
++
++byte 3:
++
++ bit 7 6 5 4 3 2 1 0
++ 0 0 w1 w0 0 0 1 0
++
++ w3..w0 = width of the finger touch
++
++byte 4:
++
++ bit 7 6 5 4 3 2 1 0
++ p3 p1 p2 p0 y11 y10 y9 y8
++
++ p7..p0 = pressure
++
++byte 5:
++
++ bit 7 6 5 4 3 2 1 0
++ y7 y6 y5 y4 y3 y2 y1 y0
++
++ y11..y0 = absolute y value (vertical)
++
++6.2.2 Two finger touch
++ ~~~~~~~~~~~~~~~~
++
++The packet format is exactly the same for two finger touch, except the hardware
++sends two 6 byte packets. The first packet contains data for the first finger,
++the second packet has data for the second finger. So for two finger touch a
++total of 12 bytes are sent.
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index 1ab1c14..9cfc70a 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
+ rc = -1;
+ }
+ break;
++
++ case 3:
++ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, reg) ||
++ elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
++ rc = -1;
++ }
++ break;
+ }
+
+ if (rc)
+@@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
+ rc = -1;
+ }
+ break;
++
++ case 3:
++ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, reg) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, val) ||
++ elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
++ rc = -1;
++ }
++ break;
+ }
+
+ if (rc)
+@@ -350,6 +372,84 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
+ input_sync(dev);
+ }
+
++/*
++ * Interpret complete data packets and report absolute mode input events for
++ * hardware version 3. (12 byte packets for two fingers)
++ */
++static void elantech_report_absolute_v3(struct psmouse *psmouse,
++ int packet_type)
++{
++ struct input_dev *dev = psmouse->dev;
++ struct elantech_data *etd = psmouse->private;
++ unsigned char *packet = psmouse->packet;
++ unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
++ unsigned int width = 0, pres = 0;
++
++ /* byte 0: n1 n0 . . . . R L */
++ fingers = (packet[0] & 0xc0) >> 6;
++
++ switch (fingers) {
++ case 3:
++ case 1:
++ /*
++ * byte 1: . . . . x11 x10 x9 x8
++ * byte 2: x7 x6 x5 x4 x4 x2 x1 x0
++ */
++ x1 = ((packet[1] & 0x0f) << 8) | packet[2];
++ /*
++ * byte 4: . . . . y11 y10 y9 y8
++ * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
++ */
++ y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
++ break;
++
++ case 2:
++ if (packet_type == PACKET_V3_HEAD) {
++ /*
++ * byte 1: . . . . ax11 ax10 ax9 ax8
++ * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
++ */
++ etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2];
++ /*
++ * byte 4: . . . . ay11 ay10 ay9 ay8
++ * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
++ */
++ etd->prev_y = etd->y_max -
++ (((packet[4] & 0x0f) << 8) | packet[5]);
++ /*
++ * wait for next packet
++ */
++ return;
++ }
++
++ /* packet_type == PACKET_V3_TAIL */
++ x1 = etd->prev_x;
++ y1 = etd->prev_y;
++ x2 = ((packet[1] & 0x0f) << 8) | packet[2];
++ y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
++ break;
++ }
++
++ pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
++ width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
++
++ input_report_key(dev, BTN_TOUCH, fingers != 0);
++ if (fingers != 0) {
++ input_report_abs(dev, ABS_X, x1);
++ input_report_abs(dev, ABS_Y, y1);
++ }
++ elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
++ input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
++ input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
++ input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
++ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
++ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
++ input_report_abs(dev, ABS_PRESSURE, pres);
++ input_report_abs(dev, ABS_TOOL_WIDTH, width);
++
++ input_sync(dev);
++}
++
+ static int elantech_packet_check_v1(struct psmouse *psmouse)
+ {
+ struct elantech_data *etd = psmouse->private;
+@@ -403,11 +503,37 @@ static int elantech_packet_check_v2(struct psmouse *psmouse)
+ }
+
+ /*
++ * We check the constant bits to determine what packet type we get,
++ * so packet checking is mandatory for v3 hardware.
++ */
++static int elantech_packet_check_v3(struct psmouse *psmouse)
++{
++ const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
++ unsigned char *packet = psmouse->packet;
++
++ /*
++ * check debounce first, it has the same signature in byte 0
++ * and byte 3 as PACKET_V3_HEAD.
++ */
++ if (!memcmp(packet, debounce_packet, sizeof(debounce_packet)))
++ return PACKET_DEBOUNCE;
++
++ if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
++ return PACKET_V3_HEAD;
++
++ if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
++ return PACKET_V3_TAIL;
++
++ return PACKET_UNKNOWN;
++}
++
++/*
+ * Process byte stream from mouse and handle complete packets
+ */
+ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+ {
+ struct elantech_data *etd = psmouse->private;
++ int packet_type;
+
+ if (psmouse->pktcnt < psmouse->pktsize)
+ return PSMOUSE_GOOD_DATA;
+@@ -429,6 +555,18 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+
+ elantech_report_absolute_v2(psmouse);
+ break;
++
++ case 3:
++ packet_type = elantech_packet_check_v3(psmouse);
++ /* ignore debounce */
++ if (packet_type == PACKET_DEBOUNCE)
++ return PSMOUSE_FULL_PACKET;
++
++ if (packet_type == PACKET_UNKNOWN)
++ return PSMOUSE_BAD_DATA;
++
++ elantech_report_absolute_v3(psmouse, packet_type);
++ break;
+ }
+
+ return PSMOUSE_FULL_PACKET;
+@@ -463,8 +601,15 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+ elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
+ elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
+ rc = -1;
+- break;
+ }
++ break;
++
++ case 3:
++ etd->reg_10 = 0x0b;
++ if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
++ rc = -1;
++
++ break;
+ }
+
+ if (rc == 0) {
+@@ -498,11 +643,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+ return rc;
+ }
+
+-static void elantech_set_range(struct psmouse *psmouse,
+- unsigned int *x_min, unsigned int *y_min,
+- unsigned int *x_max, unsigned int *y_max)
++static int elantech_set_range(struct psmouse *psmouse,
++ unsigned int *x_min, unsigned int *y_min,
++ unsigned int *x_max, unsigned int *y_max)
+ {
+ struct elantech_data *etd = psmouse->private;
++ unsigned char param[3];
+ int i;
+
+ switch (etd->hw_version) {
+@@ -530,19 +676,30 @@ static void elantech_set_range(struct psmouse *psmouse,
+ *y_max = (etd->capabilities[2] - i) * 64;
+ }
+ break;
++
++ case 3:
++ if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
++ return -1;
++
++ *x_max = (0x0f & param[0]) << 8 | param[1];
++ *y_max = (0xf0 & param[0]) << 4 | param[2];
++ break;
+ }
++
++ return 0;
+ }
+
+ /*
+ * Set the appropriate event bits for the input subsystem
+ */
+-static void elantech_set_input_params(struct psmouse *psmouse)
++static int elantech_set_input_params(struct psmouse *psmouse)
+ {
+ struct input_dev *dev = psmouse->dev;
+ struct elantech_data *etd = psmouse->private;
+ unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0;
+
+- elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max);
++ if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max))
++ return -1;
+
+ __set_bit(EV_KEY, dev->evbit);
+ __set_bit(EV_ABS, dev->evbit);
+@@ -570,6 +727,9 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+
+ case 2:
+ __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
++ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
++ /* fall through */
++ case 3:
+ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
+ input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
+ if (etd->reports_pressure) {
+@@ -578,7 +738,6 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
+ ETP_WMAX_V2, 0, 0);
+ }
+- __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
+@@ -586,6 +745,8 @@ static void elantech_set_input_params(struct psmouse *psmouse)
+ }
+
+ etd->y_max = y_max;
++
++ return 0;
+ }
+
+ struct elantech_attr_data {
+@@ -727,7 +888,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
+ * Report this in case there are Elantech models that use a different
+ * set of magic numbers
+ */
+- if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
++ if (param[0] != 0x3c || param[1] != 0x03 ||
++ (param[2] != 0xc8 && param[2] != 0x00)) {
+ pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
+ param[0], param[1], param[2]);
+ return -1;
+@@ -793,16 +955,16 @@ static int elantech_reconnect(struct psmouse *psmouse)
+ /*
+ * determine hardware version and set some properties according to it.
+ */
+-static void elantech_set_properties(struct elantech_data *etd)
++static int elantech_set_properties(struct elantech_data *etd)
+ {
+- /*
+- * Assume every version greater than 0x020030 is new EeePC style
+- * hardware with 6 byte packets, except 0x020600
+- */
+ if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
+ etd->hw_version = 1;
+- else
++ else if (etd->fw_version < 0x150600)
+ etd->hw_version = 2;
++ else if ((etd->fw_version & 0x0f0000) >> 16 == 5)
++ etd->hw_version = 3;
++ else
++ return -1;
+
+ /*
+ * Turn on packet checking by default.
+@@ -817,13 +979,15 @@ static void elantech_set_properties(struct elantech_data *etd)
+ etd->jumpy_cursor =
+ (etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
+
+- if (etd->hw_version == 2) {
++ if (etd->hw_version > 1) {
+ /* For now show extra debug information */
+ etd->debug = 1;
+
+ if (etd->fw_version >= 0x020800)
+ etd->reports_pressure = true;
+ }
++
++ return 0;
+ }
+
+ /*
+@@ -850,9 +1014,12 @@ int elantech_init(struct psmouse *psmouse)
+ pr_err("failed to query firmware version.\n");
+ goto init_fail;
+ }
+-
+ etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
+- elantech_set_properties(etd);
++
++ if (elantech_set_properties(etd)) {
++ pr_err("unknown hardware version, aborting...\n");
++ goto init_fail;
++ }
+ pr_info("assuming hardware version %d "
+ "(with firmware version 0x%02x%02x%02x)\n",
+ etd->hw_version, param[0], param[1], param[2]);
+@@ -871,7 +1038,10 @@ int elantech_init(struct psmouse *psmouse)
+ goto init_fail;
+ }
+
+- elantech_set_input_params(psmouse);
++ if (elantech_set_input_params(psmouse)) {
++ pr_err("failed to query touchpad range.\n");
++ goto init_fail;
++ }
+
+ error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
+ &elantech_attr_group);
+@@ -883,7 +1053,7 @@ int elantech_init(struct psmouse *psmouse)
+ psmouse->protocol_handler = elantech_process_byte;
+ psmouse->disconnect = elantech_disconnect;
+ psmouse->reconnect = elantech_reconnect;
+- psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
++ psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
+
+ return 0;
+
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index d9e6144..236c33c 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -16,6 +16,7 @@
+ /*
+ * Command values for Synaptics style queries
+ */
++#define ETP_FW_ID_QUERY 0x00
+ #define ETP_FW_VERSION_QUERY 0x01
+ #define ETP_CAPABILITIES_QUERY 0x02
+
+@@ -24,6 +25,7 @@
+ */
+ #define ETP_REGISTER_READ 0x10
+ #define ETP_REGISTER_WRITE 0x11
++#define ETP_REGISTER_READWRITE 0x00
+
+ /*
+ * Hardware version 2 custom PS/2 command value
+@@ -79,6 +81,14 @@
+ #define ETP_WMIN_V2 0
+ #define ETP_WMAX_V2 15
+
++/*
++ * v3 hardware has 2 kinds of packet types.
++ */
++#define PACKET_UNKNOWN 0x01
++#define PACKET_DEBOUNCE 0x02
++#define PACKET_V3_HEAD 0x03
++#define PACKET_V3_TAIL 0x04
++
+ struct elantech_data {
+ unsigned char reg_10;
+ unsigned char reg_11;
+@@ -98,6 +108,8 @@ struct elantech_data {
+ unsigned int fw_version;
+ unsigned int single_finger_reports;
+ unsigned int y_max;
++ unsigned int prev_x;
++ unsigned int prev_y;
+ unsigned char parity[256];
+ };
+
+--
+1.7.6.4
+
+
+From 5936f37c68ab27b24d6f2faf23268a9aefd3092e Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Fri, 9 Sep 2011 10:31:58 -0700
+Subject: Input: elantech - add v4 hardware support
+
+v4 hardware is a true multitouch capable touchpad (up to 5 fingers).
+The packet format is quite complex, please see protocol document for
+reference.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ Documentation/input/elantech.txt | 170 ++++++++++++++++++++++++++
+ drivers/input/mouse/elantech.c | 249 ++++++++++++++++++++++++++++++++++++--
+ drivers/input/mouse/elantech.h | 29 ++++-
+ 3 files changed, 432 insertions(+), 16 deletions(-)
+
+diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
+index cee08ee..5602eb7 100644
+--- a/Documentation/input/elantech.txt
++++ b/Documentation/input/elantech.txt
+@@ -32,6 +32,12 @@ Contents
+ 6.2 Native absolute mode 6 byte packet format
+ 6.2.1 One/Three finger touch
+ 6.2.2 Two finger touch
++ 7. Hardware version 4
++ 7.1 Registers
++ 7.2 Native absolute mode 6 byte packet format
++ 7.2.1 Status packet
++ 7.2.2 Head packet
++ 7.2.3 Motion packet
+
+
+
+@@ -573,3 +579,167 @@ The packet format is exactly the same for two finger touch, except the hardware
+ sends two 6 byte packets. The first packet contains data for the first finger,
+ the second packet has data for the second finger. So for two finger touch a
+ total of 12 bytes are sent.
++
++/////////////////////////////////////////////////////////////////////////////
++
++7. Hardware version 4
++ ==================
++
++7.1 Registers
++ ~~~~~~~~~
++* reg_07
++
++ bit 7 6 5 4 3 2 1 0
++ 0 0 0 0 0 0 0 A
++
++ A: 1 = enable absolute tracking
++
++7.2 Native absolute mode 6 byte packet format
++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++v4 hardware is a true multitouch touchpad, capable of tracking up to 5 fingers.
++Unfortunately, due to PS/2's limited bandwidth, its packet format is rather
++complex.
++
++Whenever the numbers or identities of the fingers changes, the hardware sends a
++status packet to indicate how many and which fingers is on touchpad, followed by
++head packets or motion packets. A head packet contains data of finger id, finger
++position (absolute x, y values), width, and pressure. A motion packet contains
++two fingers' position delta.
++
++For example, when status packet tells there are 2 fingers on touchpad, then we
++can expect two following head packets. If the finger status doesn't change,
++the following packets would be motion packets, only sending delta of finger
++position, until we receive a status packet.
++
++One exception is one finger touch. when a status packet tells us there is only
++one finger, the hardware would just send head packets afterwards.
++
++7.2.1 Status packet
++ ~~~~~~~~~~~~~
++
++byte 0:
++
++ bit 7 6 5 4 3 2 1 0
++ . . . . 0 1 R L
++
++ L, R = 1 when Left, Right mouse button pressed
++
++byte 1:
++
++ bit 7 6 5 4 3 2 1 0
++ . . . ft4 ft3 ft2 ft1 ft0
++
++ ft4 ft3 ft2 ft1 ft0 ftn = 1 when finger n is on touchpad
++
++byte 2: not used
++
++byte 3:
++
++ bit 7 6 5 4 3 2 1 0
++ . . . 1 0 0 0 0
++
++ constant bits
++
++byte 4:
++
++ bit 7 6 5 4 3 2 1 0
++ p . . . . . . .
++
++ p = 1 for palm
++
++byte 5: not used
++
++7.2.2 Head packet
++ ~~~~~~~~~~~
++
++byte 0:
++
++ bit 7 6 5 4 3 2 1 0
++ w3 w2 w1 w0 0 1 R L
++
++ L, R = 1 when Left, Right mouse button pressed
++ w3..w0 = finger width (spans how many trace lines)
++
++byte 1:
++
++ bit 7 6 5 4 3 2 1 0
++ p7 p6 p5 p4 x11 x10 x9 x8
++
++byte 2:
++
++ bit 7 6 5 4 3 2 1 0
++ x7 x6 x5 x4 x3 x2 x1 x0
++
++ x11..x0 = absolute x value (horizontal)
++
++byte 3:
++
++ bit 7 6 5 4 3 2 1 0
++ id2 id1 id0 1 0 0 0 1
++
++ id2..id0 = finger id
++
++byte 4:
++
++ bit 7 6 5 4 3 2 1 0
++ p3 p1 p2 p0 y11 y10 y9 y8
++
++ p7..p0 = pressure
++
++byte 5:
++
++ bit 7 6 5 4 3 2 1 0
++ y7 y6 y5 y4 y3 y2 y1 y0
++
++ y11..y0 = absolute y value (vertical)
++
++7.2.3 Motion packet
++ ~~~~~~~~~~~~~
++
++byte 0:
++
++ bit 7 6 5 4 3 2 1 0
++ id2 id1 id0 w 0 1 R L
++
++ L, R = 1 when Left, Right mouse button pressed
++ id2..id0 = finger id
++ w = 1 when delta overflows (> 127 or < -128), in this case
++ firmware sends us (delta x / 5) and (delta y / 5)
++
++byte 1:
++
++ bit 7 6 5 4 3 2 1 0
++ x7 x6 x5 x4 x3 x2 x1 x0
++
++ x7..x0 = delta x (two's complement)
++
++byte 2:
++
++ bit 7 6 5 4 3 2 1 0
++ y7 y6 y5 y4 y3 y2 y1 y0
++
++ y7..y0 = delta y (two's complement)
++
++byte 3:
++
++ bit 7 6 5 4 3 2 1 0
++ id2 id1 id0 1 0 0 1 0
++
++ id2..id0 = finger id
++
++byte 4:
++
++ bit 7 6 5 4 3 2 1 0
++ x7 x6 x5 x4 x3 x2 x1 x0
++
++ x7..x0 = delta x (two's complement)
++
++byte 5:
++
++ bit 7 6 5 4 3 2 1 0
++ y7 y6 y5 y4 y3 y2 y1 y0
++
++ y7..y0 = delta y (two's complement)
++
++ byte 0 ~ 2 for one finger
++ byte 3 ~ 5 for another
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index 9cfc70a..b8733b3 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -84,7 +84,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
+ unsigned char param[3];
+ int rc = 0;
+
+- if (reg < 0x10 || reg > 0x26)
++ if (reg < 0x07 || reg > 0x26)
+ return -1;
+
+ if (reg > 0x11 && reg < 0x20)
+@@ -109,7 +109,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
+ }
+ break;
+
+- case 3:
++ case 3 ... 4:
+ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+@@ -122,8 +122,10 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
+
+ if (rc)
+ pr_err("failed to read register 0x%02x.\n", reg);
+- else
++ else if (etd->hw_version != 4)
+ *val = param[0];
++ else
++ *val = param[1];
+
+ return rc;
+ }
+@@ -137,7 +139,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
+ struct elantech_data *etd = psmouse->private;
+ int rc = 0;
+
+- if (reg < 0x10 || reg > 0x26)
++ if (reg < 0x07 || reg > 0x26)
+ return -1;
+
+ if (reg > 0x11 && reg < 0x20)
+@@ -176,6 +178,20 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
+ rc = -1;
+ }
+ break;
++
++ case 4:
++ if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, reg) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
++ elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
++ elantech_ps2_command(psmouse, NULL, val) ||
++ elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
++ rc = -1;
++ }
++ break;
+ }
+
+ if (rc)
+@@ -409,12 +425,12 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
+ * byte 1: . . . . ax11 ax10 ax9 ax8
+ * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
+ */
+- etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2];
++ etd->mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2];
+ /*
+ * byte 4: . . . . ay11 ay10 ay9 ay8
+ * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
+ */
+- etd->prev_y = etd->y_max -
++ etd->mt[0].y = etd->y_max -
+ (((packet[4] & 0x0f) << 8) | packet[5]);
+ /*
+ * wait for next packet
+@@ -423,8 +439,8 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
+ }
+
+ /* packet_type == PACKET_V3_TAIL */
+- x1 = etd->prev_x;
+- y1 = etd->prev_y;
++ x1 = etd->mt[0].x;
++ y1 = etd->mt[0].y;
+ x2 = ((packet[1] & 0x0f) << 8) | packet[2];
+ y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
+ break;
+@@ -450,6 +466,129 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,
+ input_sync(dev);
+ }
+
++static void elantech_input_sync_v4(struct psmouse *psmouse)
++{
++ struct input_dev *dev = psmouse->dev;
++ unsigned char *packet = psmouse->packet;
++
++ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
++ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
++ input_mt_report_pointer_emulation(dev, true);
++ input_sync(dev);
++}
++
++static void process_packet_status_v4(struct psmouse *psmouse)
++{
++ struct input_dev *dev = psmouse->dev;
++ unsigned char *packet = psmouse->packet;
++ unsigned fingers;
++ int i;
++
++ /* notify finger state change */
++ fingers = packet[1] & 0x1f;
++ for (i = 0; i < ETP_MAX_FINGERS; i++) {
++ if ((fingers & (1 << i)) == 0) {
++ input_mt_slot(dev, i);
++ input_mt_report_slot_state(dev, MT_TOOL_FINGER, false);
++ }
++ }
++
++ elantech_input_sync_v4(psmouse);
++}
++
++static void process_packet_head_v4(struct psmouse *psmouse)
++{
++ struct input_dev *dev = psmouse->dev;
++ struct elantech_data *etd = psmouse->private;
++ unsigned char *packet = psmouse->packet;
++ int id = ((packet[3] & 0xe0) >> 5) - 1;
++ int pres, traces;
++
++ if (id < 0)
++ return;
++
++ etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2];
++ etd->mt[id].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
++ pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
++ traces = (packet[0] & 0xf0) >> 4;
++
++ input_mt_slot(dev, id);
++ input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
++
++ input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x);
++ input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y);
++ input_report_abs(dev, ABS_MT_PRESSURE, pres);
++ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, traces * etd->width);
++ /* report this for backwards compatibility */
++ input_report_abs(dev, ABS_TOOL_WIDTH, traces);
++
++ elantech_input_sync_v4(psmouse);
++}
++
++static void process_packet_motion_v4(struct psmouse *psmouse)
++{
++ struct input_dev *dev = psmouse->dev;
++ struct elantech_data *etd = psmouse->private;
++ unsigned char *packet = psmouse->packet;
++ int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0;
++ int id, sid;
++
++ id = ((packet[0] & 0xe0) >> 5) - 1;
++ if (id < 0)
++ return;
++
++ sid = ((packet[3] & 0xe0) >> 5) - 1;
++ weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1;
++ /*
++ * Motion packets give us the delta of x, y values of specific fingers,
++ * but in two's complement. Let the compiler do the conversion for us.
++ * Also _enlarge_ the numbers to int, in case of overflow.
++ */
++ delta_x1 = (signed char)packet[1];
++ delta_y1 = (signed char)packet[2];
++ delta_x2 = (signed char)packet[4];
++ delta_y2 = (signed char)packet[5];
++
++ etd->mt[id].x += delta_x1 * weight;
++ etd->mt[id].y -= delta_y1 * weight;
++ input_mt_slot(dev, id);
++ input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x);
++ input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y);
++
++ if (sid >= 0) {
++ etd->mt[sid].x += delta_x2 * weight;
++ etd->mt[sid].y -= delta_y2 * weight;
++ input_mt_slot(dev, sid);
++ input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[sid].x);
++ input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[sid].y);
++ }
++
++ elantech_input_sync_v4(psmouse);
++}
++
++static void elantech_report_absolute_v4(struct psmouse *psmouse,
++ int packet_type)
++{
++ switch (packet_type) {
++ case PACKET_V4_STATUS:
++ process_packet_status_v4(psmouse);
++ break;
++
++ case PACKET_V4_HEAD:
++ process_packet_head_v4(psmouse);
++ break;
++
++ case PACKET_V4_MOTION:
++ process_packet_motion_v4(psmouse);
++ break;
++
++ case PACKET_UNKNOWN:
++ default:
++ /* impossible to get here */
++ break;
++ }
++}
++
+ static int elantech_packet_check_v1(struct psmouse *psmouse)
+ {
+ struct elantech_data *etd = psmouse->private;
+@@ -504,7 +643,7 @@ static int elantech_packet_check_v2(struct psmouse *psmouse)
+
+ /*
+ * We check the constant bits to determine what packet type we get,
+- * so packet checking is mandatory for v3 hardware.
++ * so packet checking is mandatory for v3 and later hardware.
+ */
+ static int elantech_packet_check_v3(struct psmouse *psmouse)
+ {
+@@ -527,6 +666,25 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
+ return PACKET_UNKNOWN;
+ }
+
++static int elantech_packet_check_v4(struct psmouse *psmouse)
++{
++ unsigned char *packet = psmouse->packet;
++
++ if ((packet[0] & 0x0c) == 0x04 &&
++ (packet[3] & 0x1f) == 0x11)
++ return PACKET_V4_HEAD;
++
++ if ((packet[0] & 0x0c) == 0x04 &&
++ (packet[3] & 0x1f) == 0x12)
++ return PACKET_V4_MOTION;
++
++ if ((packet[0] & 0x0c) == 0x04 &&
++ (packet[3] & 0x1f) == 0x10)
++ return PACKET_V4_STATUS;
++
++ return PACKET_UNKNOWN;
++}
++
+ /*
+ * Process byte stream from mouse and handle complete packets
+ */
+@@ -567,6 +725,14 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+
+ elantech_report_absolute_v3(psmouse, packet_type);
+ break;
++
++ case 4:
++ packet_type = elantech_packet_check_v4(psmouse);
++ if (packet_type == PACKET_UNKNOWN)
++ return PSMOUSE_BAD_DATA;
++
++ elantech_report_absolute_v4(psmouse, packet_type);
++ break;
+ }
+
+ return PSMOUSE_FULL_PACKET;
+@@ -610,6 +776,13 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+ rc = -1;
+
+ break;
++
++ case 4:
++ etd->reg_07 = 0x01;
++ if (elantech_write_reg(psmouse, 0x07, etd->reg_07))
++ rc = -1;
++
++ goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */
+ }
+
+ if (rc == 0) {
+@@ -637,6 +810,7 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+ }
+ }
+
++ skip_readback_reg_10:
+ if (rc)
+ pr_err("failed to initialise registers.\n");
+
+@@ -645,10 +819,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
+
+ static int elantech_set_range(struct psmouse *psmouse,
+ unsigned int *x_min, unsigned int *y_min,
+- unsigned int *x_max, unsigned int *y_max)
++ unsigned int *x_max, unsigned int *y_max,
++ unsigned int *width)
+ {
+ struct elantech_data *etd = psmouse->private;
+ unsigned char param[3];
++ unsigned char traces;
+ int i;
+
+ switch (etd->hw_version) {
+@@ -684,6 +860,19 @@ static int elantech_set_range(struct psmouse *psmouse,
+ *x_max = (0x0f & param[0]) << 8 | param[1];
+ *y_max = (0xf0 & param[0]) << 4 | param[2];
+ break;
++
++ case 4:
++ if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
++ return -1;
++
++ *x_max = (0x0f & param[0]) << 8 | param[1];
++ *y_max = (0xf0 & param[0]) << 4 | param[2];
++ traces = etd->capabilities[1];
++ if ((traces < 2) || (traces > *x_max))
++ return -1;
++
++ *width = *x_max / (traces - 1);
++ break;
+ }
+
+ return 0;
+@@ -696,9 +885,9 @@ static int elantech_set_input_params(struct psmouse *psmouse)
+ {
+ struct input_dev *dev = psmouse->dev;
+ struct elantech_data *etd = psmouse->private;
+- unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0;
++ unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
+
+- if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max))
++ if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
+ return -1;
+
+ __set_bit(EV_KEY, dev->evbit);
+@@ -742,9 +931,37 @@ static int elantech_set_input_params(struct psmouse *psmouse)
+ input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
+ break;
++
++ case 4:
++ __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
++ /* For X to recognize me as touchpad. */
++ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
++ input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
++ /*
++ * range of pressure and width is the same as v2,
++ * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
++ */
++ input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
++ ETP_PMAX_V2, 0, 0);
++ input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
++ ETP_WMAX_V2, 0, 0);
++ /* Multitouch capable pad, up to 5 fingers. */
++ input_mt_init_slots(dev, ETP_MAX_FINGERS);
++ input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
++ input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
++ input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
++ ETP_PMAX_V2, 0, 0);
++ /*
++ * The firmware reports how many trace lines the finger spans,
++ * convert to surface unit as Protocol-B requires.
++ */
++ input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0,
++ ETP_WMAX_V2 * width, 0, 0);
++ break;
+ }
+
+ etd->y_max = y_max;
++ etd->width = width;
+
+ return 0;
+ }
+@@ -816,6 +1033,7 @@ static ssize_t elantech_set_int_attr(struct psmouse *psmouse,
+ elantech_show_int_attr, \
+ elantech_set_int_attr)
+
++ELANTECH_INT_ATTR(reg_07, 0x07);
+ ELANTECH_INT_ATTR(reg_10, 0x10);
+ ELANTECH_INT_ATTR(reg_11, 0x11);
+ ELANTECH_INT_ATTR(reg_20, 0x20);
+@@ -829,6 +1047,7 @@ ELANTECH_INT_ATTR(debug, 0);
+ ELANTECH_INT_ATTR(paritycheck, 0);
+
+ static struct attribute *elantech_attrs[] = {
++ &psmouse_attr_reg_07.dattr.attr,
+ &psmouse_attr_reg_10.dattr.attr,
+ &psmouse_attr_reg_11.dattr.attr,
+ &psmouse_attr_reg_20.dattr.attr,
+@@ -957,12 +1176,16 @@ static int elantech_reconnect(struct psmouse *psmouse)
+ */
+ static int elantech_set_properties(struct elantech_data *etd)
+ {
++ int ver = (etd->fw_version & 0x0f0000) >> 16;
++
+ if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
+ etd->hw_version = 1;
+ else if (etd->fw_version < 0x150600)
+ etd->hw_version = 2;
+- else if ((etd->fw_version & 0x0f0000) >> 16 == 5)
++ else if (ver == 5)
+ etd->hw_version = 3;
++ else if (ver == 6)
++ etd->hw_version = 4;
+ else
+ return -1;
+
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index 236c33c..7ecaef0 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -82,14 +82,37 @@
+ #define ETP_WMAX_V2 15
+
+ /*
+- * v3 hardware has 2 kinds of packet types.
++ * v3 hardware has 2 kinds of packet types,
++ * v4 hardware has 3.
+ */
+ #define PACKET_UNKNOWN 0x01
+ #define PACKET_DEBOUNCE 0x02
+ #define PACKET_V3_HEAD 0x03
+ #define PACKET_V3_TAIL 0x04
++#define PACKET_V4_HEAD 0x05
++#define PACKET_V4_MOTION 0x06
++#define PACKET_V4_STATUS 0x07
++
++/*
++ * track up to 5 fingers for v4 hardware
++ */
++#define ETP_MAX_FINGERS 5
++
++/*
++ * weight value for v4 hardware
++ */
++#define ETP_WEIGHT_VALUE 5
++
++/*
++ * The base position for one finger, v4 hardware
++ */
++struct finger_pos {
++ unsigned int x;
++ unsigned int y;
++};
+
+ struct elantech_data {
++ unsigned char reg_07;
+ unsigned char reg_10;
+ unsigned char reg_11;
+ unsigned char reg_20;
+@@ -108,8 +131,8 @@ struct elantech_data {
+ unsigned int fw_version;
+ unsigned int single_finger_reports;
+ unsigned int y_max;
+- unsigned int prev_x;
+- unsigned int prev_y;
++ unsigned int width;
++ struct finger_pos mt[ETP_MAX_FINGERS];
+ unsigned char parity[256];
+ };
+
+--
+1.7.6.4
+
+
+From 3c09085f371a68f09147abb59b35db928fe3950f Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Tue, 20 Sep 2011 22:42:51 -0700
+Subject: Input: elantech - better support all those v2 variants
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+V2 hardware has many variants. This patch adddresses two issues:
+
+ - some model also has debounce packets, but with a different signature
+ than v3. Now we just check debounce for all v2 hardware.
+
+ - due to different scanning methods the hardware uses, x and y ranges have
+ to be calculated differently. And for some specific versions, we can just
+ see them as custom-made, so set {x, y} the same values as Windows driver
+ does.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Tested-by: Richard Schütz <r.schtz at t-online.de>
+Reviewed-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 46 +++++++++++++++++++++++++++++++++++----
+ drivers/input/mouse/elantech.h | 1 +
+ 2 files changed, 42 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index b8733b3..c2d91eb 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -613,6 +613,18 @@ static int elantech_packet_check_v1(struct psmouse *psmouse)
+ etd->parity[packet[3]] == p3;
+ }
+
++static int elantech_debounce_check_v2(struct psmouse *psmouse)
++{
++ /*
++ * When we encounter packet that matches this exactly, it means the
++ * hardware is in debounce status. Just ignore the whole packet.
++ */
++ const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff };
++ unsigned char *packet = psmouse->packet;
++
++ return !memcmp(packet, debounce_packet, sizeof(debounce_packet));
++}
++
+ static int elantech_packet_check_v2(struct psmouse *psmouse)
+ {
+ struct elantech_data *etd = psmouse->private;
+@@ -708,6 +720,10 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
+ break;
+
+ case 2:
++ /* ignore debounce */
++ if (elantech_debounce_check_v2(psmouse))
++ return PSMOUSE_FULL_PACKET;
++
+ if (etd->paritycheck && !elantech_packet_check_v2(psmouse))
+ return PSMOUSE_BAD_DATA;
+
+@@ -825,7 +841,6 @@ static int elantech_set_range(struct psmouse *psmouse,
+ struct elantech_data *etd = psmouse->private;
+ unsigned char param[3];
+ unsigned char traces;
+- int i;
+
+ switch (etd->hw_version) {
+ case 1:
+@@ -844,12 +859,33 @@ static int elantech_set_range(struct psmouse *psmouse,
+ *x_max = ETP_XMAX_V2;
+ *y_max = ETP_YMAX_V2;
+ } else {
++ int i;
++ int fixed_dpi;
++
+ i = (etd->fw_version > 0x020800 &&
+ etd->fw_version < 0x020900) ? 1 : 2;
+- *x_min = 0;
+- *y_min = 0;
+- *x_max = (etd->capabilities[1] - i) * 64;
+- *y_max = (etd->capabilities[2] - i) * 64;
++
++ if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
++ return -1;
++
++ fixed_dpi = param[1] & 0x10;
++
++ if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) {
++ if (synaptics_send_cmd(psmouse, ETP_SAMPLE_QUERY, param))
++ return -1;
++
++ *x_max = (etd->capabilities[1] - i) * param[1] / 2;
++ *y_max = (etd->capabilities[2] - i) * param[2] / 2;
++ } else if (etd->fw_version == 0x040216) {
++ *x_max = 819;
++ *y_max = 405;
++ } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) {
++ *x_max = 900;
++ *y_max = 500;
++ } else {
++ *x_max = (etd->capabilities[1] - i) * 64;
++ *y_max = (etd->capabilities[2] - i) * 64;
++ }
+ }
+ break;
+
+diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
+index 7ecaef0..9e5f1aa 100644
+--- a/drivers/input/mouse/elantech.h
++++ b/drivers/input/mouse/elantech.h
+@@ -19,6 +19,7 @@
+ #define ETP_FW_ID_QUERY 0x00
+ #define ETP_FW_VERSION_QUERY 0x01
+ #define ETP_CAPABILITIES_QUERY 0x02
++#define ETP_SAMPLE_QUERY 0x03
+
+ /*
+ * Command values for register reading or writing
+--
+1.7.6.4
+
+
+From 6c0ec284648f0346e96b0079999cb7af055f58ab Mon Sep 17 00:00:00 2001
+From: JJ Ding <jj_ding at emc.com.tw>
+Date: Tue, 20 Sep 2011 22:42:51 -0700
+Subject: Input: elantech - remove module parameter force_elantech
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This essentially reverts commit f81bc788ff91d4efd4baf88b2c29713838caa8e5.
+
+With recent work on elantech driver, I believe we now have complete support
+for all elantech touchpads. So remove this hack.
+
+Signed-off-by: JJ Ding <jj_ding at emc.com.tw>
+Reviewed-by: Éric Piel <eric.piel at tremplin-utc.net>
+Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
+---
+ drivers/input/mouse/elantech.c | 12 ++----------
+ 1 files changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
+index c2d91eb..25290b3 100644
+--- a/drivers/input/mouse/elantech.c
++++ b/drivers/input/mouse/elantech.c
+@@ -28,10 +28,6 @@
+ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
+ } while (0)
+
+-static bool force_elantech;
+-module_param_named(force_elantech, force_elantech, bool, 0644);
+-MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default).");
+-
+ /*
+ * Send a Synaptics style sliced query command
+ */
+@@ -1164,12 +1160,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
+ param[0], param[1], param[2]);
+
+ if (!elantech_is_signature_valid(param)) {
+- if (!force_elantech) {
+- pr_debug("Probably not a real Elantech touchpad. Aborting.\n");
+- return -1;
+- }
+-
+- pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
++ pr_debug("Probably not a real Elantech touchpad. Aborting.\n");
++ return -1;
+ }
+
+ if (set_properties) {
+--
+1.7.6.4
+
diff --git a/kernel.spec b/kernel.spec
index 1893ab5..e8e2ca5 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -51,7 +51,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be prepended with "0.", so
# for example a 3 here will become 0.3
#
-%global baserelease 8
+%global baserelease 9
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@@ -768,6 +768,9 @@ Patch21070: oom-fix-integer-overflow-of-points.patch
#rhbz 706574
Patch21071: WMI-properly-cleanup-devices-to-avoid-crashes.patch
+#rhbz 728607
+Patch21060: elantech.patch
+
%endif
BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@@ -1416,6 +1419,9 @@ ApplyPatch oom-fix-integer-overflow-of-points.patch
#rhbz 706574
ApplyPatch WMI-properly-cleanup-devices-to-avoid-crashes.patch
+#rhbz 728607
+ApplyPatch elantech.patch
+
# END OF PATCH APPLICATIONS
%endif
@@ -2117,6 +2123,9 @@ fi
# and build.
%changelog
+* Thu Nov 03 2011 Josh Boyer <jwboyer at redhat.com>
+- Add commits queued for 3.2 for elantech driver (rhbz 728607)
+
* Wed Nov 02 2011 Josh Boyer <jwboyer at redhat.com>
- Add patch to fix oops when removing wmi module (rhbz 706574)
More information about the scm-commits
mailing list