diff mbox

[01/01] drivers:input:byd fix greedy detection of Sentelic FSP by the BYD touchpad driver

Message ID 20160925033119.rvptljq3zs4hkmmf@sherka.pkbd.org
State New, archived
Headers show

Commit Message

Christophe TORDEUX Sept. 25, 2016, 3:31 a.m. UTC
From: Christophe TORDEUX <christophe@tordeux.net>

With kernel v4.6 and later, the Sentelic touchpad STL3888_C0 and
probably other Sentelic FSP touchpads are detected as a BYD touchpad and
lose multitouch features.

During the BYD handshake in the byd_detect function, the BYD driver
mistakenly interprets a standard PS/2 protocol status request answer
from the Sentelic touchpad as a successful handshake with a BYD
touchpad. This is clearly a bug of the BYD driver.

Description of the patch: In byd_detect function, remove positive
detection result based on standard PS/2 protocol status request answer.
Replace it with positive detection based on handshake answers as they
can be inferred from the BYD touchpad datasheets found on BYD website.

Signed-off-by: Christophe TORDEUX <christophe@tordeux.net>

---
Comments/discussion:
A Sentelic touchpad STL3888_C0 is available to the author of this patch.

No BYD touchpad device is available to the author of this patch for
testing purpose. The BYD website contains 5 data sheets documents for 5
touchpads. Unfortunately the handshake procedure description from the
BYD datasheets is either not fully consistent or not fully detailed.

This means that while the author is positive the bug of Sentelic greedy
detection is fixed by this patch, the effect on detection of BYD
touchpads is not tested on actual hardware. But, because this patch
codes the detection according to expected handshake answers based on BYD
datasheets, the approach taken by this patch is probably the best in the
author's opinion.
Nevertheless alternatives can be considered.

Alternative 1: move the detection of Sentelic touchpads above the
detection of BYD touchpads in psmouse_try_protocol function. However
based on the code comments, this could have adverse effects which I
don't really know about.

Alternative2: Sentelic STL3888_C0 answers E9 status request with a
standard PS/2 protocol answer, however I found out my Sentelic
STL3888_C0 answers E8/00/E8/00/E8/00/E8/00/E9 with 00/88/64, which looks
like a handshake answer. This could be used as a test to exit the
byd_detect function. Still effect on detection of a BYD device is not
known.

---
 drivers/input/mouse/byd.c | 76 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 62 insertions(+), 14 deletions(-)
diff mbox

Patch

diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index b27aa63..b5acca0 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -35,6 +35,18 @@ 
  * BYD pad constants
  */
 
+/* Handshake answer of BTP6034 */
+#define BYD_MODEL_BTP6034	0x00E801
+/* Handshake answer of BTP6740 */
+#define BYD_MODEL_BTP6740	0x001155
+/* Handshake answers of BTP8644, BTP10463 and BTP11484 */
+#define BYD_MODEL_BTP8644	0x011155
+
+/* Handshake SETRES byte of BTP6034 and BTP6740 */
+#define BYD_SHAKE_BYTE_A	0x00
+/* Handshake SETRES byte of BTP8644, BTP10463 and BTP11484 */
+#define BYD_SHAKE_BYTE_B	0x03
+
 /*
  * True device resolution is unknown, however experiments show the
  * resolution is about 111 units/mm.
@@ -434,23 +446,59 @@  static void byd_disconnect(struct psmouse *psmouse)
 	}
 }
 
+u32 byd_try_model(u32 model)
+{
+	size_t i;
+
+	u32 byd_model[] = {
+		BYD_MODEL_BTP6034,
+		BYD_MODEL_BTP6740,
+		BYD_MODEL_BTP8644
+	};
+
+	for (i=0; i < ARRAY_SIZE(byd_model); i++) {
+		if (model ==  byd_model[i])
+			return model;
+	}
+
+	return 0;
+}
+
 int byd_detect(struct psmouse *psmouse, bool set_properties)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	u8 param[4] = {0x03, 0x00, 0x00, 0x00};
-
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-		return -1;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-		return -1;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-		return -1;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
-		return -1;
-	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
-		return -1;
-
-	if (param[1] != 0x03 || param[2] != 0x64)
+	size_t i;
+
+	u8 byd_shbyte[] = {
+		BYD_SHAKE_BYTE_A,
+		BYD_SHAKE_BYTE_B
+	};
+
+	bool detect = false;
+	for (i=0; i < ARRAY_SIZE(byd_shbyte); i++) {
+		u32 model;
+		u8 param[4] = {byd_shbyte[i], 0x00, 0x00, 0x00};
+
+		if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+			return -1;
+		if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+			return -1;
+		if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+			return -1;
+		if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+			return -1;
+		if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+			return -1;
+
+		model = param[2];
+		model += param[1] << 8;
+		model += param[0] << 16;
+		model = byd_try_model(model);
+		if (model)
+			detect = true;
+	}
+
+	if (!detect)
 		return -ENODEV;
 
 	psmouse_dbg(psmouse, "BYD touchpad detected\n");