2117 lines
64 KiB
Diff
2117 lines
64 KiB
Diff
|
From 13ac768d9a8731c8b3bab7d6c86520f290272fe7 Mon Sep 17 00:00:00 2001
|
||
|
From: JJ Ding <jj_ding@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@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@gmail.com>
|
||
|
Signed-off-by: JJ Ding <jj_ding@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@tremplin-utc.net>
|
||
|
Signed-off-by: JJ Ding <jj_ding@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Acked-by: Daniel Kurtz <djkurtz@chromium.org>
|
||
|
Acked-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Tested-by: Richard Schütz <r.schtz@t-online.de>
|
||
|
Reviewed-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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@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@emc.com.tw>
|
||
|
Reviewed-by: Éric Piel <eric.piel@tremplin-utc.net>
|
||
|
Signed-off-by: Dmitry Torokhov <dtor@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
|
||
|
|