linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad
@ 2013-09-13  4:03 Yunkang Tang
  2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Yunkang Tang @ 2013-09-13  4:03 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: yunkang.tang, linux-input

Hi all,

Here is the v2 of improving ALPS v5 protocol device.

Change since v1:
- fix the issue that previous patches were broken by mail system.
- split the modification to 2 patches.
- Change dev2's name to "ALPS PS/2 Device"

Best Regards,
Tommy


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

* [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-09-13  4:03 [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
@ 2013-09-13  4:03 ` Yunkang Tang
  2013-10-13 16:23   ` Kevin Cernekee
  2013-10-16  6:54   ` Dmitry Torokhov
  2013-09-13  4:03 ` [PATCH v2 2/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
  2013-10-16  9:37 ` [PATCH v2 0/2] " Justin Clift
  2 siblings, 2 replies; 9+ messages in thread
From: Yunkang Tang @ 2013-09-13  4:03 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: yunkang.tang, linux-input

From: Yunkang Tang <yunkang.tang@cn.alps.com>

- Add an addition argument for decode routine, new devices need this info.
- Change the dev2's name from "PS/2 Mouse" to "ALPS PS/2 Device".

Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
 drivers/input/mouse/alps.c | 17 ++++++++++-------
 drivers/input/mouse/alps.h |  5 +++--
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7c5d72a..7e8a4fb 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -461,7 +461,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
 	f->ts_middle = !!(p[3] & 0x40);
 }
 
-static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+				 struct psmouse *psmouse)
 {
 	f->first_mp = !!(p[4] & 0x40);
 	f->is_mp = !!(p[0] & 0x40);
@@ -482,15 +483,17 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
 	alps_decode_buttons_v3(f, p);
 }
 
-static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+				 struct psmouse *psmouse)
 {
-	alps_decode_pinnacle(f, p);
+	alps_decode_pinnacle(f, p, psmouse);
 
 	f->x_map |= (p[5] & 0x10) << 11;
 	f->y_map |= (p[5] & 0x20) << 6;
 }
 
-static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+				struct psmouse *psmouse)
 {
 	f->first_mp = !!(p[0] & 0x02);
 	f->is_mp = !!(p[0] & 0x20);
@@ -523,7 +526,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
 	int fingers = 0, bmap_fingers;
 	struct alps_fields f;
 
-	priv->decode_fields(&f, packet);
+	priv->decode_fields(&f, packet, psmouse);
 
 	/*
 	 * There's no single feature of touchpad position and bitmap packets
@@ -552,7 +555,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
 				fingers = bmap_fingers;
 
 			/* Now process position packet */
-			priv->decode_fields(&f, priv->multi_data);
+			priv->decode_fields(&f, priv->multi_data, psmouse);
 		} else {
 			priv->multi_packet = 0;
 		}
@@ -1792,7 +1795,7 @@ int alps_init(struct psmouse *psmouse)
 	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
 	dev2->phys = priv->phys;
 	dev2->name = (priv->flags & ALPS_DUALPOINT) ?
-		     "DualPoint Stick" : "PS/2 Mouse";
+		     "DualPoint Stick" : "ALPS PS/2 Device";
 	dev2->id.bustype = BUS_I8042;
 	dev2->id.vendor  = 0x0002;
 	dev2->id.product = PSMOUSE_ALPS;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index eee5985..cdc10f3 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -69,7 +69,7 @@ struct alps_nibble_commands {
  * @y: Y position for ST.
  * @z: Z position for ST.
  * @first_mp: Packet is the first of a multi-packet report.
- * @is_mp: Packet is part of a multi-packet report.
+ * @is_mp: Packet is the last of a multi-packet report.
  * @left: Left touchpad button is active.
  * @right: Right touchpad button is active.
  * @middle: Middle touchpad button is active.
@@ -145,7 +145,8 @@ struct alps_data {
 
 	int (*hw_init)(struct psmouse *psmouse);
 	void (*process_packet)(struct psmouse *psmouse);
-	void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+	void (*decode_fields)(struct alps_fields *f, unsigned char *p,
+			      struct psmouse *psmouse);
 	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
 
 	int prev_fin;
-- 
1.8.1.2


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

* [PATCH v2 2/2] Improve the performance of alps v5-protocol's touchpad
  2013-09-13  4:03 [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
  2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
@ 2013-09-13  4:03 ` Yunkang Tang
  2013-10-16  9:37 ` [PATCH v2 0/2] " Justin Clift
  2 siblings, 0 replies; 9+ messages in thread
From: Yunkang Tang @ 2013-09-13  4:03 UTC (permalink / raw)
  To: dmitry.torokhov; +Cc: yunkang.tang, linux-input

From: Yunkang Tang <yunkang.tang@cn.alps.com>

- Calculate the device's dimension in alps_identify().
- Change the logic of packet decoding.
- Add the new data process logic.

Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
 drivers/input/mouse/alps.c | 278 ++++++++++++++++++++++++++++++++++++++++++---
 drivers/input/mouse/alps.h |   4 +
 2 files changed, 264 insertions(+), 18 deletions(-)

diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7e8a4fb..86c956a 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -257,6 +257,75 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
 }
 
 /*
+ * Process bitmap data for V5 protocols. Return value is null.
+ *
+ * The bitmaps don't have enough data to track fingers, so this function
+ * only generates points representing a bounding box of at most two contacts.
+ * These two points are returned in x1, y1, x2, and y2.
+ */
+static void alps_process_bitmap_dolphin(struct alps_data *priv,
+					struct alps_fields *fields,
+					int *x1, int *y1, int *x2, int *y2)
+{
+	struct alps_palm_bitmap {
+		int start_bit;
+		int end_bit;
+	};
+
+	int i;
+	int box_middle_x, box_middle_y;
+	unsigned int x_map, y_map;
+	struct alps_palm_bitmap x_bitmap = {0}, y_bitmap = {0};
+
+	x_map = fields->x_map;
+	y_map = fields->y_map;
+
+	if (!x_map || !y_map)
+		return;
+
+	*x1 = *y1 = *x2 = *y2 = 0;
+
+	if (fields->fingers > 1) {
+		for (i = 0;  i < 32; i++) {
+			if (x_map & (1 << i)) {
+				x_bitmap.end_bit = priv->x_bits - i;
+				break;
+			}
+		}
+
+		for (i = 31; i >= 0; i--) {
+			if (x_map & (1 << i)) {
+				x_bitmap.start_bit = priv->x_bits - i;
+				break;
+			}
+		}
+
+		for (i = 0;  i < 32; i++) {
+			if (y_map & (1 << i)) {
+				y_bitmap.start_bit = i;
+				break;
+			}
+		}
+
+		for (i = 31; i >= 0; i--) {
+			if (y_map & (1 << i)) {
+				y_bitmap.end_bit = i;
+				break;
+			}
+		}
+
+		box_middle_x = (priv->x_max * (x_bitmap.start_bit + x_bitmap.end_bit)) /
+				(2 * (priv->x_bits - 1));
+		box_middle_y = (priv->y_max * (y_bitmap.start_bit + y_bitmap.end_bit)) /
+				(2 * (priv->y_bits - 1));
+		*x1 = fields->x;
+		*y1 = fields->y;
+		*x2 = 2 * box_middle_x - *x1;
+		*y2 = 2 * box_middle_y - *y1;
+	}
+}
+
+/*
  * Process bitmap data from v3 and v4 protocols. Returns the number of
  * fingers detected. A return value of 0 means at least one of the
  * bitmaps was empty.
@@ -495,25 +564,55 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
 static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 				struct psmouse *psmouse)
 {
+	unsigned int palm_high = 0, palm_low = 0, palm_mask = 0;
+	int i, remain_xbits;
+	struct alps_data *priv = psmouse->private;
+
 	f->first_mp = !!(p[0] & 0x02);
 	f->is_mp = !!(p[0] & 0x20);
 
-	f->fingers = ((p[0] & 0x6) >> 1 |
+	if (!f->is_mp) {
+		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
+		alps_decode_buttons_v3(f, p);
+	} else {
+		f->fingers = ((p[0] & 0x6) >> 1 |
 		     (p[0] & 0x10) >> 2);
-	f->x_map = ((p[2] & 0x60) >> 5) |
-		   ((p[4] & 0x7f) << 2) |
-		   ((p[5] & 0x7f) << 9) |
-		   ((p[3] & 0x07) << 16) |
-		   ((p[3] & 0x70) << 15) |
-		   ((p[0] & 0x01) << 22);
-	f->y_map = (p[1] & 0x7f) |
-		   ((p[2] & 0x1f) << 7);
-
-	f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
-	f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
-	f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
 
-	alps_decode_buttons_v3(f, p);
+		palm_low = (p[1] & 0x7f) |
+			   ((p[2] & 0x7f) << 7) |
+			   ((p[4] & 0x7f) << 14) |
+			   ((p[5] & 0x7f) << 21) |
+			   ((p[3] & 0x07) << 28) | ((p[3] & 0x10) << 27);
+		palm_high = ((p[3] & 0x60) >> 5) | ((p[0] & 0x01) << 2);
+
+		for (i = 0; i < priv->y_bits; i++)
+			palm_mask |= 1 << i;
+
+		/* Y-profile is stored in P(0) to p(n), n = y_bits; */
+		f->y_map = palm_low & palm_mask;
+
+		/* X-profile is stored in p(n) to p(n+x_bits). */
+		palm_mask = 0;
+		for (i = priv->y_bits; i < 32 && i < priv->y_bits + priv->x_bits; i++)
+			palm_mask |= 1 << i;
+
+		f->x_map = ((palm_low & (palm_mask)) >> priv->y_bits);
+
+		/*
+		 * In some cases, palm_low's 32bit is not enough to save
+		 * all X&Y-profiles, we need to use palm_high.
+		 */
+		remain_xbits = priv->x_bits + priv->y_bits - 32;
+		if (remain_xbits > 0) {
+			palm_mask = 0;
+			for (i = 0; i < remain_xbits; i++)
+				palm_mask |= 1 << i;
+
+			f->x_map |= ((palm_high & palm_mask) << (32 - priv->y_bits));
+		}
+	}
 }
 
 static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
@@ -745,6 +844,112 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
 	input_sync(dev);
 }
 
+
+static void alps_process_touchpad_packet_v5(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = psmouse->dev;
+	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+	int fingers = 0;
+	struct alps_fields f;
+
+	priv->decode_fields(&f, packet, psmouse);
+
+	/*
+	 * There's no single feature of touchpad position and bitmap packets
+	 * that can be used to distinguish between them. We rely on the fact
+	 * that a bitmap packet should always follow a position packet with
+	 * bit 6 of packet[4] set.
+	 */
+	if (priv->multi_packet) {
+		/*
+		 * Sometimes a position packet will indicate a multi-packet
+		 * sequence, but then what follows is another position
+		 * packet. Check for this, and when it happens process the
+		 * position packet as usual.
+		 */
+		if (f.is_mp) {
+			fingers = f.fingers;
+			priv->decode_fields(&f, priv->multi_data, psmouse);
+			alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+						    &x2, &y2);
+		} else {
+			priv->multi_packet = 0;
+		}
+	}
+
+	/*
+	 * Bit 6 of byte 0 is not usually set in position packets. The only
+	 * times it seems to be set is in situations where the data is
+	 * suspect anyway, e.g. a palm resting flat on the touchpad. Given
+	 * this combined with the fact that this bit is useful for filtering
+	 * out misidentified bitmap packets, we reject anything with this
+	 * bit set.
+	 */
+	if (f.is_mp)
+		return;
+
+	if (!priv->multi_packet && f.first_mp) {
+		priv->multi_packet = 1;
+		memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+		return;
+	}
+
+	priv->multi_packet = 0;
+
+	/*
+	 * Sometimes the hardware sends a single packet with z = 0
+	 * in the middle of a stream. Real releases generate packets
+	 * with x, y, and z all zero, so these seem to be flukes.
+	 * Ignore them.
+	 */
+	if (f.x && f.y && !f.z)
+		return;
+
+	/*
+	 * If we don't have MT data or the bitmaps were empty, we have
+	 * to rely on ST data.
+	 */
+	if (!fingers) {
+		x1 = f.x;
+		y1 = f.y;
+		fingers = f.z > 0 ? 1 : 0;
+	}
+
+	if (f.z >= 64)
+		input_report_key(dev, BTN_TOUCH, 1);
+	else
+		input_report_key(dev, BTN_TOUCH, 0);
+
+	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+	input_mt_report_finger_count(dev, fingers);
+
+	input_report_key(dev, BTN_LEFT, f.left);
+	input_report_key(dev, BTN_RIGHT, f.right);
+	input_report_key(dev, BTN_MIDDLE, f.middle);
+
+	if (f.z > 0) {
+		input_report_abs(dev, ABS_X, f.x);
+		input_report_abs(dev, ABS_Y, f.y);
+	}
+	input_report_abs(dev, ABS_PRESSURE, f.z);
+
+	input_sync(dev);
+}
+
+static void alps_process_packet_v5(struct psmouse *psmouse)
+{
+	unsigned char *packet = psmouse->packet;
+
+	/* Ignore stick point data */
+	if (packet[0] == 0xD8)
+		return;
+
+	alps_process_touchpad_packet_v5(psmouse);
+}
+
 static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 					unsigned char packet[],
 					bool report_buttons)
@@ -1522,6 +1727,41 @@ error:
 	return -1;
 }
 
+static int alps_dolphin_get_device_area(struct psmouse *psmouse,
+					struct alps_data *priv)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char param[4] = {0};
+	int num_x_electrode, num_y_electrode;
+
+	if (alps_enter_command_mode(psmouse))
+		return -1;
+
+	if (ps2_command(ps2dev, NULL, 0x00EC) ||
+	    ps2_command(ps2dev, NULL, 0x00F0) ||
+	    ps2_command(ps2dev, NULL, 0x00F0) ||
+	    ps2_command(ps2dev, NULL, 0x00F3) ||
+	    ps2_command(ps2dev, NULL, 0x000A) ||
+	    ps2_command(ps2dev, NULL, 0x00F3) ||
+	    ps2_command(ps2dev, NULL, 0x000A))
+		return -1;
+
+	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+		return -1;
+
+	num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
+	num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
+	priv->x_bits = num_x_electrode;
+	priv->y_bits = num_y_electrode;
+	priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+	priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+
+	if (alps_exit_command_mode(psmouse))
+		return -1;
+
+	return 0;
+}
+
 static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
 {
 	struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -1574,7 +1814,7 @@ static void alps_set_defaults(struct alps_data *priv)
 		break;
 	case ALPS_PROTO_V5:
 		priv->hw_init = alps_hw_init_dolphin_v1;
-		priv->process_packet = alps_process_packet_v3;
+		priv->process_packet = alps_process_packet_v5;
 		priv->decode_fields = alps_decode_dolphin;
 		priv->set_abs_params = alps_set_abs_params_mt;
 		priv->nibble_commands = alps_v3_nibble_commands;
@@ -1648,11 +1888,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 	if (alps_match_table(psmouse, priv, e7, ec) == 0) {
 		return 0;
 	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
-		   ec[0] == 0x73 && ec[1] == 0x01) {
+		   ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
 		priv->proto_version = ALPS_PROTO_V5;
 		alps_set_defaults(priv);
-
-		return 0;
+		if (alps_dolphin_get_device_area(psmouse, priv))
+			return -EIO;
+		else
+			return 0;
 	} else if (ec[0] == 0x88 && ec[1] == 0x08) {
 		priv->proto_version = ALPS_PROTO_V3;
 		alps_set_defaults(priv);
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index cdc10f3..43d89fc7 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -18,6 +18,10 @@
 #define ALPS_PROTO_V4	4
 #define ALPS_PROTO_V5	5
 
+#define DOLPHIN_COUNT_PER_ELECTRODE	64
+#define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
+#define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */
+
 /**
  * struct alps_model_info - touchpad ID table
  * @signature: E7 response string to match.
-- 
1.8.1.2


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

* Re: [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
@ 2013-10-13 16:23   ` Kevin Cernekee
  2013-10-14  5:50     ` Will Tommy
  2013-10-16  6:54   ` Dmitry Torokhov
  1 sibling, 1 reply; 9+ messages in thread
From: Kevin Cernekee @ 2013-10-13 16:23 UTC (permalink / raw)
  To: Yunkang Tang; +Cc: Dmitry Torokhov, yunkang.tang, linux-input, david turvene

> [PATCH v2 2/2] Improve the performance of alps v5-protocol's touchpad
>
> From: Yunkang Tang <yunkang.tang@xxxxxxxxxxx>
>
> - Calculate the device's dimension in alps_identify().
> - Change the logic of packet decoding.
> - Add the new data process logic.
>
> Signed-off-by: Yunkang Tang <yunkang.tang@xxxxxxxxxxx>

Hmm, somehow the [2/2] patch made it into the linux-input list
archives, but linux-input did not forward it to my inbox so I missed
it the first time around.

But thanks for sending these changes.  There has been a great deal of
interest in enhancing ALPS touchpad support, especially for the
Dolphin models.

Some review comments follow:

> ---
>  drivers/input/mouse/alps.c | 278 ++++++++++++++++++++++++++++++++++++++++++---
>  drivers/input/mouse/alps.h |   4 +
>  2 files changed, 264 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index 7e8a4fb..86c956a 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -257,6 +257,75 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
>  }
>
>  /*
> + * Process bitmap data for V5 protocols. Return value is null.
> + *
> + * The bitmaps don't have enough data to track fingers, so this function
> + * only generates points representing a bounding box of at most two contacts.
> + * These two points are returned in x1, y1, x2, and y2.
> + */
> +static void alps_process_bitmap_dolphin(struct alps_data *priv,
> +                    struct alps_fields *fields,
> +                    int *x1, int *y1, int *x2, int *y2)
> +{
> +    struct alps_palm_bitmap {
> +        int start_bit;
> +        int end_bit;
> +    };
> +
> +    int i;
> +    int box_middle_x, box_middle_y;
> +    unsigned int x_map, y_map;
> +    struct alps_palm_bitmap x_bitmap = {0}, y_bitmap = {0};
> +
> +    x_map = fields->x_map;
> +    y_map = fields->y_map;
> +
> +    if (!x_map || !y_map)
> +        return;
> +
> +    *x1 = *y1 = *x2 = *y2 = 0;
> +
> +    if (fields->fingers > 1) {
> +        for (i = 0;  i < 32; i++) {

Extra space after "i = 0;"

> +            if (x_map & (1 << i)) {
> +                x_bitmap.end_bit = priv->x_bits - i;
> +                break;
> +            }
> +        }
> +
> +        for (i = 31; i >= 0; i--) {
> +            if (x_map & (1 << i)) {
> +                x_bitmap.start_bit = priv->x_bits - i;
> +                break;
> +            }
> +        }
> +
> +        for (i = 0;  i < 32; i++) {

Same here

> +            if (y_map & (1 << i)) {
> +                y_bitmap.start_bit = i;
> +                break;
> +            }
> +        }

So, assuming x_bits == y_bits == 8, and both x_map and y_map are in
the range 0x00..0xff:

y_bitmap.* lies in the range 0..7
x_bitmap.* lies in the range 1..8

Is that correct, or is x_bitmap off by one?

> +        for (i = 31; i >= 0; i--) {
> +            if (y_map & (1 << i)) {
> +                y_bitmap.end_bit = i;
> +                break;
> +            }
> +        }

I suspect that this whole function could be simplified a bit.

Would it be possible to use ffs() and fls() instead of loops?

Just a personal preference, but if you calculated X first and then Y,
it may require fewer temporary variables and the alps_palm_bitmap
struct could be removed.

> +
> +        box_middle_x = (priv->x_max * (x_bitmap.start_bit + x_bitmap.end_bit)) /
> +                (2 * (priv->x_bits - 1));
> +        box_middle_y = (priv->y_max * (y_bitmap.start_bit + y_bitmap.end_bit)) /
> +                (2 * (priv->y_bits - 1));

These lines look a bit long - suggest running through checkpatch.pl

I assume start_bit and end_bit can never be negative, because the code
that calculates e.g. x_map will populate at most bits 0..(x_bits-1)?

> +        *x1 = fields->x;
> +        *y1 = fields->y;
> +        *x2 = 2 * box_middle_x - *x1;
> +        *y2 = 2 * box_middle_y - *y1;
> +    }
> +}
> +
> +/*
>   * Process bitmap data from v3 and v4 protocols. Returns the number of
>   * fingers detected. A return value of 0 means at least one of the
>   * bitmaps was empty.
> @@ -495,25 +564,55 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
>  static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
>                  struct psmouse *psmouse)
>  {
> +    unsigned int palm_high = 0, palm_low = 0, palm_mask = 0;
> +    int i, remain_xbits;
> +    struct alps_data *priv = psmouse->private;
> +
>      f->first_mp = !!(p[0] & 0x02);
>      f->is_mp = !!(p[0] & 0x20);
>
> -    f->fingers = ((p[0] & 0x6) >> 1 |
> +    if (!f->is_mp) {
> +        f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> +        f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> +        f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> +        alps_decode_buttons_v3(f, p);
> +    } else {
> +        f->fingers = ((p[0] & 0x6) >> 1 |
>               (p[0] & 0x10) >> 2);
> -    f->x_map = ((p[2] & 0x60) >> 5) |
> -           ((p[4] & 0x7f) << 2) |
> -           ((p[5] & 0x7f) << 9) |
> -           ((p[3] & 0x07) << 16) |
> -           ((p[3] & 0x70) << 15) |
> -           ((p[0] & 0x01) << 22);
> -    f->y_map = (p[1] & 0x7f) |
> -           ((p[2] & 0x1f) << 7);
> -
> -    f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> -    f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> -    f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>
> -    alps_decode_buttons_v3(f, p);
> +        palm_low = (p[1] & 0x7f) |
> +               ((p[2] & 0x7f) << 7) |
> +               ((p[4] & 0x7f) << 14) |
> +               ((p[5] & 0x7f) << 21) |
> +               ((p[3] & 0x07) << 28) | ((p[3] & 0x10) << 27);
> +        palm_high = ((p[3] & 0x60) >> 5) | ((p[0] & 0x01) << 2);
> +
> +        for (i = 0; i < priv->y_bits; i++)
> +            palm_mask |= 1 << i;
> +
> +        /* Y-profile is stored in P(0) to p(n), n = y_bits; */
> +        f->y_map = palm_low & palm_mask;

Suggest something like:

f->y_map = palm_low & (BIT(priv->y_bits) - 1);

> +
> +        /* X-profile is stored in p(n) to p(n+x_bits). */
> +        palm_mask = 0;
> +        for (i = priv->y_bits; i < 32 && i < priv->y_bits + priv->x_bits; i++)
> +            palm_mask |= 1 << i;
> +
> +        f->x_map = ((palm_low & (palm_mask)) >> priv->y_bits);

Likewise, maybe use:

f->x_map = (palm_low >> priv->y_bits) & (BIT(priv->x_bits) - 1);

(but double-check my math first)

> +
> +        /*
> +         * In some cases, palm_low's 32bit is not enough to save
> +         * all X&Y-profiles, we need to use palm_high.
> +         */
> +        remain_xbits = priv->x_bits + priv->y_bits - 32;
> +        if (remain_xbits > 0) {
> +            palm_mask = 0;
> +            for (i = 0; i < remain_xbits; i++)
> +                palm_mask |= 1 << i;
> +
> +            f->x_map |= ((palm_high & palm_mask) << (32 - priv->y_bits));

Would it be cleaner to just use a u64 for the palm data, instead of
splitting into low/high?  (If so you'll probably want to compile-test
a 32-bit kernel.)

> +        }
> +    }
>  }
>
>  static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
> @@ -745,6 +844,112 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
>      input_sync(dev);
>  }
>
> +
> +static void alps_process_touchpad_packet_v5(struct psmouse *psmouse)
> +{
> +    struct alps_data *priv = psmouse->private;
> +    unsigned char *packet = psmouse->packet;
> +    struct input_dev *dev = psmouse->dev;
> +    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> +    int fingers = 0;
> +    struct alps_fields f;
> +
> +    priv->decode_fields(&f, packet, psmouse);
> +
> +    /*
> +     * There's no single feature of touchpad position and bitmap packets
> +     * that can be used to distinguish between them. We rely on the fact
> +     * that a bitmap packet should always follow a position packet with
> +     * bit 6 of packet[4] set.
> +     */
> +    if (priv->multi_packet) {
> +        /*
> +         * Sometimes a position packet will indicate a multi-packet
> +         * sequence, but then what follows is another position
> +         * packet. Check for this, and when it happens process the
> +         * position packet as usual.
> +         */
> +        if (f.is_mp) {
> +            fingers = f.fingers;
> +            priv->decode_fields(&f, priv->multi_data, psmouse);
> +            alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
> +                            &x2, &y2);

Aside from this clause, alps_process_touchpad_packet_v5() is virtually
identical to alps_process_touchpad_packet_v3().  It would be good to
find a way to reuse more of the code.

> +        } else {
> +            priv->multi_packet = 0;
> +        }
> +    }
> +
> +    /*
> +     * Bit 6 of byte 0 is not usually set in position packets. The only
> +     * times it seems to be set is in situations where the data is
> +     * suspect anyway, e.g. a palm resting flat on the touchpad. Given
> +     * this combined with the fact that this bit is useful for filtering
> +     * out misidentified bitmap packets, we reject anything with this
> +     * bit set.
> +     */
> +    if (f.is_mp)
> +        return;
> +
> +    if (!priv->multi_packet && f.first_mp) {
> +        priv->multi_packet = 1;
> +        memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
> +        return;
> +    }
> +
> +    priv->multi_packet = 0;
> +
> +    /*
> +     * Sometimes the hardware sends a single packet with z = 0
> +     * in the middle of a stream. Real releases generate packets
> +     * with x, y, and z all zero, so these seem to be flukes.
> +     * Ignore them.
> +     */
> +    if (f.x && f.y && !f.z)
> +        return;
> +
> +    /*
> +     * If we don't have MT data or the bitmaps were empty, we have
> +     * to rely on ST data.
> +     */
> +    if (!fingers) {
> +        x1 = f.x;
> +        y1 = f.y;
> +        fingers = f.z > 0 ? 1 : 0;
> +    }
> +
> +    if (f.z >= 64)
> +        input_report_key(dev, BTN_TOUCH, 1);
> +    else
> +        input_report_key(dev, BTN_TOUCH, 0);
> +
> +    alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +
> +    input_mt_report_finger_count(dev, fingers);
> +
> +    input_report_key(dev, BTN_LEFT, f.left);
> +    input_report_key(dev, BTN_RIGHT, f.right);
> +    input_report_key(dev, BTN_MIDDLE, f.middle);
> +
> +    if (f.z > 0) {
> +        input_report_abs(dev, ABS_X, f.x);
> +        input_report_abs(dev, ABS_Y, f.y);
> +    }
> +    input_report_abs(dev, ABS_PRESSURE, f.z);
> +
> +    input_sync(dev);
> +}
> +
> +static void alps_process_packet_v5(struct psmouse *psmouse)
> +{
> +    unsigned char *packet = psmouse->packet;
> +
> +    /* Ignore stick point data */
> +    if (packet[0] == 0xD8)
> +        return;
> +
> +    alps_process_touchpad_packet_v5(psmouse);
> +}
> +
>  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>                      unsigned char packet[],
>                      bool report_buttons)
> @@ -1522,6 +1727,41 @@ error:
>      return -1;
>  }
>
> +static int alps_dolphin_get_device_area(struct psmouse *psmouse,
> +                    struct alps_data *priv)
> +{
> +    struct ps2dev *ps2dev = &psmouse->ps2dev;
> +    unsigned char param[4] = {0};
> +    int num_x_electrode, num_y_electrode;
> +
> +    if (alps_enter_command_mode(psmouse))
> +        return -1;
> +
> +    if (ps2_command(ps2dev, NULL, 0x00EC) ||
> +        ps2_command(ps2dev, NULL, 0x00F0) ||
> +        ps2_command(ps2dev, NULL, 0x00F0) ||
> +        ps2_command(ps2dev, NULL, 0x00F3) ||
> +        ps2_command(ps2dev, NULL, 0x000A) ||
> +        ps2_command(ps2dev, NULL, 0x00F3) ||
> +        ps2_command(ps2dev, NULL, 0x000A))
> +        return -1;
> +
> +    if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
> +        return -1;
> +
> +    num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
> +    num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);

