Skip site navigation (1)Skip section navigation (2)
Date:      9 Feb 2003 21:56:16 -0000
From:      Rahul Siddharthan <rsidd@online.fr>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/48116: Support for Synaptics touchpad
Message-ID:  <20030209215616.23069.qmail@bluerondo.a.la.turk>

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

>Number:         48116
>Category:       kern
>Synopsis:       Support for Synaptics touchpad
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 09 14:00:26 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Rahul Siddharthan
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD bluerondo.a.la.turk 5.0-CURRENT FreeBSD 5.0-CURRENT #2: Tue Jan 21 19:29:39 EST 2003 root@bluerondo.a.la.turk:/usr/obj/usr/src/sys/BLUERONDO i386


	
>Description:
This is a patch from Marcin Dalecki for supporting the extra buttons on
the Synaptics touchpad, which comes with many laptops.  He originally
posted this patch on -hackers on Jan 3, 2003.  I have been using it for
a month and it works perfectly for me.

Marcin told me in private mail that he wasn't familiar with
FreeBSD development processes and didn't plan to send-pr it, but asked
me to feel free to post it wherever it should go.  So here it is...

The diffs are against -current of Feb 9, 2002.  

>How-To-Repeat:
	
>Fix:

--- src/sys/isa/psm.c.old	Sun Feb  9 16:47:20 2003
+++ src/sys/isa/psm.c	Sun Feb  9 16:47:37 2003
@@ -268,6 +268,7 @@
 static probefunc_t enable_4dplus;
 static probefunc_t enable_mmanplus;
 static probefunc_t enable_versapad;
+static probefunc_t enable_synaptics;
 static int tame_mouse(struct psm_softc *, mousestatus_t *, unsigned char *);
 
 static struct {
@@ -300,6 +301,8 @@
       0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
     { MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
       0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
+    { MOUSE_MODEL_SYNAPTICS,		/* Synaptics TouchPad */
+      0xc0, MOUSE_PS2SYNAP_PACKETSIZE, enable_synaptics, },
     { MOUSE_MODEL_GENERIC,
       0xc0, MOUSE_PS2_PACKETSIZE, NULL, },
 };
@@ -561,6 +564,7 @@
         { MOUSE_MODEL_EXPLORER,		"IntelliMouse Explorer" },
         { MOUSE_MODEL_4D,		"4D Mouse" },
         { MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
+	{ MOUSE_MODEL_SYNAPTICS,	"Synaptics TouchPad" },
         { MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
         { MOUSE_MODEL_UNKNOWN,		NULL },
     };
@@ -1955,7 +1959,7 @@
      * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
      * into `mousestatus' button bits (MOUSE_BUTTON?DOWN).
      */
-    static int butmap[8] = {
+    static const int butmap[8] = {
         0, 
 	MOUSE_BUTTON1DOWN, 
 	MOUSE_BUTTON3DOWN, 
@@ -1965,7 +1969,7 @@
 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
     };
-    static int butmap_versapad[8] = {
+    static const int butmap_versapad[8] = {
 	0, 
 	MOUSE_BUTTON3DOWN, 
 	0, 
@@ -1978,18 +1982,18 @@
     register struct psm_softc *sc = arg;
     mousestatus_t ms;
     struct timeval tv;
-    int x, y, z;
+    int x, y, z, w;
     int c;
     int l;
     int x0, y0;
 
     /* read until there is nothing to read */
     while((c = read_aux_data_no_wait(sc->kbdc)) != -1) {
-    
+
         /* discard the byte if the device is not open */
         if ((sc->state & PSM_OPEN) == 0)
             continue;
-    
+
 	getmicrouptime(&tv);
 	if ((sc->inputbytes > 0) && timevalcmp(&tv, &sc->inputtimeout, >)) {
 	    log(LOG_DEBUG, "psmintr: delay too long; resetting byte count\n");
@@ -2005,9 +2009,9 @@
 	    continue;
 
 #if 0
-        log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
-	    sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
-	    sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
+	log(LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n",
+		sc->ipacket[0], sc->ipacket[1], sc->ipacket[2],
+		sc->ipacket[3], sc->ipacket[4], sc->ipacket[5]);
 #endif
 
 	c = sc->ipacket[0];
@@ -2311,6 +2315,80 @@
 	    }
 	    break;
 
+	case MOUSE_MODEL_SYNAPTICS:
+	    /* TouchPad PS/2 absolute mode message format
+	     *
+	     *  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[4]: X7  X6  X5  X4  X3  X2  X1  X0
+	     *  ipacket[5]: Y7  Y6  Y5  Y4  Y3  Y2  Y1  Y0
+	     *
+	     * Legend:
+	     *  L: left physical mouse button
+	     *  R: right physical mouse button
+	     *  D: down button
+	     *  U: up button
+	     *  W: "wrist" value
+	     *  X: x position
+	     *  Y: x position
+	     *  Z: pressure
+	     *
+	     * Absolute reportable limits:    0 - 6143.
+	     * Typical bezel limites:	   1472 - 5472.
+	     * Typical edge marings:	   1632 - 5312.
+	     */
+
+	    /* Sanity check for out of sync packets. */
+	    if ((sc->ipacket[0] & 0xc8) != 0x80 || (sc->ipacket[3] & 0xc8) != 0xc0)
+		continue;
+
+	    ms.button = 0;
+	    x = y = x0 = y0 = 0;
+
+	    /* pressure */
+	    z = sc->ipacket[2];
+	    w = ((sc->ipacket[0] & 0x30) >> 2) |
+		((sc->ipacket[0] & 0x04) >> 1) |
+		((sc->ipacket[3] & 0x04) >> 2);
+
+	    ms.button = 0;
+	    if (sc->ipacket[0] & 0x01)
+		ms.button |= MOUSE_BUTTON1DOWN;
+	    if (sc->ipacket[0] & 0x02)
+		ms.button |= MOUSE_BUTTON3DOWN;
+	    if ((sc->ipacket[3] & 0x01) && !(sc->ipacket[0] & 0x01))
+		ms.button |= MOUSE_BUTTON2DOWN;
+	    if ((sc->ipacket[3] & 0x02) && !(sc->ipacket[0] & 0x02))
+		ms.button |= MOUSE_BUTTON4DOWN;
+
+	    /* There is a finger on the pad */
+	    if ((w >= 4 && w <= 7) && (z >= 16 && z < 128) ) {
+		x0 = ((sc->ipacket[3] & 0x10) << 8) | ((sc->ipacket[1] & 0x0f) << 8) | sc->ipacket[4];
+		y0 = ((sc->ipacket[3] & 0x20) << 7) | ((sc->ipacket[1] & 0xf0) << 4) | sc->ipacket[5];
+
+		if (sc->flags & PSM_FLAGS_FINGERDOWN) {
+		    x0 = (x0 + sc->xold * 3) / 4;
+		    y0 = (y0 + sc->yold * 3) / 4;
+
+		    x = (x0 - sc->xold) / 4;
+		    y = (y0 - sc->yold) / 4;
+		} else {
+		    sc->flags |= PSM_FLAGS_FINGERDOWN;
+		}
+
+		sc->xold = x0;
+		sc->yold = y0;
+	    } else {
+		sc->flags &= ~PSM_FLAGS_FINGERDOWN;
+	    }
+	    z = 0;
+
+	    break;
+
 	case MOUSE_MODEL_GENERIC:
 	default:
 	    break;
@@ -2795,6 +2873,105 @@
 	return FALSE;
     set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
 
+    sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
+    return TRUE;				/* PS/2 absolute mode */
+}
+
+/* Synaptics touch pad */
+static int
+enable_synaptics(struct psm_softc *sc)
+{
+    KBDC kbdc = sc->kbdc;
+    int res;
+    int data[4];
+    int info_rot180;
+    int info_portrait;
+    int info_sensor;
+    int info_hardware;
+    int info_new_abs;
+    int info_cap_pen;
+    int info_simple_cmd;
+    int info_geometry;
+
+    if (verbose >= 2)
+        log(LOG_DEBUG, "psm: ENABLE_SYNAPTICS\n");
+
+    /* Idenfity.
+     */
+    empty_aux_buffer(kbdc, 5);
+    mouse_ext_command(kbdc, 0x00);
+    if (get_mouse_status(kbdc, data, 0, 3) < 3)
+	return FALSE;
+    if (data[1] != 0x47)
+	return FALSE;
+
+    printf("Synaptics Touchpad:\n");
+    printf("  model:          %d\n", (data[2] >> 4) & 0x0f);
+    printf("  firmware ver.:  %d.%d\n", data[2] & 0x0f, data[0]);
+
+    /* Read Model ID.
+     */
+    empty_aux_buffer(kbdc, 5);
+    mouse_ext_command(kbdc, 0x03);
+    if (get_mouse_status(kbdc, data, 0, 3) < 3)
+	return FALSE;
+
+    info_rot180     = (data[0] & 0x80);
+    info_portrait   = (data[0] & 0x40);
+    info_sensor     = (data[0] & 0x003f);
+    info_hardware   = (data[1] & 0xfe) >> 1;
+    info_new_abs    = (data[2] & 0x80);
+    info_cap_pen    = (data[2] & 0x40);
+    info_simple_cmd = (data[2] & 0x20);
+    info_geometry   = (data[2] & 0x0f);
+
+    printf("  rot180:         %s\n", info_rot180 ? "Yes" : "No");
+    printf("  portrait:       %s\n", info_portrait ? "Yes" : "No");
+    printf("  sensor:         %d\n", info_sensor);
+    printf("  hardware:       %d\n", info_hardware);
+    printf("  newABS:         %s\n", info_new_abs ? "Yes" : "No");
+    printf("  capPen:         %s\n", info_cap_pen ? "Yes" : "No");
+    printf("  simpleCmd:      %s\n", info_simple_cmd ? "Yes" : "No");
+    printf("  geometry:       %d\n", info_geometry);
+
+    /* Read Capabilities.
+     */
+    empty_aux_buffer(kbdc, 5);
+    mouse_ext_command(kbdc, 0x02);
+    if (get_mouse_status(kbdc, data, 0, 3) < 3)
+	return FALSE;
+    if (data[1] != 0x47)
+	return FALSE;
+
+    printf("  capExtended:    %s\n", (data[0] & 0x80) ? "Yes" : "No");
+    printf("  capSleep:       %s\n", (data[2] & 0x10) ? "Yes" : "No");
+    printf("  capFourButtons: %s\n", (data[2] & 0x08) ? "Yes" : "No");
+    printf("  capMultiFinger: %s\n", (data[2] & 0x02) ? "Yes" : "No");
+    printf("  capPalmDetect:  %s\n", (data[2] & 0x01) ? "Yes" : "No");
+
+    /* Now we set the operating mode to absolute.
+     */
+#define SYN_BIT_ABSOLUTE_MODE	0x80
+#define SYN_BIT_HIGH_RATE	0x40
+#define SYN_BIT_SLEEP_MODE	0x08
+#define SYN_BIT_DISABLE_GESTURE 0x04
+#define SYN_BIT_W_MODE		0x01
+
+    empty_aux_buffer(kbdc, 5);
+    mouse_ext_command(kbdc, SYN_BIT_ABSOLUTE_MODE |
+	                    SYN_BIT_HIGH_RATE |
+	                    SYN_BIT_DISABLE_GESTURE |
+	                    SYN_BIT_W_MODE);
+    res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, 0x14);
+    if (res != PSM_ACK) {
+        log(LOG_ERR, "psm: setting Synaptics TouchPad mode failed,\n");
+	return FALSE;
+    }
+
+    set_mouse_scaling(kbdc, 1);			/* set scale 1:1 */
+
+    sc->hw.buttons = 4;
     sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
 
     return TRUE;				/* PS/2 absolute mode */


--- src/sys/sys/mouse.h.old	Sun Feb  9 16:47:33 2003
+++ src/sys/sys/mouse.h	Sun Feb  9 16:47:37 2003
@@ -119,6 +119,7 @@
 #define MOUSE_MODEL_EXPLORER		10
 #define MOUSE_MODEL_4D			11
 #define MOUSE_MODEL_4DPLUS		12
+#define MOUSE_MODEL_SYNAPTICS		13
 
 typedef struct mousemode {
 	int protocol;		/* MOUSE_PROTO_XXX */
@@ -139,7 +140,7 @@
  * Bus mouse protocols:
  *   bus, InPort
  * PS/2 mouse protocol:
- *   PS/2
+ *   PS/2, Synaptics TouchPad
  */
 #define MOUSE_PROTO_UNKNOWN	(-1)
 #define MOUSE_PROTO_MS		0	/* Microsoft Serial, 3 bytes */
@@ -159,6 +160,7 @@
 #define MOUSE_PROTO_KIDSPAD	14	/* Genius Kidspad */
 #define MOUSE_PROTO_VERSAPAD	15	/* Interlink VersaPad, 6 bytes */
 #define MOUSE_PROTO_JOGDIAL	16	/* Vaio's JogDial */
+#define MOUSE_PROTO_SYNAPTICS	17	/* Synaptics TouchPad, 6 bytes */
 
 #define MOUSE_RES_UNKNOWN	(-1)
 #define MOUSE_RES_DEFAULT	0
@@ -293,12 +295,15 @@
 #define MOUSE_PS2VERSA_BUTTON3DOWN	0x01	/* right */
 #define MOUSE_PS2VERSA_TAP		0x02
 
+/* Synaptics TouchPad (PS/2 I/F) data packet */
+#define MOUSE_PS2SYNAP_PACKETSIZE	6
+
 /* 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
 
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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