On some laptops after starting them from off state (not after reboot), function
alps_probe_trackstick_v3() (called from function alps_identify()) does not
detect trackstick. To fix this problem we need to reset device. But function
alps_identify() is called also from alps_detect() and we do not want to reset
device in detect function because it will slow down initialization of all other
non alps devices.

Current alps device init sequence is:
alps_detect() --> alps_identify() (trackstick not detected)
alps_init() --> psmouse_reset() --> alps_identify() (trackstick detected)

This patch moves initialization code between driver functions so we can remove
alps_identify() call from alps_detect(). Which means that trackstick function
alps_probe_trackstick_v3() will be called only from alps_init() and only after
device reset so it will always return correct information about trackstick
presence. Code for identifying protocol version is moved to alps_init() and
because psmouse-base.c calling alps_detect() and alps_init() consecutively then
detection of both alps and also other non alps devices will not be broken.

First this patch moves code between functions:

 * Move calling function alps_probe_trackstick_v3() (for rushmore devices) from
   alps_identify() to alps_hw_init_rushmore_v3()

 * Move code for checking "E6 report" from alps_identify() to alps_detect()

 * Move code for setting correct device name string and model/protocol version
   from alps_detect() to alps_init(). To not break psmouse-base.c in function
   alps_detect() set only generic name "DualPoint TouchPad".

Next it removes alps_identify() from alps_detect() because it is not needed
anymore (code which use it was moved to alps_init()).

And last this patch fix another code for trackstick detection of protocol V3
devices. In function alps_hw_init_v3() is removed ALPS_DUALPOINT flag from
device if alps_setup_trackstick_v3() or alps_setup_trackstick_v3() returns
-ENODEV (which means trackstick is not present).

Now trackstick detection should work and in function alps_init() is set
correct name and other properties for both input devices.

Side effect of this patch is also faster alps devices initialization because
function alps_identify() is called only once (from alps_init()).

