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: sta...@vger.kernel.org  # 5.3+
Signed-off-by: Benjamin Tissoires <benjamin.tissoi...@redhat.com>
---
 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

Reply via email to