diff mbox

[6/6] Input: elantech - add v3 hardware support

Message ID 1313632629-23603-7-git-send-email-jj_ding@emc.com.tw (mailing list archive)
State New, archived
Headers show

Commit Message

JJ Ding Aug. 18, 2011, 1:57 a.m. UTC
v3 hardware's packet format is almost identical to v2 (one/three finger touch),
except when sensing two finger touch, the hardware sends 12 bytes of data.

Signed-off-by: JJ Ding <jj_ding@emc.com.tw>
---
 Documentation/input/elantech.txt |  104 ++++++++++++++++--
 drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
 drivers/input/mouse/elantech.h   |   11 ++
 3 files changed, 303 insertions(+), 30 deletions(-)

Comments

Daniel Kurtz Aug. 18, 2011, 2:57 a.m. UTC | #1
On Thu, Aug 18, 2011 at 9:57 AM, JJ Ding <jj_ding@emc.com.tw> wrote:
> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> except when sensing two finger touch, the hardware sends 12 bytes of data.
>
> Signed-off-by: JJ Ding <jj_ding@emc.com.tw>
> ---
>  Documentation/input/elantech.txt |  104 ++++++++++++++++--
>  drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
>  drivers/input/mouse/elantech.h   |   11 ++
>  3 files changed, 303 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
> index bce9941..ce578bd 100644
> --- a/Documentation/input/elantech.txt
> +++ b/Documentation/input/elantech.txt
> @@ -16,15 +16,22 @@ Contents
>
>  1. Introduction
>  2. Extra knobs
> - 3. Hardware version 1
> -    3.1 Registers
> -    3.2 Native relative mode 4 byte packet format
> -    3.3 Native absolute mode 4 byte packet format
> - 4. Hardware version 2
> + 3. Differentiating hardware versions
> + 4. Hardware version 1
>     4.1 Registers
> -    4.2 Native absolute mode 6 byte packet format
> -        4.2.1 One finger touch
> -        4.2.2 Two finger touch
> +    4.2 Native relative mode 4 byte packet format
> +    4.3 Native absolute mode 4 byte packet format
> + 5. Hardware version 2
> +    5.1 Registers
> +    5.2 Native absolute mode 6 byte packet format
> +        5.2.1 Parity checking and packet re-synchronization
> +        5.2.2 One/Three finger touch
> +        5.2.3 Two finger touch
> + 6. Hardware version 3
> +    6.1 Registers
> +    6.2 Native absolute mode 6 byte packet format
> +        6.2.1 One/Three finger touch
> +        6.2.2 Two finger touch
>
>
>
> @@ -375,7 +382,7 @@ For all the other ones, there are just a few constant bits:
>
>  In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
>
> -5.2.1 One/Three finger touch
> +5.2.2 One/Three finger touch
>       ~~~~~~~~~~~~~~~~
>
>  byte 0:
> @@ -384,7 +391,7 @@ byte 0:
>         n1  n0  w3  w2   .   .   R   L
>
>          L, R = 1 when Left, Right mouse button pressed
> -         n1..n0 = numbers of fingers on touchpad
> +         n1..n0 = number of fingers on touchpad
>
>  byte 1:
>
> @@ -432,7 +439,7 @@ byte 5:
>          y11..y0 = absolute y value (vertical)
>
>
> -4.2.2 Two finger touch
> +5.2.3 Two finger touch
>       ~~~~~~~~~~~~~~~~
>
>  Note that the two pairs of coordinates are not exactly the coordinates of the
> @@ -446,7 +453,7 @@ byte 0:
>         n1  n0  ay8 ax8  .   .   R   L
>
>          L, R = 1 when Left, Right mouse button pressed
> -         n1..n0 = numbers of fingers on touchpad
> +         n1..n0 = number of fingers on touchpad
>
>  byte 1:
>
> @@ -480,3 +487,76 @@ byte 5:
>         by7 by8 by5 by4 by3 by2 by1 by0
>
>          by8..by0 = upper-right finger absolute y value
> +
> +/////////////////////////////////////////////////////////////////////////////
> +
> +6. Hardware version 3
> +   ==================
> +
> +6.1 Registers
> +    ~~~~~~~~~
> +* reg_10
> +
> +   bit   7   6   5   4   3   2   1   0
> +         0   0   0   0   0   0   0   A
> +
> +         A: 1 = enable absolute tracking
> +
> +6.2 Native absolute mode 6 byte packet format
> +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +1 and 3 finger touch shares the same 6-byte packet format, except that
> +3 finger touch only reports the position of the center of all three fingers.
> +
> +Firmware would send 12 bytes of data for 2 finger touch.
> +
> +6.2.1 One/Three finger touch
> +      ~~~~~~~~~~~~~~~~~~~~~~
> +
> +byte 0:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        n1  n0  w3  w2   0   1   R   L
> +
> +        L, R = 1 when Left, Right mouse button pressed
> +        n1..n0 = number of fingers on touchpad
> +
> +byte 1:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        p7  p6  p5  p4 x11 x10  x9  x8
> +
> +byte 2:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        x7  x6  x5  x4  x3  x2  x1  x0
> +
> +        x11..x0 = absolute x value (horizontal)
> +
> +byte 3:
> +
> +   bit   7   6   5   4   3   2   1   0
> +         0   0  w1  w0   0   0   1   0
> +
> +         w3..w0 = width of the finger touch
> +
> +byte 4:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        p3  p1  p2  p0  y11 y10 y9  y8
> +
> +        p7..p0 = pressure
> +
> +byte 5:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        y7  y6  y5  y4  y3  y2  y1  y0
> +
> +        y11..y0 = absolute y value (vertical)
> +
> +6.2.2 Two finger touch
> +      ~~~~~~~~~~~~~~~~
> +
> +The packet format is exactly the same for two finger touch, except the hardware
> +sends two 6 byte packets. The first packet contains data for the first finger,
> +the second packet has data for the second finger. So for two finger touch a
> +total of 12 bytes are sent.
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index ddd40eb..e13a719 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
> @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
>                        rc = -1;
>                }
>                break;
> +
> +       case 3:
> +               if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +                   elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +                   elantech_ps2_command(psmouse, NULL, reg) ||
> +                   elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
> +                       rc = -1;
> +               }
> +               break;
>        }
>
>        if (rc)
> @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
>                        rc = -1;
>                }
>                break;
> +
> +       case 3:
> +               if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +                   elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +                   elantech_ps2_command(psmouse, NULL, reg) ||
> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +                   elantech_ps2_command(psmouse, NULL, val) ||
> +                   elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
> +                       rc = -1;
> +               }
> +               break;
>        }
>
>        if (rc)
> @@ -352,6 +374,94 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
>        input_sync(dev);
>  }
>
> +/*
> + * firmware tells us there's noise.
> + */
> +static inline int debounce(unsigned int x, unsigned int y)
> +{
> +       return (x == 0xfff) && (y == 0xfff);

Perhaps you could document this behavior in the elantech.txt.

> +}
> +
> +/*
> + * Interpret complete data packets and report absolute mode input events for
> + * hardware version 3. (12 byte packets for two fingers)
> + */
> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> +                                       int packet_type)
> +{
> +       struct input_dev *dev = psmouse->dev;
> +       struct elantech_data *etd = psmouse->private;
> +       unsigned char *packet = psmouse->packet;
> +       unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> +       unsigned int width = 0, pres = 0;
> +
> +       /* byte 0: n1  n0   .   .   .   .   R   L */
> +       fingers = (packet[0] & 0xc0) >> 6;
> +
> +       switch (fingers) {
> +       case 3:
> +       case 1:
> +               /*
> +                * byte 1:  .   .   .   .  x11 x10 x9  x8
> +                * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> +                */
> +               x1 = ((packet[1] & 0x0f) << 8) | packet[2];
> +               /*
> +                * byte 4:  .   .   .   .  y11 y10 y9  y8
> +                * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> +                */
> +               y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
> +
> +               if (fingers == 3 && debounce(x1, y1))
> +                       return;
> +
> +               break;
> +
> +       case 2:
> +               if (packet_type == PACKET_V3_HEAD) {
> +                       /*
> +                        * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> +                        * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> +                        */
> +                       etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2];
> +                       /*
> +                        * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> +                        * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> +                        */
> +                       etd->prev_y = etd->y_max -
> +                               (((packet[4] & 0x0f) << 8) | packet[5]);
> +                       /*
> +                        * wait for next packet
> +                        */
> +                       return;
> +               }
> +
> +               /* packet_type == PACKET_V3_TAIL */
> +               x1 = etd->prev_x;
> +               y1 = etd->prev_y;
> +               x2 = ((packet[1] & 0x0f) << 8) | packet[2];
> +               y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
> +               break;
> +       }
> +
> +       pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
> +       width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
> +
> +       input_report_key(dev, BTN_TOUCH, fingers != 0);
> +       input_report_abs(dev, ABS_X, x1);
> +       input_report_abs(dev, ABS_Y, y1);
> +       elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +       input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
> +       input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
> +       input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
> +       input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
> +       input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
> +       input_report_abs(dev, ABS_PRESSURE, pres);
> +       input_report_abs(dev, ABS_TOOL_WIDTH, width);
> +
> +       input_sync(dev);
> +}
> +
>  static int elantech_check_parity_v1(struct psmouse *psmouse)
>  {
>        struct elantech_data *etd = psmouse->private;
> @@ -396,11 +506,31 @@ static int packet_simple_check_v2(struct psmouse *psmouse)
>  }
>
>  /*
> + * We check the constant bits to determine what packet type we get,
> + * so packet checking is mandatory for v3 hardware.
> + */
> +static int determine_packet_v3(struct psmouse *psmouse)
> +{
> +       unsigned char *packet = psmouse->packet;
> +
> +       if ((packet[0] & 0x0c) == 0x04 &&
> +           (packet[3] & 0xcf) == 0x02)
> +               return PACKET_V3_HEAD;
> +
> +       if ((packet[0] & 0x0c) == 0x0c &&
> +           (packet[3] & 0xce) == 0x0c)
> +               return PACKET_V3_TAIL;
> +
> +       return PACKET_UNKNOWN;
> +}
> +
> +/*
>  * Process byte stream from mouse and handle complete packets
>  */
>  static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>  {
>        struct elantech_data *etd = psmouse->private;
> +       int packet_type;
>
>        if (psmouse->pktcnt < psmouse->pktsize)
>                return PSMOUSE_GOOD_DATA;
> @@ -422,6 +552,14 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>
>                elantech_report_absolute_v2(psmouse);
>                break;
> +
> +       case 3:
> +               packet_type = determine_packet_v3(psmouse);
> +               if (packet_type == PACKET_UNKNOWN)
> +                       goto bad_packet;
> +
> +               elantech_report_absolute_v3(psmouse, packet_type);
> +               break;
>        }
>
>        return PSMOUSE_FULL_PACKET;
> @@ -459,10 +597,17 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>                etd->reg_21 = 0x60;     /* 0x00 */
>                if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
>                    elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
> -                   elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
> +                   elantech_write_reg(psmouse, 0x21, etd->reg_21))
>                        rc = -1;
> -                       break;
> -               }
> +
> +               break;
> +
> +       case 3:
> +               etd->reg_10 = 0x0b;
> +               if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
> +                       rc = -1;
> +
> +               break;
>        }
>
>        if (rc == 0) {
> @@ -496,11 +641,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>        return rc;
>  }
>
> -static void set_range(struct psmouse *psmouse, unsigned int *x_min,
> +static int set_range(struct psmouse *psmouse, unsigned int *x_min,
>                     unsigned int *y_min, unsigned int *x_max,
>                     unsigned int *y_max, unsigned int *y_2ft_max)
>  {
>        struct elantech_data *etd = psmouse->private;
> +       unsigned char param[3];
>        int i;
>
>        switch (etd->hw_version) {
> @@ -529,19 +675,30 @@ static void set_range(struct psmouse *psmouse, unsigned int *x_min,
>                *y_max = (etd->capabilities[2] - i) * 64;
>                *y_2ft_max = (*y_max - i) * 64 / 4;
>                break;
> +
> +       case 3:
> +               if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
> +                       return -1;
> +
> +               *x_max = (0x0f & param[0]) << 8 | param[1];
> +               *y_max = (0xf0 & param[0]) << 4 | param[2];
> +               break;
>        }
> +
> +       return 0;
>  }
>
>  /*
>  * Set the appropriate event bits for the input subsystem
>  */
> -static void elantech_set_input_params(struct psmouse *psmouse)
> +static int elantech_set_input_params(struct psmouse *psmouse)
>  {
>        struct input_dev *dev = psmouse->dev;
>        struct elantech_data *etd = psmouse->private;
>        unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
>
> -       set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &y_2ft_max);
> +       if (set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &y_2ft_max))
> +               return -1;
>
>        __set_bit(EV_KEY, dev->evbit);
>        __set_bit(EV_ABS, dev->evbit);
> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
>                input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>                input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>                break;
> +
> +       case 3:
> +               input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> +               input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> +               /* range of pressure and width is the same as v2 */
> +               input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> +                                    ETP_PMAX_V2, 0, 0);
> +               input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> +                                    ETP_WMAX_V2, 0, 0);
> +               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> +               input_mt_init_slots(dev, 2);
> +               input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> +               input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> +               break;
>        }
>
>        etd->y_max = y_max;
>        etd->y_2ft_max = y_2ft_max;
> +
> +       return 0;
>  }
>
>  struct elantech_attr_data {
> @@ -727,7 +900,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
>         * Report this in case there are Elantech models that use a different
>         * set of magic numbers
>         */
> -       if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
> +       if (param[0] != 0x3c || param[1] != 0x03 ||
> +           (param[2] != 0xc8 && param[2] != 0x00)) {
>                pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
>                         param[0], param[1], param[2]);
>                return -1;
> @@ -793,16 +967,16 @@ static int elantech_reconnect(struct psmouse *psmouse)
>  /*
>  * determine hardware version and set some properties according to it.
>  */
> -static void elantech_set_properties(struct elantech_data *etd)
> +static int elantech_set_properties(struct elantech_data *etd)
>  {
> -       /*
> -        * Assume every version greater than 0x020030 is new EeePC style
> -        * hardware with 6 byte packets, except 0x020600
> -        */
>        if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
>                etd->hw_version = 1;
> -       else
> +       else if (etd->fw_version < 0x150600)
>                etd->hw_version = 2;
> +       else if ((etd->fw_version & 0x0f0000) >> 16 == 5)
> +               etd->hw_version = 3;
> +       else
> +               return -1;
>
>        /*
>         * Turn on packet checking by default.
> @@ -817,13 +991,15 @@ static void elantech_set_properties(struct elantech_data *etd)
>        etd->jumpy_cursor =
>                (etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
>
> -       if (etd->hw_version == 2) {
> +       if (etd->hw_version > 1) {
>                /* For now show extra debug information */
>                etd->debug = 1;
>
>                if (etd->fw_version >= 0x020800)
>                        etd->reports_pressure = true;
>        }
> +
> +       return 0;
>  }
>
>  /*
> @@ -850,9 +1026,12 @@ int elantech_init(struct psmouse *psmouse)
>                pr_err("failed to query firmware version.\n");
>                goto init_fail;
>        }
> -
>        etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
> -       elantech_set_properties(etd);
> +
> +       if (elantech_set_properties(etd)) {
> +               pr_err("unknown hardware version, aborting...\n");
> +               goto init_fail;
> +       }
>        pr_info("assuming hardware version %d "
>                "(with firmware version 0x%02x%02x%02x)\n",
>                etd->hw_version, param[0], param[1], param[2]);
> @@ -871,7 +1050,10 @@ int elantech_init(struct psmouse *psmouse)
>                goto init_fail;
>        }
>
> -       elantech_set_input_params(psmouse);
> +       if (elantech_set_input_params(psmouse)) {
> +               pr_err("failed to query touchpad range.\n");
> +               goto init_fail;
> +       }
>
>        error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
>                                   &elantech_attr_group);
> @@ -883,7 +1065,7 @@ int elantech_init(struct psmouse *psmouse)
>        psmouse->protocol_handler = elantech_process_byte;
>        psmouse->disconnect = elantech_disconnect;
>        psmouse->reconnect = elantech_reconnect;
> -       psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
> +       psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
>
>        return 0;
>
> diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
> index 4b7447e..4f01fc6 100644
> --- a/drivers/input/mouse/elantech.h
> +++ b/drivers/input/mouse/elantech.h
> @@ -16,6 +16,7 @@
>  /*
>  * Command values for Synaptics style queries
>  */
> +#define ETP_FW_ID_QUERY                        0x00

One tab too many?

