ACPI-SSDT0000.ASL - Surface RT
if we take a look at the ACPI table we see several GpioIO functions.
Identifying the Volume keys is easy. We can dump the GPIO-Controller from UEFI shell while a volume key is pressed or released.
Left: Vol-Down pressed; right Vol-Down not pressed
We see that we changed something with a button press. Nice! We see that 1 Byte has changed from 0xC0 to 0x80 at address 0x438 In binary: 1100 0000 -> 1000 0000 => Bit 6 has changed.
Lets take a look at 0x438
0x438 is located on the 5th GPIO Controller and is the input register. check.
Now we know that we changed Pin6 in Port S => Vol-Down is connected to PS6
S is the 19th letter of the Alphabet counting from 1 (A=1, B=2, C=3,...) S is the 18th letter of the Alphabet counting from 0 (A=0, B=1, C=2,...) TRM tells us that every port has 8 pins. So lets multiply 18 by 8 which equals 144 and add our PinOffset: 6 144+6 = 150 Convert 150 from dec to hex: 0x96
There is a Gpio with the number 0x96 it belongs to TEV2/MSHW0003
Windows device-manager screenshot
We can match the 4 GPIOs to the SurfaceHomeButtonDriver. We can see that Windows knows 4 Interrupts. At the moment we dont know how to map the WindowsIRQ to ACPI-IRQ or LinuxIRQ
Linux enumerates GPIO in the same way as ACPI:
portNumber * 8 + pinOffset (+ gpioControllerOffset)(gpioControllerOffset is 0 on tegra 3)
We know that we deal with:
Vol-Down: 0x96 / 150d Vol-Up: 0x97 / 151dWe guess 0x97 because it is a normal shared interrupt. The other 2 interrupts are WakeUp Interrupts which should belong to the Power/WindowsButton
libgpiodin your root filesystem type gpiomon <BUS> <Gpio-Number> Press the button a few times you should see the gpio chaning in realtime
first we must set the pins to GPIO mode. Tegra standard is SFIO mode. 0x6000 d000 is the GPIO Controller base 0x0000 0408 is PortS CNF register. We want to set pin 6/7 to GPIO mode -> 0b1100 0000 -> 0xC0
we can write memory with devmem
devmem 0x6000d408 8 0xC0Now the GPIO Controller treats PS6/7 as GPIO
ls ./should show
export, gpiochip0, unexportgpiochip0 is the gpio controller; 0 tells the offset we can export a pin to userspace
echo 150 > export echo 151 > exportNow we can use PS6/7 check the direction with
cat gpio150/directionit should show
"in"but you can set it with
echo in > gpio150/directionNow we can read the value
cat gpio150/valuethis should return
1if you press VOL-Down it should return
0This tells us that the pin is pulled up and active_low.
Now remove the gpio from userspace that it can be used by drivers again
echo 150 > unexport echo 151 > unexport