From nobody@FreeBSD.org  Sun May 30 21:31:43 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 3602F1065670
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 30 May 2010 21:31:43 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 119168FC0A
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 30 May 2010 21:31:42 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o4ULVfGZ054802
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 30 May 2010 21:31:41 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o4ULVfNs054801;
	Sun, 30 May 2010 21:31:41 GMT
	(envelope-from nobody)
Message-Id: <201005302131.o4ULVfNs054801@www.freebsd.org>
Date: Sun, 30 May 2010 21:31:41 GMT
From: Tamas Szakaly <sghctoma@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [PATCH] There is no IBM/Lenovo TrackPoint support in psm driver
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         147237
>Category:       kern
>Synopsis:       [psm] [patch] There is no IBM/Lenovo TrackPoint support in psm driver
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jkim
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun May 30 21:40:01 UTC 2010
>Closed-Date:    Wed Jun 26 17:30:08 UTC 2013
>Last-Modified:  Wed Jun 26 17:30:08 UTC 2013
>Originator:     Tamas Szakaly
>Release:        FreeBSD 8.1-PRERELEASE amd64
>Organization:
n/a
>Environment:
FreeBSD pamparam.teteny.elte.hu 8.1-PRERELEASE FreeBSD 8.1-PRERELEASE #25: Sun May 30 12:49:28 CEST 2010 sghctoma@pamparam.teteny.elte.hu:/usr/obj/usr/src/sys/PAMPARAM  amd64
>Description:
I am running FreeBSD 8 on a Lenovo ThinkPad x200s laptop. This model has a TrackPoint as a pointing device which is working fine as a Generic PS/2 Mouse, but I did not find a way to properly customize it (I could not achieve the sensitivity and smoothness I am accostumed to, not to mention Press to Select options).

>How-To-Repeat:
Just use FreeBSD on any TrackPoint-equipped ThinkPad.
>Fix:
In the attached patch I introduced some sysctl MIBs under hw.psm.trackpoint, and a tunable (hw.psm.trackpoint_support) to turn on/off TrackPoint support (similarly to hw.psm.synaptics.* and hw.psm.synaptics_support). I got information about the device from the document "TrackPoint System Version 4.0 Engineering Specification" which is available at http://wwwcssrv.almaden.ibm.com/trackpoint/files/ykt3eext.pdf

Patch attached with submission follows:

--- sys/dev/atkbdc/psm.c.orig	2009-08-20 22:23:28.000000000 +0200
+++ sys/dev/atkbdc/psm.c	2010-05-30 12:44:29.000000000 +0200
@@ -261,6 +261,38 @@
 	int			in_vscroll;
 } synapticsaction_t;
 
+enum {
+	TRACKPOINT_SYSCTL_SENSITIVITY,
+	TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
+	TRACKPOINT_SYSCTL_UPPER_PLATEAU,
+	TRACKPOINT_SYSCTL_BACKUP_RANGE,
+	TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
+	TRACKPOINT_SYSCTL_MINIMUM_DRAG,
+	TRACKPOINT_SYSCTL_UP_THRESHOLD,
+	TRACKPOINT_SYSCTL_THRESHOLD,
+	TRACKPOINT_SYSCTL_JENKS_CURVATURE,
+	TRACKPOINT_SYSCTL_Z_TIME,
+	TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
+	TRACKPOINT_SYSCTL_SKIP_BACKUPS
+};
+
+typedef struct trackpointinfo {
+	struct sysctl_ctx_list sysctl_ctx;
+	struct sysctl_oid *sysctl_tree;
+	int	sensitivity;
+	int	inertia;
+	int	uplateau;
+	int	reach;
+	int	draghys;
+	int	mindrag;
+	int	upthresh;
+	int	threshold;
+	int	jenks;
+	int	ztime;
+	int	pts;
+	int	skipback;
+} trackpointinfo_t;
+
 /* driver control block */
 struct psm_softc {		/* Driver status information */
 	int		unit;
@@ -275,6 +307,7 @@
 	synapticshw_t	synhw;		/* Synaptics hardware information */
 	synapticsinfo_t	syninfo;	/* Synaptics configuration */
 	synapticsaction_t synaction;	/* Synaptics action context */
+	trackpointinfo_t tpinfo;	/* IBM/Lenovo TrackPoint configuration*/
 	mousemode_t	mode;		/* operation mode */
 	mousemode_t	dflt_mode;	/* default operation mode */
 	mousestatus_t	status;		/* accumulated mouse movement */
@@ -346,6 +379,9 @@
 static int synaptics_support = 0;
 TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
 
+static int trackpoint_support = 0;
+TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
+
 static int verbose = PSM_DEBUG;
 TUNABLE_INT("debug.psm.loglevel", &verbose);
 
@@ -435,6 +471,7 @@
 static probefunc_t	enable_mmanplus;
 static probefunc_t	enable_synaptics;
 static probefunc_t	enable_versapad;
+static probefunc_t	enable_trackpoint;
 
 static struct {
 	int		model;
@@ -468,6 +505,8 @@
 	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
 	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
 	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
+	{ MOUSE_MODEL_TRACKPOINT,	/* IBM/Lenovo TrackPoint*/
+	  0xc0, MOUSE_TRACKPOINT_PACKETSIZE, enable_trackpoint },
 	{ MOUSE_MODEL_GENERIC,
 	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
 };
@@ -710,6 +749,7 @@
 		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
 		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
 		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
+		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
 		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
 	};
 	int i;
@@ -3409,6 +3449,7 @@
 				goto next;
 			break;
 
+		case MOUSE_MODEL_TRACKPOINT:
 		case MOUSE_MODEL_GENERIC:
 		default:
 			break;
@@ -4477,6 +4518,286 @@
 	return (TRUE);				/* PS/2 absolute mode */
 }
 