Signed-off-by: Pali Rohár <pali.ro...@gmail.com>
Tested-by: Pali Rohár <pali.ro...@gmail.com>
Cc: sta...@vger.kernel.org
---
 drivers/input/mouse/alps.c |   96 +++++++++++++++++++++++++++++---------------
 1 file changed, 64 insertions(+), 32 deletions(-)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index e802d28..04161b6 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1732,6 +1732,7 @@ error:
 
 static int alps_hw_init_v3(struct psmouse *psmouse)
 {
+       struct alps_data *priv = psmouse->private;
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        int reg_val;
        unsigned char param[4];
@@ -1740,9 +1741,15 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
        if (reg_val == -EIO)
                goto error;
 
-       if (reg_val == 0 &&
-           alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
-               goto error;
+       if (reg_val == 0) {
+               reg_val = alps_setup_trackstick_v3(psmouse,
+                                                  ALPS_REG_BASE_PINNACLE);
+               if (reg_val == -EIO)
+                       goto error;
+       }
+
+       if (reg_val == -ENODEV)
+               priv->flags &= ~ALPS_DUALPOINT;
 
        if (alps_enter_command_mode(psmouse) ||
            alps_absolute_mode_v3(psmouse)) {
@@ -1849,15 +1856,20 @@ static int alps_hw_init_rushmore_v3(struct psmouse 
*psmouse)
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        int reg_val, ret = -1;
 
-       if (priv->flags & ALPS_DUALPOINT) {
+       reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE);
+       if (reg_val == -EIO)
+               goto error;
+
+       if (reg_val == 0) {
                reg_val = alps_setup_trackstick_v3(psmouse,
                                                   ALPS_REG_BASE_RUSHMORE);
                if (reg_val == -EIO)
                        goto error;
-               if (reg_val == -ENODEV)
-                       priv->flags &= ~ALPS_DUALPOINT;
        }
 
+       if (reg_val == -ENODEV)
+               priv->flags &= ~ALPS_DUALPOINT;
+
        if (alps_enter_command_mode(psmouse) ||
            alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
            alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
@@ -2176,20 +2188,15 @@ static int alps_match_table(struct psmouse *psmouse, 
struct alps_data *priv,
 
 static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 {
-       unsigned char e6[4], e7[4], ec[4];
+       unsigned char e7[4], ec[4];
+       int ret;
 
        /*
         * First try "E6 report".
-        * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
-        * The bits 0-2 of the first byte will be 1s if some buttons are
-        * pressed.
         */
-       if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
-                        PSMOUSE_CMD_SETSCALE11, e6))
-               return -EIO;
-
-       if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
-               return -EINVAL;
+       ret = alps_detect(psmouse, false);
+       if (ret < 0)
+               return ret;
 
        /*
         * Now get the "E7" and "EC" reports.  These will uniquely identify
@@ -2231,12 +2238,6 @@ static int alps_identify(struct psmouse *psmouse, struct 
alps_data *priv)
                priv->y_bits = 12;
                priv->flags |= ALPS_IS_RUSHMORE;
 
-               /* hack to make addr_command, nibble_command available */
-               psmouse->private = priv;
-
-               if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
-                       priv->flags &= ~ALPS_DUALPOINT;
-
                return 0;
        } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
                   ec[2] >= 0x90 && ec[2] <= 0x9d) {
@@ -2370,14 +2371,24 @@ int alps_init(struct psmouse *psmouse)
                dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
        }
 
+       if (priv->flags & ALPS_DUALPOINT) {
+               /*
+                * format of device name is: "protocol vendor name"
+                * see function psmouse_switch_protocol() in psmouse-base.c
+                */
+               dev2->name = "AlpsPS/2 ALPS DualPoint Stick";
+               dev2->id.product = PSMOUSE_ALPS;
+               dev2->id.version = priv->proto_version;
+       } else {
+               dev2->name = "PS/2 ALPS Mouse";
+               dev2->id.product = PSMOUSE_PS2;
+               dev2->id.version = 0x0000;
+       }
+
        snprintf(priv->phys, sizeof(priv->phys), "%s/input1", 
psmouse->ps2dev.serio->phys);
        dev2->phys = priv->phys;
-       dev2->name = (priv->flags & ALPS_DUALPOINT) ?
-                    "DualPoint Stick" : "ALPS PS/2 Device";
        dev2->id.bustype = BUS_I8042;
        dev2->id.vendor  = 0x0002;
-       dev2->id.product = PSMOUSE_ALPS;
-       dev2->id.version = 0x0000;
        dev2->dev.parent = &psmouse->ps2dev.serio->dev;
 
        dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
@@ -2392,6 +2403,10 @@ int alps_init(struct psmouse *psmouse)
        if (input_register_device(priv->dev2))
                goto init_fail;
 
+       if (!(priv->flags & ALPS_DUALPOINT))
+               psmouse->name = "GlidePoint TouchPad";
+       psmouse->model = priv->proto_version;
+
        psmouse->protocol_handler = alps_process_byte;
        psmouse->poll = alps_poll;
        psmouse->disconnect = alps_disconnect;
@@ -2416,17 +2431,34 @@ init_fail:
 
 int alps_detect(struct psmouse *psmouse, bool set_properties)
 {
-       struct alps_data dummy;
+       unsigned char e6[4];
 
-       if (alps_identify(psmouse, &dummy) < 0)
-               return -1;
+       /*
+        * Try "E6 report".
+        * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+        * The bits 0-2 of the first byte will be 1s if some buttons are
+        * pressed.
+        */
+       if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
+                        PSMOUSE_CMD_SETSCALE11, e6))
+               return -EIO;
+
+       if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
+               return -EINVAL;
 
        if (set_properties) {
+               /*
+                * NOTE: To detect model and trackstick presence we need to do
+                *       full device reset. To speed up detection and prevent
+                *       calling duplicate initialization sequence (both in
+                *       alps_detect() and alps_init()) we set model/protocol
+                *       version and correct name in alps_init() (which will
+                *       do full device reset). For now set name to DualPoint.
+                */
                psmouse->vendor = "ALPS";
-               psmouse->name = dummy.flags & ALPS_DUALPOINT ?
-                               "DualPoint TouchPad" : "GlidePoint";
-               psmouse->model = dummy.proto_version << 8;
+               psmouse->name = "DualPoint TouchPad";
        }
+
        return 0;
 }
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to