linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Andrew Duggan <aduggan@synaptics.com>,
	Hans de Goede <hdegoede@redhat.com>,
	Peter Hutterer <peter.hutterer@who-t.net>,
	linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 6/7] Input: synaptics - re-route tracksticks buttons on the Lenovo 2015 series
Date: Fri,  6 Feb 2015 15:04:34 -0500	[thread overview]
Message-ID: <1423253075-23469-7-git-send-email-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <1423253075-23469-1-git-send-email-benjamin.tissoires@redhat.com>

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!

Fortunatelly, the firmware advertizes 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>
---

v2:
- forward only 3 extra buttons, not the whole array. The PS/2 base protocol
  handles only 3 buttons, so giving more than 3 will mess up REL_X and REL_Y.
- rely on SYN_CAP_EXT_BUTTONS_STICK to know if the re-routing has to be put in
  place or not

 drivers/input/mouse/synaptics.c | 45 +++++++++++++++++++++++++++++++----------
 drivers/input/mouse/synaptics.h |  5 +++++
 2 files changed, 39 insertions(+), 11 deletions(-)

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 79c4a87..dfe8235 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -585,18 +585,20 @@ static int synaptics_is_pt_packet(unsigned char *buf)
 	return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
 
-static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+static void synaptics_pass_pt_packet(struct psmouse *psmouse,
+		struct serio *ptport, unsigned char *packet)
 {
+	struct synaptics_data *priv = psmouse->private;
 	struct psmouse *child = serio_get_drvdata(ptport);
 
 	if (child && child->state == PSMOUSE_ACTIVATED) {
-		serio_interrupt(ptport, packet[1], 0);
+		serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
 		serio_interrupt(ptport, packet[4], 0);
 		serio_interrupt(ptport, packet[5], 0);
 		if (child->pktsize == 4)
 			serio_interrupt(ptport, packet[2], 0);
 	} else
-		serio_interrupt(ptport, packet[1], 0);
+		serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -842,6 +844,7 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
 	struct input_dev *dev = psmouse->dev;
 	struct synaptics_data *priv = psmouse->private;
 	int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
+	char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 	int i;
 
 	if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
@@ -852,12 +855,30 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
 	    !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
 		return;
 
-	for (i = 0; i < ext_bits; i++) {
-		input_report_key(dev, BTN_0 + 2 * i,
-			hw->ext_buttons & (1 << i));
-		input_report_key(dev, BTN_1 + 2 * i,
-			hw->ext_buttons & (1 << (i + ext_bits)));
+	if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) {
+		for (i = 0; i < ext_bits; i++) {
+			input_report_key(dev, BTN_0 + 2 * i,
+				hw->ext_buttons & (1 << i));
+			input_report_key(dev, BTN_1 + 2 * i,
+				hw->ext_buttons & (1 << (i + ext_bits)));
+		}
+		return;
 	}
+
+	/*
+	 * This generation of touchpads has the trackstick buttons
+	 * physically wired to the touchpad. Re-route them through
+	 * the pass-through interface.
+	 */
+	if (!priv->pt_port)
+		return;
+
+	/* the trackstick expects at most 3 buttons */
+	priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
+			   SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
+			   SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+
+	synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
 }
 
 static void synaptics_report_buttons(struct psmouse *psmouse,
@@ -1098,7 +1119,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 		if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
 		    synaptics_is_pt_packet(psmouse->packet)) {
 			if (priv->pt_port)
-				synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
+				synaptics_pass_pt_packet(psmouse, priv->pt_port,
+							 psmouse->packet);
 		} else
 			synaptics_process_packet(psmouse);
 
@@ -1200,8 +1222,9 @@ static void set_input_params(struct psmouse *psmouse,
 		__set_bit(BTN_BACK, dev->keybit);
 	}
 