+/* IBM/Lenovo TrackPoint */
+static int
+trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
+{
+	if (send_aux_command(kbdc, 0xe2) != PSM_ACK ||
+	    send_aux_command(kbdc, cmd) != PSM_ACK ||
+	    send_aux_command(kbdc, loc) != PSM_ACK ||
+	    send_aux_command(kbdc, val) != PSM_ACK)
+		return (EIO);
+
+	return (0);
+}
+
+static int
+trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	int error, cmd, loc, mask, max, *oldvalp;
+	struct psm_softc *sc = arg1;
+
+	loc = 0;
+	mask = 0;
+	oldvalp = NULL;
+
+	/*
+	 * The value of cmd and max will be 0x81 and 255 respectively for
+	 * the majority of cases, so we set them outside the switch, and
+	 * change them only when needed.
+	 */
+	cmd = 0x81;
+	max = 255;
+
+	switch (arg2) {
+	case TRACKPOINT_SYSCTL_SENSITIVITY:
+		loc = 0x4a;
+		oldvalp = &sc->tpinfo.sensitivity;
+		break;
+	case TRACKPOINT_SYSCTL_NEGATIVE_INERTIA:
+		loc = 0x4d;
+		oldvalp = &sc->tpinfo.inertia;
+		break;
+	case TRACKPOINT_SYSCTL_UPPER_PLATEAU:
+		loc = 0x60;
+		oldvalp = &sc->tpinfo.uplateau;
+		break;
+	case TRACKPOINT_SYSCTL_BACKUP_RANGE:
+		loc = 0x57;
+		oldvalp = &sc->tpinfo.reach;
+		break;
+	case TRACKPOINT_SYSCTL_DRAG_HYSTERESIS:
+		loc = 0x58;
+		oldvalp = &sc->tpinfo.draghys;
+		break;
+	case TRACKPOINT_SYSCTL_MINIMUM_DRAG:
+		loc = 0x59;
+		oldvalp = &sc->tpinfo.mindrag;
+		break;
+	case TRACKPOINT_SYSCTL_UP_THRESHOLD:
+		loc = 0x5a;
+		oldvalp = &sc->tpinfo.upthresh;
+		break;
+	case TRACKPOINT_SYSCTL_THRESHOLD:
+		loc = 0x5c;
+		oldvalp = &sc->tpinfo.threshold;
+		break;
+	case TRACKPOINT_SYSCTL_JENKS_CURVATURE:
+		loc = 0x5d;
+		oldvalp = &sc->tpinfo.jenks;
+		break;
+	case TRACKPOINT_SYSCTL_Z_TIME:
+		loc = 0x5e;
+		oldvalp = &sc->tpinfo.ztime;
+		break;
+	case TRACKPOINT_SYSCTL_PRESS_TO_SELECT:
+		cmd = 0x47;
+		loc = 0x2c;
+		mask = 0x01;
+		max = 1;
+		oldvalp = &sc->tpinfo.pts;
+		break;
+	case TRACKPOINT_SYSCTL_SKIP_BACKUPS:
+		cmd = 0x47;
+		loc = 0x2d;
+		mask = 0x08;
+		max = 1;
+		oldvalp = &sc->tpinfo.skipback;
+		break;
+	default:
+		return (1);
+		/* NOTREACHED */
+	}
+
+	int newval = *oldvalp;
+	if ((error = sysctl_handle_int(oidp, &newval, 0, req)) != 0)
+		return error;
+
+	if (newval == *oldvalp)
+		return (0);
+
+	if (newval < 0 || newval > max)
+		return (EINVAL);
+
+	if ((error = trackpoint_command(sc->kbdc, cmd, loc,
+			mask ? mask : newval)) != 0)
+		return (error);
+	else
+		*oldvalp = newval;
+
+	return (error);
+}
+
+static void
+trackpoint_sysctl_create_tree(struct psm_softc *sc)
+{
+	/* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
+	sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
+	sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
+	    0, "IBM/Lenovo TrackPoint");
+
+	/* hw.psm.trackpoint.sensitivity */
+	sc->tpinfo.sensitivity = 0x64;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_SENSITIVITY,
+	    trackpoint_sysctl, "I",
+	    "Sensitivity");
+
+	/* hw.psm.trackpoint.negative_inertia */
+	sc->tpinfo.inertia = 0x06;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
+	    trackpoint_sysctl, "I",
+	    "Negative inertia factor");
+
+	/* hw.psm.trackpoint.upper_plateau */
+	sc->tpinfo.uplateau = 0x61;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
+	    trackpoint_sysctl, "I",
+	    "Transfer function upper plateau speed");
+
+	/* hw.psm.trackpoint.backup_range */
+	sc->tpinfo.reach = 0x0a;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
+	    trackpoint_sysctl, "I",
+	    "Backup range");
+
+	/* hw.psm.trackpoint.drag_hysteresis */
+	sc->tpinfo.draghys = 0xff;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
+	    trackpoint_sysctl, "I",
+	    "Drag hysteresis");
+
+	/* hw.psm.trackpoint.minimum_drag */
+	sc->tpinfo.mindrag = 0x14;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
+	    trackpoint_sysctl, "I",
+	    "Minimum drag");
+
+	/* hw.psm.trackpoint.up_threshold */
+	sc->tpinfo.upthresh = 0xff;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
+	    trackpoint_sysctl, "I",
+	    "Up threshold for release");
+
+	/* hw.psm.trackpoint.threshold */
+	sc->tpinfo.threshold = 0x08;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_THRESHOLD,
+	    trackpoint_sysctl, "I",
+	    "Threshold");
+
+	/* hw.psm.trackpoint.jenks_curvature */
+	sc->tpinfo.jenks = 0x87;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
+	    trackpoint_sysctl, "I",
+	    "Jenks curvature");
+
+	/* hw.psm.trackpoint.z_time */
+	sc->tpinfo.ztime = 0x26;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_Z_TIME,
+	    trackpoint_sysctl, "I",
+	    "Z time constant");
+
+	/* hw.psm.trackpoint.press_to_select */
+	sc->tpinfo.pts = 0x00;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
+	    trackpoint_sysctl, "I",
+	    "Press to Select");
+
+	/* hw.psm.trackpoint.skip_backups */
+	sc->tpinfo.skipback = 0x00;
+	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
+	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
+	    "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
+	    sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
+	    trackpoint_sysctl, "I",
+	    "Skip backups from drags");
+}
+
+static int
+enable_trackpoint(struct psm_softc *sc)
+{
+	KBDC kbdc;
+	int id;
+
+	if (!trackpoint_support)
+		return (FALSE);
+
+	kbdc = sc->kbdc;
+	sc->hw.buttons = 3;
+
+	if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
+	    read_aux_data(kbdc) != 0x01 ||
+	    (id = read_aux_data(kbdc)) < 0x01)
+		return (FALSE);
+
+	sc->hw.hwid = id;
+
+	if (sc->tpinfo.sysctl_tree == NULL) {
+		trackpoint_sysctl_create_tree(sc);
+	} else { 
+		/*
+		 * If the tree already exist, then we are after a suspend/resume
+		 * cycle and the TrackPoint is reset to defaults. So we  have to 
+		 * set the stored values.
+		 */
+		trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
+		trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
+		trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
+		trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
+		trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
+		trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
+		trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
+		trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
+		trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
+		trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
+		if (sc->tpinfo.pts == 0x01)
+			trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
+		if (sc->tpinfo.skipback == 0x01)
+			trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
+	}
+
+	/*
+	 * TrackPoint will have to be reinitialized after
+	 * suspend/resume.
+	 */
+	sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
+	return (TRUE);
+}
+
 /*
  * Return true if 'now' is earlier than (start + (secs.usecs)).
  * Now may be NULL and the function will fetch the current time from
--- sys/sys/mouse.h.orig	2009-08-03 10:13:06.000000000 +0200
+++ sys/sys/mouse.h	2010-05-26 21:54:38.000000000 +0200
@@ -141,6 +141,7 @@
 #define MOUSE_MODEL_4D			11
 #define MOUSE_MODEL_4DPLUS		12
 #define MOUSE_MODEL_SYNAPTICS		13
+#define MOUSE_MODEL_TRACKPOINT		14
 
 typedef struct mousemode {
 	int protocol;		/* MOUSE_PROTO_XXX */
