diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-03-09 01:30:43 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-03-09 02:34:34 -0400 |
| commit | dc5465dc8a6d5cae8a0e1d8826bdcb2e4cb261ab (patch) | |
| tree | 4ab70ec5d92765f5b8e7dbcd3b2f004e20cfb852 /drivers/input/mouse | |
| parent | 02e07492cdfae9c86e3bd21c0beec88dbcc1e9e8 (diff) | |
Input: synaptics - fix middle button on Lenovo 2015 products
On the X1 Carbon 3rd gen (with a 2015 broadwell cpu), the physical middle
button of the trackstick (attached to the touchpad serio device, of course)
seems to get lost.
Actually, the touchpads reports 3 extra buttons, which falls in the switch
below to the '2' case. Let's handle the case of odd numbers also, so that
the middle button finds its way back.
Cc: stable@vger.kernel.org
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>
Diffstat (limited to 'drivers/input/mouse')
| -rw-r--r-- | drivers/input/mouse/synaptics.c | 44 |
1 files changed, 21 insertions, 23 deletions
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 9567a708aa64..e78cc5578527 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
| @@ -658,6 +658,18 @@ static void synaptics_parse_agm(const unsigned char buf[], | |||
| 658 | priv->agm_pending = true; | 658 | priv->agm_pending = true; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | static void synaptics_parse_ext_buttons(const unsigned char buf[], | ||
| 662 | struct synaptics_data *priv, | ||
| 663 | struct synaptics_hw_state *hw) | ||
| 664 | { | ||
| 665 | unsigned int ext_bits = | ||
| 666 | (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; | ||
| 667 | unsigned int ext_mask = GENMASK(ext_bits - 1, 0); | ||
| 668 | |||
| 669 | hw->ext_buttons = buf[4] & ext_mask; | ||
| 670 | hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; | ||
| 671 | } | ||
| 672 | |||
| 661 | static bool is_forcepad; | 673 | static bool is_forcepad; |
| 662 | 674 | ||
| 663 | static int synaptics_parse_hw_state(const unsigned char buf[], | 675 | static int synaptics_parse_hw_state(const unsigned char buf[], |
| @@ -744,28 +756,9 @@ static int synaptics_parse_hw_state(const unsigned char buf[], | |||
| 744 | hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; | 756 | hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; |
| 745 | } | 757 | } |
| 746 | 758 | ||
| 747 | if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && | 759 | if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && |
| 748 | ((buf[0] ^ buf[3]) & 0x02)) { | 760 | ((buf[0] ^ buf[3]) & 0x02)) { |
| 749 | switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { | 761 | synaptics_parse_ext_buttons(buf, priv, hw); |
| 750 | default: | ||
| 751 | /* | ||
| 752 | * if nExtBtn is greater than 8 it should be | ||
| 753 | * considered invalid and treated as 0 | ||
| 754 | */ | ||
| 755 | break; | ||
| 756 | case 8: | ||
| 757 | hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0; | ||
| 758 | hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0; | ||
| 759 | case 6: | ||
| 760 | hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0; | ||
| 761 | hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0; | ||
| 762 | case 4: | ||
| 763 | hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0; | ||
| 764 | hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0; | ||
| 765 | case 2: | ||
| 766 | hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0; | ||
| 767 | hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0; | ||
| 768 | } | ||
| 769 | } | 762 | } |
| 770 | } else { | 763 | } else { |
| 771 | hw->x = (((buf[1] & 0x1f) << 8) | buf[2]); | 764 | hw->x = (((buf[1] & 0x1f) << 8) | buf[2]); |
| @@ -832,6 +825,7 @@ static void synaptics_report_buttons(struct psmouse *psmouse, | |||
| 832 | { | 825 | { |
| 833 | struct input_dev *dev = psmouse->dev; | 826 | struct input_dev *dev = psmouse->dev; |
| 834 | struct synaptics_data *priv = psmouse->private; | 827 | struct synaptics_data *priv = psmouse->private; |
| 828 | int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; | ||
| 835 | int i; | 829 | int i; |
| 836 | 830 | ||
| 837 | input_report_key(dev, BTN_LEFT, hw->left); | 831 | input_report_key(dev, BTN_LEFT, hw->left); |
| @@ -845,8 +839,12 @@ static void synaptics_report_buttons(struct psmouse *psmouse, | |||
| 845 | input_report_key(dev, BTN_BACK, hw->down); | 839 | input_report_key(dev, BTN_BACK, hw->down); |
| 846 | } | 840 | } |
| 847 | 841 | ||
| 848 | for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) | 842 | for (i = 0; i < ext_bits; i++) { |
| 849 | input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i)); | 843 | input_report_key(dev, BTN_0 + 2 * i, |
| 844 | hw->ext_buttons & (1 << i)); | ||
| 845 | input_report_key(dev, BTN_1 + 2 * i, | ||
| 846 | hw->ext_buttons & (1 << (i + ext_bits))); | ||
| 847 | } | ||
| 850 | } | 848 | } |
| 851 | 849 | ||
| 852 | static void synaptics_report_slot(struct input_dev *dev, int slot, | 850 | static void synaptics_report_slot(struct input_dev *dev, int slot, |
