Skip to content

twelho/trackpoint

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

ELAN TrackPoint Firmware Experiments

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!

What?

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:

Top of TrackPoint PCB Bottom of TrackPoint PCB

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:

Why?

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.

How?

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.

Synaptics RMI4

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
Loading

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.

TrackPoint Firmware

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.

Status Quo

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![.;z8.8
000001b0: 0066 acb6 0478 415e 0060 0164 ff3b 824d  .f...xA^.`.d.;.M
000001c0: 015f 0060 ff3b 834a 0732 018a a8a8 a8ac  ._.`.;.J.2......
000001d0: 1092 a0ac 0e92 f03f 0500 057f 9e58 0100  .......?.....X..
000001e0: 1900 be58 0100 d0aa 88aa 0239 5401 078a  ...X.......9T...
000001f0: cf9f 0470 9810 0478 d0aa 88aa c99f 98a8  ...p...x........

This might point to the Zilog Z8, my other shots in the dark would be an 80C51 or some proprietary ELAN architecture, which this manufacturer is infamous for. Chucking the RANKA binary into https://dogbolt.org provided a decomp only for BinaryNinja (out/binary_ninja.c), but it seems nonsensical.

So, if you have the time and skills, I encourage you to look at the binaries. Unfortunately, we don't even have a memory map yet, so this will require a lot of experience-based deduction. If you can provide any additional info, don't hesitate to open an issue!

That's all for now, I might convert this into a blog post at some point. Thanks for reading, here's your reward for reaching the end.

About

ELAN TrackPoint Firmware Experiments

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages