aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2015-03-09 01:35:41 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-03-09 02:36:53 -0400
commitcdd9dc195916ef5644cfac079094c3c1d1616e4c (patch)
treeee98e276936443506a99af70e19af1fee6d594cd
parent3adde1f59195df2965f632e22b31f97fb371612f (diff)
Input: synaptics - re-route tracksticks buttons on the Lenovo 2015 series
The 2015 series of the Lenovo thinkpads added back the hardware buttons on top of the touchpad for the trackstick. Unfortunately, they are wired to the touchpad, and not the trackstick. Thus, they are seen as extra buttons from the kernel point of view. This leads to a problem in user space because extra buttons on synaptics devices used to be used as scroll up/down buttons. So in the end, the experience for the user is scroll events for buttons left and right when using the trackstick. Yay! Fortunately, the firmware advertises such behavior in the extended capability $10, and so we can re-route the buttons through the pass-through interface. Hallelujah-expressed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/mouse/synaptics.c47
-rw-r--r--drivers/input/mouse/synaptics.h5
2 files changed, 41 insertions, 11 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 9d599eb79f17..ecc7811cbd46 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -579,18 +579,22 @@ static int synaptics_is_pt_packet(unsigned char *buf)
579 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; 579 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
580} 580}
581 581
582static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet) 582static void synaptics_pass_pt_packet(struct psmouse *psmouse,
583 struct serio *ptport,
584 unsigned char *packet)
583{ 585{
586 struct synaptics_data *priv = psmouse->private;
584 struct psmouse *child = serio_get_drvdata(ptport); 587 struct psmouse *child = serio_get_drvdata(ptport);
585 588
586 if (child && child->state == PSMOUSE_ACTIVATED) { 589 if (child && child->state == PSMOUSE_ACTIVATED) {
587 serio_interrupt(ptport, packet[1], 0); 590 serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
588 serio_interrupt(ptport, packet[4], 0); 591 serio_interrupt(ptport, packet[4], 0);
589 serio_interrupt(ptport, packet[5], 0); 592 serio_interrupt(ptport, packet[5], 0);
590 if (child->pktsize == 4) 593 if (child->pktsize == 4)
591 serio_interrupt(ptport, packet[2], 0); 594 serio_interrupt(ptport, packet[2], 0);
592 } else 595 } else {
593 serio_interrupt(ptport, packet[1], 0); 596 serio_interrupt(ptport, packet[1], 0);
597 }
594} 598}
595 599
596static void synaptics_pt_activate(struct psmouse *psmouse) 600static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -847,6 +851,7 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
847 struct input_dev *dev = psmouse->dev; 851 struct input_dev *dev = psmouse->dev;
848 struct synaptics_data *priv = psmouse->private; 852 struct synaptics_data *priv = psmouse->private;
849 int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; 853 int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
854 char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
850 int i; 855 int i;
851 856
852 if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) 857 if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
@@ -857,12 +862,30 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
857 !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02)) 862 !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
858 return; 863 return;
859 864
860 for (i = 0; i < ext_bits; i++) { 865 if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) {
861 input_report_key(dev, BTN_0 + 2 * i, 866 for (i = 0; i < ext_bits; i++) {
862 hw->ext_buttons & (1 << i)); 867 input_report_key(dev, BTN_0 + 2 * i,
863 input_report_key(dev, BTN_1 + 2 * i, 868 hw->ext_buttons & (1 << i));
864 hw->ext_buttons & (1 << (i + ext_bits))); 869 input_report_key(dev, BTN_1 + 2 * i,
870 hw->ext_buttons & (1 << (i + ext_bits)));
871 }
872 return;
865 } 873 }
874
875 /*
876 * This generation of touchpads has the trackstick buttons
877 * physically wired to the touchpad. Re-route them through
878 * the pass-through interface.
879 */
880 if (!priv->pt_port)
881 return;
882
883 /* The trackstick expects at most 3 buttons */
884 priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) |
885 SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
886 SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
887
888 synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
866} 889}
867 890
868static void synaptics_report_buttons(struct psmouse *psmouse, 891static void synaptics_report_buttons(struct psmouse *psmouse,
@@ -1459,7 +1482,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
1459 if (SYN_CAP_PASS_THROUGH(priv->capabilities) && 1482 if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
1460 synaptics_is_pt_packet(psmouse->packet)) { 1483 synaptics_is_pt_packet(psmouse->packet)) {
1461 if (priv->pt_port) 1484 if (priv->pt_port)
1462 synaptics_pass_pt_packet(priv->pt_port, psmouse->packet); 1485 synaptics_pass_pt_packet(psmouse, priv->pt_port,
1486 psmouse->packet);
1463 } else 1487 } else
1464 synaptics_process_packet(psmouse); 1488 synaptics_process_packet(psmouse);
1465 1489
@@ -1561,8 +1585,9 @@ static void set_input_params(struct psmouse *psmouse,
1561 __set_bit(BTN_BACK, dev->keybit); 1585 __set_bit(BTN_BACK, dev->keybit);
1562 } 1586 }
1563 1587
1564 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) 1588 if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
1565 __set_bit(BTN_0 + i, dev->keybit); 1589 for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
1590 __set_bit(BTN_0 + i, dev->keybit);
1566 1591
1567 __clear_bit(EV_REL, dev->evbit); 1592 __clear_bit(EV_REL, dev->evbit);
1568 __clear_bit(REL_X, dev->relbit); 1593 __clear_bit(REL_X, dev->relbit);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 8d3761ce8f54..f39539c70219 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -111,6 +111,10 @@
111#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) 111#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000)
112#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) 112#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000)
113 113
114#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01))
115#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02))
116#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04))
117
114/* synaptics modes query bits */ 118/* synaptics modes query bits */
115#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) 119#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
116#define SYN_MODE_RATE(m) ((m) & (1 << 6)) 120#define SYN_MODE_RATE(m) ((m) & (1 << 6))
@@ -192,6 +196,7 @@ struct synaptics_data {
192 bool disable_gesture; /* disable gestures */ 196 bool disable_gesture; /* disable gestures */
193 197
194 struct serio *pt_port; /* Pass-through serio port */ 198 struct serio *pt_port; /* Pass-through serio port */
199 unsigned char pt_buttons; /* Pass-through buttons */
195 200
196 struct synaptics_mt_state mt_state; /* Current mt finger state */ 201 struct synaptics_mt_state mt_state; /* Current mt finger state */
197 bool mt_state_lost; /* mt_state may be incorrect */ 202 bool mt_state_lost; /* mt_state may be incorrect */