Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 08 Apr 2015 00:19:45 -0700
From:      Rui Paulo <rpaulo@me.com>
To:        FreeBSD-Current <freebsd-current@freebsd.org>
Subject:   Call For Testers: Synaptics touchpads
Message-ID:  <1849381.HnoQVUIgNM@akita>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--nextPart1851775.HIa3oEWMf4
Content-Transfer-Encoding: 7Bit
Content-Type: text/plain; charset="us-ascii"

Hi,

The attached patch adds support for newer touchpad features and implements two 
finger scrolling.  This is such a common feature these days that I think we 
should enable it by default and disable edge scrolling.  I've implemented some 
detection code to keep edge scrolling enabled when the touchpad has a 
dedicated area for scrolling.

Please test it and report back your experience.  To enable synaptics support, 
you need:

hw.psm.synaptics_support=1

in loader.conf.

Thanks,
-- 
Rui Paulo
--nextPart1851775.HIa3oEWMf4
Content-Disposition: attachment; filename="synaptics-update.diff"
Content-Transfer-Encoding: 7Bit
Content-Type: text/x-patch; charset="UTF-8"; name="synaptics-update.diff"

commit 20e2f66c4b38429853ef98689d359451be087de3 (HEAD, master)
Author: Rui Paulo <rpaulo@felyko.com>
Date:   Sun Apr 5 20:51:35 2015

    Improve Synaptics support for newer touchpads.
    
    Enable two finger scrolling by default and disable the edge scrolling if
    the touchpad has no physical zone for it.  Disable directional scrolling
    by default to avoid using extended buttons as scroll buttons.
    
    Add support for ClickPad.  On Lenovo laptops, this is the button
    reported when one presses the touchpad.
    
    While there, fix a problem where the extended button where not reporting
    the button release event correctly: we need to save the state of the
    buttons and report it to sysmouse until we receive a packet from the
    touchpad indicating the button has been released.  This makes it
    possible to use an extended button to resize a window.  On Lenovo
    laptops, the major buttons are actually reported as extended buttons.
    
    Tested on a Lenovo X1 (3rd gen).

diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c
index 5703daf..3c3a27c 100644
--- a/sys/dev/atkbdc/psm.c
+++ b/sys/dev/atkbdc/psm.c
@@ -198,6 +198,7 @@ typedef struct synapticsinfo {
 	struct sysctl_ctx_list	 sysctl_ctx;
 	struct sysctl_oid	*sysctl_tree;
 	int			 directional_scrolls;
+	int			 two_finger_scroll;
 	int			 min_pressure;
 	int			 max_pressure;
 	int			 max_width;
@@ -336,6 +337,7 @@ struct psm_softc {		/* Driver status information */
 	int		lasterr;
 	int		cmdcount;
 	struct sigio	*async;		/* Processes waiting for SIGIO */
+	int		extended_buttons;
 };
 static devclass_t psm_devclass;
 
@@ -2752,7 +2754,15 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
 				if (pb->ipacket[5] & 0x02)
 					touchpad_buttons |= MOUSE_BUTTON7DOWN;
 			} else {
-				touchpad_buttons |= MOUSE_BUTTON2DOWN;
+				if (pb->ipacket[4] & 0x01)
+					touchpad_buttons |= MOUSE_BUTTON1DOWN;
+				if (pb->ipacket[5] & 0x01)
+					touchpad_buttons |= MOUSE_BUTTON3DOWN;
+				if (pb->ipacket[4] & 0x02)
+					touchpad_buttons |= MOUSE_BUTTON2DOWN;
+				if (pb->ipacket[5] & 0x02)
+					touchpad_buttons |= MOUSE_BUTTON4DOWN;
+				sc->extended_buttons = touchpad_buttons;
 			}
 
 			/*
@@ -2774,13 +2784,25 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
 			mask = (1 << maskedbits) - 1;
 			pb->ipacket[4] &= ~(mask);
 			pb->ipacket[5] &= ~(mask);
+		} else	if (!sc->syninfo.directional_scrolls) {
+			/*
+			 * Keep reporting MOUSE DOWN until we get a new packet
+			 * indicating otherwise.
+			 */
+			touchpad_buttons |= sc->extended_buttons;
 		}
 	}
