Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Aug 2012 20:16:31 GMT
From:      Brandon Gooch <jamesbrandongooch@gmail.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/170834: [patch] synaptics middle and extended button support for psm(4)
Message-ID:  <201208212016.q7LKGV0f022565@red.freebsd.org>
Resent-Message-ID: <201208212020.q7LKK6cH053770@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         170834
>Category:       kern
>Synopsis:       [patch] synaptics middle and extended button support for psm(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 21 20:20:06 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Brandon Gooch
>Release:        10-CURRENT
>Organization:
>Environment:
FreeBSD m6500.local 10.0-CURRENT FreeBSD 10.0-CURRENT #5 r239361M: Sun Aug 19 19:23:01 CDT 2012     root@m6500.local:/usr/obj/usr/src/sys/DELL_M6500  amd64
>Description:
In an effort to activate the middle mouse button on my Synaptics
TouchPad (installed in a Dell M6500), I ran across PR kern/84411:

http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/84411

The attached patch, in the same spirit, establishes a
functional middle mouse button, as well as fixes the strange
"right-click mouse button + TouchPad scroll bug" talked about in at
least a couple of places on the internet (including a post by me back
in 2010):

http://forums.freebsd.org/showthread.php?t=12941
http://forums.freebsd.org/showthread.php?t=10125
http://lists.freebsd.org/pipermail/freebsd-mobile/2010-February/011929.html

Although I can't test the additional features this patch adds, e.g.
extended button support, due to hardware unavailability, I can verify
that the middle button works and the right-click spurious scroll issue
is resolved.

Also, the Synaptics PS/2 TouchPad Interfacing Guide formalizes the
support of "guest devices", which was previously represented by a
reserved bit. See section 5 of the guide:

http://www.synaptics.com/sites/default/files/511-000275-01_RevB.pdf

One important note to this is the dropped support for guest devices
from the X.org synaptics driver as of this commit:

http://cgit.freedesktop.org/xorg/driver/xf86-input-synaptics/commit/?id=b19e3782a77c171ca20fc962f95923495fdb7978

The guest device in my Dell M6500 is the Synaptics TouchStyk, an
enhanced "trackpoint"-style pointing device, which theoretically could
be represented as another pointing device (similar to how the Linux
kernel handles these devices from what I've read). However, the
Synaptics support provided by the psm(4) driver needs significantly
more work to support the devices in this manner, so this patch is more
of a stop-gap for now.
>How-To-Repeat:
Run FreeBSD on a notebook computer equipped with a Synaptics TouchPad devices which houses a middle mouse button, or supports extended button press events.
>Fix:


Patch attached with submission follows:

Index: sys/sys/mouse.h
===================================================================
--- sys/sys/mouse.h	(revision 239361)
+++ sys/sys/mouse.h	(working copy)
@@ -101,12 +101,15 @@
 	int capPen;
 	int infoSimplC;
 	int infoGeometry;
+	int nExtendedButtons;
 	int capExtended;
+	int nExtendedQueries;
+	int capMiddle;
+	int capPassthrough;
 	int capSleep;
 	int capFourButtons;
 	int capMultiFinger;
 	int capPalmDetect;
-	int capPassthrough;
 } synapticshw_t;
 
 /* iftype */
Index: sys/dev/atkbdc/psm.c
===================================================================
--- sys/dev/atkbdc/psm.c	(revision 239361)
+++ sys/dev/atkbdc/psm.c	(working copy)
@@ -2454,7 +2454,7 @@
 {
 
 	/*
-	 * PS2++ protocl packet
+	 * PS2++ protocol packet
 	 *
 	 *          b7 b6 b5 b4 b3 b2 b1 b0
 	 * byte 1:  *  1  p3 p2 1  *  *  *
@@ -2552,14 +2552,14 @@
 	static int guest_buttons;
 	int w, x0, y0;
 
-	/* TouchPad PS/2 absolute mode message format
+	/* TouchPad PS/2 absolute mode message format with capFourButtons:
 	 *
 	 *  Bits:        7   6   5   4   3   2   1   0 (LSB)
 	 *  ------------------------------------------------
 	 *  ipacket[0]:  1   0  W3  W2   0  W1   R   L
 	 *  ipacket[1]: Yb  Ya  Y9  Y8  Xb  Xa  X9  X8
 	 *  ipacket[2]: Z7  Z6  Z5  Z4  Z3  Z2  Z1  Z0
-	 *  ipacket[3]:  1   1  Yc  Xc   0  W0   D   U
+	 *  ipacket[3]:  1   1  Yc  Xc   0  W0 D^R U^L
 	 *  ipacket[4]: X7  X6  X5  X4  X3  X2  X1  X0
 	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
 	 *
@@ -2573,6 +2573,21 @@
 	 *  Y: y position
 	 *  Z: pressure
 	 *
+	 * Without capFourButtons but with nExtendeButtons and/or capMiddle
+	 *
+	 *  Bits:        7   6   5   4      3      2      1      0 (LSB)
+	 *  ------------------------------------------------------
+	 *  ipacket[3]:  1   1  Yc  Xc      0     W0    E^R    M^L
+	 *  ipacket[4]: X7  X6  X5  X4  X3|b7  X2|b5  X1|b3  X0|b1
+	 *  ipacket[5]: Y7  Y6  Y5  Y4  Y3|b8  Y2|b6  Y1|b4  Y0|b2
+	 *
+	 * Legend:
+	 *  M: Middle physical mouse button
+	 *  E: Extended mouse buttons repored instead of low bits of X and Y
+	 *  b1-b8: Extended mouse buttons
+	 *    Only ((nExtendedButtons + 1) >> 1) bits are used in packet
+	 *    4 and 5, for reading X and Y value they should be zeroed.
+	 *
 	 * Absolute reportable limits:    0 - 6143.
 	 * Typical bezel limits:       1472 - 5472.
 	 * Typical edge marings:       1632 - 5312.
@@ -2626,8 +2641,10 @@
 		w = 4;
 	}
 
-	/* Handle packets from the guest device */
-	/* XXX Documentation? */
+	/*
+	 * Handle packets from the guest device. See:
+	 * Synaptics PS/2 TouchPad Interfacing Guide, Section 5.1
+	 */
 	if (w == 3 && sc->synhw.capPassthrough) {
 		*x = ((pb->ipacket[1] & 0x10) ?
 		    pb->ipacket[4] - 256 : pb->ipacket[4]);
@@ -2655,36 +2672,49 @@
 		touchpad_buttons |= MOUSE_BUTTON3DOWN;
 
 	if (sc->synhw.capExtended && sc->synhw.capFourButtons) {
-		if ((pb->ipacket[3] & 0x01) && (pb->ipacket[0] & 0x01) == 0)
+		if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x01)
 			touchpad_buttons |= MOUSE_BUTTON4DOWN;
-		if ((pb->ipacket[3] & 0x02) && (pb->ipacket[0] & 0x02) == 0)
+		if ((pb->ipacket[3] ^ pb->ipacket[0]) & 0x02)
 			touchpad_buttons |= MOUSE_BUTTON5DOWN;
-	}
+	} else if (sc->synhw.capExtended && sc->synhw.capMiddle) {
+		/* Middle Button */
+		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x01)
+			touchpad_buttons |= MOUSE_BUTTON2DOWN;
+	} else if (sc->synhw.capExtended && (sc->synhw.nExtendedButtons > 0)) {
+		/* Extended Buttons */
+		if ((pb->ipacket[0] ^ pb->ipacket[3]) & 0x02) {
+			if (sc->syninfo.directional_scrolls) {
+				if (pb->ipacket[4] & 0x01)
+					touchpad_buttons |= MOUSE_BUTTON4DOWN;
+				if (pb->ipacket[5] & 0x01)
+					touchpad_buttons |= MOUSE_BUTTON5DOWN;
+				if (pb->ipacket[4] & 0x02)
+					touchpad_buttons |= MOUSE_BUTTON6DOWN;
+				if (pb->ipacket[5] & 0x02)
+					touchpad_buttons |= MOUSE_BUTTON7DOWN;
+			} else {
+				touchpad_buttons |= MOUSE_BUTTON2DOWN;
+			}
 
-	/*
-	 * In newer pads - bit 0x02 in the third byte of
-	 * the packet indicates that we have an extended
-	 * button press.
-	 */
-	/* XXX Documentation? */
-	if (pb->ipacket[3] & 0x02) {
-		/*
-		 * if directional_scrolls is not 1, we treat any of
-		 * the scrolling directions as middle-click.
-		 */
-		if (sc->syninfo.directional_scrolls) {
-			if (pb->ipacket[4] & 0x01)
-				touchpad_buttons |= MOUSE_BUTTON4DOWN;
-			if (pb->ipacket[5] & 0x01)
-				touchpad_buttons |= MOUSE_BUTTON5DOWN;
-			if (pb->ipacket[4] & 0x02)
-				touchpad_buttons |= MOUSE_BUTTON6DOWN;
-			if (pb->ipacket[5] & 0x02)
-				touchpad_buttons |= MOUSE_BUTTON7DOWN;
-		} else {
-			if ((pb->ipacket[4] & 0x0F) ||
-			    (pb->ipacket[5] & 0x0F))
-				touchpad_buttons |= MOUSE_BUTTON2DOWN;
+			/*
+			 * Zero out bits used by extended buttons to avoid
+			 * misinterpretation of the data absolute position. 
+			 *
+			 * The bits represented by
+			 *
+			 *     (nExtendedButtons + 1) >> 1
+			 *
+			 * will be masked out in both bytes.
+			 * The mask for n bits is computed with the formula
+			 *
+			 *     (1 << n) - 1
+			 */
+			int maskedbits = 0;
+			int mask = 0;
+			maskedbits = (sc->synhw.nExtendedButtons + 1) >> 1;
+			mask = (1 << maskedbits) - 1;
+			pb->ipacket[4] &= ~(mask);
+			pb->ipacket[5] &= ~(mask);
 		}
 	}
 
@@ -4390,15 +4420,20 @@
 	buttons = 0;
 	synhw.capExtended = (status[0] & 0x80) != 0;
 	if (synhw.capExtended) {
-		synhw.capPassthrough = (status[2] & 0x80) != 0;
-		synhw.capSleep       = (status[2] & 0x10) != 0;
-		synhw.capFourButtons = (status[2] & 0x08) != 0;
-		synhw.capMultiFinger = (status[2] & 0x02) != 0;
-		synhw.capPalmDetect  = (status[2] & 0x01) != 0;
+		synhw.nExtendedQueries = (status[0] & 0x70) != 0;
+		synhw.capMiddle        = (status[0] & 0x04) != 0;
+		synhw.capPassthrough   = (status[2] & 0x80) != 0;
+		synhw.capSleep         = (status[2] & 0x10) != 0;
+		synhw.capFourButtons   = (status[2] & 0x08) != 0;
+		synhw.capMultiFinger   = (status[2] & 0x02) != 0;
+		synhw.capPalmDetect    = (status[2] & 0x01) != 0;
 
 		if (verbose >= 2) {
 			printf("  Extended capabilities:\n");
 			printf("   capExtended: %d\n", synhw.capExtended);
+			printf("   capMiddle: %d\n", synhw.capMiddle);
+			printf("   nExtendedQueries: %d\n",
+			    synhw.nExtendedQueries);
 			printf("   capPassthrough: %d\n", synhw.capPassthrough);
 			printf("   capSleep: %d\n", synhw.capSleep);
 			printf("   capFourButtons: %d\n", synhw.capFourButtons);
@@ -4407,16 +4442,27 @@
 		}
 
 		/*
-		 * If we have bits set in status[0] & 0x70, then we can load
+		 * If nExtendedQueries is 1 or greater, then the TouchPad
+		 * supports this number of extended queries. We can load
 		 * more information about buttons using query 0x09.
 		 */
-		if ((status[0] & 0x70) != 0) {
+		if (synhw.capExtended && synhw.nExtendedQueries) {
 			if (mouse_ext_command(kbdc, 0x09) == 0)
 				return (FALSE);
 			if (get_mouse_status(kbdc, status, 0, 3) != 3)
 				return (FALSE);
-			buttons = (status[1] & 0xf0) >> 4;
+			synhw.nExtendedButtons = (status[1] & 0xf0) >> 4;
+			/*
+			 * Add the number of extended buttons to the total
+			 * button support count, including the middle button
+			 * if capMiddle support bit is set.
+			 */
+			buttons = synhw.nExtendedButtons + synhw.capMiddle;
 		} else
+			/*
+			 * If the capFourButtons support bit is set,
+			 * add a fourth button to the total button count.
+			 */
 			buttons = synhw.capFourButtons ? 1 : 0;
 	}
 	if (verbose >= 2) {
@@ -4427,6 +4473,12 @@
 	}
 
 	/*
+	 * Add the default number of 3 buttons to the total
+	 * count of supported buttons reported above.
+	 */
+	buttons += 3;
+
+	/*
 	 * Read the mode byte.
 	 *
 	 * XXX: Note the Synaptics documentation also defines the first
@@ -4453,7 +4505,6 @@
 	/* "Commit" the Set Mode Byte command sent above. */
 	set_mouse_sampling_rate(kbdc, 20);
 
-	buttons += 3;
 	VLOG(3, (LOG_DEBUG, "synaptics: END init (%d buttons)\n", buttons));
 
 	if (sc != NULL) {


>Release-Note:
>Audit-Trail:
>Unformatted:



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