HID: multitouch: Add quirks for flipped axes
Commit Message
Certain touchscreen devices, such as the ELAN9034, are oriented
incorrectly and report touches on opposite points on the X and Y axes.
For example, a 100x200 screen touched at (10,20) would report (90, 180)
and vice versa.
This is fixed by adding device quirks to transform the touch points
into the correct spaces, from X -> MAX(X) - X, and Y -> MAX(Y) - Y.
Signed-off-by: Allen Ballway <ballway@chromium.org>
---
drivers/hid/hid-multitouch.c | 46 ++++++++++++++++++++++++++++++++----
1 file changed, 42 insertions(+), 4 deletions(-)
Comments
Hi Allen,
On Tue, Dec 6, 2022 at 9:39 AM Allen Ballway <ballway@chromium.org> wrote:
>
> Certain touchscreen devices, such as the ELAN9034, are oriented
> incorrectly and report touches on opposite points on the X and Y axes.
> For example, a 100x200 screen touched at (10,20) would report (90, 180)
> and vice versa.
>
> This is fixed by adding device quirks to transform the touch points
> into the correct spaces, from X -> MAX(X) - X, and Y -> MAX(Y) - Y.
>
> Signed-off-by: Allen Ballway <ballway@chromium.org>
> ---
>
> drivers/hid/hid-multitouch.c | 46 ++++++++++++++++++++++++++++++++----
> 1 file changed, 42 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index 91a4d3fc30e08..5e14cc4b00f53 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -71,6 +71,8 @@ MODULE_LICENSE("GPL");
> #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
> #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
> #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
> +#define MT_QUIRK_FLIP_X BIT(22)
> +#define MT_QUIRK_FLIP_Y BIT(23)
>
> #define MT_INPUTMODE_TOUCHSCREEN 0x02
> #define MT_INPUTMODE_TOUCHPAD 0x03
> @@ -212,6 +214,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
> #define MT_CLS_GOOGLE 0x0111
> #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
> #define MT_CLS_SMART_TECH 0x0113
> +#define MT_CLS_ELAN_FLIPPED 0x0114
>
> #define MT_DEFAULT_MAXCONTACT 10
> #define MT_MAX_MAXCONTACT 250
> @@ -396,6 +399,17 @@ static const struct mt_class mt_classes[] = {
> MT_QUIRK_CONTACT_CNT_ACCURATE |
> MT_QUIRK_SEPARATE_APP_REPORT,
> },input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x
> + { .name = MT_CLS_ELAN_FLIPPED,
> + .quirks = MT_QUIRK_ALWAYS_VALID |
> + MT_QUIRK_IGNORE_DUPLICATES |
> + MT_QUIRK_HOVERING |
> + MT_QUIRK_CONTACT_CNT_ACCURATE |
> + MT_QUIRK_STICKY_FINGERS |
> + MT_QUIRK_WIN8_PTP_BUTTONS |
> + MT_QUIRK_FLIP_X |
> + MT_QUIRK_FLIP_Y,
> + .export_all_inputs = true },
> +
> { }
> };
>
> @@ -1115,10 +1129,30 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
> minor = minor >> 1;
> }
>
> - input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
> - input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
> - input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
> - input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
> + if (quirks & MT_QUIRK_FLIP_X) {
> + /* Inputs with a flipped X axis need to report MAX - X */
> + int x = input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x;
Maybe
x = quirks & MT_QUIRK_FLIP_X ?
input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
*slot->x;
and then report it all together?
> + int cx = input_abs_get_max(input, ABS_MT_TOOL_X) - *slot->cx;
Would like to double-check that this conversion is actually needed.
> +
> + input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
> + input_event(input, EV_ABS, ABS_MT_TOOL_X, cx);
> + } else {
> + input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
> + input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
> + }
> +
> + if (quirks & MT_QUIRK_FLIP_Y) {
> + /* Inputs with a flipped Y axis need to report MAX - Y */
> + int y = input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y;
> + int cy = input_abs_get_max(input, ABS_MT_TOOL_Y) - *slot->cy;
> +
> + input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
> + input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy);
> + } else {
> + input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
> + input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
> + }
> +
> input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
> input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
I think we might need to do something about this too as orientation will change.
> input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
> @@ -1963,6 +1997,10 @@ static const struct hid_device_id mt_devices[] = {
> USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
>
> /* Elan devices */
> + { .driver_data = MT_CLS_ELAN_FLIPPED,
> + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
> + USB_VENDOR_ID_ELAN, 0x2dcd) },
> +
I believe this needs to be plumbed through i2c-hid and involve DMI check as I am
concerned that product 0x2dcd might have been used in other devices where it was
mounted in a different way.
> { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
> HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
> USB_VENDOR_ID_ELAN, 0x313a) },
> --
> 2.39.0.rc0.267.gcb52ba06e7-goog
>
Thanks,
Dmitry
@@ -71,6 +71,8 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
#define MT_QUIRK_DISABLE_WAKEUP BIT(21)
+#define MT_QUIRK_FLIP_X BIT(22)
+#define MT_QUIRK_FLIP_Y BIT(23)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -212,6 +214,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
+#define MT_CLS_ELAN_FLIPPED 0x0114
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
@@ -396,6 +399,17 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SEPARATE_APP_REPORT,
},
+ { .name = MT_CLS_ELAN_FLIPPED,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_STICKY_FINGERS |
+ MT_QUIRK_WIN8_PTP_BUTTONS |
+ MT_QUIRK_FLIP_X |
+ MT_QUIRK_FLIP_Y,
+ .export_all_inputs = true },
+
{ }
};
@@ -1115,10 +1129,30 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1;
}
- input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
- input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
- input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
+ if (quirks & MT_QUIRK_FLIP_X) {
+ /* Inputs with a flipped X axis need to report MAX - X */
+ int x = input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x;
+ int cx = input_abs_get_max(input, ABS_MT_TOOL_X) - *slot->cx;
+
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, cx);
+ } else {
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
+ }
+
+ if (quirks & MT_QUIRK_FLIP_Y) {
+ /* Inputs with a flipped Y axis need to report MAX - Y */
+ int y = input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y;
+ int cy = input_abs_get_max(input, ABS_MT_TOOL_Y) - *slot->cy;
+
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy);
+ } else {
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
+ }
+
input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
@@ -1963,6 +1997,10 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
/* Elan devices */
+ { .driver_data = MT_CLS_ELAN_FLIPPED,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_ELAN, 0x2dcd) },
+
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_ELAN, 0x313a) },