+	/* Handle ClickPad. */
+	if (sc->synhw.capClickPad &&
+	    ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01))
+		touchpad_buttons |= MOUSE_BUTTON1DOWN;
 
 	ms->button = touchpad_buttons | guest_buttons;
 
-	/* Check pressure to detect a real wanted action on the
-	 * touchpad. */
+	/*
+	 * Check pressure to detect a real wanted action on the
+	 * touchpad.
+	 */
 	if (*z >= sc->syninfo.min_pressure) {
 		synapticsaction_t *synaction;
 		int cursor, peer, window;
@@ -2793,7 +2815,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
 		int weight_current, weight_previous, weight_len_squared;
 		int div_min, div_max, div_len;
 		int vscroll_hor_area, vscroll_ver_area;
-
+		int two_finger_scroll;
 		int len, weight_prev_x, weight_prev_y;
 		int div_max_x, div_max_y, div_x, div_y;
 
@@ -2820,6 +2842,7 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
 		div_len = sc->syninfo.div_len;
 		vscroll_hor_area = sc->syninfo.vscroll_hor_area;
 		vscroll_ver_area = sc->syninfo.vscroll_ver_area;
+		two_finger_scroll = sc->syninfo.two_finger_scroll;
 
 		/* Palm detection. */
 		if (!(
@@ -2980,23 +3003,35 @@ proc_synaptics(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *ms,
 			    dxp >= sc->syninfo.vscroll_min_delta ||
 			    dyp >= sc->syninfo.vscroll_min_delta) {
 				/* Check for horizontal scrolling. */
-				if ((vscroll_hor_area > 0 &&
+				if (!two_finger_scroll &&
+				    ((vscroll_hor_area > 0 &&
 				    synaction->start_y <= vscroll_hor_area) ||
 				    (vscroll_hor_area < 0 &&
 				     synaction->start_y >=
-				     6143 + vscroll_hor_area))
+				     6143 + vscroll_hor_area)))
 					synaction->in_vscroll += 2;
 
 				/* Check for vertical scrolling. */
-				if ((vscroll_ver_area > 0 &&
+				if (!two_finger_scroll &&
+				    ((vscroll_ver_area > 0 &&
 				    synaction->start_x <= vscroll_ver_area) ||
 				    (vscroll_ver_area < 0 &&
 				     synaction->start_x >=
-				     6143 + vscroll_ver_area))
+				     6143 + vscroll_ver_area)))
 					synaction->in_vscroll += 1;
 
+				/*
+				 * Handle two finger scrolling.
+				 */
+				if (w == 0 && two_finger_scroll) {
+					if (dyp)
+						synaction->in_vscroll += 2;
+					if (dxp)
+						synaction->in_vscroll += 1;
+				}
+
 				/* Avoid conflicts if area overlaps. */
-				if (synaction->in_vscroll == 3)
+				if (synaction->in_vscroll >= 3)
 					synaction->in_vscroll =
 					    (dxp > dyp) ? 2 : 1;
 			}
@@ -3247,6 +3282,7 @@ SYNAPTICS_END:
 	 * That's why the horizontal wheel is disabled by
 	 * default for now.
 	 */
+
 	if (ms->button & MOUSE_BUTTON4DOWN) {
 		*z = -1;
 		ms->button &= ~MOUSE_BUTTON4DOWN;
@@ -3460,7 +3496,7 @@ psmsoftintr(void *arg)
 			c = ((x < 0) ? MOUSE_PS2_XNEG : 0) |
 			    ((y < 0) ? MOUSE_PS2_YNEG : 0);
 			break;
-	
+
 		case MOUSE_MODEL_4D:
 			/*
 			 *          b7 b6 b5 b4 b3 b2 b1 b0
@@ -4108,13 +4144,21 @@ synaptics_sysctl_create_tree(struct psm_softc *sc)
 	    0, "Synaptics TouchPad");
 
 	/* hw.psm.synaptics.directional_scrolls. */
-	sc->syninfo.directional_scrolls = 1;
+	sc->syninfo.directional_scrolls = 0;
 	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
 	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
 	    "directional_scrolls", CTLFLAG_RW|CTLFLAG_ANYBODY,
 	    &sc->syninfo.directional_scrolls, 0,
 	    "Enable hardware scrolling pad (if non-zero) or register it as "
-	    "a middle-click (if 0)");
+	    "extended buttons (if 0)");
+
+	/* hw.psm.synaptics.two_finger_scroll. */
+	sc->syninfo.two_finger_scroll = 1;
+	SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), OID_AUTO,
+	    "two_finger_scroll", CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    &sc->syninfo.two_finger_scroll, 0,
+	    "Enable two finger scrolling");
 
 	/* hw.psm.synaptics.min_pressure. */
 	sc->syninfo.min_pressure = 16;
