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