>  #define ETP_FW_VERSION_QUERY           0x01
>  #define ETP_CAPABILITIES_QUERY         0x02
>
> @@ -24,6 +25,7 @@
>  */
>  #define ETP_REGISTER_READ              0x10
>  #define ETP_REGISTER_WRITE             0x11
> +#define ETP_REGISTER_READWRITE         0x00
>
>  /*
>  * Hardware version 2 custom PS/2 command value
> @@ -93,6 +95,13 @@
>  #define ETP_2FT_YMIN                   (  0 + ETP_2FT_FUZZ)
>  #define ETP_2FT_YMAX                   (192 - ETP_2FT_FUZZ)
>
> +/*
> + * v3 hardware has 2 kinds of packet types.
> + */
> +#define PACKET_UNKNOWN                 0x01
> +#define PACKET_V3_HEAD                 0x02
> +#define PACKET_V3_TAIL                 0x03
> +
>  struct elantech_data {
>        unsigned char reg_10;
>        unsigned char reg_11;
> @@ -113,6 +122,8 @@ struct elantech_data {
>        unsigned int single_finger_reports;
>        unsigned int y_max;
>        unsigned int y_2ft_max;
> +       unsigned int prev_x;
> +       unsigned int prev_y;
>        unsigned char parity[256];
>  };
>
> --
> 1.7.4.1
>
>
--
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
Wanlong Gao Aug. 18, 2011, 3:01 a.m. UTC | #2
On 08/18/2011 09:57 AM, JJ Ding wrote:
> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> except when sensing two finger touch, the hardware sends 12 bytes of data.
>
> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> ---
>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>   drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
>   drivers/input/mouse/elantech.h   |   11 ++
>   3 files changed, 303 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
> index bce9941..ce578bd 100644
> --- a/Documentation/input/elantech.txt
> +++ b/Documentation/input/elantech.txt
> @@ -16,15 +16,22 @@ Contents
>
>    1. Introduction
>    2. Extra knobs
> - 3. Hardware version 1
> -    3.1 Registers
> -    3.2 Native relative mode 4 byte packet format
> -    3.3 Native absolute mode 4 byte packet format
> - 4. Hardware version 2
> + 3. Differentiating hardware versions
> + 4. Hardware version 1
>       4.1 Registers
> -    4.2 Native absolute mode 6 byte packet format
> -        4.2.1 One finger touch
> -        4.2.2 Two finger touch
> +    4.2 Native relative mode 4 byte packet format
> +    4.3 Native absolute mode 4 byte packet format
> + 5. Hardware version 2
> +    5.1 Registers
> +    5.2 Native absolute mode 6 byte packet format
> +        5.2.1 Parity checking and packet re-synchronization
> +        5.2.2 One/Three finger touch
> +        5.2.3 Two finger touch
> + 6. Hardware version 3
> +    6.1 Registers
> +    6.2 Native absolute mode 6 byte packet format
> +        6.2.1 One/Three finger touch
> +        6.2.2 Two finger touch
>
>
>
> @@ -375,7 +382,7 @@ For all the other ones, there are just a few constant bits:
>
>   In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
>
> -5.2.1 One/Three finger touch
> +5.2.2 One/Three finger touch
>         ~~~~~~~~~~~~~~~~
>
>   byte 0:
> @@ -384,7 +391,7 @@ byte 0:
>   	 n1  n0  w3  w2   .   .   R   L
>
>            L, R = 1 when Left, Right mouse button pressed
> -         n1..n0 = numbers of fingers on touchpad
> +         n1..n0 = number of fingers on touchpad
>
>   byte 1:
>
> @@ -432,7 +439,7 @@ byte 5:
>            y11..y0 = absolute y value (vertical)
>
>
> -4.2.2 Two finger touch
> +5.2.3 Two finger touch
>         ~~~~~~~~~~~~~~~~
>
>   Note that the two pairs of coordinates are not exactly the coordinates of the
> @@ -446,7 +453,7 @@ byte 0:
>           n1  n0  ay8 ax8  .   .   R   L
>
>            L, R = 1 when Left, Right mouse button pressed
> -         n1..n0 = numbers of fingers on touchpad
> +         n1..n0 = number of fingers on touchpad
>
>   byte 1:
>
> @@ -480,3 +487,76 @@ byte 5:
>           by7 by8 by5 by4 by3 by2 by1 by0
>
>            by8..by0 = upper-right finger absolute y value
> +
> +/////////////////////////////////////////////////////////////////////////////
> +
> +6. Hardware version 3
> +   ==================
> +
> +6.1 Registers
> +    ~~~~~~~~~
> +* reg_10
> +
> +   bit   7   6   5   4   3   2   1   0
> +         0   0   0   0   0   0   0   A
> +
> +         A: 1 = enable absolute tracking
> +
> +6.2 Native absolute mode 6 byte packet format
> +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +1 and 3 finger touch shares the same 6-byte packet format, except that
> +3 finger touch only reports the position of the center of all three fingers.
> +
> +Firmware would send 12 bytes of data for 2 finger touch.
> +
> +6.2.1 One/Three finger touch
> +      ~~~~~~~~~~~~~~~~~~~~~~
> +
> +byte 0:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        n1  n0  w3  w2   0   1   R   L
> +
> +        L, R = 1 when Left, Right mouse button pressed
> +        n1..n0 = number of fingers on touchpad
> +
> +byte 1:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        p7  p6  p5  p4 x11 x10  x9  x8
> +
> +byte 2:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        x7  x6  x5  x4  x3  x2  x1  x0
> +
> +        x11..x0 = absolute x value (horizontal)
> +
> +byte 3:
> +
> +   bit   7   6   5   4   3   2   1   0
> +         0   0  w1  w0   0   0   1   0
> +
> +         w3..w0 = width of the finger touch
> +
> +byte 4:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        p3  p1  p2  p0  y11 y10 y9  y8
> +
> +        p7..p0 = pressure
> +
> +byte 5:
> +
> +   bit   7   6   5   4   3   2   1   0
> +        y7  y6  y5  y4  y3  y2  y1  y0
> +
> +        y11..y0 = absolute y value (vertical)
> +
> +6.2.2 Two finger touch
> +      ~~~~~~~~~~~~~~~~
> +
> +The packet format is exactly the same for two finger touch, except the hardware
> +sends two 6 byte packets. The first packet contains data for the first finger,
> +the second packet has data for the second finger. So for two finger touch a
> +total of 12 bytes are sent.
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index ddd40eb..e13a719 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
> @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
>   			rc = -1;
>   		}
>   		break;
> +
> +	case 3:
> +		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, reg) ||
> +		    elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
> +			rc = -1;
> +		}
> +		break;
>   	}
>
>   	if (rc)
> @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
>   			rc = -1;
>   		}
>   		break;
> +
> +	case 3:
> +		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, reg) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, val) ||
> +		    elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
> +			rc = -1;
> +		}
> +		break;
>   	}
>
>   	if (rc)
> @@ -352,6 +374,94 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
>   	input_sync(dev);
>   }
>
> +/*
> + * firmware tells us there's noise.
> + */
> +static inline int debounce(unsigned int x, unsigned int y)
> +{
> +	return (x == 0xfff)&&  (y == 0xfff);
> +}
> +
> +/*
> + * Interpret complete data packets and report absolute mode input events for
> + * hardware version 3. (12 byte packets for two fingers)
> + */
> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> +					int packet_type)
> +{
> +	struct input_dev *dev = psmouse->dev;
> +	struct elantech_data *etd = psmouse->private;
> +	unsigned char *packet = psmouse->packet;
> +	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> +	unsigned int width = 0, pres = 0;
> +
> +	/* byte 0: n1  n0   .   .   .   .   R   L */
> +	fingers = (packet[0]&  0xc0)>>  6;
> +
> +	switch (fingers) {
> +	case 3:
> +	case 1:
> +		/*
> +		 * byte 1:  .   .   .   .  x11 x10 x9  x8
> +		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> +		 */
> +		x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> +		/*
> +		 * byte 4:  .   .   .   .  y11 y10 y9  y8
> +		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> +		 */
> +		y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> +
> +		if (fingers == 3&&  debounce(x1, y1))
> +			return;
> +
> +		break;
> +
> +	case 2:
> +		if (packet_type == PACKET_V3_HEAD) {
> +			/*
> +			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> +			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> +			 */
> +			etd->prev_x = ((packet[1]&  0x0f)<<  8) | packet[2];
> +			/*
> +			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> +			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> +			 */
> +			etd->prev_y = etd->y_max -
> +				(((packet[4]&  0x0f)<<  8) | packet[5]);
> +			/*
> +			 * wait for next packet
> +			 */
> +			return;
> +		}
> +
> +		/* packet_type == PACKET_V3_TAIL */
> +		x1 = etd->prev_x;
> +		y1 = etd->prev_y;
> +		x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
> +		y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> +		break;
> +	}
> +
> +	pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
> +	width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
> +
> +	input_report_key(dev, BTN_TOUCH, fingers != 0);
> +	input_report_abs(dev, ABS_X, x1);
> +	input_report_abs(dev, ABS_Y, y1);
> +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
> +	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
> +	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
> +	input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
> +	input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
> +	input_report_abs(dev, ABS_PRESSURE, pres);
> +	input_report_abs(dev, ABS_TOOL_WIDTH, width);
> +
> +	input_sync(dev);
> +}
> +
>   static int elantech_check_parity_v1(struct psmouse *psmouse)
>   {
>   	struct elantech_data *etd = psmouse->private;
> @@ -396,11 +506,31 @@ static int packet_simple_check_v2(struct psmouse *psmouse)
>   }
>
>   /*
> + * We check the constant bits to determine what packet type we get,
> + * so packet checking is mandatory for v3 hardware.
> + */
> +static int determine_packet_v3(struct psmouse *psmouse)
elantech_check_parity_v1
packet_simple_check_v2
determine_packet_v3

