Merge branch 'for-6.3/multitouch' into for-linus
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Wed, 22 Feb 2023 09:39:05 +0000 (10:39 +0100)
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>
Wed, 22 Feb 2023 09:39:05 +0000 (10:39 +0100)
Allow to pass quirks from i2c-hid to hid-multitouch (Allen Ballway &
Dmitry Torokhov)

drivers/hid/hid-multitouch.c
drivers/hid/hid-quirks.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
drivers/hid/i2c-hid/i2c-hid.h
include/linux/hid.h

index 372cbdd..e31be0c 100644 (file)
@@ -71,6 +71,7 @@ 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_ORIENTATION_INVERT    BIT(22)
 
 #define MT_INPUTMODE_TOUCHSCREEN       0x02
 #define MT_INPUTMODE_TOUCHPAD          0x03
@@ -1009,6 +1010,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
                            struct mt_usages *slot)
 {
        struct input_mt *mt = input->mt;
+       struct hid_device *hdev = td->hdev;
        __s32 quirks = app->quirks;
        bool valid = true;
        bool confidence_state = true;
@@ -1086,6 +1088,10 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
                int orientation = wide;
                int max_azimuth;
                int azimuth;
+               int x;
+               int y;
+               int cx;
+               int cy;
 
                if (slot->a != DEFAULT_ZERO) {
                        /*
@@ -1104,6 +1110,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
                        if (azimuth > max_azimuth * 2)
                                azimuth -= max_azimuth * 4;
                        orientation = -azimuth;
+                       if (quirks & MT_QUIRK_ORIENTATION_INVERT)
+                               orientation = -orientation;
+
                }
 
                if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
@@ -1115,10 +1124,23 @@ 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);
+               x = hdev->quirks & HID_QUIRK_X_INVERT ?
+                       input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
+                       *slot->x;
+               y = hdev->quirks & HID_QUIRK_Y_INVERT ?
+                       input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y :
+                       *slot->y;
+               cx = hdev->quirks & HID_QUIRK_X_INVERT ?
+                       input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->cx :
+                       *slot->cx;
+               cy = hdev->quirks & HID_QUIRK_Y_INVERT ?
+                       input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->cy :
+                       *slot->cy;
+
+               input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
+               input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
+               input_event(input, EV_ABS, ABS_MT_TOOL_X, cx);
+               input_event(input, EV_ABS, ABS_MT_TOOL_Y, 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);
@@ -1735,6 +1757,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
                td->serial_maybe = true;
 
+
+       /* Orientation is inverted if the X or Y axes are
+        * flipped, but normalized if both are inverted.
+        */
+       if (hdev->quirks & (HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT) &&
+           !((hdev->quirks & HID_QUIRK_X_INVERT)
+             && (hdev->quirks & HID_QUIRK_Y_INVERT)))
+               td->mtclass.quirks = MT_QUIRK_ORIENTATION_INVERT;
+
        /* This allows the driver to correctly support devices
         * that emit events over several HID messages.
         */
index 5bc91f6..66e6435 100644 (file)
@@ -1237,7 +1237,7 @@ EXPORT_SYMBOL_GPL(hid_quirks_exit);
 static unsigned long hid_gets_squirk(const struct hid_device *hdev)
 {
        const struct hid_device_id *bl_entry;
-       unsigned long quirks = 0;
+       unsigned long quirks = hdev->initial_quirks;
 
        if (hid_match_id(hdev, hid_ignore_list))
                quirks |= HID_QUIRK_IGNORE;
index 0ab8f47..efbba04 100644 (file)
@@ -1025,6 +1025,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
        hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
        hid->product = le16_to_cpu(ihid->hdesc.wProductID);
 
+       hid->initial_quirks = quirks;
+       hid->initial_quirks |= i2c_hid_get_dmi_quirks(hid->vendor,
+                                                     hid->product);
+
        snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",
                 client->name, (u16)hid->vendor, (u16)hid->product);
        strscpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
@@ -1038,8 +1042,6 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
                goto err_mem_free;
        }
 
-       hid->quirks |= quirks;
-
        return 0;
 
 err_mem_free:
index 8e0f674..210f17c 100644 (file)
 #include <linux/types.h>
 #include <linux/dmi.h>
 #include <linux/mod_devicetable.h>
+#include <linux/hid.h>
 
 #include "i2c-hid.h"
+#include "../hid-ids.h"
 
 
 struct i2c_hid_desc_override {
@@ -416,6 +418,28 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
        { }     /* Terminate list */
 };
 
+static const struct hid_device_id i2c_hid_elan_flipped_quirks = {
+       HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ELAN, 0x2dcd),
+               HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT
+};
+
+/*
+ * This list contains devices which have specific issues based on the system
+ * they're on and not just the device itself. The driver_data will have a
+ * specific hid device to match against.
+ */
+static const struct dmi_system_id i2c_hid_dmi_quirk_table[] = {
+       {
+               .ident = "DynaBook K50/FR",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),
+               },
+               .driver_data = (void *)&i2c_hid_elan_flipped_quirks,
+       },
+       { }     /* Terminate list */
+};
+
 
 struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
 {
@@ -450,3 +474,21 @@ char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
        *size = override->hid_report_desc_size;
        return override->hid_report_desc;
 }
+
+u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
+{
+       u32 quirks = 0;
+       const struct dmi_system_id *system_id =
+                       dmi_first_match(i2c_hid_dmi_quirk_table);
+
+       if (system_id) {
+               const struct hid_device_id *device_id =
+                               (struct hid_device_id *)(system_id->driver_data);
+
+               if (device_id && device_id->vendor == vendor &&
+                   device_id->product == product)
+                       quirks = device_id->driver_data;
+       }
+
+       return quirks;
+}
index 96c7551..2c7b66d 100644 (file)
@@ -9,6 +9,7 @@
 struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
 char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
                                               unsigned int *size);
+u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product);
 #else
 static inline struct i2c_hid_desc
                   *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
@@ -16,6 +17,8 @@ static inline struct i2c_hid_desc
 static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
                                                             unsigned int *size)
 { return NULL; }
+static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
+{ return 0; }
 #endif
 
 /**
index 6074d2a..899d840 100644 (file)
@@ -621,6 +621,7 @@ struct hid_device {                                                 /* device report descriptor */
        unsigned long status;                                           /* see STAT flags above */
        unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
        unsigned quirks;                                                /* Various quirks the device can pull on us */
+       unsigned initial_quirks;                                        /* Initial set of quirks supplied when creating device */
        bool io_started;                                                /* If IO has started */
 
        struct list_head inputs;                                        /* The list of inputs */