* [PATCH 1/2] Input: ALPS Touchpad- Improve the performance of alps v5-protocol's touchpad
@ 2013-09-05 5:50 yunkang.tang
2013-09-09 16:26 ` Dmitry Torokhov
0 siblings, 1 reply; 2+ messages in thread
From: yunkang.tang @ 2013-09-05 5:50 UTC (permalink / raw)
To: linux-input@vger.kernel.org
Cc: dmitry.torokhov@gmail.com, yunkang.tang@cn.alps.com
<Change list>
- Calculate the device's dimension in alps_identify().
- Change the logic of packet decoding.
- Add the new data process logic.
- Change the dev2's name from "PS/2 Mouse" to "ALPS Touchpad".
--- linux-3.11/drivers/input/mouse/alps.c.orig 2013-09-04 19:51:23.585085033 +0800
+++ linux-3.11/drivers/input/mouse/alps.c 2013-09-05 11:58:02.000000000 +0800
@@ -257,6 +257,74 @@ static void alps_process_packet_v1_v2(st
}
/*
+ * 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.
@@ -461,7 +529,7 @@ static void alps_decode_buttons_v3(struc
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,35 +550,65 @@ static void alps_decode_pinnacle(struct
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)
{
+ 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)
@@ -523,7 +621,7 @@ static void alps_process_touchpad_packet
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 +650,7 @@ static void alps_process_touchpad_packet
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;
}
@@ -742,6 +840,111 @@ static void alps_process_packet_v4(struc
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)
@@ -1519,6 +1722,40 @@ 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;
@@ -1571,7 +1808,7 @@ static void alps_set_defaults(struct alp
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;
@@ -1645,11 +1882,13 @@ static int alps_identify(struct psmouse
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);
@@ -1792,7 +2031,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 Touchpad";
dev2->id.bustype = BUS_I8042;
dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
-Tommy
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH 1/2] Input: ALPS Touchpad- Improve the performance of alps v5-protocol's touchpad
2013-09-05 5:50 [PATCH 1/2] Input: ALPS Touchpad- Improve the performance of alps v5-protocol's touchpad yunkang.tang
@ 2013-09-09 16:26 ` Dmitry Torokhov
0 siblings, 0 replies; 2+ messages in thread
From: Dmitry Torokhov @ 2013-09-09 16:26 UTC (permalink / raw)
To: yunkang.tang@cn.alps.com; +Cc: linux-input@vger.kernel.org
Hi Tommy,
On Thu, Sep 05, 2013 at 05:50:48AM +0000, yunkang.tang@cn.alps.com wrote:
> <Change list>
> - Calculate the device's dimension in alps_identify().
> - Change the logic of packet decoding.
> - Add the new data process logic.
It appears that your mailer damaged the patch converting all tabs to
single spaces. Please consider using an alternative MTA (mutt, or maybe
git send-email) to post your patches.
It also apperas that there are several changes (support for never
hardware, tweaks to the older protocols) going rolled into a single
patch, would it be possible to split them into separate patches,
please?
> - Change the dev2's name from "PS/2 Mouse" to "ALPS Touchpad".
Hmm, the secondary device is never a touchpad but either trackpoint (for
confirmed dualpoint devices) or "something" we do not quite know what.
Why are you marking it as a touchpad?
Also, you forgot to add your "Signed-off-by: ..." as per
Documentation/SubmittingPatches
Thanks!
--
Dmitry
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2013-09-09 16:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-05 5:50 [PATCH 1/2] Input: ALPS Touchpad- Improve the performance of alps v5-protocol's touchpad yunkang.tang
2013-09-09 16:26 ` 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).