Module Name:    src
Committed By:   blymn
Date:           Fri Apr  1 06:31:30 UTC 2022

Modified Files:
        src/sys/dev/pckbport: synaptics.c synapticsvar.h

Log Message:
Fix regression introduced when fixing PR kern/56613 and related tweaks

* A trackpad with external buttons needs to mask a number of lower bits
  of the X and Y coordinates IFF a button is down.  This was not being
  done so a button held down looked like an out of range packet and
  was therefore dropped.

* Now that trackpads are probed for their boundaries make the emulated
  button boundary settable by a percentage, also allow the right and
  bottom boundaries to be adjusted by a percentage to allow for
  horizontal and vertical scroll regions.


To generate a diff of this commit:
cvs rdiff -u -r1.76 -r1.77 src/sys/dev/pckbport/synaptics.c
cvs rdiff -u -r1.13 -r1.14 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.76 src/sys/dev/pckbport/synaptics.c:1.77
--- src/sys/dev/pckbport/synaptics.c:1.76	Thu Mar  3 21:03:14 2022
+++ src/sys/dev/pckbport/synaptics.c	Fri Apr  1 06:31:29 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: synaptics.c,v 1.76 2022/03/03 21:03:14 blymn Exp $	*/
+/*	$NetBSD: synaptics.c,v 1.77 2022/04/01 06:31:29 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.76 2022/03/03 21:03:14 blymn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.77 2022/04/01 06:31:29 blymn Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -112,9 +112,12 @@ static int synaptics_edge_bottom = SYNAP
 static int synaptics_edge_motion_delta = 32;
 static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5;
 static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10;
-static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720;
-static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
-static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
+static int synaptics_horiz_pct = 0;
+static int synaptics_vert_pct = 0;
+static int synaptics_button_pct = 30;
+static int synaptics_button_boundary;
+static int synaptics_button2;
+static int synaptics_button3;
 static int synaptics_two_fingers_emul = 0;
 static int synaptics_scale_x = 16;
 static int synaptics_scale_y = 16;
@@ -163,6 +166,23 @@ static int synaptics_movement_threshold_
 static int synaptics_movement_enable_nodenum;
 static int synaptics_button_region_movement_nodenum;
 static int synaptics_aux_mid_button_scroll_nodenum;
+static int synaptics_horiz_pct_nodenum;
+static int synaptics_vert_pct_nodenum;
+static int synaptics_button_pct_nodenum;
+
+/*
+ * copy of edges so we can recalculate edge limit if there is 
+ * vertical scroll region
+ */
+static int synaptics_actual_edge_right;
+static int synaptics_actual_edge_bottom;
+
+static int synaptics_old_vert_pct = 0;
+static int synaptics_old_horiz_pct = 0;
+static int synaptics_old_button_pct = 0;
+static int synaptics_old_button_boundary = SYNAPTICS_EDGE_BOTTOM;
+static int synaptics_old_horiz_edge = SYNAPTICS_EDGE_BOTTOM;
+static int synaptics_old_vert_edge = SYNAPTICS_EDGE_RIGHT;
 
 /*
  * This holds the processed packet data, it is global because multiple
@@ -232,6 +252,84 @@ synaptics_special_write(struct pms_softc
 }
 
 static void
+pms_synaptics_set_boundaries(void)
+{
+	if (synaptics_vert_pct != synaptics_old_vert_pct ) {
+		synaptics_edge_right -= ((unsigned long) synaptics_vert_pct *
+		    (synaptics_actual_edge_right - synaptics_edge_left)) / 100;
+		synaptics_old_vert_pct = synaptics_vert_pct;
+		synaptics_old_vert_edge = synaptics_edge_right;
+	}
+
+	if (synaptics_edge_right != synaptics_old_vert_edge) {
+		if (synaptics_edge_right >= synaptics_actual_edge_right) {
+			synaptics_vert_pct = 0;
+			synaptics_edge_right = synaptics_actual_edge_right;
+		} else {
+			synaptics_vert_pct = 100 -
+			    ((unsigned long) 100 * synaptics_edge_right) /
+			    (synaptics_actual_edge_right - synaptics_edge_left);
+		}
+		synaptics_old_vert_edge = synaptics_edge_right;
+	}
+
+	if (synaptics_horiz_pct != synaptics_old_horiz_pct ) {
+		synaptics_edge_bottom = synaptics_actual_edge_bottom +
+		    ((unsigned long) synaptics_horiz_pct *
+		    (synaptics_edge_top - synaptics_actual_edge_bottom)) / 100;
+		synaptics_old_horiz_pct = synaptics_horiz_pct;
+		synaptics_old_horiz_edge = synaptics_edge_bottom;
+	}
+
+	if (synaptics_edge_bottom != synaptics_old_horiz_edge) {
+		if (synaptics_edge_bottom <= synaptics_actual_edge_bottom) {
+			synaptics_vert_pct = 0;
+			synaptics_edge_bottom = synaptics_actual_edge_bottom;
+		} else {
+			synaptics_horiz_pct = 100 -
+			    ((unsigned long) 100 * synaptics_edge_bottom) /
+			    (synaptics_edge_top - synaptics_actual_edge_bottom);
+		}
+		synaptics_old_horiz_edge = synaptics_edge_bottom;
+	}
+
+	if (synaptics_button_pct != synaptics_old_button_pct) {
+		synaptics_button_boundary = synaptics_edge_bottom + 
+		    ((unsigned long) synaptics_button_pct * 
+		    (synaptics_edge_top - synaptics_edge_bottom)) / 100;
+		synaptics_old_button_pct = synaptics_button_pct;
+		synaptics_old_button_boundary = synaptics_button_boundary;
+	}
+
+	if (synaptics_button_boundary != synaptics_old_button_boundary) {
+		if (synaptics_button_boundary <= synaptics_edge_bottom) {
+			synaptics_button_pct = 0;
+			synaptics_button_boundary = synaptics_edge_bottom;
+		} else {
+			synaptics_button_pct = 100 -
+			    ((unsigned long) 100 * synaptics_button_boundary) /
+			    (synaptics_edge_top - synaptics_edge_bottom);
+		}
+		synaptics_old_button_boundary = synaptics_button_boundary;
+	}
+
+	/*
+	 * recalculate the button boundary yet again just in case the
+	 * bottom edge changed above.
+	 */
+	synaptics_button_boundary = synaptics_edge_bottom + 
+	    ((unsigned long) synaptics_button_pct * 
+	    (synaptics_edge_top - synaptics_edge_bottom)) / 100;
+	synaptics_old_button_boundary = synaptics_button_boundary;
+
+	synaptics_button2 = synaptics_edge_left +
+	    (synaptics_edge_right - synaptics_edge_left) / 3;
+	synaptics_button3 = synaptics_edge_left +
+	    2 * (synaptics_edge_right - synaptics_edge_left) / 3;
+
+}
+
+static void
 pms_synaptics_probe_extended(struct pms_softc *psc)
 {
 	struct synaptics_softc *sc = &psc->u.synaptics;
@@ -258,14 +356,19 @@ pms_synaptics_probe_extended(struct pms_
 	{
 		res = synaptics_special_read(psc, SYNAPTICS_EXTENDED_QUERY, resp);
 		if (res == 0) {
-			int buttons = (resp[1] >> 4);
+			sc->num_buttons = (resp[1] >> 4);
+			if (sc->num_buttons > 0)
+				sc->button_mask = sc->button_mask <<
+				    ((sc->num_buttons + 1) >> 1);
+
 			aprint_debug_dev(psc->sc_dev,
-			    "%s: Extended Buttons: %d.\n", __func__, buttons);
+			    "%s: Extended Buttons: %d.\n", __func__,
+			    sc->num_buttons);
 
 			aprint_debug_dev(psc->sc_dev, "%s: Extended "
 			    "Capabilities: 0x%02x 0x%02x 0x%02x.\n", __func__,
 			    resp[0], resp[1], resp[2]);
-			if (buttons >= 2) {
+			if (sc->num_buttons >= 2) {
 				/* Yes. */
 				sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
 			}
@@ -405,6 +508,10 @@ pms_synaptics_probe_init(void *vsc)
 	}
 
 	sc->flags = 0;
+	sc->num_buttons = 0;
+	sc->button_mask = 0xff;
+
+	pms_synaptics_set_boundaries();
 
 	/* Check for minimum version and print a nice message. */
 	ver_major = resp[2] & 0x0f;
@@ -464,6 +571,16 @@ pms_synaptics_probe_init(void *vsc)
 			synaptics_edge_top = (resp[2] << 5) + 
 			    ((resp[1] & 0xf0) >> 3);
 
+			synaptics_actual_edge_right = synaptics_edge_right;
+
+			/*
+			 * If we have vertical scroll then steal 10%
+			 * for that region.
+			 */
+			if (sc->flags & SYN_FLAG_HAS_VERTICAL_SCROLL)
+				synaptics_edge_right -=
+				    synaptics_edge_right / 10;
+
 			aprint_normal_dev(psc->sc_dev,
 			    "Probed max coordinates right: %d, top: %d\n",
 			    synaptics_edge_right, synaptics_edge_top);
@@ -482,12 +599,23 @@ pms_synaptics_probe_init(void *vsc)
 			synaptics_edge_bottom = (resp[2] << 5) + 
 			    ((resp[1] & 0xf0) >> 3);
 
+			synaptics_actual_edge_bottom = synaptics_edge_bottom;
+
+			/*
+			 * If we have horizontal scroll then steal 10%
+			 * for that region.
+			 */
+			if (sc->flags & SYN_FLAG_HAS_HORIZONTAL_SCROLL)
+				synaptics_horiz_pct = 10;
+
 			aprint_normal_dev(psc->sc_dev,
 			    "Probed min coordinates left: %d, bottom: %d\n",
 			    synaptics_edge_left, synaptics_edge_bottom);
 		}
 	}
 
+	pms_synaptics_set_boundaries();
+
 done:
 	pms_sysctl_synaptics(&clog);
 	pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
@@ -889,6 +1017,42 @@ pms_sysctl_synaptics(struct sysctllog **
 
 	if ((rc = sysctl_createv(clog, 0, NULL, &node,
 	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "vert_scroll_percent",
+	    SYSCTL_DESCR("Percent of trackpad width to reserve for vertical scroll region"),
+	    pms_sysctl_synaptics_verify, 0,
+	    &synaptics_vert_pct,
+	    0, CTL_HW, root_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		goto err;
+
+	synaptics_vert_pct_nodenum = node->sysctl_num;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "horizontal_scroll_percent",
+	    SYSCTL_DESCR("Percent of trackpad height to reserve for scroll region"),
+	    pms_sysctl_synaptics_verify, 0,
+	    &synaptics_horiz_pct,
+	    0, CTL_HW, root_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		goto err;
+
+	synaptics_horiz_pct_nodenum = node->sysctl_num;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "button_region_percent",
+	    SYSCTL_DESCR("Percent of trackpad height to reserve for button region"),
+	    pms_sysctl_synaptics_verify, 0,
+	    &synaptics_button_pct,
+	    0, CTL_HW, root_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		goto err;
+
+	synaptics_button_pct_nodenum = node->sysctl_num;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
 	    CTLTYPE_INT, "debug",
 	    SYSCTL_DESCR("Enable debug output"),
 	    NULL, 0,
@@ -966,13 +1130,13 @@ pms_sysctl_synaptics_verify(SYSCTLFN_ARG
 			return (EINVAL);
 	} else
 	if (node.sysctl_num == synaptics_button_boundary_nodenum) {
-		if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM ||
-		    t > SYNAPTICS_EDGE_TOP)
+		if (t < 0 || t < synaptics_edge_bottom ||
+		    t > synaptics_edge_top)
 			return (EINVAL);
 	} else
 	if (node.sysctl_num == synaptics_button2_nodenum ||
 	    node.sysctl_num == synaptics_button3_nodenum) {
-		if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT)
+		if (t < synaptics_edge_left || t > synaptics_edge_right)
 			return (EINVAL);
 	} else
 	if (node.sysctl_num == synaptics_movement_enable_nodenum) {
@@ -987,10 +1151,24 @@ pms_sysctl_synaptics_verify(SYSCTLFN_ARG
 		if (t < 0 || t > 1)
 			return (EINVAL);
 	} else
+	if (node.sysctl_num == synaptics_vert_pct_nodenum) {
+		if (t < 0 || t > 100)
+			return (EINVAL);
+	} else
+	if (node.sysctl_num == synaptics_horiz_pct_nodenum) {
+		if (t < 0 || t > 100)
+			return (EINVAL);
+	} else
+	if (node.sysctl_num == synaptics_button_pct_nodenum) {
+		if (t < 0 || t > 100)
+			return (EINVAL);
+	} else
 		return (EINVAL);
 
 	*(int *)rnode->sysctl_data = t;
 
+	pms_synaptics_set_boundaries();
+
 	return (0);
 }
 
@@ -1074,6 +1252,7 @@ pms_synaptics_parse(struct pms_softc *ps
 	struct synaptics_softc *sc = &psc->u.synaptics;
 	struct synaptics_packet nsp;
 	char new_buttons, ew_mode;
+	uint8_t btn_mask, packet4, packet5;
 	unsigned v, primary_finger, secondary_finger;
 	int ext_left = -1, ext_right = -1, ext_middle = -1,
 	    ext_up = -1, ext_down = -1;
@@ -1170,6 +1349,25 @@ pms_synaptics_parse(struct pms_softc *ps
 		nsp.sp_primary = 1;
 
 		/*
+		 * If the trackpad has external buttons and one of
+		 * those buttons is pressed then the lower bits of
+		 * x and y are "stolen" for button status. We can tell
+		 * this has happened by doing an xor of the two right
+		 * button status bits residing in byte 0 and 3, if the
+		 * result is non-zero then there is an external button
+		 * report and the position bytes need to be masked.
+		 */
+		btn_mask = 0xff;
+		if ((sc->num_buttons > 0) &&
+		    ((psc->packet[0] & PMS_RBUTMASK) ^
+		     (psc->packet[3] & PMS_RBUTMASK))) {
+			btn_mask = sc->button_mask;
+		}
+
+		packet4 = psc->packet[4] & btn_mask;
+		packet5 = psc->packet[5] & btn_mask;
+
+		/*
 		 * 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.
@@ -1178,20 +1376,22 @@ pms_synaptics_parse(struct pms_softc *ps
 		 * 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 ((sc->flags & SYN_FLAG_HAS_MULTI_FINGER) &&
+		    ((nsp.sp_w == SYNAPTICS_WIDTH_TWO_FINGERS) ||
+		     (nsp.sp_w == SYNAPTICS_WIDTH_THREE_OR_MORE))) {
 			/*
 			 * 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) +
+			nsp.sp_x = (packet4 & 0xfc) +
+				((packet4 & 0x02) << 1) +
 				((psc->packet[1] & 0x0f) << 8) +
 				((psc->packet[3] & 0x10) << 8);
 
-			nsp.sp_y = (psc->packet[5] & 0xfc) +
-				((psc->packet[5] & 0x02) << 1) +
+			nsp.sp_y = (packet5 & 0xfc) +
+				((packet5 & 0x02) << 1) +
 				((psc->packet[1] & 0xf0) << 4) +
 				((psc->packet[3] & 0x20) << 7);
 
@@ -1199,17 +1399,17 @@ pms_synaptics_parse(struct pms_softc *ps
 			nsp.sp_z = psc->packet[2] & 0xfe;
 
 			/* derive the virtual finger width */
-			v = 8 + ((psc->packet[4] & 0x02) >> 1) +
-				(psc->packet[5] & 0x02) +
+			v = 8 + ((packet4 & 0x02) >> 1) +
+				(packet5 & 0x02) +
 				((psc->packet[2] & 0x01) << 2);
 
 		} else {
 			/* Absolute X/Y coordinates of finger */
-			nsp.sp_x = psc->packet[4] +
+			nsp.sp_x = packet4 +
 				((psc->packet[1] & 0x0f) << 8) +
 				((psc->packet[3] & 0x10) << 8);
 
-			nsp.sp_y = psc->packet[5] +
+			nsp.sp_y = packet5 +
 				((psc->packet[1] & 0xf0) << 4) +
 				((psc->packet[3] & 0x20) << 7);
 

Index: src/sys/dev/pckbport/synapticsvar.h
diff -u src/sys/dev/pckbport/synapticsvar.h:1.13 src/sys/dev/pckbport/synapticsvar.h:1.14
--- src/sys/dev/pckbport/synapticsvar.h:1.13	Thu Mar  3 21:03:14 2022
+++ src/sys/dev/pckbport/synapticsvar.h	Fri Apr  1 06:31:29 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: synapticsvar.h,v 1.13 2022/03/03 21:03:14 blymn Exp $	*/
+/*	$NetBSD: synapticsvar.h,v 1.14 2022/04/01 06:31:29 blymn Exp $	*/
 
 /*
  * Copyright (c) 2005, Steve C. Woodford
@@ -72,6 +72,8 @@ struct synaptics_softc {
 			    ((sc)->total_packets - (c)) : \
 			     ((c) - (sc)->total_packets))
 
+	int	num_buttons;  /* number of external buttons */
+	uint8_t	button_mask;
 	int	up_down;
 	int	prev_fingers;
 

Reply via email to