This is strictly optional, but adding a comment indicating typical
values for num_x_electrode and num_y_electrode could aid in
understanding the math.

> +    priv->x_bits = num_x_electrode;
> +    priv->y_bits = num_y_electrode;
> +    priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> +    priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
> +
> +    if (alps_exit_command_mode(psmouse))
> +        return -1;
> +
> +    return 0;
> +}
> +
>  static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
>  {
>      struct ps2dev *ps2dev = &psmouse->ps2dev;
> @@ -1574,7 +1814,7 @@ static void alps_set_defaults(struct alps_data *priv)
>          break;
>      case ALPS_PROTO_V5:
>          priv->hw_init = alps_hw_init_dolphin_v1;
> -        priv->process_packet = alps_process_packet_v3;
> +        priv->process_packet = alps_process_packet_v5;
>          priv->decode_fields = alps_decode_dolphin;
>          priv->set_abs_params = alps_set_abs_params_mt;
>          priv->nibble_commands = alps_v3_nibble_commands;
> @@ -1648,11 +1888,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
>      if (alps_match_table(psmouse, priv, e7, ec) == 0) {
>          return 0;
>      } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
> -           ec[0] == 0x73 && ec[1] == 0x01) {
> +           ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
>          priv->proto_version = ALPS_PROTO_V5;
>          alps_set_defaults(priv);
> -
> -        return 0;
> +        if (alps_dolphin_get_device_area(psmouse, priv))
> +            return -EIO;
> +        else
> +            return 0;
>      } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>          priv->proto_version = ALPS_PROTO_V3;
>          alps_set_defaults(priv);
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index cdc10f3..43d89fc7 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,6 +18,10 @@
>  #define ALPS_PROTO_V4    4
>  #define ALPS_PROTO_V5    5
>
> +#define DOLPHIN_COUNT_PER_ELECTRODE    64
> +#define DOLPHIN_PROFILE_XOFFSET        8    /* x-electrode offset */
> +#define DOLPHIN_PROFILE_YOFFSET        1    /* y-electrode offset */
> +
>  /**
>   * struct alps_model_info - touchpad ID table
>   * @signature: E7 response string to match.

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

* Re: [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-10-13 16:23   ` Kevin Cernekee
@ 2013-10-14  5:50     ` Will Tommy
  2013-10-14  6:02       ` Kevin Cernekee
  0 siblings, 1 reply; 9+ messages in thread
From: Will Tommy @ 2013-10-14  5:50 UTC (permalink / raw)
  To: Kevin Cernekee; +Cc: Dmitry Torokhov, yunkang.tang, linux-input, david turvene

Hi Kevin,

Thanks for your carefully review. It's amazing !

> So, assuming x_bits == y_bits == 8, and both x_map and y_map are in
> the range 0x00..0xff:
>
> y_bitmap.* lies in the range 0..7
> x_bitmap.* lies in the range 1..8
>
> Is that correct, or is x_bitmap off by one?

Hmm, it seems a bug of algorithm. Both x_bitmay&y_bitmap's range should be 0..7.
I'll fix it.

> I suspect that this whole function could be simplified a bit.
>
> Would it be possible to use ffs() and fls() instead of loops?
>
> Just a personal preference, but if you calculated X first and then Y,
> it may require fewer temporary variables and the alps_palm_bitmap
> struct could be removed.

Thanks for your proposal. I'll re-write this function in next submission.

> > +        box_middle_x = (priv->x_max * (x_bitmap.start_bit + x_bitmap.end_bit)) /
> > +                (2 * (priv->x_bits - 1));
> > +        box_middle_y = (priv->y_max * (y_bitmap.start_bit + y_bitmap.end_bit)) /
> > +                (2 * (priv->y_bits - 1));
> These lines look a bit long - suggest running through checkpatch.pl
>

Yes, they're longer than 80. However, in order not to let code hard to
be understood,
I decided not to split them. Anyway, since this function would be
re-written, there
would be no problem.

> I assume start_bit and end_bit can never be negative, because the code
> that calculates e.g. x_map will populate at most bits 0..(x_bits-1)?

Do you mean it's not good to define start_bit & end_bit as "int" since they have
no chance to be negative ? Actually, "unsigned char" is much better.

> Suggest something like:
>
> f->y_map = palm_low & (BIT(priv->y_bits) - 1);

> Likewise, maybe use:
>
> f->x_map = (palm_low >> priv->y_bits) & (BIT(priv->x_bits) - 1);
>
> (but double-check my math first)

> Would it be cleaner to just use a u64 for the palm data, instead of
> splitting into low/high?  (If so you'll probably want to compile-test
> a 32-bit kernel.)

> Aside from this clause, alps_process_touchpad_packet_v5() is virtually
> identical to alps_process_touchpad_packet_v3().  It would be good to
> find a way to reuse more of the code.

Okay, I'll take your advice and check the behavior on both 32-bit and 64-bit.

> This is strictly optional, but adding a comment indicating typical
> values for num_x_electrode and num_y_electrode could aid in
> understanding the math.

That's a good idea! I'll add them.

Tommy

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

* Re: [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-10-14  5:50     ` Will Tommy
@ 2013-10-14  6:02       ` Kevin Cernekee
  2013-10-14  6:10         ` Tommy Will
  0 siblings, 1 reply; 9+ messages in thread
From: Kevin Cernekee @ 2013-10-14  6:02 UTC (permalink / raw)
  To: Will Tommy; +Cc: Dmitry Torokhov, yunkang.tang, linux-input, david turvene

On Sun, Oct 13, 2013 at 10:50 PM, Will Tommy <tommywill2011@gmail.com> wrote:
>> I assume start_bit and end_bit can never be negative, because the code
>> that calculates e.g. x_map will populate at most bits 0..(x_bits-1)?
>
> Do you mean it's not good to define start_bit & end_bit as "int" since they have
> no chance to be negative ? Actually, "unsigned char" is much better.

No type change needed - I was just checking to make sure it wasn't a
risk, since getting a negative number in there would really throw off
the math...

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

* Re: [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-10-14  6:02       ` Kevin Cernekee
@ 2013-10-14  6:10         ` Tommy Will
  0 siblings, 0 replies; 9+ messages in thread
From: Tommy Will @ 2013-10-14  6:10 UTC (permalink / raw)
  To: Kevin Cernekee; +Cc: Dmitry Torokhov, yunkang.tang, linux-input, david turvene

2013/10/14 Kevin Cernekee <cernekee@gmail.com>:
> On Sun, Oct 13, 2013 at 10:50 PM, Will Tommy <tommywill2011@gmail.com> wrote:
>
> No type change needed - I was just checking to make sure it wasn't a
> risk, since getting a negative number in there would really throw off
> the math...

Got that. Thanks : )

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

* Re: [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
  2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
  2013-10-13 16:23   ` Kevin Cernekee
@ 2013-10-16  6:54   ` Dmitry Torokhov
  1 sibling, 0 replies; 9+ messages in thread
From: Dmitry Torokhov @ 2013-10-16  6:54 UTC (permalink / raw)
  To: Yunkang Tang; +Cc: yunkang.tang, linux-input

Hi Yunkang,

On Fri, Sep 13, 2013 at 12:03:29PM +0800, Yunkang Tang wrote:
> From: Yunkang Tang <yunkang.tang@cn.alps.com>
> 
> - Add an addition argument for decode routine, new devices need this info.
> - Change the dev2's name from "PS/2 Mouse" to "ALPS PS/2 Device".
> 

I carved the name change device out of this patch and applied to my
3.13 queue.

Thanks.

-- 
Dmitry

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

* Re: [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad
  2013-09-13  4:03 [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
  2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
  2013-09-13  4:03 ` [PATCH v2 2/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
@ 2013-10-16  9:37 ` Justin Clift
  2 siblings, 0 replies; 9+ messages in thread
From: Justin Clift @ 2013-10-16  9:37 UTC (permalink / raw)
  To: Yunkang Tang
  Cc: dmitry.torokhov, yunkang.tang, linux-input, Kevin Cernekee,
	Niels de Vos

On 13/09/2013, at 5:03 AM, Yunkang Tang wrote:
> Hi all,
> 
> Here is the v2 of improving ALPS v5 protocol device.
> 
> Change since v1:
> - fix the issue that previous patches were broken by mail system.
> - split the modification to 2 patches.
> - Change dev2's name to "ALPS PS/2 Device"

Thanks Tommy.  We've been trying to get recent ALPS touchpads
working through Red Hat Bugzilla issue 953211.

  https://bugzilla.redhat.com/show_bug.cgi?id=953211

Niels de Vos, CC'd, was kind enough to build a Fedora 19 kernel
with your patch added.  We've been testing it since yesterday.

Your patch works well for several models of laptop (confirmed
success):

 * Dell Inspiron 17R SE / Inspiron 7720
 * Dell Vostro 3360
 * Fujitsu Lifebook AH532

With your patches, the touchpad:

* is recognised as a touchpad
* both KDE and Gnome can control it
* 2 finger scrolling works

That being said, we have conflicting reports about 1 finger
vertical scrolling on the Inspiron 17R SE / Inspiron 7720.

* 1 finger scrolling works on my laptop (Inspiron 17R SE),
  if 2 finger scrolling is NOT enabled in Gnome3 mouse &
  touchpad settings. (seems mutually exclusive)
* 1 finger scrolling does NOT work in KDE (Inspiron 7720)
  * I'm following this up with the reporter, as it may
    turn out to be a KDE settings issue

From my point of view, I'm be happy to see these patches
be applied, and you're welcome to use:

  Tested-by: Justin Clift <jclift@redhat.com>

Side note - Thanks to the people who've tested this and
reported back. :)

* Stanislav Datskevich
* Özgür Gündoğan
* Pentarh Udi
* Arnaud Lacombe
* Gaspard Jankowiak
* myself ;>

Regards and best wishes,

Justin Clift


> Best Regards,
> Tommy

--
Open Source and Standards @ Red Hat

twitter.com/realjustinclift

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

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

end of thread, other threads:[~2013-10-16  9:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-13  4:03 [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
2013-09-13  4:03 ` [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name Yunkang Tang
2013-10-13 16:23   ` Kevin Cernekee
2013-10-14  5:50     ` Will Tommy
2013-10-14  6:02       ` Kevin Cernekee
2013-10-14  6:10         ` Tommy Will
2013-10-16  6:54   ` Dmitry Torokhov
2013-09-13  4:03 ` [PATCH v2 2/2] Improve the performance of alps v5-protocol's touchpad Yunkang Tang
2013-10-16  9:37 ` [PATCH v2 0/2] " Justin Clift

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