Bug 106323 - ALPS SS5 (SS4 v2) trackpoint too fast / jumpy because of readout "hole" in the center
Summary: ALPS SS5 (SS4 v2) trackpoint too fast / jumpy because of readout "hole" in th...
Status: RESOLVED FIXED
Alias: None
Product: Wayland
Classification: Unclassified
Component: libinput (show other bugs)
Version: unspecified
Hardware: x86-64 (AMD64) Linux (All)
: medium major
Assignee: Wayland bug list
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-04-30 10:09 UTC by Martin Wilck
Modified: 2018-06-01 10:27 UTC (History)
2 users (show)

See Also:
i915 platform:
i915 features:


Attachments
results with different scaling approaches (271.60 KB, application/gzip)
2018-05-03 16:00 UTC, Martin Wilck
Details
PATCH: libinput-measure-trackpoint-range: fix typo (764 bytes, patch)
2018-05-16 14:31 UTC, Martin Wilck
Details | Splinter Review
[PATCH] libinput-measure-trackpoint-range: minimum delta (5.48 KB, patch)
2018-05-16 14:38 UTC, Martin Wilck
Details | Splinter Review
0001-udev-default-to-a-trackpoint-range-of-160-for-the-ne.patch (1.00 KB, patch)
2018-05-25 06:38 UTC, Peter Hutterer
Details | Splinter Review
udev: support firmware detection for pointing sticks (2.67 KB, patch)
2018-05-29 07:32 UTC, Martin Wilck
Details | Splinter Review
0001-udev-drop-the-custom-firmware-detection-code-in-favo.patch (5.34 KB, patch)
2018-05-30 00:57 UTC, Peter Hutterer
Details | Splinter Review

Description Martin Wilck 2018-04-30 10:09:22 UTC
On the DELL E7470, the trackpoint (an ALPS SS5  - aka SS4 v2 - DualPoint touch pad / touch stick) is extremely jumpy and fast. libinput sees this device as "AlpsPS/2 ALPS DualPoint Stick". Selecting small entities like letters or words in a terminal is practically impossible. 

I am positive that this effect is always present on the DELL E7470, which is used a lot in our company as workplace laptop. I am not certain about other laptops with this trackpoint model.

The "best" possible set of settings that I've found for current libinput is ENV{LIBINPUT_ATTR_TRACKPOINT_RANGE}="100", the "flat" acceleration profile and a very low accel factor of -0.9 or lower, at the cost of very slow motion for large movements. With the default adaptive acceleration profile, I couldn't get satisfactory results. 

Using the "evdev" driver under X with option "ConstantDevceleration 8" and the linear or polynomial AcccelerationProfile works much better for this device than anything I've achieved with libinput. In former libinput versions, I used to set POINTINGSTICK_CONST_ACCEL=0.1 for this device and had it work almost nicely, and was caught by surprise by the change that dropped support for this tuning parameter.

Closer examination shows that the raw sensor readouts of the device behave in a peculiar way.

Here's a table of raw kernel readouts rX, rY (obtained with trace_printk()) and resulting libinput outputs lX, lY (obtained from "libinput debug-events" with ENV{LIBINPUT_ATTR_TRACKPOINT_RANGE}="100"). rA and lA denote the abolute values of the movement vector, sqrt(rX^2+rY^2) and sqrt(lX^2+lY^2), respectively. (*)

The values below are from a series of *very gentle* trackpoint movements up, right, down, and left. I actually tried to make minimal movements to the extent my fingers are able to.

time     rX  rY   rA     lx      ly       lA 
3244.62  -4  -6    7.2   -0.07   -0.11    0.1
3244.63  -6 -10   11.7   -0.49   -0.78    0.9
3244.65  -7 -13   14.8   -1.49   -2.53    2.9
3244.66  -8 -14   16.1   -3.23   -5.56    6.4
3244.67  -8 -17   18.8   -4.62   -8.61    9.8
3244.69  -8 -18   19.7   -5.59  -11.17   12.5
3244.70  -8 -23   24.4   -6.56  -14.75   16.1
3244.71  -8 -25   26.2   -7.36  -19.09   20.5
3244.72  -8 -25   26.2   -7.36  -20.93   22.2
3244.73  -8 -21   22.5   -7.36  -21.62   22.8

3246.61   6   4    7.2   -3.25  -12.09   12.5
3246.62   6   4    7.2   -0.40   -3.78    3.8
3246.64   7   4    8.1    0.41   -0.33    0.5
3246.65   9   4    9.8    2.35    1.34    2.7
3246.66  12   4   12.6    3.32    1.56    3.7
3246.68  12   6   13.4    4.56    2.05    5.0
3246.69  13   6   14.3    6.00    2.61    6.5
3246.70  15   6   16.2    7.63    3.23    8.3
3246.71  15   7   16.6    8.64    3.93    9.5
3246.73  15   7   16.6    9.58    4.30   10.5
3246.74  15   7   16.6   10.26    4.62   11.3
3246.75  10   7   12.2    8.83    4.49    9.9

3248.41   1   7    7.1    5.29    3.61    6.4
3248.42   1   7    7.1    2.73    2.83    3.9
3248.43  -1   7    7.1    0.86    2.19    2.4
3248.45  -1   7    7.1    0.00    2.04    2.0
3248.46  -1   7    7.1   -0.15    2.04    2.0
3248.47  -2   9    9.2   -0.40    2.37    2.4
3248.49  -4  12   12.6   -0.75    3.27    3.4
3248.50  -6  17   18.0   -1.58    5.48    5.7
3248.51  -7  22   23.1   -3.11    9.82   10.3
3248.53  -7  27   27.9   -5.09   16.55   17.3
3248.53  -7  27   27.9   -6.21   21.39   22.3
3248.55  -6  26   26.7   -6.21   23.46   24.3
3248.56  -5  16   16.8   -5.75   22.08   22.8
3248.57  -2   8    8.2   -4.14   15.93   16.5

3250.16  -7  -2    7.3   -2.70    6.49    7.0
3250.18  -7  -2    7.3   -1.58    1.51    2.2
3250.19  -8  -2    8.2   -1.50    0.13    1.5
3250.20 -12  -3   12.4   -3.11   -0.82    3.2
3250.22 -17  -5   17.7   -5.22   -1.42    5.4
3250.23 -23  -9   24.7   -9.82   -3.11   10.3
3250.24 -26 -13   29.1  -16.95   -6.52   18.2
3250.26 -31 -16   34.9  -22.31   -9.89   24.4
3250.27 -32 -16   35.8  -25.76  -12.42   28.6
3250.28 -30  -9   31.3  -27.37  -12.42   30.1
3250.29 -16  -4   16.5  -25.07  -10.35   27.1

You can see that rA hardly ever drops below 7. I have tested this extensively on this hardware, and it seems to be real - no matter how slightly I touch the stick, the absolute value of the readouts is either 0, or at least 7-8. Without any scaling, this means that the pointer jumps by 8 pixels for even the slightest horizontal and vertical movements, making the pointer impossible to control.

My first idea was to fix this in the kernel by dividing the readouts for X and Y by 8. That makes the device actually work nicely in the first place. But the kernel maintainers essentially recjected the patch, saying that this would cause valuable precision to be cast away. I now reckon that the best way to "fix" this would be dividing the raw readouts by 8.0 in user space before applying any other acceleration or deceleration logic. This what I think the above-mentioned settings of the "evdev" driver do, unless I'm mistaken.

The point is that correction needs to be applied to the all-important small sensor readings which determine the precision for gentle movements. LIBINPUT_ATTR_TRACKPOINT_RANGE doesn't seem to be suitable for this, and neither POINTINGSTICK_SENSITIVITY. I think that LIBINPUT_ATTR_TRACKPOINT_RANGE might work if it wasn't capped at 100. Anyway, the recommended calibration procedure "libinput measure trackpoint-range" doesn't work for this device - firstly it's almost impossible to carry out because the pointer moves much too fast, and secondly the result is too low to make the device work reliably (I made several attempts and measured 40-45, while the "best" setting for this device is 100 or more).
Comment 1 Martin Wilck 2018-04-30 10:31:07 UTC
Side note on documentation:

I'd been fooled by the fact that libinput has dropped support for the tuning parameter POINTINGSTICK_CONST_ACCEL with 1.9. This is actually documented on
https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html, but https://wayland.freedesktop.org/libinput/doc/latest/udev_config.html still lists this property.
Comment 2 Peter Hutterer 2018-05-01 07:20:12 UTC
> This what I think the above-mentioned settings of the "evdev" driver do, unless I'm mistaken.

Yep, that's what the constant deceleration does. 

> firstly it's almost impossible to carry out because the pointer moves much too fast

fwiw, doesn't really matter because the events will still come in from the device. Just push it as if it wasn't moving at some crazy speed because we really just need the realistic pressure values.

The trackpoint curve is in src/filter-trackpoint.c:trackpoint_accel_profile, you can try to put a /8.0 there before returning the factor. Does that work/help?

Unfortunately, the whole trackpoint range thing is oriented towards the ibm trackpoints and doesn't work too well on the alps ones. I have patches here to work around that but they're not complete yet. Either way, unlikely to fix the issue anyway if you need that high of a constant deceleration.
Comment 3 Martin Wilck 2018-05-02 18:58:07 UTC
(In reply to Peter Hutterer from comment #2)

> The trackpoint curve is in src/filter-trackpoint.c:trackpoint_accel_profile,
> you can try to put a /8.0 there before returning the factor. Does that
> work/help?

I don't think that'll work well. Unless I'm mistaken, it's pretty much the same thing as setting the accel factor to -1 or -0.9. It has the effect to make the pointer REALLY slow.

IMO, to get the best of both worlds for small and large movements with this stick type, we need to scale down *before* applying the acceleration profile. That would be the same thing as dividing the filter's "scale_factor" by 8, if I read the code correctly.

Quoting Masaki Ota from the mail thread:

"If we use Touchpad as Absolute mode, Track stick mode is changed to Raw mode from Mouse mode.... But TrackStick Raw mode data is much larger than Mouse mode data. (This is the cause of high speed.)"
Comment 4 Peter Hutterer 2018-05-02 22:27:52 UTC
did you try it? because the basic approach right now is: delta * factor. What the server does is delta * constant_deceleration * factor. So whether you add this to the factor or later doesn't really matter.
... after checking the server sources again: it also appears to multiply the velocity by the constant deceleration, so you'd need to apply this at the top of the function accordingly. 

libinput debug-gui is the best way to test these things, it can be run from the builddir and the pointer is controlled by libinput only, so no need to restart between recompilations.

https://wayland.freedesktop.org/libinput/doc/latest/tools.html
Comment 5 Martin Wilck 2018-05-03 09:08:12 UTC
(In reply to Peter Hutterer from comment #4)
> did you try it? because the basic approach right now is: delta * factor.
> What the server does is delta * constant_deceleration * factor. So whether
> you add this to the factor or later doesn't really matter.

I think it does matter, because if we apply the factor "late", it's applied to the maximum acceleration, too, which is bad. I don't think we should focus on mimicking the behavior of evdev + X; rather we should figure out how to make this device work nicely with libinput. And here we have the fact that the device delivers strange/unusual raw data.

But you're right, I havent't had time to actually try yet.

> libinput debug-gui is the best way to test these things, it can be run from
> the builddir and the pointer is controlled by libinput only, so no need to
> restart between recompilations.

Ah, I didn't know that, thanks. I'll try.
Comment 6 Martin Wilck 2018-05-03 16:00:14 UTC
Created attachment 139319 [details]
results with different scaling approaches

Here are results of my attempts with libinput-debug-gui.

I added some printfs trackpoint_accelerator_filter() in  to obtain the values and plotted the results.

The columns in the text file are 1: unaccelerated->x, 2: unaccelerated->y,
3: scaled.x, 4: scaled.y, 5: delta, 6: f, 7: coords.x, 8: coords.y, where variable names are from trackpoint_accelerator_filter().

The png files are plots of coords.x, coords.y (the final result), delta, and the accel factor f (result of  trackpoint_accel_profile()).
.txt and .png files of the same basename relate to each other.

In every attempt, I first tried to move the pointer from its start position to the square grid figure above left of the start position, and tried as well as I could to place the pointer on one grid point, using gentle movements. Then I made fast movements up and down.

The individual cases are:
 A) accel_factor_8: factor 1/8 applied to the end result of trackpoint_accel_profile(). This was your suggestion if I understood right.
 B) accel_factor_16: likewise, with 1/16

 C) accel_factor_nomax_8: like accel_factor_8, but division by 8 before the min(factor, max_accel) operation.
 D) accel_factor_nomax_16: like accel_factor_nomax_8, with factor 1/16.

 E) scale_factor_8: factor 1/8 applied to raw values in trackpoint_normalize_deltas().

All of this was done without setting LIBINPUT_ATTR_TRACKPOINT_RANGE which was thus at the default. accel_filter->scale_factor was 1 except for (E), where it was effectively 1/8.

In case A) and C), I didn't succeed to place the pointer in the grid as wanted. You can see that the final X,Y values in the plots quickly rise to values >5, making exact pointer placement impossible. B) and D) were better, but still not good. OTOH, in particular in B), the max speed that could be reached for strong movements was noticeably limited. You can see that the factor f is basically constant in case A) and B), so effectively no dynamic acceleration profile is applied.

Subjectively, E) was by far the best scenario. Not a big surprise, it's equivalent to the kernel patch that I'd made. You can see in the picture that the inital X,Y outputs are very small, enabling me to place the pointer exactly where I wanted (presision was better than even in B). Yet big movements were nicely accelerated.
Comment 7 Peter Hutterer 2018-05-10 05:29:40 UTC
Sorry for the delay, I was busy with http://who-t.blogspot.com/2018/05/x-server-pointer-acceleration-analysis-part1.html which is somewhat related to this here.

Thanks for the test results, very helpful. Scaling this down by 8 works for me, I'll try to figure out a generic enough patch that we can use together with a model tag. Do we have any way of detecting this hardware in userspace or do we need to enable this for each model manually?
Comment 8 Peter Hutterer 2018-05-10 06:02:14 UTC
Oh, and just to confirm: if you take the cap out for the range and set the real range for this device, does it work better? The limit of 100 is there because it matches the lenovo trackpoints I managed to test but otherwise it's arbitrary and can be removed.
Comment 9 Pali Rohár 2018-05-10 06:44:16 UTC
ALPS /dev/input/event* devices have:

bustype = BUS_I8042 (0x11)
vendor  = 0x0002
product = PSMOUSE_ALPS (0x8)
version = <protocol_version>

where <protocol_version> is following:

V1	         = 0x100
V2	         =	0x200
V3		        = 0x300
V3_RUSHMORE	= 0x310
V4		        = 0x400
V5		        = 0x500
V6		        = 0x600
V7		        = 0x700	/* t3btl t4s */
V8		        = 0x800	/* SS4btl SS4s */
V9		        = 0x900	/* ss3btl */
Comment 10 Peter Hutterer 2018-05-10 06:58:25 UTC
Forgive me for being dense but which one is SS4v2/SS5?
Comment 11 Pali Rohár 2018-05-10 07:02:31 UTC
It uses V8 protocol.
Comment 12 Martin Wilck 2018-05-16 14:30:24 UTC
Yes, setting LIBINPUT_ATTR_TRACKPOINT_RANGE to 160 (corresponding to a factor 8) or more makes the stick usable.
Comment 13 Martin Wilck 2018-05-16 14:31:09 UTC
Created attachment 139592 [details] [review]
PATCH: libinput-measure-trackpoint-range: fix typo

__bool_ -> __bool__
Comment 14 Martin Wilck 2018-05-16 14:38:38 UTC
Created attachment 139593 [details] [review]
[PATCH] libinput-measure-trackpoint-range: minimum delta

Here's a suggested patch that makes libinput-measure-trackpoint-range better suited for sticks with the characterics of ALPS. It works quite well for me, it comes up with a suggestion of ~150 for the trackpoint range.

Here I assumed that a minimum corrected delta ~ 1 is "precise enough". That may not be true. Subjectively, for me, a range value of 200 or higher works even better for small movements, so the suggestion might actually be corrected so that subpixel movements would be possible. But I'll leave these subtleties to you, as you've much more expertise in the area than myself.
Comment 15 Peter Hutterer 2018-05-25 06:38:21 UTC
Created attachment 139751 [details] [review]
0001-udev-default-to-a-trackpoint-range-of-160-for-the-ne.patch

This one should work to default to this range on all sticks. Can you please verify this?
Comment 16 Martin Wilck 2018-05-29 07:32:14 UTC
Created attachment 139822 [details] [review]
udev: support firmware detection for pointing sticks

Your patch isn't sufficient. I needed this one on top of it, otherwise hwdb lookup by firmware version doesn't work for the stick device.
Comment 17 Pali Rohár 2018-05-29 07:37:22 UTC
I think it is really a bad idea to try detect ALPS by string product name, this is fragile and can slightly change in future. As I said in comment #9 you should look at event "product" that is 0x8 and if you need also ALPS version, then look at "version".
Comment 18 Peter Hutterer 2018-05-29 08:06:08 UTC
good point, that's a follow-up we can merge though. Martin's patch looks good though, I'll get this merged tomorrow. Thanks!
Comment 19 Peter Hutterer 2018-05-30 00:34:56 UTC
commit 198c53650afe63e0cd3cac140b43f372bc6d507b
Author: Martin Wilck <>
Date:   Wed May 16 16:25:12 2018 +0200

     libinput-measure-trackpoint-range: minimum delta measurement

commit c5bfa00760737bfa7456a449a588c84430d0a4aa
Author: Martin Wilck <>
Date:   Tue May 29 09:28:09 2018 +0200

     udev: support firmware detection for pointing sticks

commit 50d8bc722c26a9f2c36f07837ae3196e31851df1
Author: Peter Hutterer <>
Date:   Fri May 25 16:37:05 2018 +1000

     udev: default to a trackpoint range of 160 for the new ALPS trackpoints
Comment 20 Peter Hutterer 2018-05-30 00:57:58 UTC
Created attachment 139839 [details] [review]
0001-udev-drop-the-custom-firmware-detection-code-in-favo.patch

Short of a typo, this should work. Much simpler too :) Can you give this a test please, thanks.
Comment 21 Martin Wilck 2018-05-30 09:07:11 UTC
I didn't grok which typo you were talking about, but the patch from comment 20 works well.
Comment 22 Martin Wilck 2018-05-30 09:32:10 UTC
I created https://github.com/wayland-project/libinput/pull/4 to backport the ALPS fixes to the stable 1.10 branch.

Tested this backport successfully here. I excluded the patch from comment 20 for now, because I thought that's more 1.11 material.
Comment 23 Peter Hutterer 2018-05-30 22:29:14 UTC
Oh, sorry. I meant "unless I introduced a typo, this should work" :) Thanks for testing, I'll get this into 1.11 and the other fixes into 1.10.8, hopefully I'll get to find time to do that one.
Comment 24 Peter Hutterer 2018-06-01 02:38:15 UTC
commit a9ef4ba1f33bf88c273eafd6d5e519e70419450b
Author: Peter Hutterer <>
Date:   Wed May 30 10:50:05 2018 +1000

     udev: drop the custom firmware detection code in favor of a modalias
Comment 25 Martin Wilck 2018-06-01 09:38:42 UTC
My stable backport doesn't work yet. I thought I'd tested it but apparently I tested something else, the udev hwdb lookup fails. Is it possible to debug this somehow, short of running udev under gdb?
Comment 26 Martin Wilck 2018-06-01 10:27:37 UTC
Forget my previous comment. I'd just forgotten to run udevadm hwdb --update.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.