NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/48831: Synaptics Touch pad (ClickPad) and Klick-by-tap-gestures do not work



>Number:         48831
>Category:       kern
>Synopsis:       Synaptics Touch pad (ClickPad) and Klick-by-tap-gestures do 
>not work
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu May 22 08:15:01 +0000 2014
>Originator:     Jörg Grundmann
>Release:        NetBSD 6.1.3
>Organization:
CenterTools GmbH
>Environment:
NetBSD joerg-netbsd-613.centertools.net 6.1.3 NetBSD 6.1.3 (GENERIC) i386
>Description:
1.
Newer notebooks like the Lenovo ThinkPad L540 have a touch pad which has no 
physical keys but the whole touch pad can be pressed to generate a left mouse 
button klick. This is not handled in the current driver.

2.
When fixing this issue, I recognized that virtual clicks are not handled 
correctly (tapping on the touch pad).

This touch pad reports version 8.1
>How-To-Repeat:
1.
On console:
$ cat /dev/wsmouse

Move finger on the touch pad -> garbage on screen -> OK
Press the whole touch pad down -> Nothing happens

Alternative:
Start Xorg Server
Mouse move by moving finger on the touch pad works.
Pressing the touch pad down does not create a "click"

2.
Start Xorg Server
Try to do "clicks" by just tapping the touch pad with one finger
-> Nothing happens
>Fix:
The following patch fixes both problems:

diff --git a/sys/dev/pckbport/synaptics.c b/sys/dev/pckbport/synaptics.c
index 50949fa..c061745 100644
--- a/sys/dev/pckbport/synaptics.c
+++ b/sys/dev/pckbport/synaptics.c
@@ -211,20 +211,66 @@ pms_synaptics_probe_init(void *vsc)
                if (sc->caps & SYNAPTICS_CAP_MULTIDETECT)
                        sc->flags |= SYN_FLAG_HAS_MULTI_FINGER;
 
+               if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT)
+                       sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT;
+
                /* Ask about extra buttons to detect up/down. */
-               if (sc->caps & SYNAPTICS_CAP_EXTNUM) {
+               if ( ((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= 
SYNAPTICS_EXTENDED_QUERY) {
                        res = pms_sliced_command(psc->sc_kbctag,
                            psc->sc_kbcslot, SYNAPTICS_EXTENDED_QUERY);
                        cmd[0] = PMS_SEND_DEV_STATUS;
                        res |= pckbport_poll_cmd(psc->sc_kbctag,
                            psc->sc_kbcslot, cmd, 1, 3, resp, 0);
-                       if (res == 0)
+                       if (res == 0) {
+                               int buttons = (resp[1] >> 4);
                                aprint_debug_dev(psc->sc_dev,
                                    "synaptics_probe: Extended "
-                                   "Capabilities 0x%02x.\n", resp[1]);
-                       if (!res && (resp[1] >> 4) >= 2) {
-                               /* Yes. */
-                               sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
+                                   "Buttons: %d.\n", buttons);
+
+                               aprint_debug_dev(psc->sc_dev,
+                                   "synaptics_probe: Extended "
+                                   "Capabilities: 0x%02x 0x%02x 0x%02x.\n",
+                                   resp[0], resp[1], resp[2]);
+                               if (buttons >= 2) {
+                                       /* Yes. */
+                                       sc->flags |= 
SYN_FLAG_HAS_UP_DOWN_BUTTONS;
+                               }
+                               if ((resp[0] & 0x1)) {
+                                       /* Vertical scroll area */
+                                       sc->flags |= 
SYN_FLAG_HAS_VERTICAL_SCROLL;
+                               }
+                               if ((resp[0] & 0x2)) {
+                                       /* Horizontal scroll area */
+                                       sc->flags |= 
SYN_FLAG_HAS_HORIZONTAL_SCROLL;
+                               }
+                               if ((resp[0] & 0x4)) {
+                                       /* Extended W-Mode */
+                                       sc->flags |= 
SYN_FLAG_HAS_EXTENDED_WMODE;
+                               }
+                       }
+               }
+
+               /* Ask about click pad */
+               if ( ((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= 
SYNAPTICS_CONTINUED_CAPABILITIES) {
+                       res = pms_sliced_command(psc->sc_kbctag,
+                           psc->sc_kbcslot, SYNAPTICS_CONTINUED_CAPABILITIES);
+                       cmd[0] = PMS_SEND_DEV_STATUS;
+                       res |= pckbport_poll_cmd(psc->sc_kbctag,
+                           psc->sc_kbcslot, cmd, 1, 3, resp, 0);
+                       if (res == 0) {
+                               u_char clickpad_type = (resp[1] & 0x1);
+                               clickpad_type |= ((resp[0] >> 4) & 0x1);
+
+                               aprint_debug_dev(psc->sc_dev,
+                                   "synaptics_probe: Continued "
+                                   "Capabilities 0x%02x 0x%02x 0x%02x.\n",
+                                   resp[0], resp[1], resp[2]);
+                               if (clickpad_type == 1) {
+                                       sc->flags |= 
SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD;
+                               }
+                               else if (clickpad_type == 2) {
+                                       sc->flags |= 
SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD;
+                               }
                        }
                }
        }
@@ -233,6 +279,10 @@ pms_synaptics_probe_init(void *vsc)
                const char comma[] = ", ";
                const char *sep = "";
                aprint_normal_dev(psc->sc_dev, "");
+               if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) {
+                       aprint_normal("%sExtended W mode", sep);
+                       sep = comma;
+               }
                if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
                        aprint_normal("%sPassthrough", sep);
                        sep = comma;
@@ -253,6 +303,26 @@ pms_synaptics_probe_init(void *vsc)
                        aprint_normal("%sPalm detect", sep);
                        sep = comma;
                }
+               if (sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
+                       aprint_normal("%sOne button click pad", sep);
+                       sep = comma;
+               }
+               if (sc->flags & SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD) {
+                       aprint_normal("%sTwo button click pad", sep);
+                       sep = comma;
+               }
+               if (sc->flags & SYN_FLAG_HAS_VERTICAL_SCROLL) {
+                       aprint_normal("%sVertical scroll", sep);
+                       sep = comma;
+               }
+               if (sc->flags & SYN_FLAG_HAS_HORIZONTAL_SCROLL) {
+                       aprint_normal("%sHorizontal scroll", sep);
+                       sep = comma;
+               }
+               if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER_REPORT) {
+                       aprint_normal("%sMulti-finger Report", sep);
+                       sep = comma;
+               }
                if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER)
                        aprint_normal("%sMulti-finger", sep);
 
@@ -276,7 +346,7 @@ pms_synaptics_enable(void *vsc)
        int res;
 
        if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
-               /* 
+               /*
                 * Extended capability probes can confuse the passthrough 
device;
                 * reset the touchpad now to cure that.
                 */
@@ -626,6 +696,8 @@ pms_synaptics_parse(struct pms_softc *psc)
        struct synaptics_softc *sc = &psc->u.synaptics;
        struct synaptics_packet sp;
 
+       memset(&sp, 0, sizeof(struct synaptics_packet));
+
        /* Absolute X/Y coordinates of finger */
        sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) +
           ((psc->packet[3] & 0x10) << 8);
@@ -663,6 +735,12 @@ pms_synaptics_parse(struct pms_softc *psc)
                sp.sp_down = 0;
        }
 
+       if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
+               /* This is not correctly specified. Read this button press
+                * from L/U bit.
+                */
+               sp.sp_left = ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? 1 : 0;
+       } else
        /* Middle button. */
        if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
                /* Old style Middle Button. */
@@ -866,12 +944,17 @@ static inline void
 synaptics_gesture_detect(struct synaptics_softc *sc,
     struct synaptics_packet *sp, int fingers)
 {
-       int gesture_len, gesture_move_x, gesture_move_y, gesture_buttons;
+       int gesture_len, gesture_buttons;
        int set_buttons;
 
        gesture_len = SYN_TIME(sc, sc->gesture_start_packet);
        gesture_buttons = sc->gesture_buttons;
 
+       if (fingers > 0 && (fingers == sc->prev_fingers)) {
+               /* Finger is still present */
+               sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
+               sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
+       } else
        if (fingers && sc->prev_fingers == 0) {
                /*
                 * Finger was just applied.
@@ -885,9 +968,16 @@ synaptics_gesture_detect(struct synaptics_softc *sc,
                if (SYN_IS_SINGLE_TAP(sc->gesture_type))
                        sc->gesture_type |= SYN_GESTURE_DRAG;
 
-               sc->gesture_start_x = sp->sp_x;
-               sc->gesture_start_y = sp->sp_y;
+               sc->gesture_start_x = abs(sp->sp_x);
+               sc->gesture_start_y = abs(sp->sp_y);
+               sc->gesture_move_x = 0;
+               sc->gesture_move_y = 0;
                sc->gesture_start_packet = sc->total_packets;
+
+#ifdef DIAGNOSTIC
+               aprint_debug("Finger applied: gesture_start_x: %d 
gesture_start_y: %d\n",
+                       sc->gesture_start_x, sc->gesture_start_y);
+#endif
        } else
        if (fingers == 0 && sc->prev_fingers != 0) {
                /*
@@ -898,13 +988,19 @@ synaptics_gesture_detect(struct synaptics_softc *sc,
                 * detected (the pad may report coordinates for any
                 * of the fingers).
                 */
-               gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
-               gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
+
+#ifdef DIAGNOSTIC
+               aprint_debug("Finger removed: gesture_len: %d (%d)\n",
+                       gesture_len, synaptics_gesture_length);
+               aprint_debug("gesture_move_x: %d (%d) sp_x: %d\n",
+                       sc->gesture_move_x, synaptics_gesture_move, 
abs(sp->sp_x));
+               aprint_debug("gesture_move_y: %d (%d) sp_y: %d\n",
+                       sc->gesture_move_y, synaptics_gesture_move, 
abs(sp->sp_y));
+#endif
 
                if (gesture_len < synaptics_gesture_length &&
-                   (sc->prev_fingers > 1 ||
-                   (gesture_move_x < synaptics_gesture_move &&
-                    gesture_move_y < synaptics_gesture_move))) {
+                   ((sc->gesture_move_x < synaptics_gesture_move &&
+                    sc->gesture_move_y < synaptics_gesture_move))) {
                        /*
                         * Looking good so far.
                         */
diff --git a/sys/dev/pckbport/synapticsreg.h b/sys/dev/pckbport/synapticsreg.h
index 27d22f1..3642a28 100644
--- a/sys/dev/pckbport/synapticsreg.h
+++ b/sys/dev/pckbport/synapticsreg.h
@@ -44,6 +44,7 @@
 #define SYNAPTICS_READ_CAPABILITIES    0x2
 #define SYNAPTICS_READ_MODEL_ID                0x3
 #define SYNAPTICS_EXTENDED_QUERY       0x9
+#define SYNAPTICS_CONTINUED_CAPABILITIES 0x0c
 
 /* Synaptics special commands */
 #define SYNAPTICS_CMD_SET_MODE2                0x14
@@ -58,6 +59,7 @@
 #define SYNAPTICS_CAP_EXTNUM           (1 << 14 | 1 << 13 | 1 << 12)
 #define SYNAPTICS_CAP_MBUTTON          (1 << 10)
 #define SYNAPTICS_CAP_PASSTHROUGH      (1 << 7)
+#define SYNAPTICS_CAP_MULTIFINGERREPORT (1 << 5)
 #define SYNAPTICS_CAP_SLEEP            (1 << 4)
 #define SYNAPTICS_CAP_4BUTTON          (1 << 3)
 #define SYNAPTICS_CAP_MULTIDETECT      (1 << 1)
diff --git a/sys/dev/pckbport/synapticsvar.h b/sys/dev/pckbport/synapticsvar.h
index a548536..28b6c0c 100644
--- a/sys/dev/pckbport/synapticsvar.h
+++ b/sys/dev/pckbport/synapticsvar.h
@@ -48,6 +48,12 @@ struct synaptics_softc {
 #define        SYN_FLAG_HAS_PASSTHROUGH        (1 << 3)
 #define        SYN_FLAG_HAS_PALM_DETECT        (1 << 4)
 #define        SYN_FLAG_HAS_MULTI_FINGER       (1 << 5)
+#define SYN_FLAG_HAS_MULTI_FINGER_REPORT (1 << 6)
+#define SYN_FLAG_HAS_VERTICAL_SCROLL (1 << 7)
+#define SYN_FLAG_HAS_HORIZONTAL_SCROLL (1 << 8)
+#define SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD (1 << 9)
+#define SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD (1 << 10)
+#define SYN_FLAG_HAS_EXTENDED_WMODE (1<<11)
 
        u_int   total_packets;          /* Total number of packets received */
 #define        SYN_TIME(sc,c)  (((sc)->total_packets >= (c)) ?         \
@@ -58,6 +64,7 @@ struct synaptics_softc {
        int     prev_fingers;
 
        int     gesture_start_x, gesture_start_y;
+       int gesture_move_x, gesture_move_y;
        u_int   gesture_start_packet;
        u_int   gesture_tap_packet;
 



Home | Main Index | Thread Index | Old Index