-	for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-		__set_bit(BTN_0 + i, dev->keybit);
+	if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10))
+		for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
+			__set_bit(BTN_0 + i, dev->keybit);
 
 	__clear_bit(EV_REL, dev->evbit);
 	__clear_bit(REL_X, dev->relbit);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 9723092..8102a72 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -111,6 +111,10 @@
 #define SYN_CAP_EXT_BUTTONS_STICK(ex10)	((ex10) & 0x010000)
 #define SYN_CAP_SECUREPAD(ex10)		((ex10) & 0x020000)
 
+#define SYN_CAP_EXT_BUTTON_STICK_L(eb)	(!!((eb) & 0x01))
+#define SYN_CAP_EXT_BUTTON_STICK_M(eb)	(!!((eb) & 0x02))
+#define SYN_CAP_EXT_BUTTON_STICK_R(eb)	(!!((eb) & 0x04))
+
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
 #define SYN_MODE_RATE(m)		((m) & (1 << 6))
@@ -179,6 +183,7 @@ struct synaptics_data {
 	bool disable_gesture;			/* disable gestures */
 
 	struct serio *pt_port;			/* Pass-through serio port */
+	unsigned char pt_buttons;		/* Pass-through buttons */
 
 	/*
 	 * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
-- 
2.1.0


  parent reply	other threads:[~2015-02-06 20:05 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-02-06 20:04 [PATCH v2 0/7] New Lenovos 2015 touchpads: party time! Benjamin Tissoires
2015-02-06 20:04 ` [PATCH v2 1/7] Input: synaptics - fix middle button on Lenovo 2015 products Benjamin Tissoires
2015-02-06 20:04 ` [PATCH v2 2/7] Input: synaptics - handle spurious release of trackstick buttons Benjamin Tissoires
2015-02-06 20:04 ` [PATCH v2 3/7] Input: synaptics - do not retrieve the board id on old firmwares Benjamin Tissoires
2015-02-06 20:04 ` [PATCH v2 4/7] Input: synaptics - retrieve the extended capabilities in query $10 Benjamin Tissoires
2015-02-06 20:04 ` [PATCH v2 5/7] Input: synaptics - remove TOPBUTTONPAD property for Lenovos 2015 Benjamin Tissoires
2015-02-06 20:04 ` Benjamin Tissoires [this message]
2015-03-09  6:45   ` [PATCH v2 6/7] Input: synaptics - re-route tracksticks buttons on the Lenovo 2015 series Dmitry Torokhov
2015-02-06 20:04 ` [PATCH v2 7/7] Input: synaptics - Remove X1 Carbon 3rd gen from the topbuttonpad list Benjamin Tissoires
2015-02-17  3:23 ` [PATCH v2 0/7] New Lenovos 2015 touchpads: party time! Benjamin Tissoires
2015-02-25 14:36   ` Benjamin Tissoires
2015-02-25 14:58     ` Hans de Goede
2015-03-09  6:46       ` Dmitry Torokhov
2015-03-09  8:24         ` Hans de Goede
2015-03-09 19:36           ` Benjamin Tissoires
2015-03-10  6:17             ` Steven Noonan
2015-03-10  7:23               ` Hans de Goede
2015-03-10 18:35                 ` Steven Noonan
2015-03-16 14:46             ` Benjamin Tissoires
2015-03-19 14:24 ` Yves-Alexis Perez
2015-03-19 14:46   ` Benjamin Tissoires
2015-03-19 15:25     ` Yves-Alexis Perez
2015-03-19 15:58       ` Benjamin Tissoires
2015-03-19 16:47         ` Yves-Alexis Perez
2015-03-19 17:06           ` Benjamin Tissoires
2015-03-19 17:43             ` Dmitry Torokhov
2015-03-19 18:29               ` Benjamin Tissoires
2015-03-20 13:59             ` Yves-Alexis Perez
2015-04-09 12:59         ` Yves-Alexis Perez
2015-04-09 13:56           ` Benjamin Tissoires

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1423253075-23469-7-git-send-email-benjamin.tissoires@redhat.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=aduggan@synaptics.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=hdegoede@redhat.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peter.hutterer@who-t.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).