Why not consistent them?
> +{
> +	unsigned char *packet = psmouse->packet;
> +
> +	if ((packet[0]&  0x0c) == 0x04&&
> +	    (packet[3]&  0xcf) == 0x02)
> +		return PACKET_V3_HEAD;
> +
> +	if ((packet[0]&  0x0c) == 0x0c&&
> +	    (packet[3]&  0xce) == 0x0c)
> +		return PACKET_V3_TAIL;
> +
> +	return PACKET_UNKNOWN;
> +}
> +
> +/*
>    * Process byte stream from mouse and handle complete packets
>    */
>   static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>   {
>   	struct elantech_data *etd = psmouse->private;
> +	int packet_type;
>
>   	if (psmouse->pktcnt<  psmouse->pktsize)
>   		return PSMOUSE_GOOD_DATA;
> @@ -422,6 +552,14 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>
>   		elantech_report_absolute_v2(psmouse);
>   		break;
> +
> +	case 3:
> +		packet_type = determine_packet_v3(psmouse);
> +		if (packet_type == PACKET_UNKNOWN)
> +			goto bad_packet;
> +
> +		elantech_report_absolute_v3(psmouse, packet_type);
> +		break;
>   	}
>
>   	return PSMOUSE_FULL_PACKET;
> @@ -459,10 +597,17 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>   		etd->reg_21 = 0x60;	/* 0x00 */
>   		if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
>   		    elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
> -		    elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
> +		    elantech_write_reg(psmouse, 0x21, etd->reg_21))
>   			rc = -1;
> -			break;
> -		}
> +
> +		break;
> +
> +	case 3:
> +		etd->reg_10 = 0x0b;
> +		if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
> +			rc = -1;
> +
> +		break;
>   	}
>
>   	if (rc == 0) {
> @@ -496,11 +641,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>   	return rc;
>   }
>
> -static void set_range(struct psmouse *psmouse, unsigned int *x_min,
> +static int set_range(struct psmouse *psmouse, unsigned int *x_min,
>   		     unsigned int *y_min, unsigned int *x_max,
>   		     unsigned int *y_max, unsigned int *y_2ft_max)
>   {
>   	struct elantech_data *etd = psmouse->private;
> +	unsigned char param[3];
>   	int i;
>
>   	switch (etd->hw_version) {
> @@ -529,19 +675,30 @@ static void set_range(struct psmouse *psmouse, unsigned int *x_min,
>   		*y_max = (etd->capabilities[2] - i) * 64;
>   		*y_2ft_max = (*y_max - i) * 64 / 4;
>   		break;
> +
> +	case 3:
> +		if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
> +			return -1;
> +
> +		*x_max = (0x0f&  param[0])<<  8 | param[1];
> +		*y_max = (0xf0&  param[0])<<  4 | param[2];
> +		break;
>   	}
> +
> +	return 0;
>   }
>
>   /*
>    * Set the appropriate event bits for the input subsystem
>    */
> -static void elantech_set_input_params(struct psmouse *psmouse)
> +static int elantech_set_input_params(struct psmouse *psmouse)
>   {
>   	struct input_dev *dev = psmouse->dev;
>   	struct elantech_data *etd = psmouse->private;
>   	unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
>
> -	set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
> +	if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
> +		return -1;
>
>   	__set_bit(EV_KEY, dev->evbit);
>   	__set_bit(EV_ABS, dev->evbit);
> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
>   		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>   		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>   		break;
> +
> +	case 3:
> +		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> +		/* range of pressure and width is the same as v2 */
> +		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> +				     ETP_PMAX_V2, 0, 0);
> +		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> +				     ETP_WMAX_V2, 0, 0);
> +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> +		input_mt_init_slots(dev, 2);
> +		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> +		break;
>   	}
>
>   	etd->y_max = y_max;
>   	etd->y_2ft_max = y_2ft_max;
> +
> +	return 0;
>   }
>
>   struct elantech_attr_data {
> @@ -727,7 +900,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
>   	 * Report this in case there are Elantech models that use a different
>   	 * set of magic numbers
>   	 */
> -	if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
> +	if (param[0] != 0x3c || param[1] != 0x03 ||
> +	    (param[2] != 0xc8&&  param[2] != 0x00)) {
>   		pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
>   			 param[0], param[1], param[2]);
>   		return -1;
> @@ -793,16 +967,16 @@ static int elantech_reconnect(struct psmouse *psmouse)
>   /*
>    * determine hardware version and set some properties according to it.
>    */
> -static void elantech_set_properties(struct elantech_data *etd)
> +static int elantech_set_properties(struct elantech_data *etd)
>   {
> -	/*
> -	 * Assume every version greater than 0x020030 is new EeePC style
> -	 * hardware with 6 byte packets, except 0x020600
> -	 */
>   	if (etd->fw_version<  0x020030 || etd->fw_version == 0x020600)
>   		etd->hw_version = 1;
> -	else
> +	else if (etd->fw_version<  0x150600)
>   		etd->hw_version = 2;
> +	else if ((etd->fw_version&  0x0f0000)>>  16 == 5)
> +		etd->hw_version = 3;
> +	else
> +		return -1;
>
>   	/*
>   	 * Turn on packet checking by default.
> @@ -817,13 +991,15 @@ static void elantech_set_properties(struct elantech_data *etd)
>   	etd->jumpy_cursor =
>   		(etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
>
> -	if (etd->hw_version == 2) {
> +	if (etd->hw_version>  1) {
>   		/* For now show extra debug information */
>   		etd->debug = 1;
>
>   		if (etd->fw_version>= 0x020800)
>   			etd->reports_pressure = true;
>   	}
> +
> +	return 0;
>   }
>
>   /*
> @@ -850,9 +1026,12 @@ int elantech_init(struct psmouse *psmouse)
>   		pr_err("failed to query firmware version.\n");
>   		goto init_fail;
>   	}
> -
>   	etd->fw_version = (param[0]<<  16) | (param[1]<<  8) | param[2];
> -	elantech_set_properties(etd);
> +
> +	if (elantech_set_properties(etd)) {
> +		pr_err("unknown hardware version, aborting...\n");
> +		goto init_fail;
> +	}
>   	pr_info("assuming hardware version %d "
>   		"(with firmware version 0x%02x%02x%02x)\n",
>   		etd->hw_version, param[0], param[1], param[2]);
> @@ -871,7 +1050,10 @@ int elantech_init(struct psmouse *psmouse)
>   		goto init_fail;
>   	}
>
> -	elantech_set_input_params(psmouse);
> +	if (elantech_set_input_params(psmouse)) {
> +		pr_err("failed to query touchpad range.\n");
> +		goto init_fail;
> +	}
>
>   	error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
>   				&elantech_attr_group);
> @@ -883,7 +1065,7 @@ int elantech_init(struct psmouse *psmouse)
>   	psmouse->protocol_handler = elantech_process_byte;
>   	psmouse->disconnect = elantech_disconnect;
>   	psmouse->reconnect = elantech_reconnect;
> -	psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
> +	psmouse->pktsize = etd->hw_version>  1 ? 6 : 4;
>
>   	return 0;
>
> diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
> index 4b7447e..4f01fc6 100644
> --- a/drivers/input/mouse/elantech.h
> +++ b/drivers/input/mouse/elantech.h
> @@ -16,6 +16,7 @@
>   /*
>    * Command values for Synaptics style queries
>    */
> +#define ETP_FW_ID_QUERY			0x00
>   #define ETP_FW_VERSION_QUERY		0x01
>   #define ETP_CAPABILITIES_QUERY		0x02
>
> @@ -24,6 +25,7 @@
>    */
>   #define ETP_REGISTER_READ		0x10
>   #define ETP_REGISTER_WRITE		0x11
> +#define ETP_REGISTER_READWRITE		0x00
>
>   /*
>    * Hardware version 2 custom PS/2 command value
> @@ -93,6 +95,13 @@
>   #define ETP_2FT_YMIN			(  0 + ETP_2FT_FUZZ)
>   #define ETP_2FT_YMAX			(192 - ETP_2FT_FUZZ)
>
> +/*
> + * v3 hardware has 2 kinds of packet types.
> + */
> +#define PACKET_UNKNOWN			0x01
> +#define PACKET_V3_HEAD			0x02
> +#define PACKET_V3_TAIL			0x03
> +
>   struct elantech_data {
>   	unsigned char reg_10;
>   	unsigned char reg_11;
> @@ -113,6 +122,8 @@ struct elantech_data {
>   	unsigned int single_finger_reports;
>   	unsigned int y_max;
>   	unsigned int y_2ft_max;
> +	unsigned int prev_x;
> +	unsigned int prev_y;
>   	unsigned char parity[256];
>   };
>
Wanlong Gao Aug. 18, 2011, 3:04 a.m. UTC | #3
On 08/18/2011 10:57 AM, Daniel Kurtz wrote:
> On Thu, Aug 18, 2011 at 9:57 AM, JJ Ding<jj_ding@emc.com.tw>  wrote:
>> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
>> except when sensing two finger touch, the hardware sends 12 bytes of data.
>>
>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>> ---
>>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>   drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
>>   drivers/input/mouse/elantech.h   |   11 ++
>>   3 files changed, 303 insertions(+), 30 deletions(-)
>>
>> diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
>> index bce9941..ce578bd 100644
>> --- a/Documentation/input/elantech.txt
>> +++ b/Documentation/input/elantech.txt
>> @@ -16,15 +16,22 @@ Contents
>>
>>   1. Introduction
>>   2. Extra knobs
>> - 3. Hardware version 1
>> -    3.1 Registers
>> -    3.2 Native relative mode 4 byte packet format
>> -    3.3 Native absolute mode 4 byte packet format
>> - 4. Hardware version 2
>> + 3. Differentiating hardware versions
>> + 4. Hardware version 1
>>      4.1 Registers
>> -    4.2 Native absolute mode 6 byte packet format
>> -        4.2.1 One finger touch
>> -        4.2.2 Two finger touch
>> +    4.2 Native relative mode 4 byte packet format
>> +    4.3 Native absolute mode 4 byte packet format
>> + 5. Hardware version 2
>> +    5.1 Registers
>> +    5.2 Native absolute mode 6 byte packet format
>> +        5.2.1 Parity checking and packet re-synchronization
>> +        5.2.2 One/Three finger touch
>> +        5.2.3 Two finger touch
>> + 6. Hardware version 3
>> +    6.1 Registers
>> +    6.2 Native absolute mode 6 byte packet format
>> +        6.2.1 One/Three finger touch
>> +        6.2.2 Two finger touch
>>
>>
>>
>> @@ -375,7 +382,7 @@ For all the other ones, there are just a few constant bits:
>>
>>   In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
>>
>> -5.2.1 One/Three finger touch
>> +5.2.2 One/Three finger touch
>>        ~~~~~~~~~~~~~~~~
>>
>>   byte 0:
>> @@ -384,7 +391,7 @@ byte 0:
>>          n1  n0  w3  w2   .   .   R   L
>>
>>           L, R = 1 when Left, Right mouse button pressed
>> -         n1..n0 = numbers of fingers on touchpad
>> +         n1..n0 = number of fingers on touchpad
>>
>>   byte 1:
>>
>> @@ -432,7 +439,7 @@ byte 5:
>>           y11..y0 = absolute y value (vertical)
>>
>>
>> -4.2.2 Two finger touch
>> +5.2.3 Two finger touch
>>        ~~~~~~~~~~~~~~~~
>>
>>   Note that the two pairs of coordinates are not exactly the coordinates of the
>> @@ -446,7 +453,7 @@ byte 0:
>>          n1  n0  ay8 ax8  .   .   R   L
>>
>>           L, R = 1 when Left, Right mouse button pressed
>> -         n1..n0 = numbers of fingers on touchpad
>> +         n1..n0 = number of fingers on touchpad
>>
>>   byte 1:
>>
>> @@ -480,3 +487,76 @@ byte 5:
>>          by7 by8 by5 by4 by3 by2 by1 by0
>>
>>           by8..by0 = upper-right finger absolute y value
>> +
>> +/////////////////////////////////////////////////////////////////////////////
>> +
>> +6. Hardware version 3
>> +   ==================
>> +
>> +6.1 Registers
>> +    ~~~~~~~~~
>> +* reg_10
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +         0   0   0   0   0   0   0   A
>> +
>> +         A: 1 = enable absolute tracking
>> +
>> +6.2 Native absolute mode 6 byte packet format
>> +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> +1 and 3 finger touch shares the same 6-byte packet format, except that
>> +3 finger touch only reports the position of the center of all three fingers.
>> +
>> +Firmware would send 12 bytes of data for 2 finger touch.
>> +
>> +6.2.1 One/Three finger touch
>> +      ~~~~~~~~~~~~~~~~~~~~~~
>> +
>> +byte 0:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +        n1  n0  w3  w2   0   1   R   L
>> +
>> +        L, R = 1 when Left, Right mouse button pressed
>> +        n1..n0 = number of fingers on touchpad
>> +
>> +byte 1:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +        p7  p6  p5  p4 x11 x10  x9  x8
>> +
>> +byte 2:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +        x7  x6  x5  x4  x3  x2  x1  x0
>> +
>> +        x11..x0 = absolute x value (horizontal)
>> +
>> +byte 3:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +         0   0  w1  w0   0   0   1   0
>> +
>> +         w3..w0 = width of the finger touch
>> +
>> +byte 4:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +        p3  p1  p2  p0  y11 y10 y9  y8
>> +
>> +        p7..p0 = pressure
>> +
>> +byte 5:
>> +
>> +   bit   7   6   5   4   3   2   1   0
>> +        y7  y6  y5  y4  y3  y2  y1  y0
>> +
>> +        y11..y0 = absolute y value (vertical)
>> +
>> +6.2.2 Two finger touch
>> +      ~~~~~~~~~~~~~~~~
>> +
>> +The packet format is exactly the same for two finger touch, except the hardware
>> +sends two 6 byte packets. The first packet contains data for the first finger,
>> +the second packet has data for the second finger. So for two finger touch a
>> +total of 12 bytes are sent.
>> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
>> index ddd40eb..e13a719 100644
>> --- a/drivers/input/mouse/elantech.c
>> +++ b/drivers/input/mouse/elantech.c
>> @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
>>                         rc = -1;
>>                 }
>>                 break;
>> +
>> +       case 3:
>> +               if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +                   elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
>> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +                   elantech_ps2_command(psmouse, NULL, reg) ||
>> +                   elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
>> +                       rc = -1;
>> +               }
>> +               break;
>>         }
>>
>>         if (rc)
>> @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
>>                         rc = -1;
>>                 }
>>                 break;
>> +
>> +       case 3:
>> +               if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +                   elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
>> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +                   elantech_ps2_command(psmouse, NULL, reg) ||
>> +                   elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +                   elantech_ps2_command(psmouse, NULL, val) ||
>> +                   elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
>> +                       rc = -1;
>> +               }
>> +               break;
>>         }
>>
>>         if (rc)
>> @@ -352,6 +374,94 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
>>         input_sync(dev);
>>   }
>>
>> +/*
>> + * firmware tells us there's noise.
>> + */
>> +static inline int debounce(unsigned int x, unsigned int y)
>> +{
>> +       return (x == 0xfff)&&  (y == 0xfff);
>
> Perhaps you could document this behavior in the elantech.txt.
>
>> +}
>> +
>> +/*
>> + * Interpret complete data packets and report absolute mode input events for
>> + * hardware version 3. (12 byte packets for two fingers)
>> + */
>> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
>> +                                       int packet_type)
>> +{
>> +       struct input_dev *dev = psmouse->dev;
>> +       struct elantech_data *etd = psmouse->private;
>> +       unsigned char *packet = psmouse->packet;
>> +       unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
>> +       unsigned int width = 0, pres = 0;
>> +
>> +       /* byte 0: n1  n0   .   .   .   .   R   L */
>> +       fingers = (packet[0]&  0xc0)>>  6;
>> +
>> +       switch (fingers) {
>> +       case 3:
>> +       case 1:
>> +               /*
>> +                * byte 1:  .   .   .   .  x11 x10 x9  x8
>> +                * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
>> +                */
>> +               x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
>> +               /*
>> +                * byte 4:  .   .   .   .  y11 y10 y9  y8
>> +                * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
>> +                */
>> +               y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
>> +
>> +               if (fingers == 3&&  debounce(x1, y1))
>> +                       return;
>> +
>> +               break;
>> +
>> +       case 2:
>> +               if (packet_type == PACKET_V3_HEAD) {
>> +                       /*
>> +                        * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
>> +                        * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
>> +                        */
>> +                       etd->prev_x = ((packet[1]&  0x0f)<<  8) | packet[2];
>> +                       /*
>> +                        * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
>> +                        * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
>> +                        */
>> +                       etd->prev_y = etd->y_max -
>> +                               (((packet[4]&  0x0f)<<  8) | packet[5]);
>> +                       /*
>> +                        * wait for next packet
>> +                        */
>> +                       return;
>> +               }
>> +
>> +               /* packet_type == PACKET_V3_TAIL */
>> +               x1 = etd->prev_x;
>> +               y1 = etd->prev_y;
>> +               x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
>> +               y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
>> +               break;
>> +       }
>> +
>> +       pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
>> +       width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
>> +
>> +       input_report_key(dev, BTN_TOUCH, fingers != 0);
>> +       input_report_abs(dev, ABS_X, x1);
>> +       input_report_abs(dev, ABS_Y, y1);
>> +       elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
>> +       input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
>> +       input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
>> +       input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
>> +       input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
>> +       input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
>> +       input_report_abs(dev, ABS_PRESSURE, pres);
>> +       input_report_abs(dev, ABS_TOOL_WIDTH, width);
>> +
>> +       input_sync(dev);
>> +}
>> +
>>   static int elantech_check_parity_v1(struct psmouse *psmouse)
>>   {
>>         struct elantech_data *etd = psmouse->private;
>> @@ -396,11 +506,31 @@ static int packet_simple_check_v2(struct psmouse *psmouse)
>>   }
>>
>>   /*
>> + * We check the constant bits to determine what packet type we get,
>> + * so packet checking is mandatory for v3 hardware.
>> + */
>> +static int determine_packet_v3(struct psmouse *psmouse)
>> +{
>> +       unsigned char *packet = psmouse->packet;
>> +
>> +       if ((packet[0]&  0x0c) == 0x04&&
>> +           (packet[3]&  0xcf) == 0x02)
>> +               return PACKET_V3_HEAD;
>> +
>> +       if ((packet[0]&  0x0c) == 0x0c&&
>> +           (packet[3]&  0xce) == 0x0c)
>> +               return PACKET_V3_TAIL;
>> +
>> +       return PACKET_UNKNOWN;
>> +}
>> +
>> +/*
>>   * Process byte stream from mouse and handle complete packets
>>   */
>>   static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>>   {
>>         struct elantech_data *etd = psmouse->private;
>> +       int packet_type;
>>
>>         if (psmouse->pktcnt<  psmouse->pktsize)
>>                 return PSMOUSE_GOOD_DATA;
>> @@ -422,6 +552,14 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>>
>>                 elantech_report_absolute_v2(psmouse);
>>                 break;
>> +
>> +       case 3:
>> +               packet_type = determine_packet_v3(psmouse);
>> +               if (packet_type == PACKET_UNKNOWN)
>> +                       goto bad_packet;
>> +
>> +               elantech_report_absolute_v3(psmouse, packet_type);
>> +               break;
>>         }
>>
>>         return PSMOUSE_FULL_PACKET;
>> @@ -459,10 +597,17 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>>                 etd->reg_21 = 0x60;     /* 0x00 */
>>                 if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
>>                     elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
>> -                   elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
>> +                   elantech_write_reg(psmouse, 0x21, etd->reg_21))
>>                         rc = -1;
>> -                       break;
>> -               }
>> +
>> +               break;
>> +
>> +       case 3:
>> +               etd->reg_10 = 0x0b;
>> +               if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
>> +                       rc = -1;
>> +
>> +               break;
>>         }
>>
>>         if (rc == 0) {
>> @@ -496,11 +641,12 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)
>>         return rc;
>>   }
>>
>> -static void set_range(struct psmouse *psmouse, unsigned int *x_min,
>> +static int set_range(struct psmouse *psmouse, unsigned int *x_min,
>>                      unsigned int *y_min, unsigned int *x_max,
>>                      unsigned int *y_max, unsigned int *y_2ft_max)
>>   {
>>         struct elantech_data *etd = psmouse->private;
>> +       unsigned char param[3];
>>         int i;
>>
>>         switch (etd->hw_version) {
>> @@ -529,19 +675,30 @@ static void set_range(struct psmouse *psmouse, unsigned int *x_min,
>>                 *y_max = (etd->capabilities[2] - i) * 64;
>>                 *y_2ft_max = (*y_max - i) * 64 / 4;
>>                 break;
>> +
>> +       case 3:
>> +               if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
>> +                       return -1;
>> +
>> +               *x_max = (0x0f&  param[0])<<  8 | param[1];
>> +               *y_max = (0xf0&  param[0])<<  4 | param[2];
>> +               break;
>>         }
>> +
>> +       return 0;
>>   }
>>
>>   /*
>>   * Set the appropriate event bits for the input subsystem
>>   */
>> -static void elantech_set_input_params(struct psmouse *psmouse)
>> +static int elantech_set_input_params(struct psmouse *psmouse)
>>   {
>>         struct input_dev *dev = psmouse->dev;
>>         struct elantech_data *etd = psmouse->private;
>>         unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
>>
>> -       set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
>> +       if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
>> +               return -1;
>>
>>         __set_bit(EV_KEY, dev->evbit);
>>         __set_bit(EV_ABS, dev->evbit);
>> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
>>                 input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>>                 input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>>                 break;
>> +
>> +       case 3:
>> +               input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
>> +               input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
>> +               /* range of pressure and width is the same as v2 */
>> +               input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
>> +                                    ETP_PMAX_V2, 0, 0);
>> +               input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
>> +                                    ETP_WMAX_V2, 0, 0);
>> +               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
>> +               input_mt_init_slots(dev, 2);
>> +               input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>> +               input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>> +               break;
>>         }
>>
>>         etd->y_max = y_max;
>>         etd->y_2ft_max = y_2ft_max;
>> +
>> +       return 0;
>>   }
>>
>>   struct elantech_attr_data {
>> @@ -727,7 +900,8 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
>>          * Report this in case there are Elantech models that use a different
>>          * set of magic numbers
>>          */
>> -       if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
>> +       if (param[0] != 0x3c || param[1] != 0x03 ||
>> +           (param[2] != 0xc8&&  param[2] != 0x00)) {
>>                 pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
>>                          param[0], param[1], param[2]);
>>                 return -1;
>> @@ -793,16 +967,16 @@ static int elantech_reconnect(struct psmouse *psmouse)
>>   /*
>>   * determine hardware version and set some properties according to it.
>>   */
>> -static void elantech_set_properties(struct elantech_data *etd)
>> +static int elantech_set_properties(struct elantech_data *etd)
>>   {
>> -       /*
>> -        * Assume every version greater than 0x020030 is new EeePC style
>> -        * hardware with 6 byte packets, except 0x020600
>> -        */
>>         if (etd->fw_version<  0x020030 || etd->fw_version == 0x020600)
>>                 etd->hw_version = 1;
>> -       else
>> +       else if (etd->fw_version<  0x150600)
>>                 etd->hw_version = 2;
>> +       else if ((etd->fw_version&  0x0f0000)>>  16 == 5)
>> +               etd->hw_version = 3;
>> +       else
>> +               return -1;
>>
>>         /*
>>          * Turn on packet checking by default.
>> @@ -817,13 +991,15 @@ static void elantech_set_properties(struct elantech_data *etd)
>>         etd->jumpy_cursor =
>>                 (etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
>>
>> -       if (etd->hw_version == 2) {
>> +       if (etd->hw_version>  1) {
>>                 /* For now show extra debug information */
>>                 etd->debug = 1;
>>
>>                 if (etd->fw_version>= 0x020800)
>>                         etd->reports_pressure = true;
>>         }
>> +
>> +       return 0;
>>   }
>>
>>   /*
>> @@ -850,9 +1026,12 @@ int elantech_init(struct psmouse *psmouse)
>>                 pr_err("failed to query firmware version.\n");
>>                 goto init_fail;
>>         }
>> -
>>         etd->fw_version = (param[0]<<  16) | (param[1]<<  8) | param[2];
>> -       elantech_set_properties(etd);
>> +
>> +       if (elantech_set_properties(etd)) {
>> +               pr_err("unknown hardware version, aborting...\n");
>> +               goto init_fail;
>> +       }
>>         pr_info("assuming hardware version %d "
>>                 "(with firmware version 0x%02x%02x%02x)\n",
>>                 etd->hw_version, param[0], param[1], param[2]);
>> @@ -871,7 +1050,10 @@ int elantech_init(struct psmouse *psmouse)
>>                 goto init_fail;
>>         }
>>
>> -       elantech_set_input_params(psmouse);
>> +       if (elantech_set_input_params(psmouse)) {
>> +               pr_err("failed to query touchpad range.\n");
>> +               goto init_fail;
>> +       }
>>
>>         error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
>>                                    &elantech_attr_group);
>> @@ -883,7 +1065,7 @@ int elantech_init(struct psmouse *psmouse)
>>         psmouse->protocol_handler = elantech_process_byte;
>>         psmouse->disconnect = elantech_disconnect;
>>         psmouse->reconnect = elantech_reconnect;
>> -       psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
>> +       psmouse->pktsize = etd->hw_version>  1 ? 6 : 4;
>>
>>         return 0;
>>
>> diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
>> index 4b7447e..4f01fc6 100644
>> --- a/drivers/input/mouse/elantech.h
>> +++ b/drivers/input/mouse/elantech.h
>> @@ -16,6 +16,7 @@
>>   /*
>>   * Command values for Synaptics style queries
>>   */
>> +#define ETP_FW_ID_QUERY                        0x00
>
> One tab too many?
No.
>
>>   #define ETP_FW_VERSION_QUERY           0x01
>>   #define ETP_CAPABILITIES_QUERY         0x02
>>
>> @@ -24,6 +25,7 @@
>>   */
>>   #define ETP_REGISTER_READ              0x10
>>   #define ETP_REGISTER_WRITE             0x11
>> +#define ETP_REGISTER_READWRITE         0x00
>>
>>   /*
>>   * Hardware version 2 custom PS/2 command value
>> @@ -93,6 +95,13 @@
>>   #define ETP_2FT_YMIN                   (  0 + ETP_2FT_FUZZ)
>>   #define ETP_2FT_YMAX                   (192 - ETP_2FT_FUZZ)
>>
>> +/*
>> + * v3 hardware has 2 kinds of packet types.
>> + */
>> +#define PACKET_UNKNOWN                 0x01
>> +#define PACKET_V3_HEAD                 0x02
>> +#define PACKET_V3_TAIL                 0x03
>> +
>>   struct elantech_data {
>>         unsigned char reg_10;
>>         unsigned char reg_11;
>> @@ -113,6 +122,8 @@ struct elantech_data {
>>         unsigned int single_finger_reports;
>>         unsigned int y_max;
>>         unsigned int y_2ft_max;
>> +       unsigned int prev_x;
>> +       unsigned int prev_y;
>>         unsigned char parity[256];
>>   };
>>
>> --
>> 1.7.4.1
>>
>>
> --
> 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
>
Daniel Kurtz Aug. 18, 2011, 3:09 a.m. UTC | #4
On Thu, Aug 18, 2011 at 11:04 AM, Wanlong Gao <gaowanlong@cn.fujitsu.com> wrote:
> On 08/18/2011 10:57 AM, Daniel Kurtz wrote:
>>
>> On Thu, Aug 18, 2011 at 9:57 AM, JJ Ding<jj_ding@emc.com.tw>  wrote:
>>>
>>> v3 hardware's packet format is almost identical to v2 (one/three finger
>>> touch),
>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>> data.
>>>
>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>> ---
>>>  Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>  drivers/input/mouse/elantech.c   |  218
>>> ++++++++++++++++++++++++++++++++++---
>>>  drivers/input/mouse/elantech.h   |   11 ++
>>>  3 files changed, 303 insertions(+), 30 deletions(-)
>>>
>>> diff --git a/Documentation/input/elantech.txt
>>> b/Documentation/input/elantech.txt
>>> index bce9941..ce578bd 100644
>>> --- a/Documentation/input/elantech.txt
>>> +++ b/Documentation/input/elantech.txt
>>> @@ -16,15 +16,22 @@ Contents
>>>
>>>  1. Introduction
>>>  2. Extra knobs
>>> - 3. Hardware version 1
>>> -    3.1 Registers
>>> -    3.2 Native relative mode 4 byte packet format
>>> -    3.3 Native absolute mode 4 byte packet format
>>> - 4. Hardware version 2
>>> + 3. Differentiating hardware versions
>>> + 4. Hardware version 1
>>>     4.1 Registers
>>> -    4.2 Native absolute mode 6 byte packet format
>>> -        4.2.1 One finger touch
>>> -        4.2.2 Two finger touch
>>> +    4.2 Native relative mode 4 byte packet format
>>> +    4.3 Native absolute mode 4 byte packet format
>>> + 5. Hardware version 2
>>> +    5.1 Registers
>>> +    5.2 Native absolute mode 6 byte packet format
>>> +        5.2.1 Parity checking and packet re-synchronization
>>> +        5.2.2 One/Three finger touch
>>> +        5.2.3 Two finger touch
>>> + 6. Hardware version 3
>>> +    6.1 Registers
>>> +    6.2 Native absolute mode 6 byte packet format
>>> +        6.2.1 One/Three finger touch
>>> +        6.2.2 Two finger touch
>>>
>>>
>>>
>>> @@ -375,7 +382,7 @@ For all the other ones, there are just a few constant
>>> bits:
>>>
>>>  In case an error is detected, all the packets are shifted by one (and
>>> packet[0] is discarded).
>>>
>>> -5.2.1 One/Three finger touch
>>> +5.2.2 One/Three finger touch
>>>       ~~~~~~~~~~~~~~~~
>>>
>>>  byte 0:
>>> @@ -384,7 +391,7 @@ byte 0:
>>>         n1  n0  w3  w2   .   .   R   L
>>>
>>>          L, R = 1 when Left, Right mouse button pressed
>>> -         n1..n0 = numbers of fingers on touchpad
>>> +         n1..n0 = number of fingers on touchpad
>>>
>>>  byte 1:
>>>
>>> @@ -432,7 +439,7 @@ byte 5:
>>>          y11..y0 = absolute y value (vertical)
>>>
>>>
>>> -4.2.2 Two finger touch
>>> +5.2.3 Two finger touch
>>>       ~~~~~~~~~~~~~~~~
>>>
>>>  Note that the two pairs of coordinates are not exactly the coordinates
>>> of the
>>> @@ -446,7 +453,7 @@ byte 0:
>>>         n1  n0  ay8 ax8  .   .   R   L
>>>
>>>          L, R = 1 when Left, Right mouse button pressed
>>> -         n1..n0 = numbers of fingers on touchpad
>>> +         n1..n0 = number of fingers on touchpad
>>>
>>>  byte 1:
>>>
>>> @@ -480,3 +487,76 @@ byte 5:
>>>         by7 by8 by5 by4 by3 by2 by1 by0
>>>
>>>          by8..by0 = upper-right finger absolute y value
>>> +
>>>
>>> +/////////////////////////////////////////////////////////////////////////////
>>> +
>>> +6. Hardware version 3
>>> +   ==================
>>> +
>>> +6.1 Registers
>>> +    ~~~~~~~~~
>>> +* reg_10
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +         0   0   0   0   0   0   0   A
>>> +
>>> +         A: 1 = enable absolute tracking
>>> +
>>> +6.2 Native absolute mode 6 byte packet format
>>> +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> +1 and 3 finger touch shares the same 6-byte packet format, except that
>>> +3 finger touch only reports the position of the center of all three
>>> fingers.
>>> +
>>> +Firmware would send 12 bytes of data for 2 finger touch.
>>> +
>>> +6.2.1 One/Three finger touch
>>> +      ~~~~~~~~~~~~~~~~~~~~~~
>>> +
>>> +byte 0:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +        n1  n0  w3  w2   0   1   R   L
>>> +
>>> +        L, R = 1 when Left, Right mouse button pressed
>>> +        n1..n0 = number of fingers on touchpad
>>> +
>>> +byte 1:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +        p7  p6  p5  p4 x11 x10  x9  x8
>>> +
>>> +byte 2:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +        x7  x6  x5  x4  x3  x2  x1  x0
>>> +
>>> +        x11..x0 = absolute x value (horizontal)
>>> +
>>> +byte 3:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +         0   0  w1  w0   0   0   1   0
>>> +
>>> +         w3..w0 = width of the finger touch
>>> +
>>> +byte 4:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +        p3  p1  p2  p0  y11 y10 y9  y8
>>> +
>>> +        p7..p0 = pressure
>>> +
>>> +byte 5:
>>> +
>>> +   bit   7   6   5   4   3   2   1   0
>>> +        y7  y6  y5  y4  y3  y2  y1  y0
>>> +
>>> +        y11..y0 = absolute y value (vertical)
>>> +
>>> +6.2.2 Two finger touch
>>> +      ~~~~~~~~~~~~~~~~
>>> +
>>> +The packet format is exactly the same for two finger touch, except the
>>> hardware
>>> +sends two 6 byte packets. The first packet contains data for the first
>>> finger,
>>> +the second packet has data for the second finger. So for two finger
>>> touch a
>>> +total of 12 bytes are sent.
>>> diff --git a/drivers/input/mouse/elantech.c
>>> b/drivers/input/mouse/elantech.c
>>> index ddd40eb..e13a719 100644
>>> --- a/drivers/input/mouse/elantech.c
>>> +++ b/drivers/input/mouse/elantech.c
>>> @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse
>>> *psmouse, unsigned char reg,
>>>                        rc = -1;
>>>                }
>>>                break;
>>> +
>>> +       case 3:
>>> +               if (elantech_ps2_command(psmouse, NULL,
>>> ETP_PS2_CUSTOM_COMMAND) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> ETP_REGISTER_READWRITE) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> ETP_PS2_CUSTOM_COMMAND) ||
>>> +                   elantech_ps2_command(psmouse, NULL, reg) ||
>>> +                   elantech_ps2_command(psmouse, param,
>>> PSMOUSE_CMD_GETINFO)) {
>>> +                       rc = -1;
>>> +               }
>>> +               break;
>>>        }
>>>
>>>        if (rc)
>>> @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse
>>> *psmouse, unsigned char reg,
>>>                        rc = -1;
>>>                }
>>>                break;
>>> +
>>> +       case 3:
>>> +               if (elantech_ps2_command(psmouse, NULL,
>>> ETP_PS2_CUSTOM_COMMAND) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> ETP_REGISTER_READWRITE) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> ETP_PS2_CUSTOM_COMMAND) ||
>>> +                   elantech_ps2_command(psmouse, NULL, reg) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> ETP_PS2_CUSTOM_COMMAND) ||
>>> +                   elantech_ps2_command(psmouse, NULL, val) ||
>>> +                   elantech_ps2_command(psmouse, NULL,
>>> PSMOUSE_CMD_SETSCALE11)) {
>>> +                       rc = -1;
>>> +               }
>>> +               break;
>>>        }
>>>
>>>        if (rc)
>>> @@ -352,6 +374,94 @@ static void elantech_report_absolute_v2(struct
>>> psmouse *psmouse)
>>>        input_sync(dev);
>>>  }
>>>
>>> +/*
>>> + * firmware tells us there's noise.
>>> + */
>>> +static inline int debounce(unsigned int x, unsigned int y)
>>> +{
>>> +       return (x == 0xfff)&&  (y == 0xfff);
>>
>> Perhaps you could document this behavior in the elantech.txt.
>>
>>> +}
>>> +
>>> +/*
>>> + * Interpret complete data packets and report absolute mode input events
>>> for
>>> + * hardware version 3. (12 byte packets for two fingers)
>>> + */
>>> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
>>> +                                       int packet_type)
>>> +{
>>> +       struct input_dev *dev = psmouse->dev;
>>> +       struct elantech_data *etd = psmouse->private;
>>> +       unsigned char *packet = psmouse->packet;
>>> +       unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
>>> +       unsigned int width = 0, pres = 0;
>>> +
>>> +       /* byte 0: n1  n0   .   .   .   .   R   L */
>>> +       fingers = (packet[0]&  0xc0)>>  6;
>>> +
>>> +       switch (fingers) {
>>> +       case 3:
>>> +       case 1:
>>> +               /*
>>> +                * byte 1:  .   .   .   .  x11 x10 x9  x8
>>> +                * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
>>> +                */
>>> +               x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
>>> +               /*
>>> +                * byte 4:  .   .   .   .  y11 y10 y9  y8
>>> +                * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
>>> +                */
>>> +               y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) |
>>> packet[5]);
>>> +
>>> +               if (fingers == 3&&  debounce(x1, y1))
>>> +                       return;
>>> +
>>> +               break;
>>> +
>>> +       case 2:
>>> +               if (packet_type == PACKET_V3_HEAD) {
>>> +                       /*
>>> +                        * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
>>> +                        * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
>>> +                        */
>>> +                       etd->prev_x = ((packet[1]&  0x0f)<<  8) |
>>> packet[2];
>>> +                       /*
>>> +                        * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
>>> +                        * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
>>> +                        */
>>> +                       etd->prev_y = etd->y_max -
>>> +                               (((packet[4]&  0x0f)<<  8) | packet[5]);
>>> +                       /*
>>> +                        * wait for next packet
>>> +                        */
>>> +                       return;
>>> +               }
>>> +
>>> +               /* packet_type == PACKET_V3_TAIL */
>>> +               x1 = etd->prev_x;
>>> +               y1 = etd->prev_y;
>>> +               x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
>>> +               y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) |
>>> packet[5]);
>>> +               break;
>>> +       }
>>> +
>>> +       pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
>>> +       width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
>>> +
>>> +       input_report_key(dev, BTN_TOUCH, fingers != 0);
>>> +       input_report_abs(dev, ABS_X, x1);
>>> +       input_report_abs(dev, ABS_Y, y1);
>>> +       elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
>>> +       input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
>>> +       input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
>>> +       input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
>>> +       input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
>>> +       input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
>>> +       input_report_abs(dev, ABS_PRESSURE, pres);
>>> +       input_report_abs(dev, ABS_TOOL_WIDTH, width);
>>> +
>>> +       input_sync(dev);
>>> +}
>>> +
>>>  static int elantech_check_parity_v1(struct psmouse *psmouse)
>>>  {
>>>        struct elantech_data *etd = psmouse->private;
>>> @@ -396,11 +506,31 @@ static int packet_simple_check_v2(struct psmouse
>>> *psmouse)
>>>  }
>>>
>>>  /*
>>> + * We check the constant bits to determine what packet type we get,
>>> + * so packet checking is mandatory for v3 hardware.
>>> + */
>>> +static int determine_packet_v3(struct psmouse *psmouse)
>>> +{
>>> +       unsigned char *packet = psmouse->packet;
>>> +
>>> +       if ((packet[0]&  0x0c) == 0x04&&
>>> +           (packet[3]&  0xcf) == 0x02)
>>> +               return PACKET_V3_HEAD;
>>> +
>>> +       if ((packet[0]&  0x0c) == 0x0c&&
>>> +           (packet[3]&  0xce) == 0x0c)
>>> +               return PACKET_V3_TAIL;
>>> +
>>> +       return PACKET_UNKNOWN;
>>> +}
>>> +
>>> +/*
>>>  * Process byte stream from mouse and handle complete packets
>>>  */
>>>  static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
>>>  {
>>>        struct elantech_data *etd = psmouse->private;
>>> +       int packet_type;
>>>
>>>        if (psmouse->pktcnt<  psmouse->pktsize)
>>>                return PSMOUSE_GOOD_DATA;
>>> @@ -422,6 +552,14 @@ static psmouse_ret_t elantech_process_byte(struct
>>> psmouse *psmouse)
>>>
>>>                elantech_report_absolute_v2(psmouse);
>>>                break;
>>> +
>>> +       case 3:
>>> +               packet_type = determine_packet_v3(psmouse);
>>> +               if (packet_type == PACKET_UNKNOWN)
>>> +                       goto bad_packet;
>>> +
>>> +               elantech_report_absolute_v3(psmouse, packet_type);
>>> +               break;
>>>        }
>>>
>>>        return PSMOUSE_FULL_PACKET;
>>> @@ -459,10 +597,17 @@ static int elantech_set_absolute_mode(struct
>>> psmouse *psmouse)
>>>                etd->reg_21 = 0x60;     /* 0x00 */
>>>                if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
>>>                    elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
>>> -                   elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
>>> +                   elantech_write_reg(psmouse, 0x21, etd->reg_21))
>>>                        rc = -1;
>>> -                       break;
>>> -               }
>>> +
>>> +               break;
>>> +
>>> +       case 3:
>>> +               etd->reg_10 = 0x0b;
>>> +               if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
>>> +                       rc = -1;
>>> +
>>> +               break;
>>>        }
>>>
>>>        if (rc == 0) {
>>> @@ -496,11 +641,12 @@ static int elantech_set_absolute_mode(struct
>>> psmouse *psmouse)
>>>        return rc;
>>>  }
>>>
>>> -static void set_range(struct psmouse *psmouse, unsigned int *x_min,
>>> +static int set_range(struct psmouse *psmouse, unsigned int *x_min,
>>>                     unsigned int *y_min, unsigned int *x_max,
>>>                     unsigned int *y_max, unsigned int *y_2ft_max)
>>>  {
>>>        struct elantech_data *etd = psmouse->private;
>>> +       unsigned char param[3];
>>>        int i;
>>>
>>>        switch (etd->hw_version) {
>>> @@ -529,19 +675,30 @@ static void set_range(struct psmouse *psmouse,
>>> unsigned int *x_min,
>>>                *y_max = (etd->capabilities[2] - i) * 64;
>>>                *y_2ft_max = (*y_max - i) * 64 / 4;
>>>                break;
>>> +
>>> +       case 3:
>>> +               if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
>>> +                       return -1;
>>> +
>>> +               *x_max = (0x0f&  param[0])<<  8 | param[1];
>>> +               *y_max = (0xf0&  param[0])<<  4 | param[2];
>>> +               break;
>>>        }
>>> +
>>> +       return 0;
>>>  }
>>>
>>>  /*
>>>  * Set the appropriate event bits for the input subsystem
>>>  */
>>> -static void elantech_set_input_params(struct psmouse *psmouse)
>>> +static int elantech_set_input_params(struct psmouse *psmouse)
>>>  {
>>>        struct input_dev *dev = psmouse->dev;
>>>        struct elantech_data *etd = psmouse->private;
>>>        unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max
>>> = 0;
>>>
>>> -       set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
>>> +       if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
>>> +               return -1;
>>>
>>>        __set_bit(EV_KEY, dev->evbit);
>>>        __set_bit(EV_ABS, dev->evbit);
>>> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct
>>> psmouse *psmouse)
>>>                input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max,
>>> 0, 0);
>>>                input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max,
>>> 0, 0);
>>>                break;
>>> +
>>> +       case 3:
>>> +               input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
>>> +               input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
>>> +               /* range of pressure and width is the same as v2 */
>>> +               input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
>>> +                                    ETP_PMAX_V2, 0, 0);
>>> +               input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
>>> +                                    ETP_WMAX_V2, 0, 0);
>>> +               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
>>> +               input_mt_init_slots(dev, 2);
>>> +               input_set_abs_params(dev, ABS_MT_POSITION_X, x_min,
>>> x_max, 0, 0);
>>> +               input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min,
>>> y_max, 0, 0);
>>> +               break;
>>>        }
>>>
>>>        etd->y_max = y_max;
>>>        etd->y_2ft_max = y_2ft_max;
>>> +
>>> +       return 0;
>>>  }
>>>
>>>  struct elantech_attr_data {
>>> @@ -727,7 +900,8 @@ int elantech_detect(struct psmouse *psmouse, bool
>>> set_properties)
>>>         * Report this in case there are Elantech models that use a
>>> different
>>>         * set of magic numbers
>>>         */
>>> -       if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
>>> +       if (param[0] != 0x3c || param[1] != 0x03 ||
>>> +           (param[2] != 0xc8&&  param[2] != 0x00)) {
>>>                pr_debug("unexpected magic knock result 0x%02x, 0x%02x,
>>> 0x%02x.\n",
>>>                         param[0], param[1], param[2]);
>>>                return -1;
>>> @@ -793,16 +967,16 @@ static int elantech_reconnect(struct psmouse
>>> *psmouse)
>>>  /*
>>>  * determine hardware version and set some properties according to it.
>>>  */
>>> -static void elantech_set_properties(struct elantech_data *etd)
>>> +static int elantech_set_properties(struct elantech_data *etd)
>>>  {
>>> -       /*
>>> -        * Assume every version greater than 0x020030 is new EeePC style
>>> -        * hardware with 6 byte packets, except 0x020600
>>> -        */
>>>        if (etd->fw_version<  0x020030 || etd->fw_version == 0x020600)
>>>                etd->hw_version = 1;
>>> -       else
>>> +       else if (etd->fw_version<  0x150600)
>>>                etd->hw_version = 2;
>>> +       else if ((etd->fw_version&  0x0f0000)>>  16 == 5)
>>> +               etd->hw_version = 3;
>>> +       else
>>> +               return -1;
>>>
>>>        /*
>>>         * Turn on packet checking by default.
>>> @@ -817,13 +991,15 @@ static void elantech_set_properties(struct
>>> elantech_data *etd)
>>>        etd->jumpy_cursor =
>>>                (etd->fw_version == 0x020022 || etd->fw_version ==
>>> 0x020600);
>>>
>>> -       if (etd->hw_version == 2) {
>>> +       if (etd->hw_version>  1) {
>>>                /* For now show extra debug information */
>>>                etd->debug = 1;
>>>
>>>                if (etd->fw_version>= 0x020800)
>>>                        etd->reports_pressure = true;
>>>        }
>>> +
>>> +       return 0;
>>>  }
>>>
>>>  /*
>>> @@ -850,9 +1026,12 @@ int elantech_init(struct psmouse *psmouse)
>>>                pr_err("failed to query firmware version.\n");
>>>                goto init_fail;
>>>        }
>>> -
>>>        etd->fw_version = (param[0]<<  16) | (param[1]<<  8) | param[2];
>>> -       elantech_set_properties(etd);
>>> +
>>> +       if (elantech_set_properties(etd)) {
>>> +               pr_err("unknown hardware version, aborting...\n");
>>> +               goto init_fail;
>>> +       }
>>>        pr_info("assuming hardware version %d "
>>>                "(with firmware version 0x%02x%02x%02x)\n",
>>>                etd->hw_version, param[0], param[1], param[2]);
>>> @@ -871,7 +1050,10 @@ int elantech_init(struct psmouse *psmouse)
>>>                goto init_fail;
>>>        }
>>>
>>> -       elantech_set_input_params(psmouse);
>>> +       if (elantech_set_input_params(psmouse)) {
>>> +               pr_err("failed to query touchpad range.\n");
>>> +               goto init_fail;
>>> +       }
>>>
>>>        error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
>>>                                   &elantech_attr_group);
>>> @@ -883,7 +1065,7 @@ int elantech_init(struct psmouse *psmouse)
>>>        psmouse->protocol_handler = elantech_process_byte;
>>>        psmouse->disconnect = elantech_disconnect;
>>>        psmouse->reconnect = elantech_reconnect;
>>> -       psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
>>> +       psmouse->pktsize = etd->hw_version>  1 ? 6 : 4;
>>>
>>>        return 0;
>>>
>>> diff --git a/drivers/input/mouse/elantech.h
>>> b/drivers/input/mouse/elantech.h
>>> index 4b7447e..4f01fc6 100644
>>> --- a/drivers/input/mouse/elantech.h
>>> +++ b/drivers/input/mouse/elantech.h
>>> @@ -16,6 +16,7 @@
>>>  /*
>>>  * Command values for Synaptics style queries
>>>  */
>>> +#define ETP_FW_ID_QUERY                        0x00
>>
>> One tab too many?
>
> No.

Yeah, weird patchwork diff'ing artifact....


>>
>>>  #define ETP_FW_VERSION_QUERY           0x01
>>>  #define ETP_CAPABILITIES_QUERY         0x02
>>>
>>> @@ -24,6 +25,7 @@
>>>  */
>>>  #define ETP_REGISTER_READ              0x10
>>>  #define ETP_REGISTER_WRITE             0x11
>>> +#define ETP_REGISTER_READWRITE         0x00
>>>
>>>  /*
>>>  * Hardware version 2 custom PS/2 command value
>>> @@ -93,6 +95,13 @@
>>>  #define ETP_2FT_YMIN                   (  0 + ETP_2FT_FUZZ)
>>>  #define ETP_2FT_YMAX                   (192 - ETP_2FT_FUZZ)
>>>
>>> +/*
>>> + * v3 hardware has 2 kinds of packet types.
>>> + */
>>> +#define PACKET_UNKNOWN                 0x01
>>> +#define PACKET_V3_HEAD                 0x02
>>> +#define PACKET_V3_TAIL                 0x03
>>> +
>>>  struct elantech_data {
>>>        unsigned char reg_10;
>>>        unsigned char reg_11;
>>> @@ -113,6 +122,8 @@ struct elantech_data {
>>>        unsigned int single_finger_reports;
>>>        unsigned int y_max;
>>>        unsigned int y_2ft_max;
>>> +       unsigned int prev_x;
>>> +       unsigned int prev_y;
>>>        unsigned char parity[256];
>>>  };
>>>
>>> --
>>> 1.7.4.1
>>>
>>>
>> --
>> 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
>>
>
>
> --
> Thanks
> Wanlong Gao
>
--
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
Wanlong Gao Aug. 18, 2011, 3:22 a.m. UTC | #5
On 08/18/2011 11:09 AM, Daniel Kurtz wrote:
> On Thu, Aug 18, 2011 at 11:04 AM, Wanlong Gao<gaowanlong@cn.fujitsu.com>  wrote:
>> On 08/18/2011 10:57 AM, Daniel Kurtz wrote:
>>>
>>> On Thu, Aug 18, 2011 at 9:57 AM, JJ Ding<jj_ding@emc.com.tw>    wrote:
>>>>
>>>> v3 hardware's packet format is almost identical to v2 (one/three finger
>>>> touch),
>>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>>> data.
>>>>
>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>>> ---
>>>>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>>   drivers/input/mouse/elantech.c   |  218
>>>> ++++++++++++++++++++++++++++++++++---
>>>>   drivers/input/mouse/elantech.h   |   11 ++
>>>>   3 files changed, 303 insertions(+), 30 deletions(-)
>>>>

>>>>
>>>> diff --git a/drivers/input/mouse/elantech.h
>>>> b/drivers/input/mouse/elantech.h
>>>> index 4b7447e..4f01fc6 100644
>>>> --- a/drivers/input/mouse/elantech.h
>>>> +++ b/drivers/input/mouse/elantech.h
>>>> @@ -16,6 +16,7 @@
>>>>   /*
>>>>   * Command values for Synaptics style queries
>>>>   */
>>>> +#define ETP_FW_ID_QUERY                        0x00
>>>
>>> One tab too many?
>>
>> No.
>
> Yeah, weird patchwork diff'ing artifact....
Yeah, it's caused by the '+' ahead the line.
Wanlong Gao Aug. 18, 2011, 3:30 a.m. UTC | #6
On 08/18/2011 09:57 AM, JJ Ding wrote:
> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> except when sensing two finger touch, the hardware sends 12 bytes of data.
>
> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> ---
>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>   drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
>   drivers/input/mouse/elantech.h   |   11 ++
>   3 files changed, 303 insertions(+), 30 deletions(-)

> +The packet format is exactly the same for two finger touch, except the hardware
> +sends two 6 byte packets. The first packet contains data for the first finger,
> +the second packet has data for the second finger. So for two finger touch a
> +total of 12 bytes are sent.
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index ddd40eb..e13a719 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
> @@ -108,6 +108,16 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
>   			rc = -1;
>   		}
>   		break;
> +
> +	case 3:
> +		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, reg) ||
> +		    elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
> +			rc = -1;
> +		}
Prefer to remove these big brace ?
also with "case 1, case 2 "?
> +		break;
>   	}
>
>   	if (rc)
> @@ -154,6 +164,18 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
>   			rc = -1;
>   		}
>   		break;
> +
> +	case 3:
> +		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, reg) ||
> +		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> +		    elantech_ps2_command(psmouse, NULL, val) ||
> +		    elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
> +			rc = -1;
> +		}
ditto

--
Thanks
Wanlong Gao
--
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
Li Zefan Aug. 18, 2011, 3:47 a.m. UTC | #7
>> +
>> +    case 3:
>> +        if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +            elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
>> +            elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>> +            elantech_ps2_command(psmouse, NULL, reg) ||
>> +            elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
>> +            rc = -1;
>> +        }
> Prefer to remove these big brace ?
> also with "case 1, case 2 "?

Just wondering What's wrong with this piece of code and what do you
sugguest to improve it?
--
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
Wanlong Gao Aug. 18, 2011, 4:15 a.m. UTC | #8
On 08/18/2011 11:47 AM, Li Zefan wrote:
>>> +
>>> +    case 3:
>>> +        if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>>> +            elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
>>> +            elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>>> +            elantech_ps2_command(psmouse, NULL, reg) ||
>>> +            elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
>>> +            rc = -1;
>>> +        }
>> Prefer to remove these big brace ?
>> also with "case 1, case 2 "?
>
> Just wondering What's wrong with this piece of code and what do you
> sugguest to improve it?

I think no need to add a '{}' with the *if* ?
and remove the '{}' in whole elantech_read_reg() and 
elantech_write_reg(), right?

-Wanlong Gao

--
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
JJ Ding Aug. 18, 2011, 5:26 a.m. UTC | #9
Hi Wanlong Gao,

On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong Gao <gaowanlong@cn.fujitsu.com> wrote:
> On 08/18/2011 09:57 AM, JJ Ding wrote:
> > v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> > except when sensing two finger touch, the hardware sends 12 bytes of data.
> >
> > Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> > ---
> >   Documentation/input/elantech.txt |  104 ++++++++++++++++--
> >   drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
> >   drivers/input/mouse/elantech.h   |   11 ++
> >   3 files changed, 303 insertions(+), 30 deletions(-)
> >
> > +static int determine_packet_v3(struct psmouse *psmouse)
> elantech_check_parity_v1
> packet_simple_check_v2
> determine_packet_v3
> 
> Why not consistent them?
OK, how do these names sound to you?

elantech_check_parity_v1
elantech_packet_check_v2
elantech_packet_check_v3

Thanks,
jj

> -- 
> Thanks
> Wanlong Gao
> --
> 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
--
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
Wanlong Gao Aug. 18, 2011, 5:31 a.m. UTC | #10
On 08/18/2011 01:26 PM, JJ Ding wrote:
> Hi Wanlong Gao,
>
> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong Gao<gaowanlong@cn.fujitsu.com>  wrote:
>> On 08/18/2011 09:57 AM, JJ Ding wrote:
>>> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
>>> except when sensing two finger touch, the hardware sends 12 bytes of data.
>>>
>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>> ---
>>>    Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>    drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
>>>    drivers/input/mouse/elantech.h   |   11 ++
>>>    3 files changed, 303 insertions(+), 30 deletions(-)
>>>
>>> +static int determine_packet_v3(struct psmouse *psmouse)
>> elantech_check_parity_v1
>> packet_simple_check_v2
>> determine_packet_v3
>>
>> Why not consistent them?
> OK, how do these names sound to you?
>
> elantech_check_parity_v1
> elantech_packet_check_v2
> elantech_packet_check_v3
>
> Thanks,
> jj

Yeah, sounds perfectly.

Thanks
-Wanlong Gao

--
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
Daniel Kurtz Aug. 18, 2011, 5:34 a.m. UTC | #11
On Thu, Aug 18, 2011 at 1:31 PM, Wanlong Gao <gaowanlong@cn.fujitsu.com> wrote:
> On 08/18/2011 01:26 PM, JJ Ding wrote:
>>
>> Hi Wanlong Gao,
>>
>> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong Gao<gaowanlong@cn.fujitsu.com>
>>  wrote:
>>>
>>> On 08/18/2011 09:57 AM, JJ Ding wrote:
>>>>
>>>> v3 hardware's packet format is almost identical to v2 (one/three finger
>>>> touch),
>>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>>> data.
>>>>
>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>>> ---
>>>>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>>   drivers/input/mouse/elantech.c   |  218
>>>> ++++++++++++++++++++++++++++++++++---
>>>>   drivers/input/mouse/elantech.h   |   11 ++
>>>>   3 files changed, 303 insertions(+), 30 deletions(-)
>>>>
>>>> +static int determine_packet_v3(struct psmouse *psmouse)
>>>
>>> elantech_check_parity_v1
>>> packet_simple_check_v2
>>> determine_packet_v3
>>>
>>> Why not consistent them?
>>
>> OK, how do these names sound to you?
>>
>> elantech_check_parity_v1
>> elantech_packet_check_v2
>> elantech_packet_check_v3
>>
>> Thanks,
>> jj
>
> Yeah, sounds perfectly.

Or just:

elantech_packet_check_v1
elantech_packet_check_v2
elantech_packet_check_v3

:)
--
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
JJ Ding Aug. 18, 2011, 5:39 a.m. UTC | #12
Hi Daniel,

On Thu, 18 Aug 2011 10:57:57 +0800, Daniel Kurtz <djkurtz@chromium.org> wrote:
> On Thu, Aug 18, 2011 at 9:57 AM, JJ Ding <jj_ding@emc.com.tw> wrote:
> > v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> > except when sensing two finger touch, the hardware sends 12 bytes of data.
> >
> > Signed-off-by: JJ Ding <jj_ding@emc.com.tw>
> > ---
> >  Documentation/input/elantech.txt |  104 ++++++++++++++++--
> >  drivers/input/mouse/elantech.c   |  218 ++++++++++++++++++++++++++++++++++---
> >  drivers/input/mouse/elantech.h   |   11 ++
> >  3 files changed, 303 insertions(+), 30 deletions(-)
> >
> > +/*
> > + * firmware tells us there's noise.
> > + */
> > +static inline int debounce(unsigned int x, unsigned int y)
> > +{
> > +       return (x == 0xfff) && (y == 0xfff);
> 
> Perhaps you could document this behavior in the elantech.txt.
OK, I will do that.

> >
> > diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
> > index 4b7447e..4f01fc6 100644
> > --- a/drivers/input/mouse/elantech.h
> > +++ b/drivers/input/mouse/elantech.h
> > @@ -16,6 +16,7 @@
> >  /*
> >  * Command values for Synaptics style queries
> >  */
> > +#define ETP_FW_ID_QUERY                        0x00
> 
> One tab too many?
> 
> >  #define ETP_FW_VERSION_QUERY           0x01
> >  #define ETP_CAPABILITIES_QUERY         0x02
> >
> > @@ -24,6 +25,7 @@
> >  */
> >  #define ETP_REGISTER_READ              0x10
> >  #define ETP_REGISTER_WRITE             0x11
> > +#define ETP_REGISTER_READWRITE         0x00
> >
> >  /*
> >  * Hardware version 2 custom PS/2 command value
> > @@ -93,6 +95,13 @@
> >  #define ETP_2FT_YMIN                   (  0 + ETP_2FT_FUZZ)
> >  #define ETP_2FT_YMAX                   (192 - ETP_2FT_FUZZ)
> >
> > +/*
> > + * v3 hardware has 2 kinds of packet types.
> > + */
> > +#define PACKET_UNKNOWN                 0x01
> > +#define PACKET_V3_HEAD                 0x02
> > +#define PACKET_V3_TAIL                 0x03
> > +
> >  struct elantech_data {
> >        unsigned char reg_10;
> >        unsigned char reg_11;
> > @@ -113,6 +122,8 @@ struct elantech_data {
> >        unsigned int single_finger_reports;
> >        unsigned int y_max;
> >        unsigned int y_2ft_max;
> > +       unsigned int prev_x;
> > +       unsigned int prev_y;
> >        unsigned char parity[256];
> >  };
> >
> > --
> > 1.7.4.1
> >
> >
--
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
Wanlong Gao Aug. 18, 2011, 5:44 a.m. UTC | #13
On 08/18/2011 01:34 PM, Daniel Kurtz wrote:
> On Thu, Aug 18, 2011 at 1:31 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>  wrote:
>> On 08/18/2011 01:26 PM, JJ Ding wrote:
>>>
>>> Hi Wanlong Gao,
>>>
>>> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong Gao<gaowanlong@cn.fujitsu.com>
>>>   wrote:
>>>>
>>>> On 08/18/2011 09:57 AM, JJ Ding wrote:
>>>>>
>>>>> v3 hardware's packet format is almost identical to v2 (one/three finger
>>>>> touch),
>>>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>>>> data.
>>>>>
>>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>>>> ---
>>>>>    Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>>>    drivers/input/mouse/elantech.c   |  218
>>>>> ++++++++++++++++++++++++++++++++++---
>>>>>    drivers/input/mouse/elantech.h   |   11 ++
>>>>>    3 files changed, 303 insertions(+), 30 deletions(-)
>>>>>
>>>>> +static int determine_packet_v3(struct psmouse *psmouse)
>>>>
>>>> elantech_check_parity_v1
>>>> packet_simple_check_v2
>>>> determine_packet_v3
>>>>
>>>> Why not consistent them?
>>>
>>> OK, how do these names sound to you?
>>>
>>> elantech_check_parity_v1
>>> elantech_packet_check_v2
>>> elantech_packet_check_v3
>>>
>>> Thanks,
>>> jj
>>
>> Yeah, sounds perfectly.
>
> Or just:
>
> elantech_packet_check_v1
> elantech_packet_check_v2
> elantech_packet_check_v3
>
> :)

Hmm... maybe they can go into an elantech_packet_check()?
like:
case 1:
	...
case 2:
	...
What do you think? ;)

Thanks
-Wanlong Gao
> --
> 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
>

--
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
Daniel Kurtz Aug. 18, 2011, 6:01 a.m. UTC | #14
On Thu, Aug 18, 2011 at 1:44 PM, Wanlong Gao <gaowanlong@cn.fujitsu.com> wrote:
> On 08/18/2011 01:34 PM, Daniel Kurtz wrote:
>>
>> On Thu, Aug 18, 2011 at 1:31 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>
>>  wrote:
>>>
>>> On 08/18/2011 01:26 PM, JJ Ding wrote:
>>>>
>>>> Hi Wanlong Gao,
>>>>
>>>> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong
>>>> Gao<gaowanlong@cn.fujitsu.com>
>>>>  wrote:
>>>>>
>>>>> On 08/18/2011 09:57 AM, JJ Ding wrote:
>>>>>>
>>>>>> v3 hardware's packet format is almost identical to v2 (one/three
>>>>>> finger
>>>>>> touch),
>>>>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>>>>> data.
>>>>>>
>>>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>>>>> ---
>>>>>>   Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>>>>   drivers/input/mouse/elantech.c   |  218
>>>>>> ++++++++++++++++++++++++++++++++++---
>>>>>>   drivers/input/mouse/elantech.h   |   11 ++
>>>>>>   3 files changed, 303 insertions(+), 30 deletions(-)
>>>>>>
>>>>>> +static int determine_packet_v3(struct psmouse *psmouse)
>>>>>
>>>>> elantech_check_parity_v1
>>>>> packet_simple_check_v2
>>>>> determine_packet_v3
>>>>>
>>>>> Why not consistent them?
>>>>
>>>> OK, how do these names sound to you?
>>>>
>>>> elantech_check_parity_v1
>>>> elantech_packet_check_v2
>>>> elantech_packet_check_v3
>>>>
>>>> Thanks,
>>>> jj
>>>
>>> Yeah, sounds perfectly.
>>
>> Or just:
>>
>> elantech_packet_check_v1
>> elantech_packet_check_v2
>> elantech_packet_check_v3
>>
>> :)
>
> Hmm... maybe they can go into an elantech_packet_check()?
> like:
> case 1:
>        ...
> case 2:
>        ...
> What do you think? ;)
>
> Thanks
> -Wanlong Gao

Since we've already parsed the hardware type at this point, it seems
inefficient to parse it again inside another function.
I would prefer individual functions.

Thanks,
-Daniel
--
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
Dmitry Torokhov Aug. 18, 2011, 6:02 a.m. UTC | #15
On Thu, Aug 18, 2011 at 12:15:00PM +0800, Wanlong Gao wrote:
> On 08/18/2011 11:47 AM, Li Zefan wrote:
> >>>+
> >>>+    case 3:
> >>>+        if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> >>>+            elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
> >>>+            elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
> >>>+            elantech_ps2_command(psmouse, NULL, reg) ||
> >>>+            elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
> >>>+            rc = -1;
> >>>+        }
> >>Prefer to remove these big brace ?
> >>also with "case 1, case 2 "?
> >
> >Just wondering What's wrong with this piece of code and what do you
> >sugguest to improve it?
> 
> I think no need to add a '{}' with the *if* ?
> and remove the '{}' in whole elantech_read_reg() and
> elantech_write_reg(), right?
> 

In case when conditon "overpowers" the body (i.e. multi-line condition)
I prefer having braces so the body stands out.

Thanks.
Wanlong Gao Aug. 18, 2011, 6:06 a.m. UTC | #16
On 08/18/2011 02:01 PM, Daniel Kurtz wrote:
> On Thu, Aug 18, 2011 at 1:44 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>  wrote:
>> On 08/18/2011 01:34 PM, Daniel Kurtz wrote:
>>>
>>> On Thu, Aug 18, 2011 at 1:31 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>
>>>   wrote:
>>>>
>>>> On 08/18/2011 01:26 PM, JJ Ding wrote:
>>>>>
>>>>> Hi Wanlong Gao,
>>>>>
>>>>> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong
>>>>> Gao<gaowanlong@cn.fujitsu.com>
>>>>>   wrote:
>>>>>>
>>>>>> On 08/18/2011 09:57 AM, JJ Ding wrote:
>>>>>>>
>>>>>>> v3 hardware's packet format is almost identical to v2 (one/three
>>>>>>> finger
>>>>>>> touch),
>>>>>>> except when sensing two finger touch, the hardware sends 12 bytes of
>>>>>>> data.
>>>>>>>
>>>>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
>>>>>>> ---
>>>>>>>    Documentation/input/elantech.txt |  104 ++++++++++++++++--
>>>>>>>    drivers/input/mouse/elantech.c   |  218
>>>>>>> ++++++++++++++++++++++++++++++++++---
>>>>>>>    drivers/input/mouse/elantech.h   |   11 ++
>>>>>>>    3 files changed, 303 insertions(+), 30 deletions(-)
>>>>>>>
>>>>>>> +static int determine_packet_v3(struct psmouse *psmouse)
>>>>>>
>>>>>> elantech_check_parity_v1
>>>>>> packet_simple_check_v2
>>>>>> determine_packet_v3
>>>>>>
>>>>>> Why not consistent them?
>>>>>
>>>>> OK, how do these names sound to you?
>>>>>
>>>>> elantech_check_parity_v1
>>>>> elantech_packet_check_v2
>>>>> elantech_packet_check_v3
>>>>>
>>>>> Thanks,
>>>>> jj
>>>>
>>>> Yeah, sounds perfectly.
>>>
>>> Or just:
>>>
>>> elantech_packet_check_v1
>>> elantech_packet_check_v2
>>> elantech_packet_check_v3
>>>
>>> :)
>>
>> Hmm... maybe they can go into an elantech_packet_check()?
>> like:
>> case 1:
>>         ...
>> case 2:
>>         ...
>> What do you think? ;)
>>
>> Thanks
>> -Wanlong Gao
>
> Since we've already parsed the hardware type at this point, it seems
> inefficient to parse it again inside another function.
> I would prefer individual functions.
>
> Thanks,
> -Daniel
>

Yeah, It makes sense.

Thanks
-Wanlong Gao
--
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
Wanlong Gao Aug. 18, 2011, 6:08 a.m. UTC | #17
On 08/18/2011 02:02 PM, Dmitry Torokhov wrote:
> On Thu, Aug 18, 2011 at 12:15:00PM +0800, Wanlong Gao wrote:
>> On 08/18/2011 11:47 AM, Li Zefan wrote:
>>>>> +
>>>>> +    case 3:
>>>>> +        if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>>>>> +            elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
>>>>> +            elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
>>>>> +            elantech_ps2_command(psmouse, NULL, reg) ||
>>>>> +            elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
>>>>> +            rc = -1;
>>>>> +        }
>>>> Prefer to remove these big brace ?
>>>> also with "case 1, case 2 "?
>>>
>>> Just wondering What's wrong with this piece of code and what do you
>>> sugguest to improve it?
>>
>> I think no need to add a '{}' with the *if* ?
>> and remove the '{}' in whole elantech_read_reg() and
>> elantech_write_reg(), right?
>>
>
> In case when conditon "overpowers" the body (i.e. multi-line condition)
> I prefer having braces so the body stands out.
>
> Thanks.
>

I see, Thanks

-Wanlong Gao


--
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
Tom Lin Aug. 18, 2011, 7:49 a.m. UTC | #18
Hi JJ
On Thu, 2011-08-18 at 14:06 +0800, Wanlong Gao wrote:
> On 08/18/2011 02:01 PM, Daniel Kurtz wrote:
> > On Thu, Aug 18, 2011 at 1:44 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>  wrote:
> >> On 08/18/2011 01:34 PM, Daniel Kurtz wrote:
> >>>
> >>> On Thu, Aug 18, 2011 at 1:31 PM, Wanlong Gao<gaowanlong@cn.fujitsu.com>
> >>>   wrote:
> >>>>
> >>>> On 08/18/2011 01:26 PM, JJ Ding wrote:
> >>>>>
> >>>>> Hi Wanlong Gao,
> >>>>>
> >>>>> On Thu, 18 Aug 2011 11:01:52 +0800, Wanlong
> >>>>> Gao<gaowanlong@cn.fujitsu.com>
> >>>>>   wrote:
> >>>>>>
> >>>>>> On 08/18/2011 09:57 AM, JJ Ding wrote:
> >>>>>>>
> >>>>>>> v3 hardware's packet format is almost identical to v2 (one/three
> >>>>>>> finger
> >>>>>>> touch),
> >>>>>>> except when sensing two finger touch, the hardware sends 12 bytes of
> >>>>>>> data.
> >>>>>>>
> >>>>>>> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> >>>>>>> ---
> >>>>>>>    Documentation/input/elantech.txt |  104 ++++++++++++++++--
> >>>>>>>    drivers/input/mouse/elantech.c   |  218
> >>>>>>> ++++++++++++++++++++++++++++++++++---
> >>>>>>>    drivers/input/mouse/elantech.h   |   11 ++
> >>>>>>>    3 files changed, 303 insertions(+), 30 deletions(-)
> >>>>>>>
> >>>>>>> +static int determine_packet_v3(struct psmouse *psmouse)
> >>>>>>
> >>>>>> elantech_check_parity_v1
> >>>>>> packet_simple_check_v2
> >>>>>> determine_packet_v3
> >>>>>>
> >>>>>> Why not consistent them?
> >>>>>
> >>>>> OK, how do these names sound to you?
> >>>>>
> >>>>> elantech_check_parity_v1
> >>>>> elantech_packet_check_v2
> >>>>> elantech_packet_check_v3
> >>>>>
> >>>>> Thanks,
> >>>>> jj
> >>>>
> >>>> Yeah, sounds perfectly.
> >>>
> >>> Or just:
> >>>
> >>> elantech_packet_check_v1
> >>> elantech_packet_check_v2
> >>> elantech_packet_check_v3
I prefer this way. 
> >>>
> >>> :)
> >>
> >> Hmm... maybe they can go into an elantech_packet_check()?
> >> like:
> >> case 1:
> >>         ...
> >> case 2:
> >>         ...
> >> What do you think? ;)
> >>
> >> Thanks
> >> -Wanlong Gao
> >
> > Since we've already parsed the hardware type at this point, it seems
> > inefficient to parse it again inside another function.
> > I would prefer individual functions.
> >
> > Thanks,
> > -Daniel
> >
> 
> Yeah, It makes sense.
> 
> Thanks
> -Wanlong Gao
> 

Thanks
-TomLin

--
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
Seth Forshee Aug. 18, 2011, 1:58 p.m. UTC | #19
On Thu, Aug 18, 2011 at 09:57:09AM +0800, JJ Ding wrote:
> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> except when sensing two finger touch, the hardware sends 12 bytes of data.

This looks mostly similar in substance to the patch I sent, although
with some good improvements resulting from your better knowledge of the
hardware :)

One suggestion below. I'll test as soon as my build finishes.

> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
>  		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>  		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>  		break;
> +
> +	case 3:
> +		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> +		/* range of pressure and width is the same as v2 */
> +		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> +				     ETP_PMAX_V2, 0, 0);
> +		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> +				     ETP_WMAX_V2, 0, 0);
> +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> +		input_mt_init_slots(dev, 2);
> +		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> +		break;

The case 3 code is nearly identical to case 2. How about this?

	case 2:
		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
		/* fall through */

	case 3:
		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
		/* range of pressure and width is the same as v2 */
		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
				     ETP_PMAX_V2, 0, 0);
		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
				     ETP_WMAX_V2, 0, 0);
		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
		input_mt_init_slots(dev, 2);
		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
		break;
--
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
Seth Forshee Aug. 18, 2011, 2:25 p.m. UTC | #20
On Thu, Aug 18, 2011 at 08:58:53AM -0500, Seth Forshee wrote:
> The case 3 code is nearly identical to case 2. How about this?
> 
> 	case 2:
> 		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
> 		/* fall through */
> 
> 	case 3:
> 		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> 		/* range of pressure and width is the same as v2 */
> 		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> 				     ETP_PMAX_V2, 0, 0);
> 		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> 				     ETP_WMAX_V2, 0, 0);
> 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> 		input_mt_init_slots(dev, 2);
> 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> 		break;

Sorry, that should have been:

	case 2:
		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
		/* fall through */

	case 3:
		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
		if (etd->reports_pressure) {
			input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
					     ETP_PMAX_V2, 0, 0);
			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
					     ETP_WMAX_V2, 0, 0);
		}
		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
		input_mt_init_slots(dev, 2);
		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
		break;
--
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
Seth Forshee Aug. 18, 2011, 5:39 p.m. UTC | #21
On Thu, Aug 18, 2011 at 09:57:09AM +0800, JJ Ding wrote:
> @@ -352,6 +374,94 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
>  	input_sync(dev);
>  }
>  
> +/*
> + * firmware tells us there's noise.
> + */
> +static inline int debounce(unsigned int x, unsigned int y)
> +{
> +	return (x == 0xfff) && (y == 0xfff);
> +}

This is problematic in my testing, in two ways.

First, it never actually triggers, because the y values passed to it are
not the raw data from the packets and as such are not 0xfff anymore in
the cases you're trying to detect.

Second, I get these packets with 1 and 2 finger touches on the Samsung
NF310, but you only check it in the 3 finger case.

As a result, I'm getting some reports with negative values for the y
position.

> +
> +/*
> + * Interpret complete data packets and report absolute mode input events for
> + * hardware version 3. (12 byte packets for two fingers)
> + */
> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> +					int packet_type)
> +{
> +	struct input_dev *dev = psmouse->dev;
> +	struct elantech_data *etd = psmouse->private;
> +	unsigned char *packet = psmouse->packet;
> +	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> +	unsigned int width = 0, pres = 0;
> +
> +	/* byte 0: n1  n0   .   .   .   .   R   L */
> +	fingers = (packet[0] & 0xc0) >> 6;
> +
> +	switch (fingers) {
> +	case 3:
> +	case 1:
> +		/*
> +		 * byte 1:  .   .   .   .  x11 x10 x9  x8
> +		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> +		 */
> +		x1 = ((packet[1] & 0x0f) << 8) | packet[2];
> +		/*
> +		 * byte 4:  .   .   .   .  y11 y10 y9  y8
> +		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> +		 */
> +		y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
> +
> +		if (fingers == 3 && debounce(x1, y1))
> +			return;
> +
> +		break;
> +
> +	case 2:
> +		if (packet_type == PACKET_V3_HEAD) {
> +			/*
> +			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> +			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> +			 */
> +			etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2];
> +			/*
> +			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> +			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> +			 */
> +			etd->prev_y = etd->y_max -
> +				(((packet[4] & 0x0f) << 8) | packet[5]);
> +			/*
> +			 * wait for next packet
> +			 */
> +			return;
> +		}
> +
> +		/* packet_type == PACKET_V3_TAIL */
> +		x1 = etd->prev_x;
> +		y1 = etd->prev_y;
> +		x2 = ((packet[1] & 0x0f) << 8) | packet[2];
> +		y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
> +		break;
> +	}
> +
> +	pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
> +	width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
> +
> +	input_report_key(dev, BTN_TOUCH, fingers != 0);
> +	input_report_abs(dev, ABS_X, x1);
> +	input_report_abs(dev, ABS_Y, y1);

You should only report the ABS_[XY] coordinates when fingers != 0. The
xorg synaptics module sees the values reported in that case as
legitimate. This is causing me to see strange behaviors when scrolling
with two-finger drags.
--
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
Wanlong Gao Aug. 19, 2011, 12:15 a.m. UTC | #22
On 08/18/2011 10:25 PM, Seth Forshee wrote:
> On Thu, Aug 18, 2011 at 08:58:53AM -0500, Seth Forshee wrote:
>> The case 3 code is nearly identical to case 2. How about this?
>>
>> 	case 2:
>> 		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
>> 		/* fall through */
>>
>> 	case 3:
>> 		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
>> 		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
>> 		/* range of pressure and width is the same as v2 */
>> 		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
>> 				     ETP_PMAX_V2, 0, 0);
>> 		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
>> 				     ETP_WMAX_V2, 0, 0);
>> 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
>> 		input_mt_init_slots(dev, 2);
>> 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>> 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>> 		break;
>
> Sorry, that should have been:
>
> 	case 2:
> 		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
> 		/* fall through */
>
> 	case 3:
> 		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> 		if (etd->reports_pressure) {
> 			input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> 					     ETP_PMAX_V2, 0, 0);
> 			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> 					     ETP_WMAX_V2, 0, 0);
> 		}
> 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> 		input_mt_init_slots(dev, 2);
> 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> 		break;

simplify, seems good.

Thanks
-Wanlong Gao
> --
> 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
>

--
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
JJ Ding Aug. 19, 2011, 2:23 a.m. UTC | #23
Hi Seth,

On Thu, 18 Aug 2011 09:25:00 -0500, Seth Forshee <seth.forshee@canonical.com> wrote:
> On Thu, Aug 18, 2011 at 08:58:53AM -0500, Seth Forshee wrote:
> 
> Sorry, that should have been:
> 
> 	case 2:
> 		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
> 		/* fall through */
> 
> 	case 3:
> 		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> 		if (etd->reports_pressure) {
> 			input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> 					     ETP_PMAX_V2, 0, 0);
> 			input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> 					     ETP_WMAX_V2, 0, 0);
> 		}
> 		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> 		input_mt_init_slots(dev, 2);
> 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> 		break;
Looks nice, thank you, I will change it.

jj
--
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
Seth Forshee Aug. 19, 2011, 12:13 p.m. UTC | #24
On Fri, Aug 19, 2011 at 04:29:57PM +0800, JJ Ding wrote:
> > You should only report the ABS_[XY] coordinates when fingers != 0. The
> > xorg synaptics module sees the values reported in that case as
> > legitimate. This is causing me to see strange behaviors when scrolling
> > with two-finger drags.
> AFAIK, though v2 and v3 differ in packet format, they really report the
> same data to the userspace. In this version of v3 support, I even try to
> make v2 and v3 report all the data in the same sequnce. If you're seeing
> this issue, maybe we should do the same with v2?

Actually neither v1 nor v2 reports ABS_[XY] unless fingers != 0. In v2
the reporting is in a switch statement on the number of fingers, and 0
is unhandled.
--
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
Éric Piel Aug. 19, 2011, 12:41 p.m. UTC | #25
Op 19-08-11 14:13, Seth Forshee schreef:
> On Fri, Aug 19, 2011 at 04:29:57PM +0800, JJ Ding wrote:
>>> You should only report the ABS_[XY] coordinates when fingers != 0. The
>>> xorg synaptics module sees the values reported in that case as
>>> legitimate. This is causing me to see strange behaviors when scrolling
>>> with two-finger drags.
>> AFAIK, though v2 and v3 differ in packet format, they really report the
>> same data to the userspace. In this version of v3 support, I even try to
>> make v2 and v3 report all the data in the same sequnce. If you're seeing
>> this issue, maybe we should do the same with v2?
>
> Actually neither v1 nor v2 reports ABS_[XY] unless fingers != 0. In v2
> the reporting is in a switch statement on the number of fingers, and 0
> is unhandled.

Yes, in other words, in the case of v1 or v2, the switch(fingers) does 
nothing if fingers == 0.

Maybe you could do put these 3 lines inside a "if (fingers != 0)":
+	input_report_abs(dev, ABS_X, x1);
+	input_report_abs(dev, ABS_Y, y1);
+	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);

Éric
--
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
Seth Forshee Aug. 19, 2011, 12:50 p.m. UTC | #26
On Fri, Aug 19, 2011 at 02:41:01PM +0200, Éric Piel wrote:
> Op 19-08-11 14:13, Seth Forshee schreef:
> >On Fri, Aug 19, 2011 at 04:29:57PM +0800, JJ Ding wrote:
> >>>You should only report the ABS_[XY] coordinates when fingers != 0. The
> >>>xorg synaptics module sees the values reported in that case as
> >>>legitimate. This is causing me to see strange behaviors when scrolling
> >>>with two-finger drags.
> >>AFAIK, though v2 and v3 differ in packet format, they really report the
> >>same data to the userspace. In this version of v3 support, I even try to
> >>make v2 and v3 report all the data in the same sequnce. If you're seeing
> >>this issue, maybe we should do the same with v2?
> >
> >Actually neither v1 nor v2 reports ABS_[XY] unless fingers != 0. In v2
> >the reporting is in a switch statement on the number of fingers, and 0
> >is unhandled.
> 
> Yes, in other words, in the case of v1 or v2, the switch(fingers)
> does nothing if fingers == 0.
> 
> Maybe you could do put these 3 lines inside a "if (fingers != 0)":
> +	input_report_abs(dev, ABS_X, x1);
> +	input_report_abs(dev, ABS_Y, y1);
> +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);

