Module Name: src
Committed By: blymn
Date: Thu Oct 21 04:49:28 UTC 2021
Modified Files:
src/sys/dev/pckbport: synaptics.c synapticsvar.h
Log Message:
Significant update to the synaptics touchpad driver.
* Accumulate packets for primary, secondary, finger count packets
before handing off to pms_synaptics_process_packet. This means
that both primary and, possibly, secondary finger locations will
be processed at the same time. Previously the processing each
packet as it arrived.
* Fix the secondary finger position reporting, there was an off by
one in the shifts when decoding which effectively halved the
reported position.
* For a clickpad, make the emulated button region "dead" so that finger
movements in this region are ignored. This makes it easier to click
a button without accidentally repositioning the cursor. There is a
sysctl variable "button_region_movement_enable" that will allow
these finger movements to be reported if this is desirable.
* Reset the finger ballistics when the number of fingers changes. This
stops the annoying position jumps when a second finger touch is added
to or removed from the touchpad.
* Add a level argument to the DPRINTF macro so one can choose their
level of debug spam via the debug sysctl variable.
To generate a diff of this commit:
cvs rdiff -u -r1.72 -r1.73 src/sys/dev/pckbport/synaptics.c
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/pckbport/synapticsvar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pckbport/synaptics.c
diff -u src/sys/dev/pckbport/synaptics.c:1.72 src/sys/dev/pckbport/synaptics.c:1.73
--- src/sys/dev/pckbport/synaptics.c:1.72 Tue Sep 28 06:16:13 2021
+++ src/sys/dev/pckbport/synaptics.c Thu Oct 21 04:49:28 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: synaptics.c,v 1.72 2021/09/28 06:16:13 nia Exp $ */
+/* $NetBSD: synaptics.c,v 1.73 2021/10/21 04:49:28 blymn Exp $ */
/*
* Copyright (c) 2005, Steve C. Woodford
@@ -48,7 +48,7 @@
#include "opt_pms.h"
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.72 2021/09/28 06:16:13 nia Exp $");
+__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.73 2021/10/21 04:49:28 blymn Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -79,11 +79,14 @@ struct synaptics_packet {
signed short sp_x; /* Unscaled absolute X/Y coordinates */
signed short sp_y;
u_char sp_z; /* Z (pressure) */
+ signed short sp_sx; /* Unscaled absolute X/Y coordinates */
+ signed short sp_sy; /* for secondary finger */
+ u_char sp_sz; /* Z (pressure) */
u_char sp_w; /* W (contact patch width) */
- signed short sp_sx; /* Secondary finger unscaled absolute */
- /* X/Y coordinates */
- signed short sp_xy;
- u_char sp_finger; /* 0 for primary, 1 for secondary */
+ u_char sp_primary; /* seen primary finger packet */
+ u_char sp_secondary; /* seen secondary finger packet */
+ u_char sp_finger_status; /* seen extended finger packet */
+ u_char sp_finger_count; /* number of fingers seen */
char sp_left; /* Left mouse button status */
char sp_right; /* Right mouse button status */
char sp_middle; /* Middle button status (possibly emulated) */
@@ -121,12 +124,13 @@ static int synaptics_max_speed_y = 32;
static int synaptics_max_speed_z = 2;
static int synaptics_movement_threshold = 4;
static int synaptics_movement_enable = 1;
+static int synaptics_button_region_movement = 1;
static bool synaptics_aux_mid_button_scroll = TRUE;
static int synaptics_debug = 0;
-#define DPRINTF(SC, FMT, ARGS...) do \
+#define DPRINTF(LEVEL, SC, FMT, ARGS...) do \
{ \
- if (synaptics_debug) { \
+ if (synaptics_debug >= LEVEL) { \
struct pms_softc *_dprintf_psc = \
container_of((SC), struct pms_softc, u.synaptics); \
device_printf(_dprintf_psc->sc_dev, FMT, ##ARGS); \
@@ -157,8 +161,16 @@ static int synaptics_max_speed_y_nodenum
static int synaptics_max_speed_z_nodenum;
static int synaptics_movement_threshold_nodenum;
static int synaptics_movement_enable_nodenum;
+static int synaptics_button_region_movement_nodenum;
static int synaptics_aux_mid_button_scroll_nodenum;
+/*
+ * This holds the processed packet data, it is global because multiple
+ * packets from the trackpad may be processed when handling multiple
+ * fingers on the trackpad to gather all the data.
+ */
+static struct synaptics_packet packet;
+
static int
synaptics_poll_cmd(struct pms_softc *psc, ...)
{
@@ -490,6 +502,10 @@ pms_synaptics_enable(void *vsc)
(sc->flags & SYN_FLAG_HAS_ADV_GESTURE_MODE))
synaptics_special_write(psc, SYNAPTICS_WRITE_DELUXE_3, 0x3);
+ /* Disable motion in the button region for clickpads */
+ if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD)
+ synaptics_button_region_movement = 0;
+
sc->up_down = 0;
sc->prev_fingers = 0;
sc->gesture_start_x = sc->gesture_start_y = 0;
@@ -497,11 +513,14 @@ pms_synaptics_enable(void *vsc)
sc->gesture_tap_packet = 0;
sc->gesture_type = 0;
sc->gesture_buttons = 0;
+ sc->total_packets = 0;
for (i = 0; i < SYN_MAX_FINGERS; i++) {
sc->rem_x[i] = sc->rem_y[i] = sc->rem_z[i] = 0;
- sc->movement_history[i] = 0;
}
sc->button_history = 0;
+
+ /* clear the packet decode structure */
+ memset(&packet, 0, sizeof(packet));
}
void
@@ -766,6 +785,18 @@ pms_sysctl_synaptics(struct sysctllog **
if ((rc = sysctl_createv(clog, 0, NULL, &node,
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+ CTLTYPE_INT, "button_region_movement_enable",
+ SYSCTL_DESCR("Enable movement within clickpad button region"),
+ pms_sysctl_synaptics_verify, 0,
+ &synaptics_button_region_movement,
+ 0, CTL_HW, root_num, CTL_CREATE,
+ CTL_EOL)) != 0)
+ goto err;
+
+ synaptics_button_region_movement_nodenum = node->sysctl_num;
+
+ if ((rc = sysctl_createv(clog, 0, NULL, &node,
+ CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
CTLTYPE_INT, "button_boundary",
SYSCTL_DESCR("Top edge of button area"),
pms_sysctl_synaptics_verify, 0,
@@ -904,6 +935,10 @@ pms_sysctl_synaptics_verify(SYSCTLFN_ARG
if (t < 0 || t > 1)
return (EINVAL);
} else
+ if (node.sysctl_num == synaptics_button_region_movement_nodenum) {
+ if (t < 0 || t > 1)
+ return (EINVAL);
+ } else
if (node.sysctl_num == synaptics_aux_mid_button_scroll_nodenum) {
if (t < 0 || t > 1)
return (EINVAL);
@@ -915,6 +950,75 @@ pms_sysctl_synaptics_verify(SYSCTLFN_ARG
return (0);
}
+/*
+ * Extract the number of fingers from the current packet and return
+ * it to the caller.
+ */
+static unsigned
+pms_synaptics_get_fingers(struct pms_softc *psc, u_char w, short z)
+{
+ struct synaptics_softc *sc = &psc->u.synaptics;
+ unsigned short ew_mode;
+ unsigned fingers;
+
+ fingers = 0;
+
+
+ /*
+ * If w is zero and z says no fingers then return
+ * no fingers, w == can also mean 2 fingers... confusing.
+ */
+ if (w == 0 && z == SYNAPTICS_FINGER_NONE)
+ return 0;
+
+ if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) &&
+ (w == SYNAPTICS_WIDTH_EXTENDED_W)) {
+ ew_mode = psc->packet[5] >> 4;
+ switch (ew_mode)
+ {
+ case SYNAPTICS_EW_WHEEL:
+ break;
+
+ case SYNAPTICS_EW_SECONDARY_FINGER:
+ /* to get here we must have 2 fingers at least */
+ fingers = 2;
+ break;
+
+ case SYNAPTICS_EW_FINGER_STATUS:
+ fingers = psc->packet[1] & 0x0f;
+ break;
+
+ default:
+ aprint_error_dev(psc->sc_dev,
+ "invalid extended w mode %d\n",
+ ew_mode);
+ return 0; /* pretend there are no fingers */
+ }
+ } else {
+
+ fingers = 1;
+
+ /*
+ * If SYN_FLAG_HAS_MULTI_FINGER is set then check
+ * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is
+ * then this will be the finger count.
+ *
+ * There are a couple of "special" values otherwise
+ * just punt with one finger, if this really is a palm
+ * then it will be caught later.
+ */
+ if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER) {
+ if (w == SYNAPTICS_WIDTH_TWO_FINGERS)
+ fingers = 2;
+ else if (w == SYNAPTICS_WIDTH_THREE_OR_MORE)
+ fingers = 3;
+ }
+
+ }
+
+ return fingers;
+}
+
/* Masks for the first byte of a packet */
#define PMS_LBUTMASK 0x01
#define PMS_RBUTMASK 0x02
@@ -924,18 +1028,24 @@ static void
pms_synaptics_parse(struct pms_softc *psc)
{
struct synaptics_softc *sc = &psc->u.synaptics;
- struct synaptics_packet sp;
+ struct synaptics_packet nsp;
char new_buttons, ew_mode;
+ unsigned v, primary_finger, secondary_finger;
- memset(&sp, 0, sizeof(sp));
+ sc->total_packets++;
+
+ memcpy(&nsp, &packet, sizeof(packet));
/* Width of finger */
- sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
- ((psc->packet[0] & 0x04) >> 1) +
- ((psc->packet[3] & 0x04) >> 2);
- sp.sp_finger = 0;
+ nsp.sp_w = ((psc->packet[0] & 0x30) >> 2)
+ + ((psc->packet[0] & 0x04) >> 1)
+ + ((psc->packet[3] & 0x04) >> 2);
+
+ v = 0;
+ primary_finger = 0;
+ secondary_finger = 0;
if ((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) &&
- (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W)) {
+ (nsp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W)) {
ew_mode = psc->packet[5] >> 4;
switch (ew_mode)
{
@@ -947,25 +1057,41 @@ pms_synaptics_parse(struct pms_softc *ps
case SYNAPTICS_EW_SECONDARY_FINGER:
/* parse the second finger report */
- sp.sp_finger = 1; /* just one other finger for now */
- sp.sp_x = psc->packet[1]
- + ((psc->packet[4] & 0x0f) << 8);
- sp.sp_y = psc->packet[2]
- + ((psc->packet[4] & 0xf0) << 4);
- sp.sp_z = (psc->packet[3] & 0x30)
- + (psc->packet[5] & 0x0f);
+ nsp.sp_secondary = 1;
+
+ nsp.sp_sx = ((psc->packet[1] & 0xfe) << 1)
+ + ((psc->packet[4] & 0x0f) << 9);
+ nsp.sp_sy = ((psc->packet[2] & 0xfe) << 1)
+ + ((psc->packet[4] & 0xf0) << 5);
+ nsp.sp_sz = (psc->packet[3] & 0x30)
+ + ((psc->packet[5] & 0x0e) << 1);
+
+ /* work out the virtual finger width */
+ v = 8 + (psc->packet[1] & 0x01) +
+ ((psc->packet[2] & 0x01) << 1) +
+ ((psc->packet[5] & 0x01) << 2);
/* keep same buttons down as primary */
- sp.sp_left = sc->button_history & PMS_LBUTMASK;
- sp.sp_middle = sc->button_history & PMS_MBUTMASK;
- sp.sp_right = sc->button_history & PMS_RBUTMASK;
+ nsp.sp_left = sc->button_history & PMS_LBUTMASK;
+ nsp.sp_middle = sc->button_history & PMS_MBUTMASK;
+ nsp.sp_right = sc->button_history & PMS_RBUTMASK;
break;
case SYNAPTICS_EW_FINGER_STATUS:
- /* reports which finger is primary/secondary
- * ignore for now.
+ /* This works but what is it good for?
+ * it gives us an index of the primary/secondary
+ * fingers but no other packets pass this
+ * index.
+ *
+ * XXX Park this, possibly handle a finger
+ * XXX change if indexes change.
*/
- return;
+ primary_finger = psc->packet[2];
+ secondary_finger = psc->packet[4];
+ nsp.sp_finger_status = 1;
+ nsp.sp_finger_count = pms_synaptics_get_fingers(psc,
+ nsp.sp_w, nsp.sp_z);
+ goto skip_position;
default:
aprint_error_dev(psc->sc_dev,
@@ -974,15 +1100,73 @@ pms_synaptics_parse(struct pms_softc *ps
return;
}
} else {
+ nsp.sp_primary = 1;
- /* Absolute X/Y coordinates of finger */
- sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) +
- ((psc->packet[3] & 0x10) << 8);
- sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) +
- ((psc->packet[3] & 0x20) << 7);
+ /*
+ * If SYN_FLAG_HAS_MULTI_FINGER is set then check
+ * sp_w is below SYNAPTICS_WIDTH_FINGER_MIN, if it is
+ * then this will be the finger count.
+ *
+ * There are a couple of "special" values otherwise
+ * just punt with one finger, if this really is a palm
+ * then it will be caught later.
+ */
+ if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER) {
+ /*
+ * To make life interesting if there are
+ * two or more fingers on the touchpad then
+ * the coordinate reporting changes and an extra
+ * "virtual" finger width is reported.
+ */
+ nsp.sp_x = (psc->packet[4] & 0xfc) +
+ ((psc->packet[4] & 0x02) << 1) +
+ ((psc->packet[1] & 0x0f) << 8) +
+ ((psc->packet[3] & 0x10) << 8);
+
+ nsp.sp_y = (psc->packet[5] & 0xfc) +
+ ((psc->packet[5] & 0x02) << 1) +
+ ((psc->packet[1] & 0xf0) << 4) +
+ ((psc->packet[3] & 0x20) << 7);
+
+ /* Pressure */
+ nsp.sp_z = psc->packet[2] & 0xfe;
+
+ /* derive the virtual finger width */
+ v = 8 + ((psc->packet[4] & 0x02) >> 1) +
+ (psc->packet[5] & 0x02) +
+ ((psc->packet[2] & 0x01) << 2);
+
+ } else {
+ /* Absolute X/Y coordinates of finger */
+ nsp.sp_x = psc->packet[4] +
+ ((psc->packet[1] & 0x0f) << 8) +
+ ((psc->packet[3] & 0x10) << 8);
+
+ nsp.sp_y = psc->packet[5] +
+ ((psc->packet[1] & 0xf0) << 4) +
+ ((psc->packet[3] & 0x20) << 7);
+
+ /* Pressure */
+ nsp.sp_z = psc->packet[2];
+ }
- /* Pressure */
- sp.sp_z = psc->packet[2];
+ nsp.sp_finger_count = pms_synaptics_get_fingers(psc,
+ nsp.sp_w, nsp.sp_z);
+
+ /*
+ * We don't have extended W so we only know if there
+ * are multiple fingers on the touchpad, only the primary
+ * location is reported so just pretend we have an
+ * unmoving second finger.
+ */
+ if (((sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
+ != SYN_FLAG_HAS_EXTENDED_WMODE) &&
+ (nsp.sp_finger_count > 1)) {
+ nsp.sp_secondary = 1;
+ nsp.sp_sx = 0;
+ nsp.sp_sy = 0;
+ nsp.sp_sz = 0;
+ }
if ((psc->packet[0] ^ psc->packet[3]) & 0x02) {
/* extended buttons */
@@ -1018,26 +1202,26 @@ pms_synaptics_parse(struct pms_softc *ps
sc->ext_down = 0;
} else {
/* Left/Right button handling. */
- sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
- sp.sp_right = psc->packet[0] & PMS_RBUTMASK;
+ nsp.sp_left = psc->packet[0] & PMS_LBUTMASK;
+ nsp.sp_right = psc->packet[0] & PMS_RBUTMASK;
}
/* Up/Down buttons. */
if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
/* Old up/down buttons. */
- sp.sp_up = sp.sp_left ^
+ nsp.sp_up = nsp.sp_left ^
(psc->packet[3] & PMS_LBUTMASK);
- sp.sp_down = sp.sp_right ^
+ nsp.sp_down = nsp.sp_right ^
(psc->packet[3] & PMS_RBUTMASK);
} else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS &&
((psc->packet[0] & PMS_RBUTMASK) ^
(psc->packet[3] & PMS_RBUTMASK))) {
/* New up/down button. */
- sp.sp_up = psc->packet[4] & SYN_1BUTMASK;
- sp.sp_down = psc->packet[5] & SYN_2BUTMASK;
+ nsp.sp_up = psc->packet[4] & SYN_1BUTMASK;
+ nsp.sp_down = psc->packet[5] & SYN_2BUTMASK;
} else {
- sp.sp_up = 0;
- sp.sp_down = 0;
+ nsp.sp_up = 0;
+ nsp.sp_down = 0;
}
new_buttons = 0;
@@ -1050,19 +1234,19 @@ pms_synaptics_parse(struct pms_softc *ps
*/
u_char bstate = (psc->packet[0] ^ psc->packet[3])
& 0x01;
- if (sp.sp_y < synaptics_button_boundary) {
- if (sp.sp_x > synaptics_button3) {
- sp.sp_right =
+ if (nsp.sp_y < synaptics_button_boundary) {
+ if (nsp.sp_x > synaptics_button3) {
+ nsp.sp_right =
bstate ? PMS_RBUTMASK : 0;
- } else if (sp.sp_x > synaptics_button2) {
- sp.sp_middle =
+ } else if (nsp.sp_x > synaptics_button2) {
+ nsp.sp_middle =
bstate ? PMS_MBUTMASK : 0;
} else {
- sp.sp_left = bstate ? PMS_LBUTMASK : 0;
+ nsp.sp_left = bstate ? PMS_LBUTMASK : 0;
}
} else
- sp.sp_left = bstate ? 1 : 0;
- new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right;
+ nsp.sp_left = bstate ? 1 : 0;
+ new_buttons = nsp.sp_left | nsp.sp_middle | nsp.sp_right;
if (new_buttons != sc->button_history) {
if (sc->button_history == 0)
sc->button_history = new_buttons;
@@ -1072,47 +1256,47 @@ pms_synaptics_parse(struct pms_softc *ps
* case finger comes off in a different
* region.
*/
- sp.sp_left = 0;
- sp.sp_middle = 0;
- sp.sp_right = 0;
+ nsp.sp_left = 0;
+ nsp.sp_middle = 0;
+ nsp.sp_right = 0;
} else {
/* make sure we keep the same button even
* if the finger moves to a different
* region. This precludes chording
* but, oh well.
*/
- sp.sp_left = sc->button_history & PMS_LBUTMASK;
- sp.sp_middle = sc->button_history
+ nsp.sp_left = sc->button_history & PMS_LBUTMASK;
+ nsp.sp_middle = sc->button_history
& PMS_MBUTMASK;
- sp.sp_right = sc->button_history & PMS_RBUTMASK;
+ nsp.sp_right = sc->button_history & PMS_RBUTMASK;
}
}
} else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
/* Old style Middle Button. */
- sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
+ nsp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
(psc->packet[3] & PMS_LBUTMASK);
} else if (synaptics_up_down_emul != 1) {
- sp.sp_middle = 0;
+ nsp.sp_middle = 0;
}
/* Overlay extended button state */
- sp.sp_left |= sc->ext_left;
- sp.sp_right |= sc->ext_right;
- sp.sp_middle |= sc->ext_middle;
- sp.sp_up |= sc->ext_up;
- sp.sp_down |= sc->ext_down;
+ nsp.sp_left |= sc->ext_left;
+ nsp.sp_right |= sc->ext_right;
+ nsp.sp_middle |= sc->ext_middle;
+ nsp.sp_up |= sc->ext_up;
+ nsp.sp_down |= sc->ext_down;
switch (synaptics_up_down_emul) {
case 1:
/* Do middle button emulation using up/down buttons */
- sp.sp_middle = sp.sp_up | sp.sp_down;
- sp.sp_up = sp.sp_down = 0;
+ nsp.sp_middle = nsp.sp_up | nsp.sp_down;
+ nsp.sp_up = nsp.sp_down = 0;
break;
case 3:
/* Do left/right button emulation using up/down buttons */
- sp.sp_left = sp.sp_left | sp.sp_up;
- sp.sp_right = sp.sp_right | sp.sp_down;
- sp.sp_up = sp.sp_down = 0;
+ nsp.sp_left = nsp.sp_left | nsp.sp_up;
+ nsp.sp_right = nsp.sp_right | nsp.sp_down;
+ nsp.sp_up = nsp.sp_down = 0;
break;
default:
/*
@@ -1123,7 +1307,90 @@ pms_synaptics_parse(struct pms_softc *ps
}
}
- pms_synaptics_process_packet(psc, &sp);
+ /* set the finger count only if we haven't seen an extended-w
+ * finger count status
+ */
+ if (nsp.sp_finger_status == 0)
+ nsp.sp_finger_count = pms_synaptics_get_fingers(psc, nsp.sp_w,
+ nsp.sp_z);
+
+skip_position:
+ DPRINTF(20, sc,
+ "synaptics_parse: sp_x %d sp_y %d sp_z %d, sp_sx %d, sp_sy %d, "
+ "sp_sz %d, sp_w %d sp_finger_count %d, sp_primary %d, "
+ "sp_secondary %d, v %d, primary_finger %d, secondary_finger %d\n",
+ nsp.sp_x, nsp.sp_y, nsp.sp_z, nsp.sp_sx,
+ nsp.sp_sy, nsp.sp_sz, nsp.sp_w, nsp.sp_finger_count,
+ nsp.sp_primary, nsp.sp_secondary, v, primary_finger,
+ secondary_finger);
+
+
+ /* If no fingers and we at least saw the primary finger
+ * or the buttons changed then process the last packet.
+ */
+ if (pms_synaptics_get_fingers(psc, nsp.sp_w, nsp.sp_z) == 0) {
+ if (nsp.sp_primary == 1) {
+ pms_synaptics_process_packet(psc, &nsp);
+ sc->packet_count[SYN_PRIMARY_FINGER] = 0;
+ sc->packet_count[SYN_SECONDARY_FINGER] = 0;
+ }
+
+ /* clear the fingers seen since we have processed */
+ nsp.sp_primary = 0;
+ nsp.sp_secondary = 0;
+ nsp.sp_finger_status = 0;
+ } else if (nsp.sp_finger_count != packet.sp_finger_count) {
+ /*
+ * If the number of fingers changes then send the current packet
+ * for processing and restart the process.
+ */
+ if (packet.sp_primary == 1) {
+ pms_synaptics_process_packet(psc, &packet);
+ sc->packet_count[SYN_PRIMARY_FINGER]++;
+ }
+
+ sc->packet_count[SYN_PRIMARY_FINGER] = 0;
+ sc->packet_count[SYN_SECONDARY_FINGER] = 0;
+ }
+
+ /* Only one finger, process the new packet */
+ if (nsp.sp_finger_count == 1) {
+ if (nsp.sp_finger_count != packet.sp_finger_count) {
+ sc->packet_count[SYN_PRIMARY_FINGER] = 0;
+ sc->packet_count[SYN_SECONDARY_FINGER] = 0;
+ }
+ pms_synaptics_process_packet(psc, &nsp);
+
+ /* clear the fingers seen since we have processed */
+ nsp.sp_primary = 0;
+ nsp.sp_secondary = 0;
+ nsp.sp_finger_status = 0;
+
+ sc->packet_count[SYN_PRIMARY_FINGER]++;
+ }
+
+ /*
+ * More than one finger and we have seen the primary and secondary
+ * fingers then process the packet.
+ */
+ if ((nsp.sp_finger_count > 1) && (nsp.sp_primary == 1)
+ && (nsp.sp_secondary == 1)) {
+ if (nsp.sp_finger_count != packet.sp_finger_count) {
+ sc->packet_count[SYN_PRIMARY_FINGER] = 0;
+ sc->packet_count[SYN_SECONDARY_FINGER] = 0;
+ }
+ pms_synaptics_process_packet(psc, &nsp);
+
+ /* clear the fingers seen since we have processed */
+ nsp.sp_primary = 0;
+ nsp.sp_secondary = 0;
+ nsp.sp_finger_status = 0;
+
+ sc->packet_count[SYN_PRIMARY_FINGER]++;
+ sc->packet_count[SYN_SECONDARY_FINGER]++;
+ }
+
+ memcpy(&packet, &nsp, sizeof(packet));
}
/*
@@ -1302,9 +1569,11 @@ synaptics_finger_detect(struct synaptics
* Detect 2 and 3 fingers if supported, but only if multiple
* fingers appear within the tap gesture time period.
*/
- if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER &&
- SYN_TIME(sc, sc->gesture_start_packet,
- sp->sp_finger) < synaptics_gesture_length) {
+ if ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) &&
+ ((SYN_TIME(sc, sc->gesture_start_packet)
+ < synaptics_gesture_length) ||
+ SYN_TIME(sc, sc->gesture_start_packet)
+ < synaptics_gesture_length)) {
switch (sp->sp_w) {
case SYNAPTICS_WIDTH_TWO_FINGERS:
fingers = 2;
@@ -1334,7 +1603,7 @@ synaptics_gesture_detect(struct synaptic
int gesture_len, gesture_buttons;
int set_buttons;
- gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger);
+ gesture_len = SYN_TIME(sc, sc->gesture_start_packet);
gesture_buttons = sc->gesture_buttons;
if (fingers > 0 && (fingers == sc->prev_fingers)) {
@@ -1359,9 +1628,9 @@ synaptics_gesture_detect(struct synaptic
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[0];
+ sc->gesture_start_packet = sc->total_packets;
- DPRINTF(sc, "Finger applied:"
+ DPRINTF(10, sc, "Finger applied:"
" gesture_start_x: %d"
" gesture_start_y: %d\n",
sc->gesture_start_x, sc->gesture_start_y);
@@ -1376,11 +1645,11 @@ synaptics_gesture_detect(struct synaptic
* of the fingers).
*/
- DPRINTF(sc, "Finger removed: gesture_len: %d (%d)\n",
+ DPRINTF(10, sc, "Finger removed: gesture_len: %d (%d)\n",
gesture_len, synaptics_gesture_length);
- DPRINTF(sc, "gesture_move_x: %d (%d) sp_x: %d\n",
+ DPRINTF(10, sc, "gesture_move_x: %d (%d) sp_x: %d\n",
sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x));
- DPRINTF(sc, "gesture_move_y: %d (%d) sp_y: %d\n",
+ DPRINTF(10, sc, "gesture_move_y: %d (%d) sp_y: %d\n",
sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y));
if (gesture_len < synaptics_gesture_length &&
@@ -1400,7 +1669,7 @@ synaptics_gesture_detect(struct synaptic
* Single tap gesture. Set the tap length timer
* and flag a single-click.
*/
- sc->gesture_tap_packet = sc->total_packets[0];
+ sc->gesture_tap_packet = sc->total_packets;
sc->gesture_type |= SYN_GESTURE_SINGLE;
/*
@@ -1457,11 +1726,17 @@ synaptics_gesture_detect(struct synaptic
* Activate the relevant button(s) until the
* gesture tap timer has expired.
*/
- if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) <
+ if (SYN_TIME(sc, sc->gesture_tap_packet) <
synaptics_gesture_length)
set_buttons = 1;
else
sc->gesture_type &= ~SYN_GESTURE_SINGLE;
+ DPRINTF(10, sc, "synaptics_gesture: single tap, buttons %d\n",
+ set_buttons);
+ DPRINTF(10, sc, "synaptics_gesture: single tap, tap at %d, current %d\n",
+ sc->gesture_tap_packet, sc->total_packets);
+ DPRINTF(10, sc, "synaptics_gesture: single tap, tap_time %d, gesture len %d\n",
+ SYN_TIME(sc, sc->gesture_tap_packet), synaptics_gesture_length);
} else
if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
/*
@@ -1487,11 +1762,9 @@ synaptics_gesture_detect(struct synaptic
static inline int
synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history,
- int value)
+ int value, u_int count)
{
- int a, b, rv, count;
-
- count = sc->total_packets[finger];
+ int a, b, rv;
/*
* Once we've accumulated at least SYN_HIST_SIZE values, combine
@@ -1504,7 +1777,7 @@ synaptics_filter_policy(struct synaptics
* Using a rolling average helps to filter out jitter caused by
* tiny finger movements.
*/
- if (sc->movement_history[finger] >= SYN_HIST_SIZE) {
+ if (count >= SYN_HIST_SIZE) {
a = (history[(count + 0) % SYN_HIST_SIZE] +
history[(count + 1) % SYN_HIST_SIZE]) / 2;
@@ -1596,19 +1869,32 @@ synaptics_scale(int delta, int scale, in
static inline void
synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp,
- int finger, int *dxp, int *dyp, int *dzp)
+ int *dxp, int *dyp, int *dzp, int *sdxp, int *sdyp, int *sdzp)
{
- int dx, dy, dz, edge;
+ int dx, dy, dz, sdx, sdy, sdz, edge;
- dx = dy = dz = 0;
+ dx = dy = dz = sdx = sdy = sdz = 0;
/*
- * Compute the next values of dx and dy and dz.
+ * Compute the next values of dx, dy, dz, sdx, sdy, sdz.
*/
- dx = synaptics_filter_policy(sc, finger, sc->history_x[finger],
- sp->sp_x);
- dy = synaptics_filter_policy(sc, finger, sc->history_y[finger],
- sp->sp_y);
+ dx = synaptics_filter_policy(sc, 0,
+ sc->history_x[SYN_PRIMARY_FINGER], sp->sp_x,
+ sc->packet_count[SYN_PRIMARY_FINGER]);
+ dy = synaptics_filter_policy(sc, 0,
+ sc->history_y[SYN_PRIMARY_FINGER], sp->sp_y,
+ sc->packet_count[SYN_PRIMARY_FINGER]);
+
+ if (sp->sp_finger_count > 1) {
+ sdx = synaptics_filter_policy(sc, 1,
+ sc->history_x[SYN_SECONDARY_FINGER], sp->sp_sx,
+ sc->packet_count[SYN_SECONDARY_FINGER]);
+ sdy = synaptics_filter_policy(sc, 1,
+ sc->history_y[SYN_SECONDARY_FINGER], sp->sp_sy,
+ sc->packet_count[SYN_SECONDARY_FINGER]);
+ DPRINTF(10, sc, "synaptics_movement: dx %d dy %d sdx %d sdy %d\n",
+ dx, dy, sdx, sdy);
+ }
/*
* If we're dealing with a drag gesture, and the finger moves to
@@ -1626,14 +1912,43 @@ synaptics_movement(struct synaptics_soft
dy -= synaptics_edge_motion(sc, dy, 1);
if (edge & SYN_EDGE_TOP)
dy += synaptics_edge_motion(sc, dy, -1);
+
+ if (sp->sp_finger_count > 1) {
+ edge = synaptics_check_edge(sp->sp_sx, sp->sp_sy);
+
+ if (edge & SYN_EDGE_LEFT)
+ sdx -= synaptics_edge_motion(sc, sdx, 1);
+ if (edge & SYN_EDGE_RIGHT)
+ sdx += synaptics_edge_motion(sc, sdx, -1);
+ if (edge & SYN_EDGE_BOTTOM)
+ sdy -= synaptics_edge_motion(sc, sdy, 1);
+ if (edge & SYN_EDGE_TOP)
+ sdy += synaptics_edge_motion(sc, sdy, -1);
+ }
}
/*
* Apply scaling to the deltas
*/
- dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x[finger]);
- dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y[finger]);
- dz = synaptics_scale(dz, synaptics_scale_z, &sc->rem_z[finger]);
+ dx = synaptics_scale(dx, synaptics_scale_x,
+ &sc->rem_x[SYN_PRIMARY_FINGER]);
+ dy = synaptics_scale(dy, synaptics_scale_y,
+ &sc->rem_y[SYN_PRIMARY_FINGER]);
+ dz = synaptics_scale(dz, synaptics_scale_z,
+ &sc->rem_z[SYN_PRIMARY_FINGER]);
+
+ if (sp->sp_finger_count > 1) {
+ sdx = synaptics_scale(sdx, synaptics_scale_x,
+ &sc->rem_x[SYN_SECONDARY_FINGER]);
+ sdy = synaptics_scale(sdy, synaptics_scale_y,
+ &sc->rem_y[SYN_SECONDARY_FINGER]);
+ sdz = synaptics_scale(sdz, synaptics_scale_z,
+ &sc->rem_z[SYN_SECONDARY_FINGER]);
+
+ DPRINTF(10, sc,
+ "synaptics_movement 2: dx %d dy %d sdx %d sdy %d\n",
+ dx, dy, sdx, sdy);
+ }
/*
* Clamp deltas to specified maximums.
@@ -1645,21 +1960,34 @@ synaptics_movement(struct synaptics_soft
if (abs(dz) > synaptics_max_speed_z)
dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z;
+ if (sp->sp_finger_count > 1) {
+ if (abs(sdx) > synaptics_max_speed_x)
+ sdx = ((sdx >= 0)? 1 : -1) * synaptics_max_speed_x;
+ if (abs(dy) > synaptics_max_speed_y)
+ sdy = ((sdy >= 0)? 1 : -1) * synaptics_max_speed_y;
+ if (abs(sdz) > synaptics_max_speed_z)
+ sdz = ((sdz >= 0)? 1 : -1) * synaptics_max_speed_z;
+ }
+
*dxp = dx;
*dyp = dy;
*dzp = dz;
+ *sdxp = sdx;
+ *sdyp = sdy;
+ *sdzp = sdz;
- sc->movement_history[finger]++;
}
static void
pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp)
{
struct synaptics_softc *sc = &psc->u.synaptics;
- int dx, dy, dz;
+ int dx, dy, dz, sdx, sdy, sdz;
int fingers, palm, buttons, changed;
int s;
+ sdx = sdy = sdz = 0;
+
/*
* Do Z-axis emulation using up/down buttons if required.
* Note that the pad will send a one second burst of packets
@@ -1691,10 +2019,9 @@ pms_synaptics_process_packet(struct pms_
fingers = synaptics_finger_detect(sc, sp, &palm);
/*
- * Do gesture processing only if we didn't detect a palm and
- * it is not the seondary finger.
+ * Do gesture processing only if we didn't detect a palm.
*/
- if ((sp->sp_finger == 0) && (palm == 0))
+ if (palm == 0)
synaptics_gesture_detect(sc, sp, fingers);
else
sc->gesture_type = sc->gesture_buttons = 0;
@@ -1711,46 +2038,85 @@ pms_synaptics_process_packet(struct pms_
psc->buttons ^= changed;
sc->prev_fingers = fingers;
- sc->total_packets[sp->sp_finger]++;
/*
* Do movement processing IFF we have a single finger and no palm or
* a secondary finger and no palm.
*/
if (palm == 0 && synaptics_movement_enable) {
- if (fingers == 1) {
+ if (fingers > 0) {
+ synaptics_movement(sc, sp, &dx, &dy, &dz, &sdx, &sdy,
+ &sdz);
+
/*
- * Single finger - normal movement.
+ * Check if there are two fingers, if there are then
+ * check if we have a clickpad, if we do then we
+ * don't scroll iff one of the fingers is in the
+ * button region. Otherwise interpret as a scroll
*/
- synaptics_movement(sc, sp, sp->sp_finger,
- &dx, &dy, &dz);
- } else if (fingers == 2 && sc->gesture_type == 0) {
+ if (sp->sp_finger_count >= 2 && sc->gesture_type == 0 ) {
+ if (!(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) ||
+ ((sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) &&
+ (sp->sp_y > synaptics_button_boundary) &&
+ (sp->sp_sy > synaptics_button_boundary))) {
+ s = spltty();
+ wsmouse_precision_scroll(
+ psc->sc_wsmousedev, dx, dy);
+ splx(s);
+ return;
+ }
+ }
+
/*
- * Multiple finger movement. Interpret it as scrolling.
+ * Allow user to turn off movements in the button
+ * region of a click pad.
*/
- synaptics_movement(sc, sp, sp->sp_finger,
- &dx, &dy, &dz);
- s = spltty();
- wsmouse_precision_scroll(psc->sc_wsmousedev, dx, dy);
- splx(s);
- return;
+ if (sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
+ if ((sp->sp_y < synaptics_button_boundary) &&
+ (!synaptics_button_region_movement)) {
+ dx = dy = dz = 0;
+ }
+
+ if ((sp->sp_sy < synaptics_button_boundary) &&
+ (!synaptics_button_region_movement)) {
+ sdx = sdy = sdz = 0;
+ }
+ }
+
+ /* Now work out which finger to report, just
+ * go with the one that has moved the most.
+ */
+ if ((abs(dx) + abs(dy) + abs(dz)) <
+ (abs(sdx) + abs(sdy) + abs(sdz))) {
+ /* secondary finger wins */
+ dx = sdx;
+ dy = sdy;
+ dz = sdz;
+ }
} else {
/*
* No valid finger. Therefore no movement.
*/
- sc->movement_history[sp->sp_finger] = 0;
- sc->rem_x[sp->sp_finger] = sc->rem_y[sp->sp_finger] = 0;
+ sc->rem_x[SYN_PRIMARY_FINGER] = 0;
+ sc->rem_y[SYN_PRIMARY_FINGER] = 0;
+ sc->rem_x[SYN_SECONDARY_FINGER] = 0;
+ sc->rem_y[SYN_SECONDARY_FINGER] = 0;
dx = dy = 0;
}
} else {
/*
* No valid finger. Therefore no movement.
*/
- sc->movement_history[0] = 0;
- sc->rem_x[0] = sc->rem_y[0] = sc->rem_z[0] = 0;
+ sc->rem_x[SYN_PRIMARY_FINGER] = 0;
+ sc->rem_y[SYN_PRIMARY_FINGER] = 0;
+ sc->rem_z[SYN_PRIMARY_FINGER] = 0;
dx = dy = dz = 0;
}
+ DPRINTF(10, sc,
+ "pms_synaptics_process_packet: dx %d dy %d dz %d sdx %d sdy %d sdz %d\n",
+ dx, dy, dz, sdx, sdy, sdz);
+
/*
* Pass the final results up to wsmouse_input() if necessary.
*/
Index: src/sys/dev/pckbport/synapticsvar.h
diff -u src/sys/dev/pckbport/synapticsvar.h:1.11 src/sys/dev/pckbport/synapticsvar.h:1.12
--- src/sys/dev/pckbport/synapticsvar.h:1.11 Wed Jun 30 22:13:27 2021
+++ src/sys/dev/pckbport/synapticsvar.h Thu Oct 21 04:49:28 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: synapticsvar.h,v 1.11 2021/06/30 22:13:27 blymn Exp $ */
+/* $NetBSD: synapticsvar.h,v 1.12 2021/10/21 04:49:28 blymn Exp $ */
/*
* Copyright (c) 2005, Steve C. Woodford
@@ -39,6 +39,8 @@
#define _DEV_PCKBCPORT_SYNAPTICSVAR_H_
#define SYN_MAX_FINGERS 2
+#define SYN_PRIMARY_FINGER 0
+#define SYN_SECONDARY_FINGER 1
struct synaptics_softc {
int caps;
@@ -59,11 +61,14 @@ struct synaptics_softc {
#define SYN_FLAG_HAS_ADV_GESTURE_MODE (1 << 12)
/* Total number of packets received */
- u_int total_packets[SYN_MAX_FINGERS];
+ u_int total_packets;
-#define SYN_TIME(sc,c,n) (((sc)->total_packets[(n)] >= (c)) ? \
- ((sc)->total_packets[(n)] - (c)) : \
- ((c) - (sc)->total_packets[(n)]))
+ /* Keep a per finger count for ballistics */
+ u_int packet_count[SYN_MAX_FINGERS];
+
+#define SYN_TIME(sc,c) (((sc)->total_packets >= (c)) ? \
+ ((sc)->total_packets - (c)) : \
+ ((c) - (sc)->total_packets))
int up_down;
int prev_fingers;
@@ -88,7 +93,6 @@ struct synaptics_softc {
int rem_x[SYN_MAX_FINGERS];
int rem_y[SYN_MAX_FINGERS];
int rem_z[SYN_MAX_FINGERS];
- u_int movement_history[SYN_MAX_FINGERS];
int history_x[SYN_MAX_FINGERS][SYN_HIST_SIZE];
int history_y[SYN_MAX_FINGERS][SYN_HIST_SIZE];
int history_z[SYN_MAX_FINGERS][SYN_HIST_SIZE];