@@ -211,6 +212,9 @@
 /* Synaptics Touchpad */
 #define MOUSE_SYNAPTICS_PACKETSIZE	6	/* '3' works better */
 
+/* IBM/Lenovo TrackPoint */
+#define MOUSE_TRACKPOINT_PACKETSIZE	3
+
 /* Microsoft Serial mouse data packet */
 #define MOUSE_MSS_PACKETSIZE	3
 #define MOUSE_MSS_SYNCMASK	0x40


>Release-Note:
>Audit-Trail:

From: Lars Engels <lars.engels@0x20.net>
To: bug-followup@FreeBSD.org
Cc: Tamas Szakaly <sghctoma@gmail.com>
Subject: Re: kern/147237: [psm] [patch] There is no IBM/Lenovo TrackPoint
 support in psm driver
Date: Tue, 28 Aug 2012 11:23:15 +0200

 --NT59pYSnj1ZLVgEN
 Content-Type: multipart/mixed; boundary="lBqJz4CGKwlWe7/k"
 Content-Disposition: inline
 
 
 --lBqJz4CGKwlWe7/k
 Content-Type: text/plain; charset=utf-8
 Content-Disposition: inline
 
 Hi Tamas,
 
 thanks a lot for the patch. Attached is an updated version that works
 more or less for me.
 
 The problem is that when PSM_CONFIG_INITAFTERSUSPEND is added to
 sc->config my X200 hangs when I resume. Without INITAFTERSUSPEND
 resuming works, but the trackpoint's config is reset to its default
 values.
 
 Another issue I have on a T61 is that this one also has a Synaptics
 touchpad and I added hw.psm.synaptics_support=1 and
 hw.psm.trackpoint_support=1 to loader.conf.
 As the synaptics devices is matched first, it the trackpoint function is
 never run.
 
 
 
 --lBqJz4CGKwlWe7/k
 Content-Type: text/x-diff; charset=utf-8
 Content-Disposition: attachment; filename="psm_trackpoint.diff"
 Content-Transfer-Encoding: quoted-printable
 
 Index: sys/dev/atkbdc/psm.c
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 --- sys/dev/atkbdc/psm.c	(revision 238992)
 +++ sys/dev/atkbdc/psm.c	(working copy)
 @@ -256,6 +256,38 @@
  	int			in_vscroll;
  } synapticsaction_t;
 =20
 +enum {
 +	TRACKPOINT_SYSCTL_SENSITIVITY,
 +	TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
 +	TRACKPOINT_SYSCTL_UPPER_PLATEAU,
 +	TRACKPOINT_SYSCTL_BACKUP_RANGE,
 +	TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
 +	TRACKPOINT_SYSCTL_MINIMUM_DRAG,
 +	TRACKPOINT_SYSCTL_UP_THRESHOLD,
 +	TRACKPOINT_SYSCTL_THRESHOLD,
 +	TRACKPOINT_SYSCTL_JENKS_CURVATURE,
 +	TRACKPOINT_SYSCTL_Z_TIME,
 +	TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
 +	TRACKPOINT_SYSCTL_SKIP_BACKUPS
 +};
 +
 +typedef struct trackpointinfo {
 +	struct sysctl_ctx_list sysctl_ctx;
 +	struct sysctl_oid *sysctl_tree;
 +	int	sensitivity;
 +	int	inertia;
 +	int	uplateau;
 +	int	reach;
 +	int	draghys;
 +	int	mindrag;
 +	int	upthresh;
 +	int	threshold;
 +	int	jenks;
 +	int	ztime;
 +	int	pts;
 +	int	skipback;
 +} trackpointinfo_t;
 +
  /* driver control block */
  struct psm_softc {		/* Driver status information */
  	int		unit;
 @@ -270,6 +302,7 @@
  	synapticshw_t	synhw;		/* Synaptics hardware information */
  	synapticsinfo_t	syninfo;	/* Synaptics configuration */
  	synapticsaction_t synaction;	/* Synaptics action context */
 +	trackpointinfo_t tpinfo;	/* IBM/Lenovo TrackPoint configuration*/
  	mousemode_t	mode;		/* operation mode */
  	mousemode_t	dflt_mode;	/* default operation mode */
  	mousestatus_t	status;		/* accumulated mouse movement */
 @@ -340,6 +373,9 @@
  static int synaptics_support =3D 0;
  TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
 =20
 +static int trackpoint_support =3D 0;
 +TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
 +
  static int verbose =3D PSM_DEBUG;
  TUNABLE_INT("debug.psm.loglevel", &verbose);
 =20
 @@ -429,6 +465,7 @@
  static probefunc_t	enable_mmanplus;
  static probefunc_t	enable_synaptics;
  static probefunc_t	enable_versapad;
 +static probefunc_t	enable_trackpoint;
 =20
  static struct {
  	int		model;
 @@ -462,6 +499,8 @@
  	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
  	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
  	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
 +	{ MOUSE_MODEL_TRACKPOINT,	/* IBM/Lenovo TrackPoint*/
 +	  0xc0, MOUSE_TRACKPOINT_PACKETSIZE, enable_trackpoint },
  	{ MOUSE_MODEL_GENERIC,
  	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
  };
 @@ -704,6 +743,7 @@
  		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
  		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
  		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
 +		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
  		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
  	};
  	int i;
 @@ -3434,6 +3474,7 @@
  				goto next;
  			break;
 =20
 +		case MOUSE_MODEL_TRACKPOINT:
  		case MOUSE_MODEL_GENERIC:
  		default:
  			break;
 @@ -4487,6 +4528,285 @@
  	return (TRUE);				/* PS/2 absolute mode */
  }
 =20
 +/* IBM/Lenovo TrackPoint */
 +static int
 +trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
 +{
 +	if (send_aux_command(kbdc, 0xe2) !=3D PSM_ACK ||
 +	    send_aux_command(kbdc, cmd) !=3D PSM_ACK ||
 +	    send_aux_command(kbdc, loc) !=3D PSM_ACK ||
 +	    send_aux_command(kbdc, val) !=3D PSM_ACK)
 +		return (EIO);
 +
 +	return (0);
 +}
 +
 +static int
 +trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
 +{
 +	int error, cmd, loc, mask, max, *oldvalp;
 +	struct psm_softc *sc =3D arg1;
 +
 +	loc =3D 0;
 +	mask =3D 0;
 +	oldvalp =3D NULL;
 +
 +	/*
 +	 * The value of cmd and max will be 0x81 and 255 respectively for
 +	 * the majority of cases, so we set them outside the switch, and
 +	 * change them only when needed.
 +	 */
 +	cmd =3D 0x81;
 +	max =3D 255;
 +
 +	switch (arg2) {
 +	case TRACKPOINT_SYSCTL_SENSITIVITY:
 +		loc =3D 0x4a;
 +		oldvalp =3D &sc->tpinfo.sensitivity;
 +		break;
 +	case TRACKPOINT_SYSCTL_NEGATIVE_INERTIA:
 +		loc =3D 0x4d;
 +		oldvalp =3D &sc->tpinfo.inertia;
 +		break;
 +	case TRACKPOINT_SYSCTL_UPPER_PLATEAU:
 +		loc =3D 0x60;
 +		oldvalp =3D &sc->tpinfo.uplateau;
 +		break;
 +	case TRACKPOINT_SYSCTL_BACKUP_RANGE:
 +		loc =3D 0x57;
 +		oldvalp =3D &sc->tpinfo.reach;
 +		break;
 +	case TRACKPOINT_SYSCTL_DRAG_HYSTERESIS:
 +		loc =3D 0x58;
 +		oldvalp =3D &sc->tpinfo.draghys;
 +		break;
 +	case TRACKPOINT_SYSCTL_MINIMUM_DRAG:
 +		loc =3D 0x59;
 +		oldvalp =3D &sc->tpinfo.mindrag;
 +		break;
 +	case TRACKPOINT_SYSCTL_UP_THRESHOLD:
 +		loc =3D 0x5a;
 +		oldvalp =3D &sc->tpinfo.upthresh;
 +		break;
 +	case TRACKPOINT_SYSCTL_THRESHOLD:
 +		loc =3D 0x5c;
 +		oldvalp =3D &sc->tpinfo.threshold;
 +		break;
 +	case TRACKPOINT_SYSCTL_JENKS_CURVATURE:
 +		loc =3D 0x5d;
 +		oldvalp =3D &sc->tpinfo.jenks;
 +		break;
 +	case TRACKPOINT_SYSCTL_Z_TIME:
 +		loc =3D 0x5e;
 +		oldvalp =3D &sc->tpinfo.ztime;
 +		break;
 +	case TRACKPOINT_SYSCTL_PRESS_TO_SELECT:
 +		cmd =3D 0x47;
 +		loc =3D 0x2c;
 +		mask =3D 0x01;
 +		max =3D 1;
 +		oldvalp =3D &sc->tpinfo.pts;
 +		break;
 +	case TRACKPOINT_SYSCTL_SKIP_BACKUPS:
 +		cmd =3D 0x47;
 +		loc =3D 0x2d;
 +		mask =3D 0x08;
 +		max =3D 1;
 +		oldvalp =3D &sc->tpinfo.skipback;
 +		break;
 +	default:
 +		return (1);
 +		/* NOTREACHED */
 +	}
 +
 +	int newval =3D *oldvalp;
 +	if ((error =3D sysctl_handle_int(oidp, &newval, 0, req)) !=3D 0)
 +		return error;
 +
 +	if (newval =3D=3D *oldvalp)
 +		return (0);
 +
 +	if (newval < 0 || newval > max)
 +		return (EINVAL);
 +
 +	if ((error =3D trackpoint_command(sc->kbdc, cmd, loc,
 +			mask ? mask : newval)) !=3D 0)
 +		return (error);
 +	else
 +		*oldvalp =3D newval;
 +
 +	return (error);
 +}
 +
 +static void
 +trackpoint_sysctl_create_tree(struct psm_softc *sc)
 +{
 +	/* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
 +	sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
 +	sc->tpinfo.sysctl_tree =3D SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
 +	    0, "IBM/Lenovo TrackPoint");
 +
 +	/* hw.psm.trackpoint.sensitivity */
 +	sc->tpinfo.sensitivity =3D 0x64;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_SENSITIVITY,
 +	    trackpoint_sysctl, "I",
 +	    "Sensitivity");
 +
 +	/* hw.psm.trackpoint.negative_inertia */
 +	sc->tpinfo.inertia =3D 0x06;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
 +	    trackpoint_sysctl, "I",
 +	    "Negative inertia factor");
 +
 +	/* hw.psm.trackpoint.upper_plateau */
 +	sc->tpinfo.uplateau =3D 0x61;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
 +	    trackpoint_sysctl, "I",
 +	    "Transfer function upper plateau speed");
 +
 +	/* hw.psm.trackpoint.backup_range */
 +	sc->tpinfo.reach =3D 0x0a;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
 +	    trackpoint_sysctl, "I",
 +	    "Backup range");
 +
 +	/* hw.psm.trackpoint.drag_hysteresis */
 +	sc->tpinfo.draghys =3D 0xff;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
 +	    trackpoint_sysctl, "I",
 +	    "Drag hysteresis");
 +
 +	/* hw.psm.trackpoint.minimum_drag */
 +	sc->tpinfo.mindrag =3D 0x14;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
 +	    trackpoint_sysctl, "I",
 +	    "Minimum drag");
 +
 +	/* hw.psm.trackpoint.up_threshold */
 +	sc->tpinfo.upthresh =3D 0xff;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
 +	    trackpoint_sysctl, "I",
 +	    "Up threshold for release");
 +
 +	/* hw.psm.trackpoint.threshold */
 +	sc->tpinfo.threshold =3D 0x08;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_THRESHOLD,
 +	    trackpoint_sysctl, "I",
 +	    "Threshold");
 +
 +	/* hw.psm.trackpoint.jenks_curvature */
 +	sc->tpinfo.jenks =3D 0x87;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
 +	    trackpoint_sysctl, "I",
 +	    "Jenks curvature");
 +
 +	/* hw.psm.trackpoint.z_time */
 +	sc->tpinfo.ztime =3D 0x26;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_Z_TIME,
 +	    trackpoint_sysctl, "I",
 +	    "Z time constant");
 +
 +	/* hw.psm.trackpoint.press_to_select */
 +	sc->tpinfo.pts =3D 0x00;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
 +	    trackpoint_sysctl, "I",
 +	    "Press to Select");
 +
 +	/* hw.psm.trackpoint.skip_backups */
 +	sc->tpinfo.skipback =3D 0x00;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
 +	    trackpoint_sysctl, "I",
 +	    "Skip backups from drags");
 +}
 +
 +static int
 +enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
 +{
 +	int id;
 +
 +	if (!trackpoint_support)
 +		return (FALSE);
 +
 +	kbdc =3D sc->kbdc;
 +	sc->hw.buttons =3D 3;
 +
 +	if (send_aux_command(kbdc, 0xe1) !=3D PSM_ACK ||
 +	    read_aux_data(kbdc) !=3D 0x01 ||
 +	    (id =3D read_aux_data(kbdc)) < 0x01)
 +		return (FALSE);
 +
 +	sc->hw.hwid =3D id;
 +
 +	if (sc->tpinfo.sysctl_tree =3D=3D NULL) {
 +		trackpoint_sysctl_create_tree(sc);
 +	} else {=20
 +		/*
 +		 * If the tree already exist, then we are after a suspend/resume
 +		 * cycle and the TrackPoint is reset to defaults. So we  have to=20
 +		 * set the stored values.
 +		 */
 +		trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
 +		trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
 +		trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
 +		trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
 +		trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
 +		trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
 +		trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
 +		trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
 +		trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
 +		trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
 +		if (sc->tpinfo.pts =3D=3D 0x01)
 +			trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
 +		if (sc->tpinfo.skipback =3D=3D 0x01)
 +			trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
 +	}
 +
 +	/*
 +	 * TrackPoint will have to be reinitialized after
 +	 * suspend/resume.
 +	 */
 +	sc->config |=3D PSM_CONFIG_HOOKRESUME;
 +
 +	return (TRUE);
 +}
 +
  /*
   * Return true if 'now' is earlier than (start + (secs.usecs)).
   * Now may be NULL and the function will fetch the current time from
 
 --lBqJz4CGKwlWe7/k--
 
 --NT59pYSnj1ZLVgEN
 Content-Type: application/pgp-signature
 
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (FreeBSD)
 
 iEYEARECAAYFAlA8jgIACgkQKc512sD3afjPbQCghVNuvB5HKSY0YRVuGXI/9XxM
 z+cAn30fkkvBbk98kUuUeCqvWk6TkDf5
 =w8rU
 -----END PGP SIGNATURE-----
 
 --NT59pYSnj1ZLVgEN--
Responsible-Changed-From-To: freebsd-bugs->jkim 
Responsible-Changed-By: jkim 
Responsible-Changed-When: Mon Mar 18 22:50:18 UTC 2013 
Responsible-Changed-Why:  
I'll take it. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/147237: commit references a PR
Date: Mon, 18 Mar 2013 23:23:02 +0000 (UTC)

 Author: jkim
 Date: Mon Mar 18 23:22:47 2013
 New Revision: 248478
 URL: http://svnweb.freebsd.org/changeset/base/248478
 
 Log:
   Add preliminary support for IBM/Lenovo TrackPoint.
   
   PR:		kern/147237 (based on the initial patch for 8.x)
   Tested by:	glebius (device detection and suspend/resume)
   MFC after:	1 month
 
 Modified:
   head/share/man/man4/psm.4
   head/sys/dev/atkbdc/psm.c
   head/sys/sys/mouse.h
   head/usr.sbin/moused/moused.c
 
 Modified: head/share/man/man4/psm.4
 ==============================================================================
 --- head/share/man/man4/psm.4	Mon Mar 18 22:38:30 2013	(r248477)
 +++ head/share/man/man4/psm.4	Mon Mar 18 23:22:47 2013	(r248478)
 @@ -26,7 +26,7 @@
  .\"
  .\" $FreeBSD$
  .\"
 -.Dd March 27, 2012
 +.Dd March 18, 2013
  .Dt PSM 4
  .Os
  .Sh NAME
 @@ -339,6 +339,12 @@ at boot-time.
  This will enable
  .Nm
  to handle packets from guest devices (sticks) and extra buttons.
 +Similarly, extended support for IBM/Lenovo TrackPoint can be enabled
 +by setting
 +.Va hw.psm.trackpoint_support
 +to
 +.Em 1
 +at boot-time.
  .Pp
  Tap and drag gestures can be disabled by setting
  .Va hw.psm.tap_enabled
 @@ -832,8 +838,8 @@ In contrast, some pad products, e.g.\& s
  and Interlink VersaPad, treat the tapping action
  as fourth button events.
  .Pp
 -It is reported that ALPS GlidePoint, Synaptics Touchpad, and
 -Interlink VersaPad require
 +It is reported that ALPS GlidePoint, Synaptics Touchpad, IBM/Lenovo
 +TrackPoint, and Interlink VersaPad require
  .Em INITAFTERSUSPEND
  flag in order to recover from suspended state.
  This flag is automatically set when one of these devices is detected by the
 
 Modified: head/sys/dev/atkbdc/psm.c
 ==============================================================================
 --- head/sys/dev/atkbdc/psm.c	Mon Mar 18 22:38:30 2013	(r248477)
 +++ head/sys/dev/atkbdc/psm.c	Mon Mar 18 23:22:47 2013	(r248478)
 @@ -260,6 +260,38 @@ typedef struct synapticsaction {
  	int			in_vscroll;
  } synapticsaction_t;
  
 +enum {
 +	TRACKPOINT_SYSCTL_SENSITIVITY,
 +	TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
 +	TRACKPOINT_SYSCTL_UPPER_PLATEAU,
 +	TRACKPOINT_SYSCTL_BACKUP_RANGE,
 +	TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
 +	TRACKPOINT_SYSCTL_MINIMUM_DRAG,
 +	TRACKPOINT_SYSCTL_UP_THRESHOLD,
 +	TRACKPOINT_SYSCTL_THRESHOLD,
 +	TRACKPOINT_SYSCTL_JENKS_CURVATURE,
 +	TRACKPOINT_SYSCTL_Z_TIME,
 +	TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
 +	TRACKPOINT_SYSCTL_SKIP_BACKUPS
 +};
 +
 +typedef struct trackpointinfo {
 +	struct sysctl_ctx_list sysctl_ctx;
 +	struct sysctl_oid *sysctl_tree;
 +	int	sensitivity;
 +	int	inertia;
 +	int	uplateau;
 +	int	reach;
 +	int	draghys;
 +	int	mindrag;
 +	int	upthresh;
 +	int	threshold;
 +	int	jenks;
 +	int	ztime;
 +	int	pts;
 +	int	skipback;
 +} trackpointinfo_t;
 +
  /* driver control block */
  struct psm_softc {		/* Driver status information */
  	int		unit;
 @@ -274,6 +306,8 @@ struct psm_softc {		/* Driver status inf
  	synapticshw_t	synhw;		/* Synaptics hardware information */
  	synapticsinfo_t	syninfo;	/* Synaptics configuration */
  	synapticsaction_t synaction;	/* Synaptics action context */
 +	int		tphw;		/* TrackPoint hardware information */
 +	trackpointinfo_t tpinfo;	/* TrackPoint configuration */
  	mousemode_t	mode;		/* operation mode */
  	mousemode_t	dflt_mode;	/* default operation mode */
  	mousestatus_t	status;		/* accumulated mouse movement */
 @@ -344,6 +378,9 @@ TUNABLE_INT("hw.psm.tap_enabled", &tap_e
  static int synaptics_support = 0;
  TUNABLE_INT("hw.psm.synaptics_support", &synaptics_support);
  
 +static int trackpoint_support = 0;
 +TUNABLE_INT("hw.psm.trackpoint_support", &trackpoint_support);
 +
  static int verbose = PSM_DEBUG;
  TUNABLE_INT("debug.psm.loglevel", &verbose);
  
 @@ -432,6 +469,7 @@ static probefunc_t	enable_4dmouse;
  static probefunc_t	enable_4dplus;
  static probefunc_t	enable_mmanplus;
  static probefunc_t	enable_synaptics;
 +static probefunc_t	enable_trackpoint;
  static probefunc_t	enable_versapad;
  
  static struct {
 @@ -466,6 +504,8 @@ static struct {
  	  0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse },
  	{ MOUSE_MODEL_VERSAPAD,		/* Interlink electronics VersaPad */
  	  0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad },
 +	{ MOUSE_MODEL_TRACKPOINT,	/* IBM/Lenovo TrackPoint */
 +	  0xc0, MOUSE_PS2_PACKETSIZE, enable_trackpoint },
  	{ MOUSE_MODEL_GENERIC,
  	  0xc0, MOUSE_PS2_PACKETSIZE, NULL },
  };
 @@ -708,6 +748,7 @@ model_name(int model)
  		{ MOUSE_MODEL_4DPLUS,		"4D+ Mouse" },
  		{ MOUSE_MODEL_SYNAPTICS,	"Synaptics Touchpad" },
  		{ MOUSE_MODEL_GENERIC,		"Generic PS/2 mouse" },
 +		{ MOUSE_MODEL_TRACKPOINT,	"IBM/Lenovo TrackPoint" },
  		{ MOUSE_MODEL_UNKNOWN,		"Unknown" },
  	};
  	int i;
 @@ -1452,7 +1493,7 @@ psmattach(device_t dev)
  		sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
  		break;
  	default:
 -		if (sc->synhw.infoMajor >= 4)
 +		if (sc->synhw.infoMajor >= 4 || sc->tphw > 0)
  			sc->config |= PSM_CONFIG_INITAFTERSUSPEND;
  		break;
  	}
 @@ -3442,6 +3483,7 @@ psmsoftintr(void *arg)
  				goto next;
  			break;
  
 +		case MOUSE_MODEL_TRACKPOINT:
  		case MOUSE_MODEL_GENERIC:
  		default:
  			break;
 @@ -4474,6 +4516,233 @@ enable_synaptics(KBDC kbdc, struct psm_s
  	return (TRUE);
  }
  
 +/* IBM/Lenovo TrackPoint */
 +static int
 +trackpoint_command(KBDC kbdc, int cmd, int loc, int val)
 +{
 +	const int seq[] = { 0xe2, cmd, loc, val };
 +	int i;
 +
 +	for (i = 0; i < nitems(seq); i++)
 +		if (send_aux_command(kbdc, seq[i]) != PSM_ACK)
 +			return (EIO);
 +	return (0);
 +}
 +
 +#define	PSM_TPINFO(x)	offsetof(struct psm_softc, tpinfo.x)
 +#define	TPMASK		0
 +#define	TPLOC		1
 +#define	TPINFO		2
 +
 +static int
 +trackpoint_sysctl(SYSCTL_HANDLER_ARGS)
 +{
 +	static const int data[][3] = {
 +		{ 0x00, 0x4a, PSM_TPINFO(sensitivity) },
 +		{ 0x00, 0x4d, PSM_TPINFO(inertia) },
 +		{ 0x00, 0x60, PSM_TPINFO(uplateau) },
 +		{ 0x00, 0x57, PSM_TPINFO(reach) },
 +		{ 0x00, 0x58, PSM_TPINFO(draghys) },
 +		{ 0x00, 0x59, PSM_TPINFO(mindrag) },
 +		{ 0x00, 0x5a, PSM_TPINFO(upthresh) },
 +		{ 0x00, 0x5c, PSM_TPINFO(threshold) },
 +		{ 0x00, 0x5d, PSM_TPINFO(jenks) },
 +		{ 0x00, 0x5e, PSM_TPINFO(ztime) },
 +		{ 0x01, 0x2c, PSM_TPINFO(pts) },
 +		{ 0x08, 0x2d, PSM_TPINFO(skipback) }
 +	};
 +	struct psm_softc *sc;
 +	int error, newval, *oldvalp;
 +	const int *tp;
 +
 +	if (arg1 == NULL || arg2 < 0 || arg2 >= nitems(data))
 +		return (EINVAL);
 +	sc = arg1;
 +	tp = data[arg2];
 +	oldvalp = (int *)((intptr_t)sc + tp[TPINFO]);
 +	newval = *oldvalp;
 +	error = sysctl_handle_int(oidp, &newval, 0, req);
 +	if (error != 0)
 +		return (error);
 +	if (newval == *oldvalp)
 +		return (0);
 +	if (newval < 0 || newval > (tp[TPMASK] == 0 ? 255 : 1))
 +		return (EINVAL);
 +	error = trackpoint_command(sc->kbdc, tp[TPMASK] == 0 ? 0x81 : 0x47,
 +	    tp[TPLOC], tp[TPMASK] == 0 ? newval : tp[TPMASK]);
 +	if (error != 0)
 +		return (error);
 +	*oldvalp = newval;
 +
 +	return (0);
 +}
 +
 +static void
 +trackpoint_sysctl_create_tree(struct psm_softc *sc)
 +{
 +
 +	if (sc->tpinfo.sysctl_tree != NULL)
 +		return;
 +
 +	/* Attach extra trackpoint sysctl nodes under hw.psm.trackpoint */
 +	sysctl_ctx_init(&sc->tpinfo.sysctl_ctx);
 +	sc->tpinfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "trackpoint", CTLFLAG_RD,
 +	    0, "IBM/Lenovo TrackPoint");
 +
 +	/* hw.psm.trackpoint.sensitivity */
 +	sc->tpinfo.sensitivity = 0x64;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "sensitivity", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_SENSITIVITY,
 +	    trackpoint_sysctl, "I",
 +	    "Sensitivity");
 +
 +	/* hw.psm.trackpoint.negative_inertia */
 +	sc->tpinfo.inertia = 0x06;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "negative_inertia", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_NEGATIVE_INERTIA,
 +	    trackpoint_sysctl, "I",
 +	    "Negative inertia factor");
 +
 +	/* hw.psm.trackpoint.upper_plateau */
 +	sc->tpinfo.uplateau = 0x61;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "upper_plateau", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_UPPER_PLATEAU,
 +	    trackpoint_sysctl, "I",
 +	    "Transfer function upper plateau speed");
 +
 +	/* hw.psm.trackpoint.backup_range */
 +	sc->tpinfo.reach = 0x0a;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "backup_range", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_BACKUP_RANGE,
 +	    trackpoint_sysctl, "I",
 +	    "Backup range");
 +
 +	/* hw.psm.trackpoint.drag_hysteresis */
 +	sc->tpinfo.draghys = 0xff;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "drag_hysteresis", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_DRAG_HYSTERESIS,
 +	    trackpoint_sysctl, "I",
 +	    "Drag hysteresis");
 +
 +	/* hw.psm.trackpoint.minimum_drag */
 +	sc->tpinfo.mindrag = 0x14;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "minimum_drag", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_MINIMUM_DRAG,
 +	    trackpoint_sysctl, "I",
 +	    "Minimum drag");
 +
 +	/* hw.psm.trackpoint.up_threshold */
 +	sc->tpinfo.upthresh = 0xff;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "up_threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_UP_THRESHOLD,
 +	    trackpoint_sysctl, "I",
 +	    "Up threshold for release");
 +
 +	/* hw.psm.trackpoint.threshold */
 +	sc->tpinfo.threshold = 0x08;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "threshold", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_THRESHOLD,
 +	    trackpoint_sysctl, "I",
 +	    "Threshold");
 +
 +	/* hw.psm.trackpoint.jenks_curvature */
 +	sc->tpinfo.jenks = 0x87;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "jenks_curvature", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_JENKS_CURVATURE,
 +	    trackpoint_sysctl, "I",
 +	    "Jenks curvature");
 +
 +	/* hw.psm.trackpoint.z_time */
 +	sc->tpinfo.ztime = 0x26;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "z_time", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_Z_TIME,
 +	    trackpoint_sysctl, "I",
 +	    "Z time constant");
 +
 +	/* hw.psm.trackpoint.press_to_select */
 +	sc->tpinfo.pts = 0x00;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "press_to_select", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_PRESS_TO_SELECT,
 +	    trackpoint_sysctl, "I",
 +	    "Press to Select");
 +
 +	/* hw.psm.trackpoint.skip_backups */
 +	sc->tpinfo.skipback = 0x00;
 +	SYSCTL_ADD_PROC(&sc->tpinfo.sysctl_ctx,
 +	    SYSCTL_CHILDREN(sc->tpinfo.sysctl_tree), OID_AUTO,
 +	    "skip_backups", CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_ANYBODY,
 +	    sc, TRACKPOINT_SYSCTL_SKIP_BACKUPS,
 +	    trackpoint_sysctl, "I",
 +	    "Skip backups from drags");
 +}
 +
 +static int
 +enable_trackpoint(KBDC kbdc, struct psm_softc *sc)
 +{
 +	int id;
 +
 +	kbdc = sc->kbdc;
 +
 +	if (send_aux_command(kbdc, 0xe1) != PSM_ACK ||
 +	    read_aux_data(kbdc) != 0x01)
 +		return (FALSE);
 +	id = read_aux_data(kbdc);
 +	if (id < 0x01)
 +		return (FALSE);
 +	if (sc != NULL)
 +		sc->tphw = id;
 +	if (!trackpoint_support)
 +		return (FALSE);
 +
 +	if (sc != NULL) {
 +		/* Create sysctl tree. */
 +		trackpoint_sysctl_create_tree(sc);
 +
 +		trackpoint_command(kbdc, 0x81, 0x4a, sc->tpinfo.sensitivity);
 +		trackpoint_command(kbdc, 0x81, 0x4d, sc->tpinfo.inertia);
 +		trackpoint_command(kbdc, 0x81, 0x60, sc->tpinfo.uplateau);
 +		trackpoint_command(kbdc, 0x81, 0x57, sc->tpinfo.reach);
 +		trackpoint_command(kbdc, 0x81, 0x58, sc->tpinfo.draghys);
 +		trackpoint_command(kbdc, 0x81, 0x59, sc->tpinfo.mindrag);
 +		trackpoint_command(kbdc, 0x81, 0x5a, sc->tpinfo.upthresh);
 +		trackpoint_command(kbdc, 0x81, 0x5c, sc->tpinfo.threshold);
 +		trackpoint_command(kbdc, 0x81, 0x5d, sc->tpinfo.jenks);
 +		trackpoint_command(kbdc, 0x81, 0x5e, sc->tpinfo.ztime);
 +		if (sc->tpinfo.pts == 0x01)
 +			trackpoint_command(kbdc, 0x47, 0x2c, 0x01);
 +		if (sc->tpinfo.skipback == 0x01)
 +			trackpoint_command(kbdc, 0x47, 0x2d, 0x08);
 +
 +		sc->hw.hwid = id;
 +		sc->hw.buttons = 3;
 +	}
 +
 +	return (TRUE);
 +}
 +
  /* Interlink electronics VersaPad */
  static int
  enable_versapad(KBDC kbdc, struct psm_softc *sc)
 
 Modified: head/sys/sys/mouse.h
 ==============================================================================
 --- head/sys/sys/mouse.h	Mon Mar 18 22:38:30 2013	(r248477)
 +++ head/sys/sys/mouse.h	Mon Mar 18 23:22:47 2013	(r248478)
 @@ -141,6 +141,7 @@ typedef struct synapticshw {
  #define MOUSE_MODEL_4D			11
  #define MOUSE_MODEL_4DPLUS		12
  #define MOUSE_MODEL_SYNAPTICS		13
 +#define	MOUSE_MODEL_TRACKPOINT		14
  
  typedef struct mousemode {
  	int protocol;		/* MOUSE_PROTO_XXX */
 
 Modified: head/usr.sbin/moused/moused.c
 ==============================================================================
 --- head/usr.sbin/moused/moused.c	Mon Mar 18 22:38:30 2013	(r248477)
 +++ head/usr.sbin/moused/moused.c	Mon Mar 18 23:22:47 2013	(r248478)
 @@ -245,6 +245,7 @@ static symtab_t	rmodels[] = {
      { "4D Mouse",		MOUSE_MODEL_4D,			0 },
      { "4D+ Mouse",		MOUSE_MODEL_4DPLUS,		0 },
      { "Synaptics Touchpad",	MOUSE_MODEL_SYNAPTICS,		0 },
 +    { "TrackPoint",		MOUSE_MODEL_TRACKPOINT,		0 },
      { "generic",		MOUSE_MODEL_GENERIC,		0 },
      { NULL,			MOUSE_MODEL_UNKNOWN,		0 },
  };
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jkim 
State-Changed-When: Tue Mar 19 20:53:03 UTC 2013 
State-Changed-Why:  
A patch based on the submission was committed to head as r248478. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=147237 
State-Changed-From-To: patched->closed 
State-Changed-By: jkim 
State-Changed-When: Wed Jun 26 17:26:37 UTC 2013 
State-Changed-Why:  
Merged to stable/9 (r250078 and r250610) some time ago. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=147237 
>Unformatted:
