Thread (17 messages) 17 messages, 4 authors, 2011-09-13

Re: [PATCH v5 7/8] Input: elantech - add v3 hardware support

From: Daniel Kurtz <hidden>
Date: 2011-09-05 08:48:10
Also in: lkml

Hi JJ,

On Mon, Sep 5, 2011 at 4:39 PM, Daniel Kurtz [off-list ref] wrote:
Hi JJ,

On Mon, Sep 5, 2011 at 3:10 PM, JJ Ding [off-list ref] wrote:
quoted
Hi Daniel,

On Mon, 5 Sep 2011 12:35:28 +0800, Daniel Kurtz [off-list ref] wrote:
quoted
Hi JJ,

On Mon, Sep 5, 2011 at 10:16 AM, JJ Ding [off-list ref] wrote:
quoted
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 2ae7c49..c4ceefd 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)
@@ -350,6 +372,84 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
       input_sync(dev);
 }

+/*
+ * 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]);
+               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);
+       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);
Originally, v3 was using semi-mt, which reported corner coordinates of
a box containing at least two of the N touches on the touchpad.  I
thought this was due to hardware limitation.

If the hardware really can report true positions for (up to) 3
contacts, then using pure MT-B is a good approach.  This driver still
seems to mix semi-mt and MT-B together a bit.

Can you report all three contacts in their own slots, 0, 1 and 2,
instead of just reoprting two of them with 0,1?

Also, when reporting the 'legacy single touch' coordinate (ABS_X,
ABS_Y), please use:
input_mt_report_pointer_emulation(), instead of always reporting the
last (x1,y1).  Otherwise the single touch point will bounce back and
forth between 1st and 3rd touch.
v3 can only track the true positions of two fingers. With 3 finger
touch, it reports the lowest value of x and the biggest value of y,
among the three fingers. v3 changed the protocol so it could report
2-finger touch data w/o reduced resolution and improved the hardware to
truly track 2 fingers independently, otherwise it's pretty much the same
as v2.

If I read this code correctly, it looks like in the 3-finger case,
(x1,y1) as reported in the (ABS_X, ABS_Y), and in the call to
elantech_report_semi_mt_data() will bounce back and forth between the
1st finger and 3rd finger ("lowest value of x and the biggest value of
y").  Won't this be very confusing for userspace (i.e.
xf86-input=synaptics)?
Oh, never mind.  Sorry for the confusion.  I guess in the 3-finger
case, you only get "3-finger" packets containing the single ("lowest
value of x and the biggest value of y") bounding box coordinate, not
V3_HEAD/V3_TAIL packets.
I believe this shouldn't be reported as MT-B slot 0, though.  If
anything, perhaps you should use MT-B slot 2 for this coordinate?
It's not really the third finger, but at least it won't be considered
a continuation of the motion of the first finger.
I guess you really have no choice but to use it as the (ABS_X, ABS_Y)
coordinate.

-Dan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help