diff mbox

Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530

Message ID 20140214205126.GB15526@lantern (mailing list archive)
State New, archived
Headers show

Commit Message

Ulrik De Bie Feb. 14, 2014, 8:51 p.m. UTC
Sorry it took me some time to have an email addres that would allow clean
mails. Below you can find the updated patch previously sent on linux-input
mailinglist. David Herrman asked to resent this patch as a proper git patch so
here it is now. 

It also available on https://github.com/ulrikdb/linux.git elantech_trackpoint
from commit 38dbfb59d1175ef458d006556061adeaa8751b72 (Linus 3.14-rc1) up to 
d69e103a35c944721966105790d14adf79098a4c 

Please when responding please send either to linux-input or put Ulrik De Bie <ulrik.debie-os@e2big.org> in CC:, Thanks.


The Lenovo L530 trackpoint does not work out of the box. It gives sync errors
as shown below when the trackpoint or trackpoint mouse buttons are pressed and
no input is received by userspace:
[   29.010641] psmouse serio1: Touchpad at isa0060/serio1/input0 lost sync at byte 6
The touchpad does work.

The alternative is to do a downgrade to generic ps/2 mouse (modprobe psmouse proto=bare)
but this has the disadvantage that touchpad can't be disabled (I want trackpoint, not touchpad).

With this patch, the trackpoint is provided as another input device; currently called 'TPPS/2 IBM TrackPoint'
The trackpoint now succesfully works and I can disable the touchpad with synclient TouchPadOff=1
The patch will also output messages that do not follow the expected pattern.
In the mean time I've seen 2 unknown packets occasionally:
0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 0x00
I don't know what those are for, but they can be safely ignored.

Currently all packets that are not known to v3 touchpad and where packet[3] (the fourth byte) lowest
nibble is 6 are now recognized as PACKET_TRACKPOINT and processed by the new elantech_report_trackpoint.

This has been verified to work on a laptop where the touchpad/trackpoint combined identify themselves as:
psmouse serio1: elantech: assuming hardware version 3 (with firmware version 0x350f02)
psmouse serio1: elantech: Synaptics capabilities query result 0xb9, 0x15, 0x0c.

Since I can't send clean email from yahoo, I've switched to a different email address: ulrik.debie-os@e2big.org
Signed-off-by: Ulrik De Bie <ulrik_opensource-kernel@yahoo.com>
Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>

Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
---
 drivers/input/mouse/elantech.c | 78 +++++++++++++++++++++++++++++++++++++++++-
 drivers/input/mouse/elantech.h |  3 ++
 2 files changed, 80 insertions(+), 1 deletion(-)

Comments

Ulrik De Bie March 20, 2014, 7:59 p.m. UTC | #1
Hi Dmitry,

Could you please have a look at this patch. It solves the bugzilla bug
https://bugzilla.kernel.org/show_bug.cgi?id=48161

Thanks,
Best regards,
Ulrik De Bie

On Fri, Feb 14, 2014 at 09:51:26PM +0100, Ulrik De Bie wrote:
> Date:	Fri, 14 Feb 2014 21:51:26 +0100
> From: Ulrik De Bie <ulrik.debie-os@e2big.org>
> To: linux-input@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org, Dmitry Torokhov
>  <dmitry.torokhov@gmail.com>, David Herrmann <dh.herrmann@gmail.com>,
>  Jonathan Aquilina <eagles051387@gmail.com>, Ulrik De Bie
>  <ulrik_opensource-kernel@yahoo.com>
> Subject: [PATCH] Input: Support in the elantech driver of the trackpoint
>  present on for instance Lenovo L530
> X-Mailing-List:	linux-input@vger.kernel.org
> 
> Sorry it took me some time to have an email addres that would allow clean
> mails. Below you can find the updated patch previously sent on linux-input
> mailinglist. David Herrman asked to resent this patch as a proper git patch so
> here it is now. 
> 
> It also available on https://github.com/ulrikdb/linux.git elantech_trackpoint
> from commit 38dbfb59d1175ef458d006556061adeaa8751b72 (Linus 3.14-rc1) up to 
> d69e103a35c944721966105790d14adf79098a4c 
> 
> Please when responding please send either to linux-input or put Ulrik De Bie <ulrik.debie-os@e2big.org> in CC:, Thanks.
> 
> 
> The Lenovo L530 trackpoint does not work out of the box. It gives sync errors
> as shown below when the trackpoint or trackpoint mouse buttons are pressed and
> no input is received by userspace:
> [   29.010641] psmouse serio1: Touchpad at isa0060/serio1/input0 lost sync at byte 6
> The touchpad does work.
> 
> The alternative is to do a downgrade to generic ps/2 mouse (modprobe psmouse proto=bare)
> but this has the disadvantage that touchpad can't be disabled (I want trackpoint, not touchpad).
> 
> With this patch, the trackpoint is provided as another input device; currently called 'TPPS/2 IBM TrackPoint'
> The trackpoint now succesfully works and I can disable the touchpad with synclient TouchPadOff=1
> The patch will also output messages that do not follow the expected pattern.
> In the mean time I've seen 2 unknown packets occasionally:
> 0x04 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
> 0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 0x00
> I don't know what those are for, but they can be safely ignored.
> 
> Currently all packets that are not known to v3 touchpad and where packet[3] (the fourth byte) lowest
> nibble is 6 are now recognized as PACKET_TRACKPOINT and processed by the new elantech_report_trackpoint.
> 
> This has been verified to work on a laptop where the touchpad/trackpoint combined identify themselves as:
> psmouse serio1: elantech: assuming hardware version 3 (with firmware version 0x350f02)
> psmouse serio1: elantech: Synaptics capabilities query result 0xb9, 0x15, 0x0c.
> 
> Since I can't send clean email from yahoo, I've switched to a different email address: ulrik.debie-os@e2big.org
> Signed-off-by: Ulrik De Bie <ulrik_opensource-kernel@yahoo.com>
> Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
> 
> Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
> ---
>  drivers/input/mouse/elantech.c | 78 +++++++++++++++++++++++++++++++++++++++++-
>  drivers/input/mouse/elantech.h |  3 ++
>  2 files changed, 80 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index ef1cf52..21d693b 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
> @@ -402,6 +402,54 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
>  	input_sync(dev);
>  }
>  
> +static void elantech_report_trackpoint(struct psmouse *psmouse,
> +				       int packet_type)
> +{
> +	/* byte 0:  0   0 ~sx ~sy   0   M   R   L */
> +	/* byte 1: sx   0   0   0   0   0   0   0 */
> +	/* byte 2: sy   0   0   0   0   0   0   0 */
> +	/* byte 3:  0   0  sy  sx   0   1   1   0 */
> +	/* byte 4: x7  x6  x5  x4  x3  x2  x1  x0 */
> +	/* byte 5: y7  y6  y5  y4  y3  y2  y1  y0 */
> +
> +	/*
> +	 * x and y are written in two's complement spread
> +	 * over 9 bits with sx/sy the relative top bit and
> +	 * x7..x0 and y7..y0 the lower bits.
> +	 * The sign of y is opposite to what the input driver
> +	 * expects for a relative movement
> +	 */
> +
> +	struct elantech_data *etd = psmouse->private;
> +	struct input_dev *dev2 = etd->dev2;
> +	unsigned char *packet = psmouse->packet;
> +	int x, y;
> +	input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
> +	input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
> +	input_report_key(dev2, BTN_MIDDLE, packet[0] & 0x04);
> +	x = (s32) ((u32) ((packet[1] & 0x80) ? 0UL : 0xFFFFFF00UL) | (u32)
> +		   packet[4]);
> +	y = -(s32) ((u32) ((packet[2] & 0x80) ? 0UL : 0xFFFFFF00UL) | (u32)
> +		    packet[5]);
> +	input_report_rel(dev2, REL_X, x);
> +	input_report_rel(dev2, REL_Y, y);
> +	switch ((((u32) packet[0] & 0xF8) << 24) | ((u32) packet[1] << 16)
> +		| (u32) packet[2] << 8 | (u32) packet[3]) {
> +	case 0x00808036UL:
> +	case 0x10008026UL:
> +	case 0x20800016UL:
> +	case 0x30000006UL:
> +		break;
> +	default:
> +		/* Dump unexpected packet sequences if debug=1 (default) */
> +		if (etd->debug == 1)
> +			elantech_packet_dump(psmouse);
> +		break;
> +	}
> +
> +	input_sync(dev2);
> +}
> +
>  /*
>   * Interpret complete data packets and report absolute mode input events for
>   * hardware version 3. (12 byte packets for two fingers)
> @@ -700,8 +748,11 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
>  
>  		if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
>  			return PACKET_V3_TAIL;
> +		if ((packet[3]&0x0f) == 0x06)
> +			return PACKET_TRACKPOINT;
>  	}
>  
> +
>  	return PACKET_UNKNOWN;
>  }
>  
> @@ -783,7 +834,10 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>  		if (packet_type == PACKET_UNKNOWN)
>  			return PSMOUSE_BAD_DATA;
>  
> -		elantech_report_absolute_v3(psmouse, packet_type);
> +		if (packet_type == PACKET_TRACKPOINT)
> +			elantech_report_trackpoint(psmouse, packet_type);
> +		else
> +			elantech_report_absolute_v3(psmouse, packet_type);
>  		break;
>  
>  	case 4:
> @@ -1400,10 +1454,15 @@ int elantech_init(struct psmouse *psmouse)
>  	struct elantech_data *etd;
>  	int i, error;
>  	unsigned char param[3];
> +	struct input_dev *dev2;
>  
>  	psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
>  	if (!etd)
>  		return -ENOMEM;
> +	dev2 = input_allocate_device();
> +	if (!dev2)
> +		goto init_fail;
> +	etd->dev2 = dev2;
>  
>  	psmouse_reset(psmouse);
>  
> @@ -1463,9 +1522,26 @@ int elantech_init(struct psmouse *psmouse)
>  	psmouse->reconnect = elantech_reconnect;
>  	psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
>  
> +	snprintf(etd->phys, sizeof(etd->phys), "%s/input1",
> +		psmouse->ps2dev.serio->phys);
> +	dev2->phys = etd->phys;
> +	dev2->name = "TPPS/2 IBM TrackPoint";
> +	dev2->id.bustype = BUS_I8042;
> +	dev2->id.vendor  = 0x0002;
> +	dev2->id.product = PSMOUSE_ELANTECH;
> +	dev2->id.version = 0x0000;
> +	dev2->dev.parent = &psmouse->ps2dev.serio->dev;
> +	dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
> +	dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
> +	dev2->keybit[BIT_WORD(BTN_LEFT)] =
> +		BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
> +
> +	if (input_register_device(etd->dev2))
> +		goto init_fail;
>  	return 0;
>  
>   init_fail:
> +	input_free_device(dev2);
>  	kfree(etd);
>  	return -1;
>  }
> diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
> index 036a04a..27cf191 100644
> --- a/drivers/input/mouse/elantech.h
> +++ b/drivers/input/mouse/elantech.h
> @@ -94,6 +94,7 @@
>  #define PACKET_V4_HEAD			0x05
>  #define PACKET_V4_MOTION		0x06
>  #define PACKET_V4_STATUS		0x07
> +#define PACKET_TRACKPOINT		0x08
>  
>  /*
>   * track up to 5 fingers for v4 hardware
> @@ -114,6 +115,8 @@ struct finger_pos {
>  };
>  
>  struct elantech_data {
> +	struct input_dev *dev2;		/* Relative device */
> +	char	phys[32];
>  	unsigned char reg_07;
>  	unsigned char reg_10;
>  	unsigned char reg_11;
> -- 
> 1.8.5.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulrik De Bie June 12, 2014, 6:15 p.m. UTC | #2
This patch adds support for trackpoint on elantech driver for v3 models

Changes since v1:
* New patch now with reference to 3.14rc1
* Added etd->trackpoint_present to indicate presence of trackpoint (based
  on MSB of etd->capabilities[0])
* trackpoint will only be registered now when MSB of etd->capabilities[0] is
  set; got confirmation that this is the indicator of trackpoint
* Added input_unregister_device/input_free_device in elantech_disconnect()
* Fixed a bug in cleaning up when elantech_init fails
* Rename commit to be more specific (now also applicable to future elantech
  v3 models with trackpoint)
* input device name 'TPPS/2 IBM TrackPoint' changed to
  'Elantech PS/2 TrackPoint', this patch is not ibm/lenovo specific!
* dev2 renamed to tp_dev to indicate that this is the trackpoint device
* etd->phys renamed to etd->tp_phys
* Added Lenovo 530 and Fujitsu H730 to the laptop list because those are now
  also known.
* Added psmouse_reset at the end of elantech_init when it fails
* Added warning when trackpoint packets are received with no trackpoint detected

The patch is also available from:
https://github.com/ulrikdb/linux/commit/74f8d3a9307c109ae40c02072dc9c16d3557c3d4

Ulrik De Bie (1):
  elantech: Add support for trackpoint found on some v3 models

 drivers/input/mouse/elantech.c | 104 +++++++++++++++++++++++++++++++++++++++--
 drivers/input/mouse/elantech.h |   4 ++
 2 files changed, 105 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index ef1cf52..21d693b 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -402,6 +402,54 @@  static void elantech_report_absolute_v2(struct psmouse *psmouse)
 	input_sync(dev);
 }
 
