Subject: Re: Ibm thinkpad trackpoint issue
To: None <current-users@netbsd.org>
From: Michael van Elst <mlelstv@serpens.de>
List: current-users
Date: 09/09/2006 09:46:32
gdt@ir.bbn.com (Greg Troxel) writes:

>on most thinkpads with both trackpoint and touchpad ("UltraNav"), they
>both work unless you adjust the bios, and the system sees a single
>PS/2 mouse.  Sometimes you have to diable touchpad to get the middle
>trackpoint button to work; it works under windows so there's some
>richer interface NetBSD doesn't support yet.

Yes. There is a passthrough mode where the data of the second device
is sent encapsulated. I made a crude patch for my T43:

Index: synaptics.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pckbport/synaptics.c,v
retrieving revision 1.5
diff -u -r1.5 synaptics.c
--- synaptics.c	27 Feb 2005 00:27:42 -0000	1.5
+++ synaptics.c	9 Sep 2006 09:44:18 -0000
@@ -644,12 +644,107 @@
 #define PMS_MBUTMASK 0x04
 
 static void
+pms_synaptics_parse(struct pms_softc *psc)
+{
+	struct synaptics_softc *sc = &psc->u.synaptics;
+	struct synaptics_packet sp;
+
+	/* 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);
+
+	/* Pressure */
+	sp.sp_z = psc->packet[2];
+
+	/* Width of finger */
+	sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
+	    ((psc->packet[0] & 0x04) >> 1) +
+	    ((psc->packet[3] & 0x04) >> 2);
+
+	/* Left/Right button handling. */
+	sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
+	sp.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 ^
+		    (psc->packet[3] & PMS_LBUTMASK);
+		sp.sp_down = sp.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;
+	} else {
+		sp.sp_up = 0;
+		sp.sp_down = 0;
+	}
+
+	/* Middle button. */
+	if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
+		/* Old style Middle Button. */
+		sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
+		    (psc->packet[3] & PMS_LBUTMASK);
+	} else
+	if (synaptics_up_down_emul == 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;
+	} else
+		sp.sp_middle = 0;
+
+	pms_synaptics_process_packet(psc, &sp);
+}
+
+static void
+pms_synaptics_passthrough(struct pms_softc *psc)
+{
+	int dx, dy, dz;
+	int buttons, changed;
+	int s;
+
+	buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) |
+		((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) |
+		((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0);
+
+	dx = psc->packet[4];
+	if (dx >= 128)
+		dx -= 256;
+	if (dx == -128)
+		dx = -127;
+
+	dy = psc->packet[5];
+	if (dy >= 128)
+		dy -= 256;
+	if (dy == -128)
+		dy = -127;
+
+	dz = 0;
+
+	changed = buttons ^ (psc->buttons & 0xe0);
+	psc->buttons ^= changed;
+
+	if (dx || dy || dz || changed) {
+		buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
+		s = spltty();
+		wsmouse_input(psc->sc_wsmousedev,
+			buttons, dx, dy, dz,
+			WSMOUSE_INPUT_DELTA);
+		splx(s);
+	}
+}
+
+static void
 pms_synaptics_input(void *vsc, int data)
 {
 	struct pms_softc *psc = vsc;
-	struct synaptics_softc *sc = &psc->u.synaptics;
 	struct timeval diff;
-	struct synaptics_packet sp;
 	int s;
 
 	if (!psc->sc_enabled) {
@@ -688,7 +783,7 @@
 
 	case 3:
 		if ((data & 8) == 8) {
-#ifdef SYNAPTICS_DEBUG
+#ifdef SYNAPTICSDEBUG
 			printf("%s: pms_input: dropped in relative mode, "
 			    "reset\n", psc->sc_dev.dv_xname);
 #endif
@@ -707,60 +802,13 @@
 		 */
 		psc->inputstate = 0;
 
-		/* 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);
-
-		/* Pressure */
-		sp.sp_z = psc->packet[2];
-
-		/* Width of finger */
-		sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
-		    ((psc->packet[0] & 0x04) >> 1) +
-		    ((psc->packet[3] & 0x04) >> 2);
-
-		/* Left/Right button handling. */
-		sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
-		sp.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 ^
-			    (psc->packet[3] & PMS_LBUTMASK);
-			sp.sp_down = sp.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;
+		if ((psc->packet[0] & 0xfc) == 0x84 &&
+		    (psc->packet[3] & 0xcc) == 0xc4) {
+			/* PS/2 passthrough */
+			pms_synaptics_passthrough(psc);
 		} else {
-			sp.sp_up = 0;
-			sp.sp_down = 0;
+			pms_synaptics_parse(psc);
 		}
-
-		/* Middle button. */
-		if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
-			/* Old style Middle Button. */
-			sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
-			    (psc->packet[3] & PMS_LBUTMASK);
-		} else
-		if (synaptics_up_down_emul == 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;
-		} else
-			sp.sp_middle = 0;
-
-		/*
-		 * Go process the new packet
-		 */
-		pms_synaptics_process_packet(psc, &sp);
 	}
 }
 
@@ -1205,8 +1253,8 @@
 	    (sp->sp_right ? 0x4 : 0) |
 	    (sp->sp_up ? 0x8 : 0) |
 	    (sp->sp_down ? 0x10 : 0);
-	changed = buttons ^ psc->buttons;
-	psc->buttons = buttons;
+	changed = buttons ^ (psc->buttons & 0x1f);
+	psc->buttons ^= changed;
 
 	sc->prev_fingers = fingers;
 	sc->total_packets++;
@@ -1229,6 +1277,7 @@
 	 * Pass the final results up to wsmouse_input() if necessary.
 	 */
 	if (dx || dy || dz || changed) {
+		buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
 		s = spltty();
 		wsmouse_input(psc->sc_wsmousedev, buttons, dx, dy, dz,
 		    WSMOUSE_INPUT_DELTA);



-- 
-- 
                                Michael van Elst
Internet: mlelstv@serpens.de
                                "A potential Snark may lurk in every tree."