kern/147237: [psm] [patch] There is no IBM/Lenovo TrackPoint
support in psm driver
Lars Engels
lars.engels at 0x20.net
Tue Aug 28 09:30:04 UTC 2012
The following reply was made to PR kern/147237; it has been noted by GNATS.
From: Lars Engels <lars.engels at 0x20.net>
To: bug-followup at FreeBSD.org
Cc: Tamas Szakaly <sghctoma at 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--
More information about the freebsd-bugs
mailing list