@@ -4519,7 +4563,27 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
 				return (FALSE);
 			if (get_mouse_status(kbdc, status, 0, 3) != 3)
 				return (FALSE);
+			synhw.verticalScroll   = (status[0] & 0x01) != 0;
+			synhw.horizontalScroll = (status[0] & 0x02) != 0;
+			synhw.verticalWheel    = (status[0] & 0x08) != 0;
 			synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
+			if (verbose >= 2) {
+				printf("  Extended model ID:\n");
+				printf("   verticalScroll: %d\n",
+				    synhw.verticalScroll);
+				printf("   horizontalScroll: %d\n",
+				    synhw.horizontalScroll);
+				printf("   verticalWheel: %d\n",
+				    synhw.verticalWheel);
+				printf("   nExtendedButtons: %d\n",
+				    synhw.nExtendedButtons);
+			}
+			/*
+			 * Turn off two finger scroll if we have a
+			 * physical area reserved for scrolling.
+			 */
+			if (synhw.verticalScroll)
+				sc->syninfo.two_finger_scroll = 0;
 			/*
 			 * Add the number of extended buttons to the total
 			 * button support count, including the middle button
@@ -4540,6 +4604,42 @@ enable_synaptics(KBDC kbdc, struct psm_softc *sc)
 			printf("  No extended capabilities\n");
 	}
 
+	/* Read the continued capabilities bits. */
+	if (mouse_ext_command(kbdc, 0xc) != 0 &&
+	    get_mouse_status(kbdc, status, 0, 3) == 3) {
+		synhw.capClickPad         = (status[1] & 0x01) << 1;
+		synhw.capClickPad        |= (status[0] & 0x10) != 0;
+		synhw.capDeluxeLEDs       = (status[1] & 0x02) != 0;
+		synhw.noAbsoluteFilter    = (status[1] & 0x04) != 0;
+		synhw.capReportsV         = (status[1] & 0x08) != 0;
+		synhw.capUniformClickPad  = (status[1] & 0x10) != 0;
+		synhw.capReportsMin       = (status[1] & 0x20) != 0;
+		synhw.capInterTouch       = (status[1] & 0x40) != 0;
+		synhw.capReportsMax       = (status[2] & 0x02) != 0;
+		synhw.capClearPad         = (status[2] & 0x04) != 0;
+		synhw.capAdvancedGestures = (status[2] & 0x08) != 0;
+		synhw.capCoveredPad       = (status[2] & 0x80) != 0;
+
+		if (verbose >= 2) {
+			printf("  Continued capabilities:\n");
+			printf("   capClickPad: %d\n", synhw.capClickPad);
+			printf("   capDeluxeLEDs: %d\n", synhw.capDeluxeLEDs);
+			printf("   noAbsoluteFilter: %d\n",
+			    synhw.noAbsoluteFilter);
+			printf("   capReportsV: %d\n", synhw.capReportsV);
+			printf("   capUniformClickPad: %d\n",
+			    synhw.capUniformClickPad);
+			printf("   capReportsMin: %d\n", synhw.capReportsMin);
+			printf("   capInterTouch: %d\n", synhw.capInterTouch);
+			printf("   capReportsMax: %d\n", synhw.capReportsMax);
+			printf("   capClearPad: %d\n", synhw.capClearPad);
+			printf("   capAdvancedGestures: %d\n",
+			    synhw.capAdvancedGestures);
+			printf("   capCoveredPad: %d\n", synhw.capCoveredPad);
+		}
+		buttons += synhw.capClickPad;
+	}
+
 	/*
 	 * Add the default number of 3 buttons to the total
 	 * count of supported buttons reported above.
diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h
index 1b391bf..5329693 100644
--- a/sys/sys/mouse.h
+++ b/sys/sys/mouse.h
@@ -86,7 +86,7 @@ typedef struct mousehw {
 	int type;		/* mouse/track ball/pad... */
 	int model;		/* I/F dependent model ID: MOUSE_MODEL_XXX */
 	int hwid;		/* I/F dependent hardware ID
-				 * for the PS/2 mouse, it will be PSM_XXX_ID 
+				 * for the PS/2 mouse, it will be PSM_XXX_ID
 				 */
 } mousehw_t;
 
