Commit 16ea8a65 authored by Adya's avatar Adya

Moved files + + mainline driver

parent ae8090d4
# Goodix Touchscreen Linux Driver
## With added support for Active Stylus Pen
This is a clone of the `drivers/input/touchscreen/goodix.c` file from the Linux mainline source code with a few modifications to **add support for the Goodix active pen**. (see `goodix_mainline.c` for the original driver)
*(Note: the driver has only been tested on the Chuwi Surbook thus far, feel free to let me know if it works on other devices)*
*(Note: unfortunately, the stylus buttons have yet to be supported. I will push to that repository as soon as support is added)*
#### The initial problems
With the mainline driver, the input events generated by **a finger or a pen were not differentiated** which led to spurious events reported to the system.
- When the pen comes sufficiently close to the screen without coming into contact with it, the driver is expected to report a Proximity event for the Pen tool. However, it **instead reports a Touch event just as if a finger was pressing down on the screen** which makes the pen utterly unusable.
- Moreover, the pen and the touchscreen **share a single device** (of the form `/dev/input/eventX`).
*Note*: if we report the Tool type to the system correctly, one might actually want them to share a single device (to simulate a graphics tablet that support finger events in addition to pen events) and thus might not consider this as a problem. But trying to do so led me to having the touchscreen not respond as well as it did before: the libinput events triggered by finger touch were definitely what you'd expect them to be.
#### The reason
The reason behind this is very simple: the **mainline driver code does not check the Tool type** of the touch report. There is a specific bit in the input data read from the touchscreen controller that is set to 1 when the input event is detected to be triggered by an active pen, but the mainline driver does not utilize it and only report events as `MT_TOOL_FINGER`.
#### The solutions
- For the reasons exposed in the "*Note*" above, I decided to **split the physical device into two logical devices** at the kernel driver level:
- One for the touchscreen, which:
- reports events triggered by **fingers only** ;
- is identified as a **Touchscreen device** by `libinput` that generates events such as `TOUCH_DOWN`, `TOUCH_UP`, `TOUCH_MOTION`, `TOUCH_FRAME`, etc.
*(this is the same as if we were using the mainline driver which works perfectly as far as finger events are concerned)*
- One for the pen, which:
- reports events triggered by the **pen only** ;
- is identified as a **Tablet device** by `libinput` that generates events such as `TABLET_TOOL_PROXIMITY`, `TABLET_TOOL_AXIS`, `TABLET_TOOL_TIP`, etc.
- Now, to solve the first problem, we just need to **check whether the bit that indicates the Tool type is set or not** in the input data read from the TS controller. If it is set, we report the event to the Pen logical device, and if it isn't, to the Touchscreen logical device.
#### Build the driver
Open a terminal and follow these steps:
1. **Clone** this repository:
`$ git clone`
2. **Move** into the folder:
`$ cd goodix-touchscreen-linux-driver`
3. **Build** the driver:
`$ make`
4. If no error occurs, **test** the driver (you need to have root privileges):
`# rmmod goodix`
`# insmod goodix.ko`
If the touchscreen and the pen work as you want them to, install the driver on your machine by following the steps below.
#### Install the driver
Assuming you are in the cloned directory and you already successfully built the driver, follow these steps:
1. **Compress** into xz format the driver:
`$ xz goodix.ko`
2. **Replace** the current driver with the new one (root privileges required):
`# mv goodix.ko.xz /lib/modules/$(uname -r)/kernel/drivers/input/touchscreen/goodix.ko.xz`
It should be up and working now, even after reboot.
#### Troubleshooting
If you are having trouble getting the driver to work, you might want to check the results of some of the following commands:
`$ dmesg | grep -i goodix`
`$ cat /proc/bus/input/devices | grep -B 1 -A 8 -i goodix`
`# libinput list-devices | grep -A 17 -i goodix`
`# libinput debug-events`
`$ xinput list`
- `eventX - Goodix Active Stylus Pen: libinput bug: missing tablet capabilities: resolution. Ignoring this device` (from the output of `# libinput debug-events`)
- **Reason**: This error is very likely to occur, if you are using `libinput` of course. It indicates that `udev` misses some resolution information for the pen device and thus cannot present it as a Tablet device.
- **Solution**: **Update the `hwdb`** (HardWare DataBase) of your machine to add the missing resolution information by following these steps:
1. **Locate** the `evdev.hwdb` file (should be in `/usr/lib/udev/hwdb.d/` or `/etc/udev/hwdb.d/`):
`# find / -type f -name *-evdev.hwdb`
2. **Edit** the file by appending the following (replace `2736` by the your horizontal resolution in pixels and `1824` by your vertical resolution, if necessary):
# Goodix Touchscreen and Pen
3. **Update** the hwdb:
`# systemd-hwdb update`
4. **Apply** the changes:
`# udevadm trigger`
5. **Reload** the driver (see step 4 of `Build the driver` section) (alternatively, you can reboot if you followed the steps of the `Install the driver` section)
#### Credits
Credit goes mostly to the orignal driver developers as well as the Goodix developers behind the driver for Android (at which I did not manage to port to x86/x86_64 architecture. The code in `goodix.c` of my repository is basically a merge of the two from the mainline and that android driver with a few additions of mine. This repository is thus still under the **GPLv2 License**.
\ No newline at end of file
......@@ -69,13 +69,6 @@ struct goodix_ts_data {
#define GOODIX_TOOL_TYPE(id_byte) \
#define GOODIX_TOOL_TYPE_TO_MT_TOOL(tool_type) \
#define GOODIX_TOOL_TYPE_TO_STRING(tool_type) \
(tool_type == GOODIX_TOOL_FINGER ? "Finger" : \
(tool_type == GOODIX_TOOL_PEN ? "Pen" : "" ))
struct goodix_point {
u8 id :7; /* ID of the point: 4 bits */
bool tool_type :1; /* Tool type (Finger or Pen) */
......@@ -90,8 +83,6 @@ struct goodix_input_report {
struct goodix_point *points;
#define GOODIX_IS_READY(report) (report->flags & 0x8)
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
......@@ -441,14 +432,9 @@ static void goodix_process_events(struct goodix_ts_data *ts)
* Bit 4 of the first byte reports the status of the capacitive
* Windows/Home button.
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
for (i = 0; i < touch_num; i++)
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
if (GOODIX_KEYDOWN_EVENT(report.keys) || GOODIX_KEYDOWN_EVENT(prev_keys)) {
input_report_key(ts->pen_dev, BTN_STYLUS,
......@@ -712,7 +698,7 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
* Must be called during probe
static void goodix_read_config(struct goodix_ts_data *ts,
struct input_dev *input_dev)
struct input_dev *dev)
int x_max, y_max;
......@@ -734,8 +720,8 @@ static void goodix_read_config(struct goodix_ts_data *ts,
x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
if (x_max && y_max) {
input_abs_set_max(input_dev, ABS_MT_POSITION_X, x_max - 1);
input_abs_set_max(input_dev, ABS_MT_POSITION_Y, y_max - 1);
input_abs_set_max(dev, ABS_MT_POSITION_X, x_max - 1);
input_abs_set_max(dev, ABS_MT_POSITION_Y, y_max - 1);
......@@ -849,9 +835,9 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
ts->prop.max_y = GOODIX_MAX_HEIGHT - 1;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
ABS_MT_POSITION_X, ts->prop.max_x);
ABS_MT_POSITION_X, ts->prop.max_x);
ABS_MT_POSITION_Y, ts->prop.max_y);
ABS_MT_POSITION_Y, ts->prop.max_y);
if (dmi_check_system(rotated_screen)) {
......@@ -925,15 +911,14 @@ static int goodix_configure_pen_dev(struct goodix_ts_data *ts)
input_set_abs_params(ts->pen_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts, ts->pen_dev);
/* Try overriding touchscreen parameters via device properties */
touchscreen_parse_properties(ts->pen_dev, true, &ts->prop);
ABS_MT_POSITION_X, ts->prop.max_x);
ABS_MT_POSITION_X, ts->prop.max_x);
ABS_MT_POSITION_Y, ts->prop.max_y);
error = input_mt_init_slots(ts->pen_dev, ts->max_touch_num,
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment