linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530
@ 2014-08-20 18:18 Ulrik De Bie
  2014-08-20 18:18 ` [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models Ulrik De Bie
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Ulrik De Bie @ 2014-08-20 18:18 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Hans de Goede, David Herrmann, ulrik.debie-os

Hi Dmitry,

I posted these 2 months ago, but haven't seen any comments from you.
Could you please review these ?

Thanks,
Ulrik

Patch 1 adds support for trackpoint on elantech driver for v3 models.
Patch 2 adds a psmouse_reset when the elantech probes fails. Patch 2 depends
on Patch 1.

Changes since v3:
* Patch1: added (correct) error after input_allocate_device failure in elantech_init()
* Patch2: added more explanation to the why

Changes since v2:
* psmouse_reset change is now moved to a separate patch
* comments/white spaces/newlines  cleanup
* Unexpected trackpoint message warning now only printed once
* removed some unnecessary casts
* Deleted etd->trackpoint_present and use instead etd->tp_dev to indicate the
  presence of a trackpoint
* Propagate the error when elantech_init fails

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 patches are also available from:
https://github.com/ulrikdb/linux/commit/53d8424bc2143d34c2be76064892079fe1917a9e
https://github.com/ulrikdb/linux/commit/cf12fcc6cdf51a7aad48d056750478aecd9d7eca



Ulrik De Bie (2):
  elantech: Add support for trackpoint found on some v3 models
  elantech: Call psmouse_reset when elantech probe fails

 drivers/input/mouse/elantech.c | 123 +++++++++++++++++++++++++++++++++++++++--
 drivers/input/mouse/elantech.h |   3 +
 2 files changed, 122 insertions(+), 4 deletions(-)

-- 
2.1.0.rc1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models
  2014-08-20 18:18 [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Ulrik De Bie
@ 2014-08-20 18:18 ` Ulrik De Bie
  2014-08-24 22:14   ` Dmitry Torokhov
  2014-08-20 18:18 ` [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails Ulrik De Bie
  2014-08-21 18:04 ` [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Dmitry Torokhov
  2 siblings, 1 reply; 8+ messages in thread
From: Ulrik De Bie @ 2014-08-20 18:18 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Hans de Goede, David Herrmann, ulrik.debie-os

Some elantech v3 touchpad equipped laptops also have a trackpoint, before
this commit, these give sync errors. With this patch, the trackpoint is
provided as another input device: 'Elantech PS/2 TrackPoint'

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 Lenovo L530 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.

Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
---
 drivers/input/mouse/elantech.c | 122 +++++++++++++++++++++++++++++++++++++++--
 drivers/input/mouse/elantech.h |   3 +
 2 files changed, 121 insertions(+), 4 deletions(-)

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index ee2a04d..5dd620a 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -403,6 +403,71 @@ 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 *tp_dev = etd->tp_dev;
+	unsigned char *packet = psmouse->packet;
+	int x, y;
+	u32 t;
+
+	if (!tp_dev) {
+		static bool __section(.data.unlikely) __warned;
+
+		if (!__warned) {
+			__warned = true;
+			psmouse_err(psmouse, "Unexpected trackpoint message\n");
+			if (etd->debug == 1)
+				elantech_packet_dump(psmouse);
+		}
+
+		return;
+	}
+
+	input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
+	input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
+	input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
+
+	x = ((packet[1] & 0x80) ? 0U : 0xFFFFFF00U) | packet[4];
+	y = -(int)(((packet[2] & 0x80) ? 0U : 0xFFFFFF00U) | packet[5]);
+
+	input_report_rel(tp_dev, REL_X, x);
+	input_report_rel(tp_dev, REL_Y, y);
+
+	t = (((u32)packet[0] & 0xF8) << 24) | ((u32)packet[1] << 16)
+		| (u32)packet[2] << 8 | (u32)packet[3];
+	switch (t) {
+	case 0x00808036U:
+	case 0x10008026U:
+	case 0x20800016U:
+	case 0x30000006U:
+		break;
+	default:
+		/* Dump unexpected packet sequences if debug=1 (default) */
+		if (etd->debug == 1)
+			elantech_packet_dump(psmouse);
+		break;
+	}
+
+	input_sync(tp_dev);
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 3. (12 byte packets for two fingers)
@@ -715,6 +780,8 @@ 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;
@@ -798,7 +865,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:
@@ -1018,8 +1088,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Asus UX31               0x361f00        20, 15, 0e      clickpad
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
+ * Lenovo L530             0x350f02        b9, 15, 0c      2 hw buttons (*)
  * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons
  * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad
  * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad
@@ -1029,6 +1101,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Samsung RF710           0x450f00        ?               2 hw buttons
  * System76 Pangolin       0x250f01        ?               2 hw buttons
  * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
  */
 static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
 {
@@ -1324,6 +1398,10 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
  */
 static void elantech_disconnect(struct psmouse *psmouse)
 {
+	struct elantech_data *etd = psmouse->private;
+
+	if (etd->tp_dev)
+		input_unregister_device(etd->tp_dev);
 	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
 			   &elantech_attr_group);
 	kfree(psmouse->private);
@@ -1438,8 +1516,10 @@ static int elantech_set_properties(struct elantech_data *etd)
 int elantech_init(struct psmouse *psmouse)
 {
 	struct elantech_data *etd;
-	int i, error;
+	int i;
+	int error = -EINVAL;
 	unsigned char param[3];
+	struct input_dev *tp_dev;
 
 	psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
 	if (!etd)
@@ -1498,14 +1578,48 @@ int elantech_init(struct psmouse *psmouse)
 		goto init_fail;
 	}
 
+	/* The MSB indicates the presence of the trackpoint */
+	if ((etd->capabilities[0] & 0x80) == 0x80) {
+		tp_dev = input_allocate_device();
+
+		if (!tp_dev) {
+			error = -ENOMEM;
+			goto init_fail_tp_alloc;
+		}
+
+		etd->tp_dev = tp_dev;
+		snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1",
+			psmouse->ps2dev.serio->phys);
+		tp_dev->phys = etd->tp_phys;
+		tp_dev->name = "Elantech PS/2 TrackPoint";
+		tp_dev->id.bustype = BUS_I8042;
+		tp_dev->id.vendor  = 0x0002;
+		tp_dev->id.product = PSMOUSE_ELANTECH;
+		tp_dev->id.version = 0x0000;
+		tp_dev->dev.parent = &psmouse->ps2dev.serio->dev;
+		tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+		tp_dev->relbit[BIT_WORD(REL_X)] =
+			BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+		tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
+			BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+			BIT_MASK(BTN_RIGHT);
+		error = input_register_device(etd->tp_dev);
+		if (error < 0)
+			goto init_fail_tp_reg;
+	}
+
 	psmouse->protocol_handler = elantech_process_byte;
 	psmouse->disconnect = elantech_disconnect;
 	psmouse->reconnect = elantech_reconnect;
 	psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
 
 	return 0;
-
+ init_fail_tp_reg:
+	input_free_device(tp_dev);
+ init_fail_tp_alloc:
+	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
+			   &elantech_attr_group);
  init_fail:
 	kfree(etd);
-	return -1;
+	return error;
 }
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 9e0e2a1..e410336 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 *tp_dev;	/* Relative device for trackpoint */
+	char	tp_phys[32];
 	unsigned char reg_07;
 	unsigned char reg_10;
 	unsigned char reg_11;
-- 
2.1.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails
  2014-08-20 18:18 [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Ulrik De Bie
  2014-08-20 18:18 ` [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models Ulrik De Bie
@ 2014-08-20 18:18 ` Ulrik De Bie
  2014-08-23  0:11   ` Dmitry Torokhov
  2014-08-21 18:04 ` [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Dmitry Torokhov
  2 siblings, 1 reply; 8+ messages in thread
From: Ulrik De Bie @ 2014-08-20 18:18 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Hans de Goede, David Herrmann, ulrik.debie-os

elantech_init() calls elantech_set_absolute_mode which sets the driver in
an absolute mode. When after this the elantech_init fails, it is best
to turn the ps/2 mouse emulation mode back on by calling psmouse_reset()
so that it can work as a regular mouse.

Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
---
 drivers/input/mouse/elantech.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 5dd620a..771291c 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1620,6 +1620,7 @@ int elantech_init(struct psmouse *psmouse)
 	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
 			   &elantech_attr_group);
  init_fail:
+	psmouse_reset(psmouse);
 	kfree(etd);
 	return error;
 }
-- 
2.1.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530
  2014-08-20 18:18 [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Ulrik De Bie
  2014-08-20 18:18 ` [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models Ulrik De Bie
  2014-08-20 18:18 ` [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails Ulrik De Bie
@ 2014-08-21 18:04 ` Dmitry Torokhov
  2 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2014-08-21 18:04 UTC (permalink / raw)
  To: Ulrik De Bie; +Cc: linux-input, Hans de Goede, David Herrmann

Hi Ulrik,
On Wed, Aug 20, 2014 at 08:18:10PM +0200, Ulrik De Bie wrote:
> Hi Dmitry,
> 
> I posted these 2 months ago, but haven't seen any comments from you.
> Could you please review these ?

I will try to go over them by the end of this week, if you do not hear from me
please do not hesitate to ping me again.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails
  2014-08-20 18:18 ` [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails Ulrik De Bie
@ 2014-08-23  0:11   ` Dmitry Torokhov
  0 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2014-08-23  0:11 UTC (permalink / raw)
  To: Ulrik De Bie; +Cc: linux-input, Hans de Goede, David Herrmann

On Wed, Aug 20, 2014 at 08:18:12PM +0200, Ulrik De Bie wrote:
> elantech_init() calls elantech_set_absolute_mode which sets the driver in
> an absolute mode. When after this the elantech_init fails, it is best
> to turn the ps/2 mouse emulation mode back on by calling psmouse_reset()
> so that it can work as a regular mouse.
> 
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>

Applied, thank you.

> ---
>  drivers/input/mouse/elantech.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index 5dd620a..771291c 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
> @@ -1620,6 +1620,7 @@ int elantech_init(struct psmouse *psmouse)
>  	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
>  			   &elantech_attr_group);
>   init_fail:
> +	psmouse_reset(psmouse);
>  	kfree(etd);
>  	return error;
>  }
> -- 
> 2.1.0.rc1
> 

-- 
Dmitry

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models
  2014-08-20 18:18 ` [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models Ulrik De Bie
@ 2014-08-24 22:14   ` Dmitry Torokhov
  2014-08-26 19:30     ` [PATCH 1/1] Input: elantech: Correct the sign of the x/y movement for trackpoint Ulrik De Bie
  0 siblings, 1 reply; 8+ messages in thread
From: Dmitry Torokhov @ 2014-08-24 22:14 UTC (permalink / raw)
  To: Ulrik De Bie; +Cc: linux-input, Hans de Goede, David Herrmann

Hi Ulrik,

On Wed, Aug 20, 2014 at 08:18:11PM +0200, Ulrik De Bie wrote:
> +
> +	t = (((u32)packet[0] & 0xF8) << 24) | ((u32)packet[1] << 16)
> +		| (u32)packet[2] << 8 | (u32)packet[3];

Majority of devices with Elantech will be little-endian devices, so if we use
get_unaligned_le32() we'll save a few ops. Does the version of patch below
still work for you?

Thanks!

-- 
Dmitry


Input: elantech - add support for trackpoint found on some v3 models

From: Ulrik De Bie <ulrik.debie-os@e2big.org>

Some elantech v3 touchpad equipped laptops also have a trackpoint, before
this commit, these give sync errors. With this patch, the trackpoint is
provided as another input device: 'Elantech PS/2 TrackPoint'

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 Lenovo L530 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.

Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/mouse/elantech.c |  136 +++++++++++++++++++++++++++++++++++++---
 drivers/input/mouse/elantech.h |    3 +
 2 files changed, 130 insertions(+), 9 deletions(-)

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index ee2a04d..b4d645a 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -18,6 +18,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <asm/unaligned.h>
 #include "psmouse.h"
 #include "elantech.h"
 
@@ -403,6 +404,68 @@ 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 *tp_dev = etd->tp_dev;
+	unsigned char *packet = psmouse->packet;
+	int x, y;
+	u32 t;
+
+	if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev,
+			  !tp_dev,
+			  psmouse_fmt("Unexpected trackpoint message\n"))) {
+		if (etd->debug == 1)
+			elantech_packet_dump(psmouse);
+		return;
+	}
+
+	t = get_unaligned_le32(&packet[0]);
+
+	switch (t & ~7U) {
+	case 0x06000030U:
+	case 0x16008020U:
+	case 0x26800010U:
+	case 0x36808000U:
+		x = packet[4] - (int)(packet[1] << 1);
+		y = (int)(packet[2] << 1) - packet[5];
+
+		input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
+		input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
+		input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
+
+		input_report_rel(tp_dev, REL_X, x);
+		input_report_rel(tp_dev, REL_Y, y);
+
+		input_sync(tp_dev);
+
+		break;
+
+	default:
+		/* Dump unexpected packet sequences if debug=1 (default) */
+		if (etd->debug == 1)
+			elantech_packet_dump(psmouse);
+
+		break;
+	}
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 3. (12 byte packets for two fingers)
@@ -715,6 +778,8 @@ 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;
@@ -791,14 +856,23 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 
 	case 3:
 		packet_type = elantech_packet_check_v3(psmouse);
-		/* ignore debounce */
-		if (packet_type == PACKET_DEBOUNCE)
-			return PSMOUSE_FULL_PACKET;
-
-		if (packet_type == PACKET_UNKNOWN)
+		switch (packet_type) {
+		case PACKET_UNKNOWN:
 			return PSMOUSE_BAD_DATA;
 
-		elantech_report_absolute_v3(psmouse, packet_type);
+		case PACKET_DEBOUNCE:
+			/* ignore debounce */
+			break;
+
+		case PACKET_TRACKPOINT:
+			elantech_report_trackpoint(psmouse, packet_type);
+			break;
+
+		default:
+			elantech_report_absolute_v3(psmouse, packet_type);
+			break;
+		}
+
 		break;
 
 	case 4:
@@ -1018,8 +1092,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Asus UX31               0x361f00        20, 15, 0e      clickpad
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
+ * Lenovo L530             0x350f02        b9, 15, 0c      2 hw buttons (*)
  * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons
  * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad
  * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad
@@ -1029,6 +1105,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Samsung RF710           0x450f00        ?               2 hw buttons
  * System76 Pangolin       0x250f01        ?               2 hw buttons
  * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
  */
 static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
 {
@@ -1324,6 +1402,10 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
  */
 static void elantech_disconnect(struct psmouse *psmouse)
 {
+	struct elantech_data *etd = psmouse->private;
+
+	if (etd->tp_dev)
+		input_unregister_device(etd->tp_dev);
 	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
 			   &elantech_attr_group);
 	kfree(psmouse->private);
@@ -1438,8 +1520,10 @@ static int elantech_set_properties(struct elantech_data *etd)
 int elantech_init(struct psmouse *psmouse)
 {
 	struct elantech_data *etd;
-	int i, error;
+	int i;
+	int error = -EINVAL;
 	unsigned char param[3];
+	struct input_dev *tp_dev;
 
 	psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
 	if (!etd)
@@ -1498,14 +1582,48 @@ int elantech_init(struct psmouse *psmouse)
 		goto init_fail;
 	}
 
+	/* The MSB indicates the presence of the trackpoint */
+	if ((etd->capabilities[0] & 0x80) == 0x80) {
+		tp_dev = input_allocate_device();
+
+		if (!tp_dev) {
+			error = -ENOMEM;
+			goto init_fail_tp_alloc;
+		}
+
+		etd->tp_dev = tp_dev;
+		snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1",
+			psmouse->ps2dev.serio->phys);
+		tp_dev->phys = etd->tp_phys;
+		tp_dev->name = "Elantech PS/2 TrackPoint";
+		tp_dev->id.bustype = BUS_I8042;
+		tp_dev->id.vendor  = 0x0002;
+		tp_dev->id.product = PSMOUSE_ELANTECH;
+		tp_dev->id.version = 0x0000;
+		tp_dev->dev.parent = &psmouse->ps2dev.serio->dev;
+		tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+		tp_dev->relbit[BIT_WORD(REL_X)] =
+			BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+		tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
+			BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+			BIT_MASK(BTN_RIGHT);
+		error = input_register_device(etd->tp_dev);
+		if (error < 0)
+			goto init_fail_tp_reg;
+	}
+
 	psmouse->protocol_handler = elantech_process_byte;
 	psmouse->disconnect = elantech_disconnect;
 	psmouse->reconnect = elantech_reconnect;
 	psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
 
 	return 0;
-
+ init_fail_tp_reg:
+	input_free_device(tp_dev);
+ init_fail_tp_alloc:
+	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
+			   &elantech_attr_group);
  init_fail:
 	kfree(etd);
-	return -1;
+	return error;
 }
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 9e0e2a1..6f3afec 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 *tp_dev;	/* Relative device for trackpoint */
+	char tp_phys[32];
 	unsigned char reg_07;
 	unsigned char reg_10;
 	unsigned char reg_11;

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 1/1] Input: elantech: Correct the sign of the x/y movement for trackpoint
  2014-08-24 22:14   ` Dmitry Torokhov
@ 2014-08-26 19:30     ` Ulrik De Bie
  2014-08-26 22:45       ` Dmitry Torokhov
  0 siblings, 1 reply; 8+ messages in thread
From: Ulrik De Bie @ 2014-08-26 19:30 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Hans de Goede, David Herrmann, ulrik.debie-os

Hi Dmitry,

Thank you for your feedback !

The x/y movement calculation was wrong, probably caused by my wrong documentation at the beginning of the elantech_report_trackpoint function.
When applying this patch to your patch, it works.

Thanks !
--
Ulrik

Input: elantech: Correct the sign of the x/y movement for trackpoint

From: Ulrik De Bie <ulrik.debie-os@e2big.org>

The sign bit in the documentation of the trackpoint x/y movement is corrected.
The sign bit in the calculation of the x/y movement for trackpoint is corrected.

Signed-off-by: Ulrik De Bie <ulrik.debie-os@e2big.org>
---
 drivers/input/mouse/elantech.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index b4d645a..63533e5 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -408,10 +408,10 @@ 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 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
 	 *
@@ -443,8 +443,8 @@ static void elantech_report_trackpoint(struct psmouse *psmouse,
 	case 0x16008020U:
 	case 0x26800010U:
 	case 0x36808000U:
-		x = packet[4] - (int)(packet[1] << 1);
-		y = (int)(packet[2] << 1) - packet[5];
+		x = packet[4] - (int)((packet[1]^0x80) << 1);
+		y = (int)((packet[2]^0x80) << 1) - packet[5];
 
 		input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
 		input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
-- 
2.1.0.rc1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/1] Input: elantech: Correct the sign of the x/y movement for trackpoint
  2014-08-26 19:30     ` [PATCH 1/1] Input: elantech: Correct the sign of the x/y movement for trackpoint Ulrik De Bie
@ 2014-08-26 22:45       ` Dmitry Torokhov
  0 siblings, 0 replies; 8+ messages in thread
From: Dmitry Torokhov @ 2014-08-26 22:45 UTC (permalink / raw)
  To: Ulrik De Bie; +Cc: linux-input, Hans de Goede, David Herrmann

Hi Ulrik,

On Tue, Aug 26, 2014 at 09:30:23PM +0200, Ulrik De Bie wrote:
> Hi Dmitry,
> 
> Thank you for your feedback !
> 
> The x/y movement calculation was wrong, probably caused by my wrong
> documentation at the beginning of the elantech_report_trackpoint
> function.  When applying this patch to your patch, it works.

Thank you for testing and providing both the original patch and the
fixup. I folded everything together and applied, I'll try to get it in
3.17.

Thanks!

-- 
Dmitry

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-08-26 22:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-20 18:18 [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Ulrik De Bie
2014-08-20 18:18 ` [PATCH RESEND v4 1/2] elantech: Add support for trackpoint found on some v3 models Ulrik De Bie
2014-08-24 22:14   ` Dmitry Torokhov
2014-08-26 19:30     ` [PATCH 1/1] Input: elantech: Correct the sign of the x/y movement for trackpoint Ulrik De Bie
2014-08-26 22:45       ` Dmitry Torokhov
2014-08-20 18:18 ` [PATCH RESEND v4 2/2] elantech: Call psmouse_reset when elantech probe fails Ulrik De Bie
2014-08-23  0:11   ` Dmitry Torokhov
2014-08-21 18:04 ` [PATCH RESEND v4 0/2] Input: Support in the elantech driver of the trackpoint present on for instance Lenovo L530 Dmitry Torokhov

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).