Comment 154 for bug 1887190

Revision history for this message
Coiby Xu (coiby) wrote :

@wangjun

Thank you for sharing the results and investigating this touchpad issue!

One thing confuses me is for the ELAN touchpad, no single interrupt fires when you put finger on the touchpad while for the Synaptics touchpad, you still see interrupts firing but with a very rate of ~7Hz. Judging from the ACPI DSDT tables, different variants of this laptop model share the same GPIO chip. So this difference is unexpected. Understanding the difference may help us why the GPIO interrupt controller is malfunctioning.

Based on your results, I guess the ELAN touchpad somehow de-asserts its interrupt line connected to the GPIO pin. Could you further do the following experiment?

The following C program is to let GPIO controller quickly generate some interrupts then disable the firing of interrupts by toggling pin#130's direction with an time interval (ms). For the Synaptics touchpad, There is no interrupt firing unless internal > 120ms. So somehow the GPIO controller can only generate interrupt when its pin holding the signal for enough time. My hypothesis is the GPIO is not setup properly so it stays in a idle state or it's clock frequency is too small (so I don't think the touchpad issue is caused by mis-configuration of the direction of the pin). I want to see if the result from the ELAN touchpad would also support this hypothesis.

1. Find out the reliable way to trigger an interrupt which is crucial for this experiment.

   You told me there will be interrupt firing by simply setting the pin's direction to "out". You can check it's reliable by following the steps

    a. Don't put your finger on the touchpad
    b. Open a terminal window and run `sudo dmesg -W`
    c. In another terminal, "cd /sys/class/gpio/gpio386"
    e. "echo out > direction" and see if the following dmesg output will keeping popping out in the previous terminal window

        ```
        [ 138.233653] i2c_hid i2c-MSFT0001:00: i2c_hid_get_input: IRQ triggered but there's no data
        ```
    d. Then "echo in > direction", now the dmesg output in step 3 should stop popping out.
    f. Repeat step e-d for around 5 times

If you are certain now, use the following C Program,
```c
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <fcntl.h>

#include <errno.h>
void write_to_pin130(char *d, size_t size)
{
 int fd;
 fd = open("/sys/class/gpio/gpio386/direction", O_WRONLY);
 write(fd, d, size);
        perror("Status:");
 close(fd);
}
void toggle_pin130(int interval_ms)
{
 struct timespec ts, ts1;

 write_to_pin130("out", 3);

 clock_gettime(CLOCK_MONOTONIC, &ts);

 usleep(interval_ms*1000);

 write_to_pin130("in", 2);
 clock_gettime(CLOCK_MONOTONIC, &ts1);
 printf("Interval: %.1f (real), %d (set)\n", (ts1.tv_sec-ts.tv_sec)*1000.0+(ts1.tv_nsec-ts.tv_nsec)/1000.0, interval_ms);

}
int main(int argc, char **argv)
{
 struct timespec ts;
 int interval_ms = atoi(argv[1]);
 toggle_pin130(interval_ms);

}
```

For me, it seems it's reliable to toggle the value to trigger a interrupt. You can follow similar steps to test it,

    a. Don't put your finger on the touchpad
    b. Open a terminal window and run `sudo dmesg -W`
    c. In another terminal, "cd /sys/class/gpio/gpio386"
    e. "echo 1 > value" and see if the following dmesg output will keeping popping up in the previous terminal window

        ```
        [ 138.233653] i2c_hid i2c-MSFT0001:00: i2c_hid_get_input: IRQ triggered but there's no data
        ```
    d. Then "echo 0 > value", now the dmesg output in step 3 should stop popping up
    f. Repeat step e-d for around 5 times

If the results are positive, use the following C program,
```
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <fcntl.h>

#include <errno.h>
void write_to_pin130(char *d)
{
 int fd;
 fd = open("/sys/class/gpio/gpio386/value", O_WRONLY);
 write(fd, d, 1);
        perror("Status:");
 close(fd);
}
void toggle_pin130(int interval_ms)
{
 struct timespec ts, ts1;
 char d = '0';
 write_to_pin130(&d);

 clock_gettime(CLOCK_MONOTONIC, &ts);

 usleep(interval_ms*1000);

 d = '1';
 write_to_pin130(&d);
 clock_gettime(CLOCK_MONOTONIC, &ts1);
 printf("Interval: %.1f (real), %d (set)\n", (ts1.tv_sec-ts.tv_sec)*1000.0+(ts1.tv_nsec-ts.tv_nsec)/1000.0, interval_ms);

}
int main(int argc, char **argv)
{
 struct timespec ts;
 int interval_ms = atoi(argv[1]);
 toggle_pin130(interval_ms);

}
```

2. Build (you can simply run `make fire_touchpad_pin_irq.c`) and run it as a root user
    $ sudo ./fire_touchpad_pin_irq N

   N is the time interval in ms. You may start with 100 and keep increasing N it until you see a couple of messages like follows pop up,

        [ 138.233653] i2c_hid i2c-MSFT0001:00: i2c_hid_get_input: IRQ triggered but there's no data

    With larger N, you will see more messages popping up one time.