Some notes on reverse engineering the ELAN TrackPoint firmware, for a future attempt to make it significantly more responsive than it is today on T4XX and T14 Gen X ThinkPads. If you discovered this wondering about similar things, open an issue, let's chat!
The TrackPoint is a keyboard-integrated pointing stick. It's like a minified low-travel version of a joystick found on game controllers. Here I'm specifically looking at the TrackPoint IV, and the variant of it manufactured by ELAN. I disassembled my keyboard, and found out that the controller is labeled 33306B 3900 1944 BG19AX1:
Unfortunately, it is very much undocumented, with just some mentions of people trying to figure out its pinout for modding it into their custom keyboards:
- https://electronics.stackexchange.com/q/562258
- https://reddit.com/r/thinkpad/comments/osjzcn/need_help_identifying_correct_pinouts_for
Because while the TrackPoint concept is great, the implementation kinda sucks, and the issue is probably the ELAN firmware. Look at these evhz results for my glass Synaptics trackpad (running in RMI4 mode), the first value is the event timestamp I've added:
Synaptics TM3418-002: XXXXXXXXXX023916, Latest 134Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX031486, Latest 132Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX038939, Latest 134Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX046312, Latest 135Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX053749, Latest 134Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX061229, Latest 133Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX068678, Latest 134Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX076022, Latest 136Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX083418, Latest 135Hz, Average 134Hz
Synaptics TM3418-002: XXXXXXXXXX090544, Latest 140Hz, Average 134Hz
Perfectly smooth as one would expect, with very little variance around 134 Hz. Now look at the ELAN TrackPoint:
TPPS/2 Elan TrackPoint: XXXXXXXXXX068192, Latest 62Hz, Average 24039Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX079820, Latest 85Hz, Average 24040Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX079827, Latest 142857Hz, Average 26271Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX093325, Latest 74Hz, Average 22366Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX100826, Latest 133Hz, Average 22366Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX187246, Latest 11Hz, Average 22364Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX187255, Latest 111111Hz, Average 24099Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX199586, Latest 81Hz, Average 24098Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX206367, Latest 147Hz, Average 24100Hz
TPPS/2 Elan TrackPoint: XXXXXXXXXX213810, Latest 134Hz, Average 24101Hz
This causes the cursor to stutter significantly, subjectively it feels around a 20 Hz refresh rate. Changing /sys/bus/serio/devices/serio3/{rate,resolution,sensitivity} has no impact.
Well, this is the tricky part. I've not figured out how to mod the firmware yet. But we have the existing (binary) firmware and an open source flashing tool. For now, this just documents what I have found to date.
In my ThinkPad, the ELAN TrackPoint is attached to a PS/2 pass-through port on the Synaptics TrackPad. The input device connections look something like this:
flowchart LR
keyboard(Keyboard) -->|PS/2 KBD| i8042(i8042)
pst(ELAN TrackPoint) -->|PS/2| tp(Synaptics Trackpad)
tp -->|RMI4 I²C| system(System)
tp -->|PS/2 AUX| i8042
i8042 --> system
By default, the Synaptics Trackpad is connected to the system through PS/2 (through the i8042 peripheral). However, setting psmouse.synaptics_intertouch=1 allows Linux to address it directly through a much faster I²C interface using the RMI4 protocol. This protocol has a feature called Function 0x03 (or f03 in Linux), which allows for passing through an external PS/2 peripheral. Unfortunately, documentation for this function is lacking, so the best reference is probably the Linux kernel driver.
It's possible that the Synaptics PS/2 pass-through implementation is to blame for the timing inconsistency, but there has been at least some effort put in to prevent latency, and the pass-through seems to be pretty simple and direct in the first place. I did not observe any timing or parity errors when looking at the PS/2 over RMI4 f03 debug logs via rmi_core.debug_flags=15. Notably, the TrackPoint appears laggy regardless of if the TrackPad is using PS/2 or RMI4.
This leaves the TrackPoint itself as the source of the inconsistent events. Unlike the original TPM754-based hardware, the ELAN TrackPoint has updatable firmware. Lenovo appears to have released a single update, n20g907w, to fix a "long drift issue" (newer updates seem to be the same, but with added Win 11 support).
The update did install, but didn't really change anything on my ThinkPad. More importantly, it extracts the TrackPoint firmware, or more specifically, thee nearly-identical variants of it with minor differences (likely some calibration values):
Additionally, jinglewu/epstps2iap (and my fork for safekeeping) provides us with an open source flashing tool that can read these three firmware files, select the right one, and flash it to the TrackPoint using ELAN's IAP (In-Application Programming) protocol (warning: I haven't tested this tool yet). This flow should be equivalent to the Windows-based updaters distributed by Lenovo.
The next step would be to reverse-engineer the firmware binaries, or more likely, just one of them since they're almost identical. This is the hard part: while the firmware is relatively small (24 KiB), we know almost nothing about the TrackPoint MCU, except that it has IAP-programmable EEPROM/flash memory, a PS/2 interface and presumably some analog inputs for reading the TrackPoint sensors. The markings on the chip seem to give no hints, and disassembling the binaries gives no obvious hints about the compiler or architecture. From the first 512 bytes, we see a bunch of Z8Z8Z8... strings:
00000000: 579e 1a38 5a38 5a38 983f a605 983f a805 W..8Z8Z8.?...?..
00000010: 983f 8205 983f 8405 983f 8605 983f 8805 .?...?...?...?..
00000020: 983f 8a05 5a38 5a38 5a38 5a38 5a38 5a38 .?..Z8Z8Z8Z8Z8Z8
00000030: 5a38 5a38 5a38 5a38 5a38 5a38 5a38 5a38 Z8Z8Z8Z8Z8Z8Z8Z8
00000040: 5a38 5a38 5a38 5a38 5a38 5a38 983f 8c05 Z8Z8Z8Z8Z8Z8.?..
00000050: 983f 8e05 983f 9005 983f 9205 5a38 5a38 .?...?...?..Z8Z8
00000060: 5a38 5a38 983f 9405 983f 9605 983f 9805 Z8Z8.?...?...?..
00000070: 983f 9a05 983f 9c05 983f 9e05 5a38 5a38 .?...?...?..Z8Z8
00000080: 983f a005 983f a205 cb9e 1a38 5a38 5a38 .?...?.....8Z8Z8
00000090: 5a38 5a38 5a38 5a38 5a38 5a38 983f a405 Z8Z8Z8Z8Z8Z8.?..
000000a0: 5a38 5a38 5a38 5a38 5a38 5a38 5a38 5a38 Z8Z8Z8Z8Z8Z8Z8Z8
000000b0: ff63 016b 91b3 ff63 016b 0030 81b0 84c0 .c.k...c.k.0....
000000c0: 1e38 1a38 1a38 1a38 1a38 1a38 1a38 1a38 .8.8.8.8.8.8.8.8
000000d0: 1a38 1a38 1a38 1a38 1a38 1a38 1a38 1a38 .8.8.8.8.8.8.8.8
000000e0: 1a38 1a38 1a38 1a38 1a38 1a38 1a38 1a38 .8.8.8.8.8.8.8.8
000000f0: 1a38 1a38 1a38 1a38 1a38 1a38 1a38 1a38 .8.8.8.8.8.8.8.8
00000100: 1200 0100 0700 8005 6760 8068 8fb0 1260 ........g`.h...`
00000110: be58 0700 0160 be58 0800 0760 be58 0900 .X...`.X...`.X..
00000120: 0060 be58 0000 c8a8 0b78 fd60 2f68 0b59 .`.X.....x.`/h.Y
00000130: 0b5a 2639 aa55 463a cc33 2229 983a c005 .Z&9.UF:.3").:..
00000140: 0060 8fb0 6260 b168 efb0 c8aa 80a8 a0aa .`..b`.h........
00000150: 37c1 7cc1 bdc1 92c1 b0a8 0060 0178 0378 7.|........`.x.x
00000160: 0578 2060 0278 8060 0568 0478 2060 0159 .x `.x.`.h.x `.Y
00000170: ff66 ff6e ff3b dd58 e060 2f68 2cb6 c53e .f.n.;.X.`/h,..>
00000180: 00e1 acb6 ff3b 7a38 1a38 0066 acb6 78a9 .....;z8.8.f..x.
00000190: 1a38 d0ac fd91 a8aa 88a8 0470 2061 2cb6 .8.........p a,.
000001a0: c53e 00e1 acb6 015a 215b ff3b 7a38 1a38 .>.....Z
