diff options
author | jkim <jkim@FreeBSD.org> | 2013-03-18 23:22:47 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2013-03-18 23:22:47 +0000 |
commit | 5ebabf1d3ec364fc2e9df54a9694a9402fb5a8bc (patch) | |
tree | d3fa69410c34a19f9e2d50f1b22f3417136f1d7c | |
parent | 8d05d984e8a9a632b3de9eed9ad8c765b40f88d9 (diff) | |
download | FreeBSD-src-5ebabf1d3ec364fc2e9df54a9694a9402fb5a8bc.zip FreeBSD-src-5ebabf1d3ec364fc2e9df54a9694a9402fb5a8bc.tar.gz |
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
-rw-r--r-- | share/man/man4/psm.4 | 12 | ||||
-rw-r--r-- | sys/dev/atkbdc/psm.c | 271 | ||||
-rw-r--r-- | sys/sys/mouse.h | 1 | ||||
-rw-r--r-- | usr.sbin/moused/moused.c | 1 |
4 files changed, 281 insertions, 4 deletions
diff --git a/share/man/man4/psm.4 b/share/man/man4/psm.4 index ffcd1d5..99835fb 100644 --- a/share/man/man4/psm.4 +++ b/share/man/man4/psm.4 @@ -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.\& some versions of ALPS GlidePoint 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 diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index 7cf6508..f47b717 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -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 information */ 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_enabled); 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_softc *sc) 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) diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h index f8039ae..e0b70ff 100644 --- a/sys/sys/mouse.h +++ b/sys/sys/mouse.h @@ -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 */ diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/moused.c index 93eec99..0e278c4 100644 --- a/usr.sbin/moused/moused.c +++ b/usr.sbin/moused/moused.c @@ -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 }, }; |