HID: retain initial quirks set up when creating HID devices
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 7 Feb 2023 23:03:30 +0000 (15:03 -0800)
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>
Thu, 9 Feb 2023 13:24:30 +0000 (14:24 +0100)
In certain circumstances, such as when creating I2C-connected HID
devices, we want to pass and retain some quirks (axis inversion, etc).
The source of such quirks may be device tree, or DMI data, or something
else not readily available to the HID core itself and therefore cannot
be reconstructed easily. To allow this, introduce "initial_quirks" field
in hid_device structure and use it when determining the final set of
quirks.

This fixes the problem with i2c-hid setting up device-tree sourced
quirks too late and losing them on device rebind, and also allows to
sever the tie between hid-code and i2c-hid when applying DMI-based
quirks.

Fixes: b60d3c803d76 ("HID: i2c-hid-of: Expose the touchscreen-inverted properties")
Fixes: a2f416bf062a ("HID: multitouch: Add quirks for flipped axes")
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Tested-by: Allen Ballway <ballway@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: Alistair Francis <alistair@alistair23.me>
Link: https://lore.kernel.org/r/Y+LYwu3Zs13hdVDy@google.com
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
drivers/hid/hid-quirks.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
include/linux/hid.h

index 78452faf3c9b4abf7da63b723da33a0d5c8e37ed..ada71746e55f0ff2f52a2572095ffc265375a54e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/input/elan-i2c-ids.h>
 
 #include "hid-ids.h"
-#include "i2c-hid/i2c-hid.h"
 
 /*
  * Alphabetically sorted by vendor then product.
@@ -1238,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;
@@ -1299,11 +1298,6 @@ unsigned long hid_lookup_quirk(const struct hid_device *hdev)
                quirks = hid_gets_squirk(hdev);
        mutex_unlock(&dquirks_lock);
 
-       /* Get quirks specific to I2C devices */
-       if (IS_ENABLED(CONFIG_I2C_DMI_CORE) && IS_ENABLED(CONFIG_DMI) &&
-           hdev->bus == BUS_I2C)
-               quirks |= i2c_hid_get_dmi_quirks(hdev->vendor, hdev->product);
-
        return quirks;
 }
 EXPORT_SYMBOL_GPL(hid_lookup_quirk);
index b86b62f971080b78259bebd057ec0697f305418f..72f2c379812c71c1f995cd926f88d00306e3a3bc 100644 (file)
@@ -1035,6 +1035,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));
@@ -1048,8 +1052,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 554a7dc285365c78a626645afb007fccd5e4ac7e..210f17c3a0be05f47b78b7839ac9f3a0b28be5eb 100644 (file)
@@ -492,4 +492,3 @@ u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
 
        return quirks;
 }
-EXPORT_SYMBOL_GPL(i2c_hid_get_dmi_quirks);
index 8677ae38599e4390a9278a98d95cb763662189e0..48563dc09e1715b7a5d53ace3a9391dd98568c81 100644 (file)
@@ -619,6 +619,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 */