@@ -113,6 +113,21 @@ typedef struct synapticshw {
 	int capBallistics;
 	int nExtendedButtons;
 	int nExtendedQueries;
+	int capClickPad;
+	int capDeluxeLEDs;
+	int noAbsoluteFilter;
+	int capReportsV;
+	int capUniformClickPad;
+	int capReportsMin;
+	int capInterTouch;
+	int capReportsMax;
+	int capClearPad;
+	int capAdvancedGestures;
+	int multiFingerMode;
+	int capCoveredPad;
+	int verticalScroll;
+	int horizontalScroll;
+	int verticalWheel;
 } synapticshw_t;
 
 /* iftype */
@@ -272,7 +287,7 @@ typedef struct mousevar {
 #define MOUSE_PS2_BUTTON2DOWN	0x04	/* middle */
 #define MOUSE_PS2_BUTTON3DOWN	0x02	/* right */
 #define MOUSE_PS2_TAP		MOUSE_PS2_SYNC /* GlidePoint (PS/2) `tapping'
-					        * Yes! this is the same bit 
+					        * Yes! this is the same bit
 						* as SYNC!
 					 	*/
 
@@ -327,11 +342,11 @@ typedef struct mousevar {
 #define MOUSE_PS2VERSA_TAP		0x02
 
 /* A4 Tech 4D Mouse (PS/2) data packet */
-#define MOUSE_4D_PACKETSIZE		3	
+#define MOUSE_4D_PACKETSIZE		3
 #define MOUSE_4D_WHEELBITS		0xf0
 
 /* A4 Tech 4D+ Mouse (PS/2) data packet */
-#define MOUSE_4DPLUS_PACKETSIZE		3	
+#define MOUSE_4DPLUS_PACKETSIZE		3
 #define MOUSE_4DPLUS_ZNEG		0x04	/* sign bit */
 #define MOUSE_4DPLUS_BUTTON4DOWN	0x08
 
@@ -343,7 +358,7 @@ typedef struct mousevar {
  * as at the level 0.  There are additional three bytes which shows
  * `dz' and the states of additional buttons.  `dz' is expressed as the
  * sum of the byte 5 and 6 which contain signed seven bit values.
- * The states of the button 4 though 10 are in the bit 0 though 6 in 
+ * The states of the button 4 though 10 are in the bit 0 though 6 in
  * the byte 7 respectively: 1 indicates the button is up.
  */
 #define MOUSE_SYS_PACKETSIZE	8

--nextPart1851775.HIa3oEWMf4--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1849381.HnoQVUIgNM>