I don't think elantech_report_semi_mt_data() should be moved inside the
condition. It's doing the right thing when fingers is 0.
--
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
Éric Piel Aug. 19, 2011, 1:03 p.m. UTC | #27
Op 18-08-11 03:57, JJ Ding schreef:
> v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> except when sensing two finger touch, the hardware sends 12 bytes of data.
>
> Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
Hi,
A couple of comments, in line.

:
:
> diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> index ddd40eb..e13a719 100644
> --- a/drivers/input/mouse/elantech.c
> +++ b/drivers/input/mouse/elantech.c
:
> +/*
> + * Interpret complete data packets and report absolute mode input events for
> + * hardware version 3. (12 byte packets for two fingers)
> + */
> +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> +					int packet_type)
> +{
> +	struct input_dev *dev = psmouse->dev;
> +	struct elantech_data *etd = psmouse->private;
> +	unsigned char *packet = psmouse->packet;
> +	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> +	unsigned int width = 0, pres = 0;
> +
> +	/* byte 0: n1  n0   .   .   .   .   R   L */
> +	fingers = (packet[0]&  0xc0)>>  6;
> +
> +	switch (fingers) {
> +	case 3:
> +	case 1:
> +		/*
> +		 * byte 1:  .   .   .   .  x11 x10 x9  x8
> +		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> +		 */
> +		x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> +		/*
> +		 * byte 4:  .   .   .   .  y11 y10 y9  y8
> +		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> +		 */
> +		y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> +
> +		if (fingers == 3&&  debounce(x1, y1))
> +			return;
> +
> +		break;
> +
> +	case 2:
> +		if (packet_type == PACKET_V3_HEAD) {
> +			/*
> +			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> +			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> +			 */
> +			etd->prev_x = ((packet[1]&  0x0f)<<  8) | packet[2];
> +			/*
> +			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> +			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> +			 */
> +			etd->prev_y = etd->y_max -
> +				(((packet[4]&  0x0f)<<  8) | packet[5]);
> +			/*
> +			 * wait for next packet
> +			 */
> +			return;
> +		}
> +
> +		/* packet_type == PACKET_V3_TAIL */
> +		x1 = etd->prev_x;
> +		y1 = etd->prev_y;
> +		x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
> +		y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> +		break;
> +	}
You actually have three times the same formula, so you could simplify it:

if (fingers !=0 ) {
	/*
	 * byte 1:  .   .   .   .  x11 x10 x9  x8
	 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
	 */
	x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
	/*
	 * byte 4:  .   .   .   .  y11 y10 y9  y8
	 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
	 */
	y1 = ((packet[4]&  0x0f)<<  8) | packet[5];
}

if ((fingers == 3) && debounce(x1, y1))
	return;

if (fingers == 2) {
	if (packet_type == PACKET_V3_HEAD)) {
		/* wait for next packet */
		etd->prev_x = x1;
		etd->prev_y = etd->y_max - y1;
		return;
	} else {
		/* packet_type == PACKET_V3_TAIL */
		x2 = etd->prev_x;
		y2 = etd->prev_y;
	}
}


> +
> +	pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
> +	width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
What about the case of two fingers? Are pressure and width correct for 
both fingers? In that case, maybe it should also be saved from 
PACKET_V3_HEAD.


> +
> +	input_report_key(dev, BTN_TOUCH, fingers != 0);
> +	input_report_abs(dev, ABS_X, x1);
> +	input_report_abs(dev, ABS_Y, y1);
> +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
> +	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
> +	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
> +	input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
> +	input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
> +	input_report_abs(dev, ABS_PRESSURE, pres);
> +	input_report_abs(dev, ABS_TOOL_WIDTH, width);
> +
> +	input_sync(dev);
> +}
> +
:
>
>   /*
>    * Set the appropriate event bits for the input subsystem
>    */
> -static void elantech_set_input_params(struct psmouse *psmouse)
> +static int elantech_set_input_params(struct psmouse *psmouse)
>   {
>   	struct input_dev *dev = psmouse->dev;
>   	struct elantech_data *etd = psmouse->private;
>   	unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
>
> -	set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
> +	if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
> +		return -1;
>
>   	__set_bit(EV_KEY, dev->evbit);
>   	__set_bit(EV_ABS, dev->evbit);
> @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
>   		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
>   		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
>   		break;
> +
> +	case 3:
> +		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> +		/* range of pressure and width is the same as v2 */
> +		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> +				     ETP_PMAX_V2, 0, 0);
> +		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> +				     ETP_WMAX_V2, 0, 0);
> +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
Does v3 have the same limitation in MT about only reporting the edges of 
the bounding box? Or are the two fingers always reported independently? 
If that is so, you can drop this line :-)


> +		input_mt_init_slots(dev, 2);
> +		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> +		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> +		break;
>   	}
>

Cheers,
Éric
--
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
Éric Piel Aug. 19, 2011, 1:39 p.m. UTC | #28
Op 19-08-11 14:50, Seth Forshee schreef:
>>
>> Yes, in other words, in the case of v1 or v2, the switch(fingers)
>> does nothing if fingers == 0.
>>
>> Maybe you could do put these 3 lines inside a "if (fingers != 0)":
>> +	input_report_abs(dev, ABS_X, x1);
>> +	input_report_abs(dev, ABS_Y, y1);
>> +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
>
> I don't think elantech_report_semi_mt_data() should be moved inside the
> condition. It's doing the right thing when fingers is 0.
Oh, right, it already tests for this case :-) My mistake.

Éric
--
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
JJ Ding Aug. 22, 2011, 12:55 a.m. UTC | #29
Hi Seth,

On Fri, 19 Aug 2011 07:13:08 -0500, Seth Forshee <seth.forshee@canonical.com> wrote:
> On Fri, Aug 19, 2011 at 04:29:57PM +0800, JJ Ding wrote:
> > > You should only report the ABS_[XY] coordinates when fingers != 0. The
> > > xorg synaptics module sees the values reported in that case as
> > > legitimate. This is causing me to see strange behaviors when scrolling
> > > with two-finger drags.
> > AFAIK, though v2 and v3 differ in packet format, they really report the
> > same data to the userspace. In this version of v3 support, I even try to
> > make v2 and v3 report all the data in the same sequnce. If you're seeing
> > this issue, maybe we should do the same with v2?
> 
> Actually neither v1 nor v2 reports ABS_[XY] unless fingers != 0. In v2
> the reporting is in a switch statement on the number of fingers, and 0
> is unhandled.
Yes, You are right. Sorry I misread your reply about this. I will fix
this as you suggested.

jj
--
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
JJ Ding Aug. 22, 2011, 6:05 a.m. UTC | #30
Hi Éric,

Thanks for your comments, a few lines below:

On Fri, 19 Aug 2011 15:03:04 +0200, Éric Piel <E.A.B.Piel@tudelft.nl> wrote:
> Op 18-08-11 03:57, JJ Ding schreef:
> > v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> > except when sensing two finger touch, the hardware sends 12 bytes of data.
> >
> > Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> Hi,
> A couple of comments, in line.
> 
> :
> :
> > diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> > index ddd40eb..e13a719 100644
> > --- a/drivers/input/mouse/elantech.c
> > +++ b/drivers/input/mouse/elantech.c
> :
> > +/*
> > + * Interpret complete data packets and report absolute mode input events for
> > + * hardware version 3. (12 byte packets for two fingers)
> > + */
> > +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> > +					int packet_type)
> > +{
> > +	struct input_dev *dev = psmouse->dev;
> > +	struct elantech_data *etd = psmouse->private;
> > +	unsigned char *packet = psmouse->packet;
> > +	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> > +	unsigned int width = 0, pres = 0;
> > +
> > +	/* byte 0: n1  n0   .   .   .   .   R   L */
> > +	fingers = (packet[0]&  0xc0)>>  6;
> > +
> > +	switch (fingers) {
> > +	case 3:
> > +	case 1:
> > +		/*
> > +		 * byte 1:  .   .   .   .  x11 x10 x9  x8
> > +		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> > +		 */
> > +		x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> > +		/*
> > +		 * byte 4:  .   .   .   .  y11 y10 y9  y8
> > +		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> > +		 */
> > +		y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> > +
> > +		if (fingers == 3&&  debounce(x1, y1))
> > +			return;
> > +
> > +		break;
> > +
> > +	case 2:
> > +		if (packet_type == PACKET_V3_HEAD) {
> > +			/*
> > +			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> > +			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> > +			 */
> > +			etd->prev_x = ((packet[1]&  0x0f)<<  8) | packet[2];
> > +			/*
> > +			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> > +			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> > +			 */
> > +			etd->prev_y = etd->y_max -
> > +				(((packet[4]&  0x0f)<<  8) | packet[5]);
> > +			/*
> > +			 * wait for next packet
> > +			 */
> > +			return;
> > +		}
> > +
> > +		/* packet_type == PACKET_V3_TAIL */
> > +		x1 = etd->prev_x;
> > +		y1 = etd->prev_y;
> > +		x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
> > +		y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> > +		break;
> > +	}
> You actually have three times the same formula, so you could simplify it:
> 
> if (fingers !=0 ) {
> 	/*
> 	 * byte 1:  .   .   .   .  x11 x10 x9  x8
> 	 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> 	 */
> 	x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> 	/*
> 	 * byte 4:  .   .   .   .  y11 y10 y9  y8
> 	 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> 	 */
> 	y1 = ((packet[4]&  0x0f)<<  8) | packet[5];
> }
> 
> if ((fingers == 3) && debounce(x1, y1))
> 	return;
we need one more line here, for fingers != 2 :
y1 = etd->y_max - y1;
> if (fingers == 2) {
> 	if (packet_type == PACKET_V3_HEAD)) {
> 		/* wait for next packet */
> 		etd->prev_x = x1;
> 		etd->prev_y = etd->y_max - y1;
                etd->prev_y = y1;
> 		return;
> 	} else {
> 		/* packet_type == PACKET_V3_TAIL */
> 		x2 = etd->prev_x;
> 		y2 = etd->prev_y;
> 	}
> }
I like this compact version, but it seems to me this is not as straight
forward as the original switch case. I am OK with either. Is there
anyone who has more to say about this?
> 
> > +
> > +	pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
> > +	width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
> What about the case of two fingers? Are pressure and width correct for 
> both fingers? In that case, maybe it should also be saved from 
> PACKET_V3_HEAD.
I am told (by our firmware guy) that pres and width are sent the same
value for two finger touch.
> 
> > +
> > +	input_report_key(dev, BTN_TOUCH, fingers != 0);
> > +	input_report_abs(dev, ABS_X, x1);
> > +	input_report_abs(dev, ABS_Y, y1);
> > +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> > +	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
> > +	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
> > +	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
> > +	input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
> > +	input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
> > +	input_report_abs(dev, ABS_PRESSURE, pres);
> > +	input_report_abs(dev, ABS_TOOL_WIDTH, width);
> > +
> > +	input_sync(dev);
> > +}
> > +
> :
> >
> >   /*
> >    * Set the appropriate event bits for the input subsystem
> >    */
> > -static void elantech_set_input_params(struct psmouse *psmouse)
> > +static int elantech_set_input_params(struct psmouse *psmouse)
> >   {
> >   	struct input_dev *dev = psmouse->dev;
> >   	struct elantech_data *etd = psmouse->private;
> >   	unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
> >
> > -	set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
> > +	if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
> > +		return -1;
> >
> >   	__set_bit(EV_KEY, dev->evbit);
> >   	__set_bit(EV_ABS, dev->evbit);
> > @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
> >   		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> >   		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> >   		break;
> > +
> > +	case 3:
> > +		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> > +		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> > +		/* range of pressure and width is the same as v2 */
> > +		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> > +				     ETP_PMAX_V2, 0, 0);
> > +		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> > +				     ETP_WMAX_V2, 0, 0);
> > +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> Does v3 have the same limitation in MT about only reporting the edges of 
> the bounding box? Or are the two fingers always reported independently? 
> If that is so, you can drop this line :-)
I suppose it's the same as v2, but I have to comfirm with our firmware team.
I will ckeck this.
> 
> > +		input_mt_init_slots(dev, 2);
> > +		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> > +		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> > +		break;
> >   	}
> >
> 
> Cheers,
> Éric
> --
> 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
--
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
Tom Lin Aug. 22, 2011, 7:20 a.m. UTC | #31
Hi JJ
On Mon, 2011-08-22 at 14:05 +0800, JJ Ding wrote:
> Hi Éric,
> 
> Thanks for your comments, a few lines below:
> 
> On Fri, 19 Aug 2011 15:03:04 +0200, Éric Piel <E.A.B.Piel@tudelft.nl> wrote:
> > Op 18-08-11 03:57, JJ Ding schreef:
> > > v3 hardware's packet format is almost identical to v2 (one/three finger touch),
> > > except when sensing two finger touch, the hardware sends 12 bytes of data.
> > >
> > > Signed-off-by: JJ Ding<jj_ding@emc.com.tw>
> > Hi,
> > A couple of comments, in line.
> > 
> > :
> > :
> > > diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
> > > index ddd40eb..e13a719 100644
> > > --- a/drivers/input/mouse/elantech.c
> > > +++ b/drivers/input/mouse/elantech.c
> > :
> > > +/*
> > > + * Interpret complete data packets and report absolute mode input events for
> > > + * hardware version 3. (12 byte packets for two fingers)
> > > + */
> > > +static void elantech_report_absolute_v3(struct psmouse *psmouse,
> > > +					int packet_type)
> > > +{
> > > +	struct input_dev *dev = psmouse->dev;
> > > +	struct elantech_data *etd = psmouse->private;
> > > +	unsigned char *packet = psmouse->packet;
> > > +	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> > > +	unsigned int width = 0, pres = 0;
> > > +
> > > +	/* byte 0: n1  n0   .   .   .   .   R   L */
> > > +	fingers = (packet[0]&  0xc0)>>  6;
> > > +
> > > +	switch (fingers) {
> > > +	case 3:
> > > +	case 1:
> > > +		/*
> > > +		 * byte 1:  .   .   .   .  x11 x10 x9  x8
> > > +		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> > > +		 */
> > > +		x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> > > +		/*
> > > +		 * byte 4:  .   .   .   .  y11 y10 y9  y8
> > > +		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> > > +		 */
> > > +		y1 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> > > +
> > > +		if (fingers == 3&&  debounce(x1, y1))
> > > +			return;
> > > +
> > > +		break;
> > > +
> > > +	case 2:
> > > +		if (packet_type == PACKET_V3_HEAD) {
> > > +			/*
> > > +			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
> > > +			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
> > > +			 */
> > > +			etd->prev_x = ((packet[1]&  0x0f)<<  8) | packet[2];
> > > +			/*
> > > +			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
> > > +			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
> > > +			 */
> > > +			etd->prev_y = etd->y_max -
> > > +				(((packet[4]&  0x0f)<<  8) | packet[5]);
> > > +			/*
> > > +			 * wait for next packet
> > > +			 */
> > > +			return;
> > > +		}
> > > +
> > > +		/* packet_type == PACKET_V3_TAIL */
> > > +		x1 = etd->prev_x;
> > > +		y1 = etd->prev_y;
> > > +		x2 = ((packet[1]&  0x0f)<<  8) | packet[2];
> > > +		y2 = etd->y_max - (((packet[4]&  0x0f)<<  8) | packet[5]);
> > > +		break;
> > > +	}
> > You actually have three times the same formula, so you could simplify it:
> > 
> > if (fingers !=0 ) {
> > 	/*
> > 	 * byte 1:  .   .   .   .  x11 x10 x9  x8
> > 	 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
> > 	 */
> > 	x1 = ((packet[1]&  0x0f)<<  8) | packet[2];
> > 	/*
> > 	 * byte 4:  .   .   .   .  y11 y10 y9  y8
> > 	 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
> > 	 */
> > 	y1 = ((packet[4]&  0x0f)<<  8) | packet[5];
> > }
> > 
> > if ((fingers == 3) && debounce(x1, y1))
> > 	return;
> we need one more line here, for fingers != 2 :
> y1 = etd->y_max - y1;
> > if (fingers == 2) {
> > 	if (packet_type == PACKET_V3_HEAD)) {
> > 		/* wait for next packet */
> > 		etd->prev_x = x1;
> > 		etd->prev_y = etd->y_max - y1;
>                 etd->prev_y = y1;
> > 		return;
> > 	} else {
> > 		/* packet_type == PACKET_V3_TAIL */
> > 		x2 = etd->prev_x;
> > 		y2 = etd->prev_y;
> > 	}
> > }
> I like this compact version, but it seems to me this is not as straight
> forward as the original switch case. I am OK with either. Is there
> anyone who has more to say about this?
Éric's version is compact but this is not straight forward as original
code and does not improve more performances. Then other versions of
"elantech_report_absolute" also needed to  modify the same style . so I
prefer original style.
> > 
> > > +
> > > +	pres = (packet[1]&  0xf0) | ((packet[4]&  0xf0)>>  4);
> > > +	width = ((packet[0]&  0x30)>>  2) | ((packet[3]&  0x30)>>  4);
> > What about the case of two fingers? Are pressure and width correct for 
> > both fingers? In that case, maybe it should also be saved from 
> > PACKET_V3_HEAD.
> I am told (by our firmware guy) that pres and width are sent the same
> value for two finger touch.
> > 
> > > +
> > > +	input_report_key(dev, BTN_TOUCH, fingers != 0);
> > > +	input_report_abs(dev, ABS_X, x1);
> > > +	input_report_abs(dev, ABS_Y, y1);
> > > +	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> > > +	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
> > > +	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
> > > +	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
> > > +	input_report_key(dev, BTN_LEFT, packet[0]&  0x01);
> > > +	input_report_key(dev, BTN_RIGHT, packet[0]&  0x02);
> > > +	input_report_abs(dev, ABS_PRESSURE, pres);
> > > +	input_report_abs(dev, ABS_TOOL_WIDTH, width);
> > > +
> > > +	input_sync(dev);
> > > +}
> > > +
> > :
> > >
> > >   /*
> > >    * Set the appropriate event bits for the input subsystem
> > >    */
> > > -static void elantech_set_input_params(struct psmouse *psmouse)
> > > +static int elantech_set_input_params(struct psmouse *psmouse)
> > >   {
> > >   	struct input_dev *dev = psmouse->dev;
> > >   	struct elantech_data *etd = psmouse->private;
> > >   	unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
> > >
> > > -	set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max);
> > > +	if (set_range(psmouse,&x_min,&y_min,&x_max,&y_max,&y_2ft_max))
> > > +		return -1;
> > >
> > >   	__set_bit(EV_KEY, dev->evbit);
> > >   	__set_bit(EV_ABS, dev->evbit);
> > > @@ -582,10 +739,26 @@ static void elantech_set_input_params(struct psmouse *psmouse)
> > >   		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> > >   		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> > >   		break;
> > > +
> > > +	case 3:
> > > +		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
> > > +		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
> > > +		/* range of pressure and width is the same as v2 */
> > > +		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
> > > +				     ETP_PMAX_V2, 0, 0);
> > > +		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
> > > +				     ETP_WMAX_V2, 0, 0);
> > > +		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
> > Does v3 have the same limitation in MT about only reporting the edges of 
> > the bounding box? Or are the two fingers always reported independently? 
> > If that is so, you can drop this line :-)
> I suppose it's the same as v2, but I have to comfirm with our firmware team.
> I will ckeck this.
> > 
> > > +		input_mt_init_slots(dev, 2);
> > > +		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
> > > +		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
> > > +		break;
> > >   	}
> > >
> > 
> > Cheers,
> > Éric
> > --
> > 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
> 
> 


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

