aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/alps.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-01-13 23:46:09 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-15 18:44:18 -0500
commita09221e83e13e09a33109b9b037484eade901cea (patch)
tree1d1537f13303b394dbd14f4cd1e4ea7972b7934a /drivers/input/mouse/alps.c
parent3296f71cd2fde7a2ad52e66a27eae419f6328066 (diff)
Input: ALPS - fix trackstick detection on some Dell Latitudes
On some Dell Latitudes we fail to identify presence of trackstick unless we reset the device. The issue is quite benign as we do perform reset in alps_init(), so the trackstick ends up working, but mouse name reported to userspace is not accurate. In order to fix the issue while avoiding the additional lengthy reset we move the resrt to alps_detect() and keep the discovered state to be used later in alps_init(). Reported-by: Pali Rohár <pali.rohar@gmail.com> Tested-by: Pali Rohár <pali.rohar@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mouse/alps.c')
-rw-r--r--drivers/input/mouse/alps.c78
1 files changed, 56 insertions, 22 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index b97832b622cb..d164690bfdf7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1796,7 +1796,7 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
1796 * all. 1796 * all.
1797 */ 1797 */
1798 if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) { 1798 if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
1799 psmouse_warn(psmouse, "trackstick E7 report failed\n"); 1799 psmouse_warn(psmouse, "Failed to initialize trackstick (E7 report failed)\n");
1800 ret = -ENODEV; 1800 ret = -ENODEV;
1801 } else { 1801 } else {
1802 psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param); 1802 psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param);
@@ -1961,8 +1961,6 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
1961 ALPS_REG_BASE_RUSHMORE); 1961 ALPS_REG_BASE_RUSHMORE);
1962 if (reg_val == -EIO) 1962 if (reg_val == -EIO)
1963 goto error; 1963 goto error;
1964 if (reg_val == -ENODEV)
1965 priv->flags &= ~ALPS_DUALPOINT;
1966 } 1964 }
1967 1965
1968 if (alps_enter_command_mode(psmouse) || 1966 if (alps_enter_command_mode(psmouse) ||
@@ -2305,6 +2303,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
2305{ 2303{
2306 const struct alps_protocol_info *protocol; 2304 const struct alps_protocol_info *protocol;
2307 unsigned char e6[4], e7[4], ec[4]; 2305 unsigned char e6[4], e7[4], ec[4];
2306 int error;
2308 2307
2309 /* 2308 /*
2310 * First try "E6 report". 2309 * First try "E6 report".
@@ -2350,10 +2349,15 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
2350 } 2349 }
2351 } 2350 }
2352 2351
2353 /* Save the Firmware version */ 2352 if (priv) {
2354 memcpy(priv->fw_ver, ec, 3); 2353 /* Save the Firmware version */
2354 memcpy(priv->fw_ver, ec, 3);
2355 error = alps_set_protocol(psmouse, priv, protocol);
2356 if (error)
2357 return error;
2358 }
2355 2359
2356 return alps_set_protocol(psmouse, priv, protocol); 2360 return 0;
2357} 2361}
2358 2362
2359static int alps_reconnect(struct psmouse *psmouse) 2363static int alps_reconnect(struct psmouse *psmouse)
@@ -2407,22 +2411,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
2407 2411
2408int alps_init(struct psmouse *psmouse) 2412int alps_init(struct psmouse *psmouse)
2409{ 2413{
2410 struct alps_data *priv; 2414 struct alps_data *priv = psmouse->private;
2411 struct input_dev *dev1 = psmouse->dev, *dev2; 2415 struct input_dev *dev1 = psmouse->dev, *dev2;
2416 int error;
2412 2417
2413 priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
2414 dev2 = input_allocate_device(); 2418 dev2 = input_allocate_device();
2415 if (!priv || !dev2) 2419 if (!dev2) {
2420 error = -ENOMEM;
2416 goto init_fail; 2421 goto init_fail;
2422 }
2417 2423
2418 priv->dev2 = dev2; 2424 priv->dev2 = dev2;
2419 2425
2420 psmouse_reset(psmouse); 2426 error = priv->hw_init(psmouse);
2421 2427 if (error)
2422 if (alps_identify(psmouse, priv) < 0)
2423 goto init_fail;
2424
2425 if (priv->hw_init(psmouse))
2426 goto init_fail; 2428 goto init_fail;
2427 2429
2428 /* 2430 /*
@@ -2520,24 +2522,56 @@ int alps_init(struct psmouse *psmouse)
2520init_fail: 2522init_fail:
2521 psmouse_reset(psmouse); 2523 psmouse_reset(psmouse);
2522 input_free_device(dev2); 2524 input_free_device(dev2);
2523 kfree(priv); 2525 /*
2526 * Even though we did not allocate psmouse->private we do free
2527 * it here.
2528 */
2529 kfree(psmouse->private);
2524 psmouse->private = NULL; 2530 psmouse->private = NULL;
2525 return -1; 2531 return error;
2526} 2532}
2527 2533
2528int alps_detect(struct psmouse *psmouse, bool set_properties) 2534int alps_detect(struct psmouse *psmouse, bool set_properties)
2529{ 2535{
2530 struct alps_data dummy; 2536 struct alps_data *priv;
2537 int error;
2531 2538
2532 if (alps_identify(psmouse, &dummy) < 0) 2539 error = alps_identify(psmouse, NULL);
2533 return -1; 2540 if (error)
2541 return error;
2542
2543 /*
2544 * Reset the device to make sure it is fully operational:
2545 * on some laptops, like certain Dell Latitudes, we may
2546 * fail to properly detect presence of trackstick if device
2547 * has not been reset.
2548 */
2549 psmouse_reset(psmouse);
2550
2551 priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
2552 if (!priv)
2553 return -ENOMEM;
2554
2555 error = alps_identify(psmouse, priv);
2556 if (error)
2557 return error;
2534 2558
2535 if (set_properties) { 2559 if (set_properties) {
2536 psmouse->vendor = "ALPS"; 2560 psmouse->vendor = "ALPS";
2537 psmouse->name = dummy.flags & ALPS_DUALPOINT ? 2561 psmouse->name = priv->flags & ALPS_DUALPOINT ?
2538 "DualPoint TouchPad" : "GlidePoint"; 2562 "DualPoint TouchPad" : "GlidePoint";
2539 psmouse->model = dummy.proto_version; 2563 psmouse->model = priv->proto_version;
2564 } else {
2565 /*
2566 * Destroy alps_data structure we allocated earlier since
2567 * this was just a "trial run". Otherwise we'll keep it
2568 * to be used by alps_init() which has to be called if
2569 * we succeed and set_properties is true.
2570 */
2571 kfree(priv);
2572 psmouse->private = NULL;
2540 } 2573 }
2574
2541 return 0; 2575 return 0;
2542} 2576}
2543 2577