Reverse engineering the Elan KTF2K touchscreen driverWritten by Paul Kocialkowski 3 comments
I recently acquired an Allwinner A13 unbranded tablet in order to port Replicant to it: this platform is well supported by free software (the Linux kenrel and the u-boot bootloader) and there is an active community of developers working on free software for the Allwinner A1x platforms: linux-sunxi.
The tablet I ended up with contains an Elan EKTF2000 touchscreen, but I couldn't find any touchscreen driver for it in the linux-sunxi kernel tree: the source code was just not released, even though it's marked as being GPL-licensed. Moreover, since the tablet is unbranded, there was no one I could contact to request source code. So I asked around, and it turned out that nobody knew about source code that would have been released for that touchscreen. However, the tablet came with Android preinstalled and there was an ektf2k.ko module.
After some research, I finally found a driver for elan ktf2000 touchscreens written by HTC. It seemed to match mine (both use I2C) and preliminary tests revealed that the same protocol (on top of I2C) was used by my touchscreen. However, it was not quite enough to write an usable implementation for my device: as a matter of fact, the returned coordinates from my touchscreen did not match the screen size: it reported values up to 896x576 while the screen size is 800x640. So the whole issue was about figuring out these values (896 and 576) at run time in order to scale down to the actual screen size.
The preinstalled Android system came with a kernel module called ektf2k.so which is the actual driver. When loaded, I saw this message on the kernel logs:
[elan] __fw_packet_handler: x resolution: 576, y resolution: 896
Which meant that this driver had the code to get the values from the touchscreen chip.
I quickly understood how the touchscreen protocol works by reading the HTC driver, and it turned out that requests were arrays of 4 bytes, with the first one set to 0x53 (indicating a request) and the second one set to a particular command (indicating what we request). Now considering that requests are usually static tables that are defined in code (that's the way it's done in the HTC driver), declared at the beginning of the function, I knew that the static array of 4 bytes corresponding to the request for the size I needed to find out was held somewhere in the ektf2k.ko module.
Thanks to objdump, I decompiled the module (it is legal to perform such reverse engineering in Europe) and looked at the assembly code for the function __fw_packet_handler. I clearly saw the different calls to elan_ktf2k_ts_get_data and printk, but no sign of the data packets. I then looked at the .rodata section, that contains, as its name suggests, the read-only data, where the packets would likely be stored. The string “__fw_packet_handler” is stored at offset 0170 In this section. Right before, I found the following data:
0160 53000001 53600000 53630000 53f00001 S...S`..Sc..S...
Looks very much like static arrays of data with the first byte set to 0x53! So I tried issuing requests with the commands 0x00, 0x60, 0x63 and 0xf0 and received the height with 0x60 and the width with 0x63! It was not in the most obvious format but 576 is 0x240 and 896 is 0x380, so it was easy to see that the responses were containing these values.
In the end, I completed my implementation, and I now have a fully working touchscreen (with up to 5 contact points) with the free software kernel!
The patch is: input: Elan KTF2K touchscreen driver with CTP bindings
Update: I recently found the source code that partially matches the kernel module preinstalled in my tablet: ektf2k.c