summaryrefslogtreecommitdiff
path: root/drivers/input/mouse/elantech.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse/elantech.c')
-rw-r--r--drivers/input/mouse/elantech.c85
1 files changed, 57 insertions, 28 deletions
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index b27684f267bf..0520c2e19927 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -11,6 +11,7 @@
*/
#include <linux/delay.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/serio.h>
@@ -24,6 +25,10 @@
printk(KERN_DEBUG format, ##arg); \
} 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
*/
@@ -181,13 +186,17 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
static int old_fingers;
if (etd->fw_version_maj == 0x01) {
- /* byte 0: D U p1 p2 1 p3 R L
- byte 1: f 0 th tw x9 x8 y9 y8 */
+ /*
+ * byte 0: D U p1 p2 1 p3 R L
+ * byte 1: f 0 th tw x9 x8 y9 y8
+ */
fingers = ((packet[1] & 0x80) >> 7) +
((packet[1] & 0x30) >> 4);
} else {
- /* byte 0: n1 n0 p2 p1 1 p3 R L
- byte 1: 0 0 0 0 x9 x8 y9 y8 */
+ /*
+ * byte 0: n1 n0 p2 p1 1 p3 R L
+ * byte 1: 0 0 0 0 x9 x8 y9 y8
+ */
fingers = (packet[0] & 0xc0) >> 6;
}
@@ -201,13 +210,15 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_report_key(dev, BTN_TOUCH, fingers != 0);
- /* byte 2: x7 x6 x5 x4 x3 x2 x1 x0
- byte 3: y7 y6 y5 y4 y3 y2 y1 y0 */
+ /*
+ * byte 2: x7 x6 x5 x4 x3 x2 x1 x0
+ * byte 3: y7 y6 y5 y4 y3 y2 y1 y0
+ */
if (fingers) {
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]));
+ input_report_abs(dev, ABS_Y,
+ ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3]));
}
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
@@ -246,34 +257,47 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
switch (fingers) {
case 1:
- /* byte 1: x15 x14 x13 x12 x11 x10 x9 x8
- byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */
- input_report_abs(dev, ABS_X, (packet[1] << 8) | packet[2]);
- /* byte 4: y15 y14 y13 y12 y11 y10 y8 y8
- byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */
- input_report_abs(dev, ABS_Y, ETP_YMAX_V2 -
- ((packet[4] << 8) | packet[5]));
+ /*
+ * byte 1: . . . . . x10 x9 x8
+ * byte 2: x7 x6 x5 x4 x4 x2 x1 x0
+ */
+ input_report_abs(dev, ABS_X,
+ ((packet[1] & 0x07) << 8) | packet[2]);
+ /*
+ * byte 4: . . . . . . y9 y8
+ * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
+ */
+ input_report_abs(dev, ABS_Y,
+ ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
break;
case 2:
- /* The coordinate of each finger is reported separately with
- a lower resolution for two finger touches */
- /* byte 0: . . ay8 ax8 . . . .
- byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */
+ /*
+ * The coordinate of each finger is reported separately
+ * with a lower resolution for two finger touches:
+ * byte 0: . . ay8 ax8 . . . .
+ * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
+ */
x1 = ((packet[0] & 0x10) << 4) | packet[1];
/* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]);
- /* byte 3: . . by8 bx8 . . . .
- byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */
+ /*
+ * byte 3: . . by8 bx8 . . . .
+ * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
+ */
x2 = ((packet[3] & 0x10) << 4) | packet[4];
/* 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 */
+ /*
+ * 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);
- /* For compatibility with the proprietary X Elantech driver
- report both coordinates as hat coordinates */
+ /*
+ * For compatibility with the proprietary X Elantech driver
+ * report both coordinates as hat coordinates
+ */
input_report_abs(dev, ABS_HAT0X, x1);
input_report_abs(dev, ABS_HAT0Y, y1);
input_report_abs(dev, ABS_HAT1X, x2);
@@ -595,8 +619,12 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
param[0], param[1], param[2]);
if (param[0] == 0 || param[1] != 0) {
- pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
- return -1;
+ if (!force_elantech) {
+ pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
+ return -1;
+ }
+
+ pr_debug("elantech.c: Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
}
if (set_properties) {
@@ -665,7 +693,8 @@ int elantech_init(struct psmouse *psmouse)
* Assume every version greater than this is new EeePC style
* hardware with 6 byte packets
*/
- if (etd->fw_version_maj >= 0x02 && etd->fw_version_min >= 0x30) {
+ if ((etd->fw_version_maj == 0x02 && etd->fw_version_min >= 0x30) ||
+ etd->fw_version_maj > 0x02) {
etd->hw_version = 2;
/* For now show extra debug information */
etd->debug = 1;