+static void elantech_report_trackpoint(struct psmouse *psmouse,
+				       int packet_type)
+{
+	/* byte 0:  0   0 ~sx ~sy   0   M   R   L */
+	/* byte 1: sx   0   0   0   0   0   0   0 */
+	/* byte 2: sy   0   0   0   0   0   0   0 */
+	/* byte 3:  0   0  sy  sx   0   1   1   0 */
+	/* byte 4: x7  x6  x5  x4  x3  x2  x1  x0 */
+	/* byte 5: y7  y6  y5  y4  y3  y2  y1  y0 */
+
+	/*
+	 * x and y are written in two's complement spread
+	 * over 9 bits with sx/sy the relative top bit and
+	 * x7..x0 and y7..y0 the lower bits.
+	 * The sign of y is opposite to what the input driver
+	 * expects for a relative movement
+	 */
+
+	struct elantech_data *etd = psmouse->private;
+	struct input_dev *dev2 = etd->dev2;
+	unsigned char *packet = psmouse->packet;
+	int x, y;
+	input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
+	input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
+	input_report_key(dev2, BTN_MIDDLE, packet[0] & 0x04);
+	x = (s32) ((u32) ((packet[1] & 0x80) ? 0UL : 0xFFFFFF00UL) | (u32)
+		   packet[4]);
+	y = -(s32) ((u32) ((packet[2] & 0x80) ? 0UL : 0xFFFFFF00UL) | (u32)
+		    packet[5]);
+	input_report_rel(dev2, REL_X, x);
+	input_report_rel(dev2, REL_Y, y);
+	switch ((((u32) packet[0] & 0xF8) << 24) | ((u32) packet[1] << 16)
+		| (u32) packet[2] << 8 | (u32) packet[3]) {
+	case 0x00808036UL:
+	case 0x10008026UL:
+	case 0x20800016UL:
+	case 0x30000006UL:
+		break;
+	default:
+		/* Dump unexpected packet sequences if debug=1 (default) */
+		if (etd->debug == 1)
+			elantech_packet_dump(psmouse);
+		break;
+	}
+
+	input_sync(dev2);
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 3. (12 byte packets for two fingers)
@@ -700,8 +748,11 @@  static int elantech_packet_check_v3(struct psmouse *psmouse)
 
 		if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
 			return PACKET_V3_TAIL;
+		if ((packet[3]&0x0f) == 0x06)
+			return PACKET_TRACKPOINT;
 	}
 
+
 	return PACKET_UNKNOWN;
 }
 
@@ -783,7 +834,10 @@  static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 		if (packet_type == PACKET_UNKNOWN)
 			return PSMOUSE_BAD_DATA;
 
-		elantech_report_absolute_v3(psmouse, packet_type);
+		if (packet_type == PACKET_TRACKPOINT)
+			elantech_report_trackpoint(psmouse, packet_type);
+		else
+			elantech_report_absolute_v3(psmouse, packet_type);
 		break;
 
 	case 4:
@@ -1400,10 +1454,15 @@  int elantech_init(struct psmouse *psmouse)
 	struct elantech_data *etd;
 	int i, error;
 	unsigned char param[3];
+	struct input_dev *dev2;
 
 	psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
 	if (!etd)
 		return -ENOMEM;
+	dev2 = input_allocate_device();
+	if (!dev2)
+		goto init_fail;
+	etd->dev2 = dev2;
 
 	psmouse_reset(psmouse);
 
@@ -1463,9 +1522,26 @@  int elantech_init(struct psmouse *psmouse)
 	psmouse->reconnect = elantech_reconnect;
 	psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
 
+	snprintf(etd->phys, sizeof(etd->phys), "%s/input1",
+		psmouse->ps2dev.serio->phys);
+	dev2->phys = etd->phys;
+	dev2->name = "TPPS/2 IBM TrackPoint";
+	dev2->id.bustype = BUS_I8042;
+	dev2->id.vendor  = 0x0002;
+	dev2->id.product = PSMOUSE_ELANTECH;
+	dev2->id.version = 0x0000;
+	dev2->dev.parent = &psmouse->ps2dev.serio->dev;
+	dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+	dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+	dev2->keybit[BIT_WORD(BTN_LEFT)] =
+		BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+
+	if (input_register_device(etd->dev2))
+		goto init_fail;
 	return 0;
 
  init_fail:
+	input_free_device(dev2);
 	kfree(etd);
 	return -1;
 }
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 036a04a..27cf191 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -94,6 +94,7 @@ 
 #define PACKET_V4_HEAD			0x05
 #define PACKET_V4_MOTION		0x06
 #define PACKET_V4_STATUS		0x07
+#define PACKET_TRACKPOINT		0x08
 
 /*
  * track up to 5 fingers for v4 hardware
@@ -114,6 +115,8 @@  struct finger_pos {
 };
 
 struct elantech_data {
+	struct input_dev *dev2;		/* Relative device */
+	char	phys[32];
 	unsigned char reg_07;
 	unsigned char reg_10;
 	unsigned char reg_11;