Patch

diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
index bce9941..ce578bd 100644
--- a/Documentation/input/elantech.txt
+++ b/Documentation/input/elantech.txt
@@ -16,15 +16,22 @@  Contents
 
  1. Introduction
  2. Extra knobs
- 3. Hardware version 1
-    3.1 Registers
-    3.2 Native relative mode 4 byte packet format
-    3.3 Native absolute mode 4 byte packet format
- 4. Hardware version 2
+ 3. Differentiating hardware versions
+ 4. Hardware version 1
     4.1 Registers
-    4.2 Native absolute mode 6 byte packet format
-        4.2.1 One finger touch
-        4.2.2 Two finger touch
+    4.2 Native relative mode 4 byte packet format
+    4.3 Native absolute mode 4 byte packet format
+ 5. Hardware version 2
+    5.1 Registers
+    5.2 Native absolute mode 6 byte packet format
+        5.2.1 Parity checking and packet re-synchronization
+        5.2.2 One/Three finger touch
+        5.2.3 Two finger touch
+ 6. Hardware version 3
+    6.1 Registers
+    6.2 Native absolute mode 6 byte packet format
+        6.2.1 One/Three finger touch
+        6.2.2 Two finger touch
 
 
 
@@ -375,7 +382,7 @@  For all the other ones, there are just a few constant bits:
 
 In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
 
-5.2.1 One/Three finger touch
+5.2.2 One/Three finger touch
       ~~~~~~~~~~~~~~~~
 
 byte 0:
@@ -384,7 +391,7 @@  byte 0:
 	 n1  n0  w3  w2   .   .   R   L
 
          L, R = 1 when Left, Right mouse button pressed
-         n1..n0 = numbers of fingers on touchpad
+         n1..n0 = number of fingers on touchpad
 
 byte 1:
 
@@ -432,7 +439,7 @@  byte 5:
          y11..y0 = absolute y value (vertical)
 
 
-4.2.2 Two finger touch
+5.2.3 Two finger touch
       ~~~~~~~~~~~~~~~~
 
 Note that the two pairs of coordinates are not exactly the coordinates of the
@@ -446,7 +453,7 @@  byte 0:
         n1  n0  ay8 ax8  .   .   R   L
 
          L, R = 1 when Left, Right mouse button pressed
-         n1..n0 = numbers of fingers on touchpad
+         n1..n0 = number of fingers on touchpad
 
 byte 1:
 
@@ -480,3 +487,76 @@  byte 5:
         by7 by8 by5 by4 by3 by2 by1 by0
 
          by8..by0 = upper-right finger absolute y value
+
+/////////////////////////////////////////////////////////////////////////////
+
+6. Hardware version 3
+   ==================
+
+6.1 Registers
+    ~~~~~~~~~
+* reg_10
+
+   bit   7   6   5   4   3   2   1   0
+         0   0   0   0   0   0   0   A
+
+         A: 1 = enable absolute tracking
+
+6.2 Native absolute mode 6 byte packet format
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 and 3 finger touch shares the same 6-byte packet format, except that
+3 finger touch only reports the position of the center of all three fingers.
+
+Firmware would send 12 bytes of data for 2 finger touch.
+
+6.2.1 One/Three finger touch
+      ~~~~~~~~~~~~~~~~~~~~~~
+
+byte 0:
+
+   bit   7   6   5   4   3   2   1   0
+        n1  n0  w3  w2   0   1   R   L
+
+        L, R = 1 when Left, Right mouse button pressed
+        n1..n0 = number of fingers on touchpad
+
+byte 1:
+
+   bit   7   6   5   4   3   2   1   0
+        p7  p6  p5  p4 x11 x10  x9  x8
+
+byte 2:
+
+   bit   7   6   5   4   3   2   1   0
+        x7  x6  x5  x4  x3  x2  x1  x0
+
+        x11..x0 = absolute x value (horizontal)
+
+byte 3:
+
+   bit   7   6   5   4   3   2   1   0
+         0   0  w1  w0   0   0   1   0
+
+         w3..w0 = width of the finger touch
+
+byte 4:
+
+   bit   7   6   5   4   3   2   1   0
+        p3  p1  p2  p0  y11 y10 y9  y8
+
+        p7..p0 = pressure
+
+byte 5:
+
+   bit   7   6   5   4   3   2   1   0
+        y7  y6  y5  y4  y3  y2  y1  y0
+
+        y11..y0 = absolute y value (vertical)
+
+6.2.2 Two finger touch
+      ~~~~~~~~~~~~~~~~
+
+The packet format is exactly the same for two finger touch, except the hardware
+sends two 6 byte packets. The first packet contains data for the first finger,
+the second packet has data for the second finger. So for two finger touch a
+total of 12 bytes are sent.
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index ddd40eb..e13a719 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -108,6 +108,16 @@  static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg,
 			rc = -1;
 		}
 		break;
+
+	case 3:
+		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+		    elantech_ps2_command(psmouse, NULL, reg) ||
+		    elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) {
+			rc = -1;
+		}
+		break;
 	}
 
 	if (rc)
@@ -154,6 +164,18 @@  static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg,
 			rc = -1;
 		}
 		break;
+
+	case 3:
+		if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+		    elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) ||
+		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+		    elantech_ps2_command(psmouse, NULL, reg) ||
+		    elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) ||
+		    elantech_ps2_command(psmouse, NULL, val) ||
+		    elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) {
+			rc = -1;
+		}
+		break;
 	}
 
 	if (rc)
@@ -352,6 +374,94 @@  static void elantech_report_absolute_v2(struct psmouse *psmouse)
 	input_sync(dev);
 }
 
+/*
+ * firmware tells us there's noise.
+ */
+static inline int debounce(unsigned int x, unsigned int y)
+{
+	return (x == 0xfff) && (y == 0xfff);
+}
+
+/*
+ * Interpret complete data packets and report absolute mode input events for
+ * hardware version 3. (12 byte packets for two fingers)
+ */
+static void elantech_report_absolute_v3(struct psmouse *psmouse,
+					int packet_type)
+{
+	struct input_dev *dev = psmouse->dev;
+	struct elantech_data *etd = psmouse->private;
+	unsigned char *packet = psmouse->packet;
+	unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+	unsigned int width = 0, pres = 0;
+
+	/* byte 0: n1  n0   .   .   .   .   R   L */
+	fingers = (packet[0] & 0xc0) >> 6;
+
+	switch (fingers) {
+	case 3:
+	case 1:
+		/*
+		 * byte 1:  .   .   .   .  x11 x10 x9  x8
+		 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
+		 */
+		x1 = ((packet[1] & 0x0f) << 8) | packet[2];
+		/*
+		 * byte 4:  .   .   .   .  y11 y10 y9  y8
+		 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
+		 */
+		y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
+
+		if (fingers == 3 && debounce(x1, y1))
+			return;
+
+		break;
+
+	case 2:
+		if (packet_type == PACKET_V3_HEAD) {
+			/*
+			 * byte 1:   .    .    .    .  ax11 ax10 ax9  ax8
+			 * byte 2: ax7  ax6  ax5  ax4  ax3  ax2  ax1  ax0
+			 */
+			etd->prev_x = ((packet[1] & 0x0f) << 8) | packet[2];
+			/*
+			 * byte 4:   .    .    .    .  ay11 ay10 ay9  ay8
+			 * byte 5: ay7  ay6  ay5  ay4  ay3  ay2  ay1  ay0
+			 */
+			etd->prev_y = etd->y_max -
+				(((packet[4] & 0x0f) << 8) | packet[5]);
+			/*
+			 * wait for next packet
+			 */
+			return;
+		}
+
+		/* packet_type == PACKET_V3_TAIL */
+		x1 = etd->prev_x;
+		y1 = etd->prev_y;
+		x2 = ((packet[1] & 0x0f) << 8) | packet[2];
+		y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]);
+		break;
+	}
+
+	pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+	width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
+
+	input_report_key(dev, BTN_TOUCH, fingers != 0);
+	input_report_abs(dev, ABS_X, x1);
+	input_report_abs(dev, ABS_Y, y1);
+	elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
+	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
+	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
+	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+	input_report_abs(dev, ABS_PRESSURE, pres);
+	input_report_abs(dev, ABS_TOOL_WIDTH, width);
+
+	input_sync(dev);
+}
+
 static int elantech_check_parity_v1(struct psmouse *psmouse)
 {
 	struct elantech_data *etd = psmouse->private;
@@ -396,11 +506,31 @@  static int packet_simple_check_v2(struct psmouse *psmouse)
 }
 
 /*
+ * We check the constant bits to determine what packet type we get,
+ * so packet checking is mandatory for v3 hardware.
+ */
+static int determine_packet_v3(struct psmouse *psmouse)
+{
+	unsigned char *packet = psmouse->packet;
+
+	if ((packet[0] & 0x0c) == 0x04 &&
+	    (packet[3] & 0xcf) == 0x02)
+		return PACKET_V3_HEAD;
+
+	if ((packet[0] & 0x0c) == 0x0c &&
+	    (packet[3] & 0xce) == 0x0c)
+		return PACKET_V3_TAIL;
+
+	return PACKET_UNKNOWN;
+}
+
+/*
  * Process byte stream from mouse and handle complete packets
  */
 static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 {
 	struct elantech_data *etd = psmouse->private;
+	int packet_type;
 
 	if (psmouse->pktcnt < psmouse->pktsize)
 		return PSMOUSE_GOOD_DATA;
@@ -422,6 +552,14 @@  static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 
 		elantech_report_absolute_v2(psmouse);
 		break;
+
+	case 3:
+		packet_type = determine_packet_v3(psmouse);
+		if (packet_type == PACKET_UNKNOWN)
+			goto bad_packet;
+
+		elantech_report_absolute_v3(psmouse, packet_type);
+		break;
 	}
 
 	return PSMOUSE_FULL_PACKET;
@@ -459,10 +597,17 @@  static int elantech_set_absolute_mode(struct psmouse *psmouse)
 		etd->reg_21 = 0x60;	/* 0x00 */
 		if (elantech_write_reg(psmouse, 0x10, etd->reg_10) ||
 		    elantech_write_reg(psmouse, 0x11, etd->reg_11) ||
-		    elantech_write_reg(psmouse, 0x21, etd->reg_21)) {
+		    elantech_write_reg(psmouse, 0x21, etd->reg_21))
 			rc = -1;
-			break;
-		}
+
+		break;
+
+	case 3:
+		etd->reg_10 = 0x0b;
+		if (elantech_write_reg(psmouse, 0x10, etd->reg_10))
+			rc = -1;
+
+		break;
 	}
 
 	if (rc == 0) {
@@ -496,11 +641,12 @@  static int elantech_set_absolute_mode(struct psmouse *psmouse)
 	return rc;
 }
 
-static void set_range(struct psmouse *psmouse, unsigned int *x_min,
+static int set_range(struct psmouse *psmouse, unsigned int *x_min,
 		     unsigned int *y_min, unsigned int *x_max,
 		     unsigned int *y_max, unsigned int *y_2ft_max)
 {
 	struct elantech_data *etd = psmouse->private;
+	unsigned char param[3];
 	int i;
 
 	switch (etd->hw_version) {
@@ -529,19 +675,30 @@  static void set_range(struct psmouse *psmouse, unsigned int *x_min,
 		*y_max = (etd->capabilities[2] - i) * 64;
 		*y_2ft_max = (*y_max - i) * 64 / 4;
 		break;
+
+	case 3:
+		if (synaptics_send_cmd(psmouse, ETP_FW_ID_QUERY, param))
+			return -1;
+
+		*x_max = (0x0f & param[0]) << 8 | param[1];
+		*y_max = (0xf0 & param[0]) << 4 | param[2];
+		break;
 	}
+
+	return 0;
 }
 
 /*
  * Set the appropriate event bits for the input subsystem
  */
-static void elantech_set_input_params(struct psmouse *psmouse)
+static int elantech_set_input_params(struct psmouse *psmouse)
 {
 	struct input_dev *dev = psmouse->dev;
 	struct elantech_data *etd = psmouse->private;
 	unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, y_2ft_max = 0;
 
-	set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &y_2ft_max);
+	if (set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &y_2ft_max))
+		return -1;
 
 	__set_bit(EV_KEY, dev->evbit);
 	__set_bit(EV_ABS, dev->evbit);
@@ -582,10 +739,26 @@  static void elantech_set_input_params(struct psmouse *psmouse)
 		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
 		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
 		break;
+
+	case 3:
+		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
+		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
+		/* range of pressure and width is the same as v2 */
+		input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
+				     ETP_PMAX_V2, 0, 0);
+		input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
+				     ETP_WMAX_V2, 0, 0);
+		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+		input_mt_init_slots(dev, 2);
+		input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
+		input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
+		break;
 	}
 
 	etd->y_max = y_max;
 	etd->y_2ft_max = y_2ft_max;
+
+	return 0;
 }
 
 struct elantech_attr_data {
@@ -727,7 +900,8 @@  int elantech_detect(struct psmouse *psmouse, bool set_properties)
 	 * Report this in case there are Elantech models that use a different
 	 * set of magic numbers
 	 */
-	if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
+	if (param[0] != 0x3c || param[1] != 0x03 ||
+	    (param[2] != 0xc8 && param[2] != 0x00)) {
 		pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
 			 param[0], param[1], param[2]);
 		return -1;
@@ -793,16 +967,16 @@  static int elantech_reconnect(struct psmouse *psmouse)
 /*
  * determine hardware version and set some properties according to it.
  */
-static void elantech_set_properties(struct elantech_data *etd)
+static int elantech_set_properties(struct elantech_data *etd)
 {
-	/*
-	 * Assume every version greater than 0x020030 is new EeePC style
-	 * hardware with 6 byte packets, except 0x020600
-	 */
 	if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600)
 		etd->hw_version = 1;
-	else
+	else if (etd->fw_version < 0x150600)
 		etd->hw_version = 2;
+	else if ((etd->fw_version & 0x0f0000) >> 16 == 5)
+		etd->hw_version = 3;
+	else
+		return -1;
 
 	/*
 	 * Turn on packet checking by default.
@@ -817,13 +991,15 @@  static void elantech_set_properties(struct elantech_data *etd)
 	etd->jumpy_cursor =
 		(etd->fw_version == 0x020022 || etd->fw_version == 0x020600);
 
-	if (etd->hw_version == 2) {
+	if (etd->hw_version > 1) {
 		/* For now show extra debug information */
 		etd->debug = 1;
 
 		if (etd->fw_version >= 0x020800)
 			etd->reports_pressure = true;
 	}
+
+	return 0;
 }
 
 /*
@@ -850,9 +1026,12 @@  int elantech_init(struct psmouse *psmouse)
 		pr_err("failed to query firmware version.\n");
 		goto init_fail;
 	}
-
 	etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
-	elantech_set_properties(etd);
+
+	if (elantech_set_properties(etd)) {
+		pr_err("unknown hardware version, aborting...\n");
+		goto init_fail;
+	}
 	pr_info("assuming hardware version %d "
 		"(with firmware version 0x%02x%02x%02x)\n",
 		etd->hw_version, param[0], param[1], param[2]);
@@ -871,7 +1050,10 @@  int elantech_init(struct psmouse *psmouse)
 		goto init_fail;
 	}
 
-	elantech_set_input_params(psmouse);
+	if (elantech_set_input_params(psmouse)) {
+		pr_err("failed to query touchpad range.\n");
+		goto init_fail;
+	}
 
 	error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
 				   &elantech_attr_group);
@@ -883,7 +1065,7 @@  int elantech_init(struct psmouse *psmouse)
 	psmouse->protocol_handler = elantech_process_byte;
 	psmouse->disconnect = elantech_disconnect;
 	psmouse->reconnect = elantech_reconnect;
-	psmouse->pktsize = etd->hw_version == 2 ? 6 : 4;
+	psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
 
 	return 0;
 
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 4b7447e..4f01fc6 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -16,6 +16,7 @@ 
 /*
  * Command values for Synaptics style queries
  */
+#define ETP_FW_ID_QUERY			0x00
 #define ETP_FW_VERSION_QUERY		0x01
 #define ETP_CAPABILITIES_QUERY		0x02
 
@@ -24,6 +25,7 @@ 
  */
 #define ETP_REGISTER_READ		0x10
 #define ETP_REGISTER_WRITE		0x11
+#define ETP_REGISTER_READWRITE		0x00
 
 /*
  * Hardware version 2 custom PS/2 command value
@@ -93,6 +95,13 @@ 
 #define ETP_2FT_YMIN			(  0 + ETP_2FT_FUZZ)
 #define ETP_2FT_YMAX			(192 - ETP_2FT_FUZZ)
 
+/*
+ * v3 hardware has 2 kinds of packet types.
+ */
+#define PACKET_UNKNOWN			0x01
+#define PACKET_V3_HEAD			0x02
+#define PACKET_V3_TAIL			0x03
+
 struct elantech_data {
 	unsigned char reg_10;
 	unsigned char reg_11;
@@ -113,6 +122,8 @@  struct elantech_data {
 	unsigned int single_finger_reports;
 	unsigned int y_max;
 	unsigned int y_2ft_max;
+	unsigned int prev_x;
+	unsigned int prev_y;
 	unsigned char parity[256];
 };