From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Hans de Goede <hdegoede@redhat.com>
Cc: Yunkang Tang <yunkang.tang@cn.alps.com>, linux-input@vger.kernel.org
Subject: Re: [PATCH 14/14] alps: Add support for v7 devices
Date: Fri, 25 Jul 2014 22:58:11 -0700 [thread overview]
Message-ID: <20140726055811.GA31435@core.coreip.homeip.net> (raw)
In-Reply-To: <1404919459-23561-15-git-send-email-hdegoede@redhat.com>
Hi Hans,
On Wed, Jul 09, 2014 at 05:24:19PM +0200, Hans de Goede wrote:
> From: Yunkang Tang <yunkang.tang@cn.alps.com>
>
> Such as found on the new Toshiba Portégé Z30-A and Z40-A.
>
> Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
> [hdegoede@redhat.com: Remove softbutton handling, this is done in userspace]
> [hdegoede@redhat.com: Report INPUT_PROP_BUTTONPAD]
> [hdegoede@redhat.com: Do not report fake PRESSURE, reporting BTN_TOUCH is
> enough]
> [hdegoede@redhat.com: Various cleanups / refactoring]
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> drivers/input/mouse/alps.c | 257 ++++++++++++++++++++++++++++++++++++++++++++-
> drivers/input/mouse/alps.h | 18 ++++
> 2 files changed, 272 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index ad3a708..8b9b4b0 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -100,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> 6-byte ALPS packet */
> #define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */
> +#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
>
> static const struct alps_model_info alps_model_data[] = {
> { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> @@ -845,6 +846,177 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> alps_report_semi_mt_data(psmouse, f->fingers);
> }
>
> +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> +{
> + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> + return false;
> + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> + return false;
> + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> + return false;
> + return true;
Maybe:
switch (psmouse->pktcnt) {
case 3:
return (psmouse->packet[2] & 0x40) == 0x40;
case 4:
return (psmouse->packet[3] & 0x48) == 0x48;
case 6:
return (psmouse->packet[5] & 0x40) == 0x00;
}
return true;
?
> +}
> +
> +static unsigned char alps_get_packet_id_v7(char *byte)
> +{
> + unsigned char packet_id;
> +
> + if (byte[4] & 0x40)
> + packet_id = V7_PACKET_ID_TWO;
> + else if (byte[4] & 0x01)
> + packet_id = V7_PACKET_ID_MULTI;
> + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> + packet_id = V7_PACKET_ID_NEW;
> + else if (byte[1] == 0x00 && byte[4] == 0x00)
> + packet_id = V7_PACKET_ID_IDLE;
> + else
> + packet_id = V7_PACKET_ID_UNKNOWN;
> +
> + return packet_id;
> +}
> +
> +static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
> + unsigned char *pkt,
> + unsigned char pkt_id)
> +{
> + mt[0].x = ((pkt[2] & 0x80) << 4);
> + mt[0].x |= ((pkt[2] & 0x3F) << 5);
> + mt[0].x |= ((pkt[3] & 0x30) >> 1);
> + mt[0].x |= (pkt[3] & 0x07);
> + mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> +
> + mt[1].x = ((pkt[3] & 0x80) << 4);
> + mt[1].x |= ((pkt[4] & 0x80) << 3);
> + mt[1].x |= ((pkt[4] & 0x3F) << 4);
> + mt[1].y = ((pkt[5] & 0x80) << 3);
> + mt[1].y |= ((pkt[5] & 0x3F) << 4);
> +
> + if (pkt_id == V7_PACKET_ID_TWO) {
> + mt[1].x &= ~0x000F;
> + mt[1].y |= 0x000F;
> + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> + mt[1].x &= ~0x003F;
> + mt[1].y &= ~0x0020;
> + mt[1].y |= ((pkt[4] & 0x02) << 4);
> + mt[1].y |= 0x001F;
> + } else if (pkt_id == V7_PACKET_ID_NEW) {
> + mt[1].x &= ~0x003F;
> + mt[1].x |= (pkt[0] & 0x20);
> + mt[1].y |= 0x000F;
> + }
> +
> + mt[0].y = 0x7FF - mt[0].y;
> + mt[1].y = 0x7FF - mt[1].y;
> +}
> +
> +static int alps_get_mt_count(struct input_mt_pos *mt)
> +{
> + int i;
> +
> + for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
> + ;
/* empty */;
just to make sure...
> +
> + return i;
> +}
> +
> +static int alps_decode_packet_v7(struct alps_fields *f,
> + unsigned char *p,
> + struct psmouse *psmouse)
> +{
> + unsigned char pkt_id;
> +
> + pkt_id = alps_get_packet_id_v7(p);
> + if (pkt_id == V7_PACKET_ID_IDLE)
> + return 0;
> + if (pkt_id == V7_PACKET_ID_UNKNOWN)
> + return -1;
> +
> + alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
> +
> + if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
> + f->left = (p[0] & 0x80) >> 7;
> + f->right = (p[0] & 0x20) >> 5;
> + f->middle = (p[0] & 0x10) >> 4;
> + }
> +
> + if (pkt_id == V7_PACKET_ID_TWO)
> + f->fingers = alps_get_mt_count(f->mt);
> + else if (pkt_id == V7_PACKET_ID_MULTI)
> + f->fingers = 3 + (p[5] & 0x03);
> +
> + return 0;
> +}
> +
> +static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned char *packet = psmouse->packet;
> + struct input_dev *dev2 = priv->dev2;
> + int x, y, z, left, right, middle;
> +
> + /*
> + * b7 b6 b5 b4 b3 b2 b1 b0
> + * Byte0 0 1 0 0 1 0 0 0
> + * Byte1 1 1 * * 1 M R L
> + * Byte2 X7 1 X5 X4 X3 X2 X1 X0
> + * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
> + * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
> + * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
> + * M / R / L: Middle / Right / Left button
> + */
> +
> + x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
> + y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
> + ((packet[3] & 0x20) << 1);
> + z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
> +
> + left = (packet[1] & 0x01);
> + right = (packet[1] & 0x02) >> 1;
> + middle = (packet[1] & 0x04) >> 2;
> +
> + /* Divide 2 since trackpoint's speed is too fast */
> + input_report_rel(dev2, REL_X, (char)x / 2);
> + input_report_rel(dev2, REL_Y, -((char)y / 2));
> +
> + input_report_key(dev2, BTN_LEFT, left);
> + input_report_key(dev2, BTN_RIGHT, right);
> + input_report_key(dev2, BTN_MIDDLE, middle);
> +
> + input_sync(dev2);
> +}
> +
> +static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + struct input_dev *dev = psmouse->dev;
> + struct alps_fields *f = &priv->f;
> +
> + memset(f, 0, sizeof(*f));
> +
> + if (priv->decode_fields(f, psmouse->packet, psmouse))
> + return;
> +
> + alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
> +
> + input_mt_report_finger_count(dev, f->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);
> +
> + input_sync(dev);
> +}
> +
> +static void alps_process_packet_v7(struct psmouse *psmouse)
> +{
> + unsigned char *packet = psmouse->packet;
> +
> + if ((packet[0] == 0x48) && ((packet[4] & 0x47) == 0x06))
> + alps_process_trackstick_packet_v7(psmouse);
> + else
> + alps_process_touchpad_packet_v7(psmouse);
> +}
> +
> static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> unsigned char packet[],
> bool report_buttons)
> @@ -1009,6 +1181,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> return PSMOUSE_BAD_DATA;
> }
>
> + if (priv->proto_version == ALPS_PROTO_V7 &&
> + !alps_is_valid_package_v7(psmouse)) {
> + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> + psmouse->pktcnt - 1,
> + psmouse->packet[psmouse->pktcnt - 1]);
> + return PSMOUSE_BAD_DATA;
> + }
> +
> if (psmouse->pktcnt == psmouse->pktsize) {
> priv->process_packet(psmouse);
> return PSMOUSE_FULL_PACKET;
> @@ -1121,6 +1301,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> return 0;
> }
>
> +static int alps_check_valid_firmware_id(unsigned char id[])
bool
> +{
> + int valid = 1;
bool; true
> +
> + if (id[0] == 0x73)
> + valid = 1;
true
> + else if (id[0] == 0x88) {
> + if ((id[1] == 0x07) ||
> + (id[1] == 0x08) ||
> + ((id[1] & 0xf0) == 0xB0))
> + valid = 1;
true
> + }
> +
> + return valid;
Hmmm, does not make sense - it is never false...
> +}
> +
> static int alps_enter_command_mode(struct psmouse *psmouse)
> {
> unsigned char param[4];
> @@ -1130,8 +1326,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> return -1;
> }
>
> - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> - param[0] != 0x73) {
> + if (!alps_check_valid_firmware_id(param)) {
> psmouse_dbg(psmouse,
> "unknown response while entering command mode\n");
> return -1;
> @@ -1785,6 +1980,32 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
> return 0;
> }
>
> +static int alps_hw_init_v7(struct psmouse *psmouse)
> +{
> + struct ps2dev *ps2dev = &psmouse->ps2dev;
> + int reg_val, ret = -1;
> +
> + if (alps_enter_command_mode(psmouse) ||
> + alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
> + goto error;
> +
> + if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
> + goto error;
> +
> + reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
> + if (reg_val == -1)
> + goto error;
> + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
> + goto error;
> +
> + alps_exit_command_mode(psmouse);
> + return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
> +
> +error:
> + alps_exit_command_mode(psmouse);
> + return ret;
> +}
> +
> static void alps_set_defaults(struct alps_data *priv)
> {
> priv->byte0 = 0x8f;
> @@ -1843,6 +2064,21 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->x_max = 2047;
> priv->y_max = 1535;
> break;
> + case ALPS_PROTO_V7:
> + priv->hw_init = alps_hw_init_v7;
> + priv->process_packet = alps_process_packet_v7;
> + priv->decode_fields = alps_decode_packet_v7;
> + priv->set_abs_params = alps_set_abs_params_mt;
> + priv->nibble_commands = alps_v3_nibble_commands;
> + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> + priv->x_max = 0xfff;
> + priv->y_max = 0x7ff;
> + priv->byte0 = 0x48;
> + priv->mask0 = 0x48;
> +
> + if (priv->fw_ver[1] != 0xba)
> + priv->flags |= ALPS_BUTTONPAD;
> + break;
> }
> }
>
> @@ -1914,6 +2150,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> return -EIO;
> else
> return 0;
> + } else if (ec[0] == 0x88 &&
> + ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
> + priv->proto_version = ALPS_PROTO_V7;
> + alps_set_defaults(priv);
> +
> + return 0;
> } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> priv->proto_version = ALPS_PROTO_V3;
> alps_set_defaults(priv);
> @@ -1985,6 +2227,10 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>
> set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
> set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
> +
> + /* V7 is real multi-touch */
> + if (priv->proto_version == ALPS_PROTO_V7)
> + clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> }
>
> int alps_init(struct psmouse *psmouse)
> @@ -2030,7 +2276,9 @@ int alps_init(struct psmouse *psmouse)
> dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
>
> priv->set_abs_params(priv, dev1);
> - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
> + /* No pressure on V7 */
> + if (priv->proto_version != ALPS_PROTO_V7)
> + input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
>
> if (priv->flags & ALPS_WHEEL) {
> dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
> @@ -2047,6 +2295,9 @@ int alps_init(struct psmouse *psmouse)
> dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
> dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
> dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
> + } else if (priv->flags & ALPS_BUTTONPAD) {
> + set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
> + clear_bit(BTN_RIGHT, dev1->keybit);
> } else {
> dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
> }
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index e3d0f09..a98ac9b 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -20,6 +20,7 @@
> #define ALPS_PROTO_V4 4
> #define ALPS_PROTO_V5 5
> #define ALPS_PROTO_V6 6
> +#define ALPS_PROTO_V7 7 /* t3btl t4s */
>
> #define MAX_TOUCHES 2
>
> @@ -27,6 +28,23 @@
> #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
>
> +/*
> + * enum V7_PACKET_ID - defines the packet type for V7
> + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> + * or there's button activities.
> + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> + * previous packet.
> +*/
> +enum V7_PACKET_ID {
> + V7_PACKET_ID_IDLE,
> + V7_PACKET_ID_TWO,
> + V7_PACKET_ID_MULTI,
> + V7_PACKET_ID_NEW,
> + V7_PACKET_ID_UNKNOWN,
> +};
> +
> /**
> * struct alps_model_info - touchpad ID table
> * @signature: E7 response string to match.
> --
> 2.0.0
>
Thanks.
--
Dmitry
--
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
next prev parent reply other threads:[~2014-07-26 5:58 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-09 15:24 [PATCH 00/14] alps: bugfixes, cleanups and new hardware support Hans de Goede
2014-07-09 15:24 ` [PATCH 01/14] alps: Fix rushmore packet decoding Hans de Goede
2014-07-09 15:24 ` [PATCH 02/14] alps: Always report 2 fingers (or more) when receiving mt data on v3 models Hans de Goede
2014-07-09 15:24 ` [PATCH 03/14] alps: process_bitmap: Don't invert the Y-axis on Rushmore Hans de Goede
2014-07-09 15:24 ` [PATCH 04/14] alps: process_bitmap: Add alps_get_bitmap_points() helper function Hans de Goede
2014-07-09 15:24 ` [PATCH 05/14] alps: process_bitmap: Fix counting of high point bits Hans de Goede
2014-07-09 15:24 ` [PATCH 06/14] alps: process_bitmap: Round down when spreading adjescent fingers over 2 points Hans de Goede
2014-07-09 15:24 ` [PATCH 07/14] alps: Use struct input_mt_pos to track coordinates Hans de Goede
2014-07-09 15:24 ` [PATCH 08/14] alps: Use input_mt_assign_slots && input_mt_sync_frame instead of DIY Hans de Goede
2014-07-09 15:24 ` [PATCH 09/14] alps: Use single touch data when v3 mt data contains only one finger Hans de Goede
2014-07-09 15:24 ` [PATCH 10/14] alps: Add an alps_report_semi_mt_data function Hans de Goede
2014-07-09 15:24 ` [PATCH 11/14] alps: Report 2 touches when we've > 2 fingers Hans de Goede
2014-07-09 15:24 ` [PATCH 12/14] alps: Change decode function prototype to return an int Hans de Goede
2014-07-09 15:24 ` [PATCH 13/14] alps: Cache firmware version Hans de Goede
2014-07-09 15:24 ` [PATCH 14/14] alps: Add support for v7 devices Hans de Goede
2014-07-26 5:58 ` Dmitry Torokhov [this message]
2014-07-26 8:22 ` Hans de Goede
2014-07-26 5:59 ` [PATCH 00/14] alps: bugfixes, cleanups and new hardware support Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140726055811.GA31435@core.coreip.homeip.net \
--to=dmitry.torokhov@gmail.com \
--cc=hdegoede@redhat.com \
--cc=linux-input@vger.kernel.org \
--cc=yunkang.tang@cn.alps.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).