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