[PATCH] input - elantech: force query XY range after absolute mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



For some v3 hw versions, if the ETP_FW_ID_QUERY command is
issued before the call to set_absolute_mode(), the returned
values are wrong.

Force an other ETP_FW_ID_QUERY after set_absolute_mode()
to get correct values.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=209027
Cc: stable@xxxxxxxxxxxxxxx  # 5.3+
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx>
---
 drivers/input/mouse/elantech.c | 161 +++++++++++++++++++--------------
 1 file changed, 91 insertions(+), 70 deletions(-)

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 90f8765f9efc..ff8e5fb61dab 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1593,80 +1593,12 @@ static int elantech_set_properties(struct elantech_device_info *info)
 	return 0;
 }
 
-static int elantech_query_info(struct psmouse *psmouse,
-			       struct elantech_device_info *info)
+static int elantech_get_range(struct psmouse *psmouse,
+			      struct elantech_device_info *info)
 {
 	unsigned char param[3];
 	unsigned char traces;
 
-	memset(info, 0, sizeof(*info));
-
-	/*
-	 * Do the version query again so we can store the result
-	 */
-	if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
-		psmouse_err(psmouse, "failed to query firmware version.\n");
-		return -EINVAL;
-	}
-	info->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
-
-	if (elantech_set_properties(info)) {
-		psmouse_err(psmouse, "unknown hardware version, aborting...\n");
-		return -EINVAL;
-	}
-	psmouse_info(psmouse,
-		     "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n",
-		     info->hw_version, param[0], param[1], param[2]);
-
-	if (info->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
-	    info->capabilities)) {
-		psmouse_err(psmouse, "failed to query capabilities.\n");
-		return -EINVAL;
-	}
-	psmouse_info(psmouse,
-		     "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
-		     info->capabilities[0], info->capabilities[1],
-		     info->capabilities[2]);
-
-	if (info->hw_version != 1) {
-		if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, info->samples)) {
-			psmouse_err(psmouse, "failed to query sample data\n");
-			return -EINVAL;
-		}
-		psmouse_info(psmouse,
-			     "Elan sample query result %02x, %02x, %02x\n",
-			     info->samples[0],
-			     info->samples[1],
-			     info->samples[2]);
-	}
-
-	if (info->samples[1] == 0x74 && info->hw_version == 0x03) {
-		/*
-		 * This module has a bug which makes absolute mode
-		 * unusable, so let's abort so we'll be using standard
-		 * PS/2 protocol.
-		 */
-		psmouse_info(psmouse,
-			     "absolute mode broken, forcing standard PS/2 protocol\n");
-		return -ENODEV;
-	}
-
-	/* The MSB indicates the presence of the trackpoint */
-	info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
-
-	info->x_res = 31;
-	info->y_res = 31;
-	if (info->hw_version == 4) {
-		if (elantech_get_resolution_v4(psmouse,
-					       &info->x_res,
-					       &info->y_res,
-					       &info->bus)) {
-			psmouse_warn(psmouse,
-				     "failed to query resolution data.\n");
-		}
-	}
-
-	/* query range information */
 	switch (info->hw_version) {
 	case 1:
 		info->x_min = ETP_XMIN_V1;
@@ -1745,6 +1677,87 @@ static int elantech_query_info(struct psmouse *psmouse,
 		break;
 	}
 
+	return 0;
+}
+
+static int elantech_query_info(struct psmouse *psmouse,
+			       struct elantech_device_info *info)
+{
+	unsigned char param[3];
+	int error;
+
+	memset(info, 0, sizeof(*info));
+
+	/*
+	 * Do the version query again so we can store the result
+	 */
+	if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
+		psmouse_err(psmouse, "failed to query firmware version.\n");
+		return -EINVAL;
+	}
+	info->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
+
+	if (elantech_set_properties(info)) {
+		psmouse_err(psmouse, "unknown hardware version, aborting...\n");
+		return -EINVAL;
+	}
+	psmouse_info(psmouse,
+		     "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n",
+		     info->hw_version, param[0], param[1], param[2]);
+
+	if (info->send_cmd(psmouse, ETP_CAPABILITIES_QUERY,
+	    info->capabilities)) {
+		psmouse_err(psmouse, "failed to query capabilities.\n");
+		return -EINVAL;
+	}
+	psmouse_info(psmouse,
+		     "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n",
+		     info->capabilities[0], info->capabilities[1],
+		     info->capabilities[2]);
+
+	if (info->hw_version != 1) {
+		if (info->send_cmd(psmouse, ETP_SAMPLE_QUERY, info->samples)) {
+			psmouse_err(psmouse, "failed to query sample data\n");
+			return -EINVAL;
+		}
+		psmouse_info(psmouse,
+			     "Elan sample query result %02x, %02x, %02x\n",
+			     info->samples[0],
+			     info->samples[1],
+			     info->samples[2]);
+	}
+
+	if (info->samples[1] == 0x74 && info->hw_version == 0x03) {
+		/*
+		 * This module has a bug which makes absolute mode
+		 * unusable, so let's abort so we'll be using standard
+		 * PS/2 protocol.
+		 */
+		psmouse_info(psmouse,
+			     "absolute mode broken, forcing standard PS/2 protocol\n");
+		return -ENODEV;
+	}
+
+	/* The MSB indicates the presence of the trackpoint */
+	info->has_trackpoint = (info->capabilities[0] & 0x80) == 0x80;
+
+	info->x_res = 31;
+	info->y_res = 31;
+	if (info->hw_version == 4) {
+		if (elantech_get_resolution_v4(psmouse,
+					       &info->x_res,
+					       &info->y_res,
+					       &info->bus)) {
+			psmouse_warn(psmouse,
+				     "failed to query resolution data.\n");
+		}
+	}
+
+	/* query range information */
+	error = elantech_get_range(psmouse, info);
+	if (error)
+		return error;
+
 	/* check for the middle button: DMI matching or new v4 firmwares */
 	info->has_middle_button = dmi_check_system(elantech_dmi_has_middle_button) ||
 				  (ETP_NEW_IC_SMBUS_HOST_NOTIFY(info->fw_version) &&
@@ -1942,6 +1955,14 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
 		goto init_fail;
 	}
 
+	/*
+	 * some hardware v3 send wrong min max coordinates if the
+	 * call to get those is made before elantech_set_absolute_mode().
+	 */
+	error = elantech_get_range(psmouse, &etd->info);
+	if (error)
+		goto init_fail;
+
 	if (info->fw_version == 0x381f17) {
 		etd->original_set_rate = psmouse->set_rate;
 		psmouse->set_rate = elantech_set_rate_restore_reg_07;
-- 
2.26.2




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux