I’ve had a few laptops over the years, and one of the first things I do whenever I’ve got a new piece of hardware is open it up.
Well, I live in India, and the environment here is quite dusty, so this act of opening and cleaning happens quite often.
Unfortunately, if you own a laptop with a plastic body, this becomes quite an issue, as plastic body laptops have knurled nuts pushed into the body, the plastic housings of these nuts tend to break over time if you regularly screw and unscrew. them.
This is especially a problem with the screws holding the LCD hinge to the main body, as these tend to break first, I’ve had at least 2 laptops that have broken this way.
So, coming back to the main title of this post, I had an old HP laptop lying around that had a broken hinge nut collecting dust, so I thought, Why not make something useful out of it?
^^ My actual HP laptop :D ^^
So the plan was to use the motherboard as an external PC, encased in a acrylic case with all the RGB shenanigans. What was left were the keyboard, touchpad, and display.
The keyboard was the part of the main body that broke with the hinge, so that’s a goner.
The displays eDP cable pads rusted and broke after being exposed to the bare environment for years.
But somehow, the touchpad was fine and dandy.
The Saviour of Touchpads
So, the time came to reverse engineer the touchpad and hopefully use it in some other useful projects in the future.
There are many ways to approach the problem of reverse engineering hardware.
In our case, we have complete access to the system that we are trying to reverse engineer, which makes our job easy.
We can observe the system from 2 sides:
- The Software
- The Hardware
From the software side, the laptops run Linux, which in itself helps us a lot, We can look into the kernel logs to see how it enumerates all the hardware.
Let’s look into the kernel logs via dmesg and see if something comes up related to our touchpad.
Voila! We can see the psmouse kernel module enumerating a synaptics touchpad, and we can also see the module logs list the max and min. values that the touchpad can output, and a string of possible touchpad IDs that match the one we have.
The beauty of Linux is that almost all of it is open source, including the device drivers, which are a huge chunk of the kernel source.
So we can just look into the source of the corresponding kernel module that enumerated our hardware to see how it works.
Looking at the sources, we can see how the module handles the device initialization, queries the hardware, identifies the capabilities of the device, setting its mode and then receiving packets and sending them forward into the input subsystem.
We also get to see that the module uses the psmouse module sources to actually send and receive packets, so we now know for sure that our touchpad uses the good old PS/2 protocol to communicate with our laptop.
Digging more into this, touchpads actually support 3 protocols to communicate with any system, these can be
- I2C/SMBUS (RMI3/4)
- USB (HID)
Most old models use the PS/2 interface, and the modern ones use I2C / USB to communicate with the system.
Synaptics actually uses the RMI3/RMI4 interface over I2C on newer touchpads.
Now it’s time to look at this from the hardware side.
So this is our touchpad, from the HP Pavillion AU116-TX laptop.
From the back side, we can see a single button at the bottom middle, the main synaptics IC (T1321B) in the middle, an FFC connector and the supporting FFC, and some enamel wires that I have soldered to some test pads.
Looking on the internet for the Synaptics T13221B chip, I could find almost nothing except for some weird Chinese sellers offering the chip.
So, sadly, no datasheet for it.
Probing various test points on the touchpad PCB with my trusted Rigol DS1054Z, I mapped the VCC,GND, DATA, and CLK for the PS/2 interface.
Testpad - FFC pin - SIGNAL
- T23 - pin 4 - GND
- T20 - pin 1 - 3V3
- T12 - pin 2 - DATA
- T11 - pin 3 - CLK
- T10 - pin 5 - 3V3
- T9 - pin 6 - 3V3
One way to know what any piece of hardware is doing is to sniff its communication, The RIGOL is an awesome scope and has in-built protocol decoders for lots of protocols, but unfortunately, PS/2 isn’t one of them.
So I had to do this the old way…
Using the DSO, I captured the data transmission between the touchpad and the laptop, and I got three different segments of data transfer, I exported the capture to a CSV file to further analyse the communication on my PC.
Using MATLAB, we can plot Channel 1 and Channel 2 of the captured data to decode whats happening.
You can see three different sections of communication that are happening.
Zooming in on individual sections, we can decode the packets.
I decoded parts of it, and here is what is happening..
** Possible Probe by BIOS ** 0xF2 -> Read Device Type 0xFA <- ACK 0x00 <- Response ** DELAY ** ** LARGE PACKETS (1) ** 0xF2 -> Read Device Type 0xFA <- ACK 0x00 <- Response 0xF6 -> Set Defaults 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x0A -> DATA 0xFA <- ACK 0xE8 -> Set Resolution 0xFA <- ACK 0x00 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x14 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x3C -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x28 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x14 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x14 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x3C -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x28 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x14 -> DATA 0xFA <- ACK 0xF3 -> Set Sample Rate 0xFA <- ACK 0x14 -> DATA 0xFA <- ACK 0xF2 -> Read Device Type 0xFA <- ACK 0x00 <- Response 0xE8 -> Set Resolution 0xFA <- ACK 0x00 -> DATA 0xFA -> ACK 0xE8 -> Set Resolution 0xFA <- ACK 0x00 -> DATA 0xFA -> ACK 0xE8 -> Set Resolution 0xFA <- ACK 0x00 -> DATA 0xFA -> ACK 0xE8 -> Set Resolution 0xFA <- ACK 0x00 -> DATA 0xFA -> ACK 0xE9 -> Status Request (ACK + 3 BYTE DATA) 0xFA <- ACK 0x01 <- DATA 0x47 <- DATA 0x18 <- DATA 0xFF -> Reset 0xFA <- ACK ** DELAY ** ** LARGE PACKETS (2) ** Further communication done by the Linux kernel module is here, almost the same as above.
Synaptics has a PS/2 touchpad interfacing guide that provides excellent documentation regarding the PS/2 protocol and how to interface. with their touchpads over these protocols, the decoding of packets was based on that documentation.
So basically, once we power up the touchpad, it does a Power On Self Test and recalibrates itself, after that, it sends a completion code of 0xAA00.
After that, we can begin sending commands to the touchpad.
We need to do a few things to set up the touchpad,
- Disable the touchpad reporting.
- Set the touchpad mode byte via the special mode byte set sequence.
- Set resolution
- Set sample rate.
- Enable stream mode
- Enable touchpad reporting.
The touchpad has two modes, absolute mode and relative mode.
Relative mode is the one you might be familiar with because that’s what is usually used by mouse(mice?) to communicate relative movement.
Absolute mode gives you the absolute position of finger on the touchpad.
So now that we know what pins do what, and how the PC initialises the touchpad, we need a way to communicate with the touchpad ourselves, Here comes the RPI-Pico to the rescue.
I hooked the touchpad to a Raspberry Pi Pico and wrote a PS/2 bit-banging library to send and receive packets.
I initialised the touchpad based on the above mentioned method with the mode byte set to absolute mode and data streaming enabled, which means the touchpad would automatically send me packets once a touch has been registered, and there we have it.
Plotting absolute X and Y coordinates
In one of the coming blog posts, I will use machine learning on a microcontroller for number detection using this touchpad.
Stay tuned for that!