From d951ae1ce8033dea91c532810536809d0e691615 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 2 Nov 2021 11:40:25 -0700 Subject: [PATCH 01/32] HID: i2c-hid: Report wakeup events The i2c-hid driver generally supports wakeup, bit it currently doesn't report wakeup events to the PM subsystem. Change that. Signed-off-by: Matthias Kaehlcke Acked-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 517141138b007..68d9a089e3e85 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -522,9 +522,12 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf); - if (test_bit(I2C_HID_STARTED, &ihid->flags)) + if (test_bit(I2C_HID_STARTED, &ihid->flags)) { + pm_wakeup_event(&ihid->client->dev, 0); + hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2, ret_size - 2, 1); + } return; } From 03dada294d0830f3bc994909f2e74ecaa3aa92a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20La=C3=ADns?= Date: Thu, 11 Nov 2021 16:44:11 +0000 Subject: [PATCH 02/32] HID: logitech: add myself as a reviewer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, I have to use a separate email address and maintain several filters to monitor changes to Logitech drivers, so that I can have an opportunity to review them. Since I am very interested in keeping up with the changes, as I have a lot of the hardware and maintain the main userspace stacks that depend on these drivers, I would like to mark myself as a reviewer. I would also be open to be marked as a maintainer if Benjamin thinks it makes sense. Signed-off-by: Filipe Laíns Signed-off-by: Jiri Kosina --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 74158b271cb74..5381b6f16cb35 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8436,6 +8436,12 @@ F: drivers/hid/ F: include/linux/hid* F: include/uapi/linux/hid* +HID LOGITECH DRIVERS +R: Filipe Laíns +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-logitech-* + HID PLAYSTATION DRIVER M: Roderick Colenbrander L: linux-input@vger.kernel.org From 0b91b4e4dae63cd43871fc2012370b86ee588f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 17:52:08 +0100 Subject: [PATCH 03/32] HID: magicmouse: Report battery level over USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When connected over USB, the Apple Magic Mouse 2 and the Apple Magic Trackpad 2 register multiple interfaces, one of them is used to report the battery level. However, unlike when connected over Bluetooth, the battery level is not reported automatically and it is required to fetch it manually. Fix the battery report descriptor and add a timer to fetch the battery level. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 94 +++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 686788ebf3e1e..167b6a5dd226a 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -57,6 +57,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define MOUSE_REPORT_ID 0x29 #define MOUSE2_REPORT_ID 0x12 #define DOUBLE_REPORT_ID 0xf7 +#define USB_BATTERY_TIMEOUT_MS 60000 + /* These definitions are not precise, but they're close enough. (Bits * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem * to be some kind of bit mask -- 0x20 may be a near-field reading, @@ -140,6 +142,7 @@ struct magicmouse_sc { struct hid_device *hdev; struct delayed_work work; + struct timer_list battery_timer; }; static int magicmouse_firm_touch(struct magicmouse_sc *msc) @@ -735,6 +738,44 @@ static void magicmouse_enable_mt_work(struct work_struct *work) hid_err(msc->hdev, "unable to request touch data (%d)\n", ret); } +static int magicmouse_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE || + (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 && + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void magicmouse_battery_timer_tick(struct timer_list *t) +{ + struct magicmouse_sc *msc = from_timer(msc, t, battery_timer); + struct hid_device *hdev = msc->hdev; + + if (magicmouse_fetch_battery(hdev) == 0) { + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + } +} + static int magicmouse_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -742,11 +783,6 @@ static int magicmouse_probe(struct hid_device *hdev, struct hid_report *report; int ret; - if (id->vendor == USB_VENDOR_ID_APPLE && - id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && - hdev->type != HID_TYPE_USBMOUSE) - return -ENODEV; - msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); if (msc == NULL) { hid_err(hdev, "can't alloc magicmouse descriptor\n"); @@ -772,6 +808,16 @@ static int magicmouse_probe(struct hid_device *hdev, return ret; } + timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0); + mod_timer(&msc->battery_timer, + jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS)); + magicmouse_fetch_battery(hdev); + + if (id->vendor == USB_VENDOR_ID_APPLE && + (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE))) + return 0; + if (!msc->input) { hid_err(hdev, "magicmouse input not registered\n"); ret = -ENOMEM; @@ -832,17 +878,52 @@ static void magicmouse_remove(struct hid_device *hdev) { struct magicmouse_sc *msc = hid_get_drvdata(hdev); - if (msc) + if (msc) { cancel_delayed_work_sync(&msc->work); + del_timer_sync(&msc->battery_timer); + } hid_hw_stop(hdev); } +static __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x02, // Usage (Mouse) 2 + */ + if (hdev->vendor == USB_VENDOR_ID_APPLE && + (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && + *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up magicmouse battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x02; + } + + return rdesc; +} + static const struct hid_device_id magic_mice[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, @@ -858,6 +939,7 @@ static struct hid_driver magicmouse_driver = { .id_table = magic_mice, .probe = magicmouse_probe, .remove = magicmouse_remove, + .report_fixup = magicmouse_report_fixup, .raw_event = magicmouse_raw_event, .event = magicmouse_event, .input_mapping = magicmouse_input_mapping, From a5fe7864d8ada170f19cc47d176bf8260ffb4263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:53 +0100 Subject: [PATCH 04/32] HID: apple: Do not reset quirks when the Fn key is not found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a keyboard without a function key is detected, instead of removing all quirks, remove only the APPLE_HAS_FN quirk. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2c9c5faa74a97..a4ca5ed00e5f5 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -428,7 +428,7 @@ static int apple_input_configured(struct hid_device *hdev, if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); - asc->quirks = 0; + asc->quirks &= ~APPLE_HAS_FN; } return 0; From 7f52ece242e9714d94d3bab630ea1dd2236e7d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:54 +0100 Subject: [PATCH 05/32] HID: apple: Use BIT to define quirks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the existing quirk hardcoded values with the BIT macro in order to simplify including new quirks. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index a4ca5ed00e5f5..b34aeed292a28 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -21,15 +21,15 @@ #include "hid-ids.h" -#define APPLE_RDESC_JIS 0x0001 -#define APPLE_IGNORE_MOUSE 0x0002 -#define APPLE_HAS_FN 0x0004 -/* 0x0008 reserved, was: APPLE_HIDDEV */ -#define APPLE_ISO_TILDE_QUIRK 0x0010 -#define APPLE_MIGHTYMOUSE 0x0020 -#define APPLE_INVERT_HWHEEL 0x0040 -/* 0x0080 reserved, was: APPLE_IGNORE_HIDINPUT */ -#define APPLE_NUMLOCK_EMULATION 0x0100 +#define APPLE_RDESC_JIS BIT(0) +#define APPLE_IGNORE_MOUSE BIT(1) +#define APPLE_HAS_FN BIT(2) +/* BIT(3) reserved, was: APPLE_HIDDEV */ +#define APPLE_ISO_TILDE_QUIRK BIT(4) +#define APPLE_MIGHTYMOUSE BIT(5) +#define APPLE_INVERT_HWHEEL BIT(6) +/* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ +#define APPLE_NUMLOCK_EMULATION BIT(8) #define APPLE_FLAG_FKEY 0x01 From 6e143293e17a73c9313f91c5ca3aaacbaef030cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Thu, 18 Nov 2021 08:29:55 +0100 Subject: [PATCH 06/32] HID: apple: Report Magic Keyboard battery over USB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When connected over USB, the Apple Magic Keyboard 2015 registers 3 different interfaces. One of them is used to report the battery level. However, unlike when connected over Bluetooth, the battery level is not reported automatically and it is required to fetch it manually. Add a new quirk to fix the battery report descriptor and a timer to fetch the battery level. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 87 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index b34aeed292a28..2bd8276411e07 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -16,8 +16,10 @@ #include #include +#include #include #include +#include #include "hid-ids.h" @@ -30,10 +32,12 @@ #define APPLE_INVERT_HWHEEL BIT(6) /* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */ #define APPLE_NUMLOCK_EMULATION BIT(8) +#define APPLE_RDESC_BATTERY BIT(9) #define APPLE_FLAG_FKEY 0x01 #define HID_COUNTRY_INTERNATIONAL_ISO 13 +#define APPLE_BATTERY_TIMEOUT_MS 60000 static unsigned int fnmode = 1; module_param(fnmode, uint, 0644); @@ -58,10 +62,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); struct apple_sc { + struct hid_device *hdev; unsigned long quirks; unsigned int fn_on; unsigned int fn_found; DECLARE_BITMAP(pressed_numlock, KEY_CNT); + struct timer_list battery_timer; }; struct apple_key_translation { @@ -333,6 +339,43 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static int apple_fetch_battery(struct hid_device *hdev) +{ +#ifdef CONFIG_HID_BATTERY_STRENGTH + struct apple_sc *asc = hid_get_drvdata(hdev); + struct hid_report_enum *report_enum; + struct hid_report *report; + + if (!(asc->quirks & APPLE_RDESC_BATTERY) || !hdev->battery) + return -1; + + report_enum = &hdev->report_enum[hdev->battery_report_type]; + report = report_enum->report_id_hash[hdev->battery_report_id]; + + if (!report || report->maxfield < 1) + return -1; + + if (hdev->battery_capacity == hdev->battery_max) + return -1; + + hid_hw_request(hdev, report, HID_REQ_GET_REPORT); + return 0; +#else + return -1; +#endif +} + +static void apple_battery_timer_tick(struct timer_list *t) +{ + struct apple_sc *asc = from_timer(asc, t, battery_timer); + struct hid_device *hdev = asc->hdev; + + if (apple_fetch_battery(hdev) == 0) { + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + } +} + /* * MacBook JIS keyboard has wrong logical maximum * Magic Keyboard JIS has wrong logical maximum @@ -354,6 +397,30 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc, "fixing up MacBook JIS keyboard report descriptor\n"); rdesc[53] = rdesc[59] = 0xe7; } + + /* + * Change the usage from: + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0 + * 0x09, 0x0b, // Usage (Vendor Usage 0x0b) 3 + * To: + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x06, // Usage (Keyboard) 2 + */ + if ((asc->quirks & APPLE_RDESC_BATTERY) && *rsize == 83 && + rdesc[46] == 0x84 && rdesc[58] == 0x85) { + hid_info(hdev, + "fixing up Magic Keyboard battery report descriptor\n"); + *rsize = *rsize - 1; + rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL); + if (!rdesc) + return NULL; + + rdesc[0] = 0x05; + rdesc[1] = 0x01; + rdesc[2] = 0x09; + rdesc[3] = 0x06; + } + return rdesc; } @@ -447,6 +514,7 @@ static int apple_probe(struct hid_device *hdev, return -ENOMEM; } + asc->hdev = hdev; asc->quirks = quirks; hid_set_drvdata(hdev, asc); @@ -463,9 +531,23 @@ static int apple_probe(struct hid_device *hdev, return ret; } + timer_setup(&asc->battery_timer, apple_battery_timer_tick, 0); + mod_timer(&asc->battery_timer, + jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS)); + apple_fetch_battery(hdev); + return 0; } +static void apple_remove(struct hid_device *hdev) +{ + struct apple_sc *asc = hid_get_drvdata(hdev); + + del_timer_sync(&asc->battery_timer); + + hid_hw_stop(hdev); +} + static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE), .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL }, @@ -540,11 +622,11 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015), - .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), @@ -650,6 +732,7 @@ static struct hid_driver apple_driver = { .id_table = apple_devices, .report_fixup = apple_report_fixup, .probe = apple_probe, + .remove = apple_remove, .event = apple_event, .input_mapping = apple_input_mapping, .input_mapped = apple_input_mapped, From 9e3562080950b6e3fe38a5e34ddd5b1c618f2019 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Dec 2021 10:53:33 +0100 Subject: [PATCH 07/32] HID: add suspend/resume helpers There is a lot of duplication of code in the HID low level drivers. Better have everything in one place so we can eventually extend it in a generic way. Signed-off-by: Benjamin Tissoires Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20211202095334.14399-4-benjamin.tissoires@redhat.com --- drivers/hid/hid-core.c | 29 ++++++++++++++++++++++ drivers/hid/i2c-hid/i2c-hid-core.c | 15 +++-------- drivers/hid/surface-hid/surface_hid_core.c | 25 ++++--------------- drivers/hid/usbhid/hid-core.c | 19 ++++++-------- include/linux/hid.h | 10 ++++++++ 5 files changed, 56 insertions(+), 42 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index dbed2524fd47b..5402329d6eca6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2126,6 +2126,35 @@ void hid_hw_close(struct hid_device *hdev) } EXPORT_SYMBOL_GPL(hid_hw_close); +#ifdef CONFIG_PM +int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) +{ + if (hdev->driver && hdev->driver->suspend) + return hdev->driver->suspend(hdev, state); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_suspend); + +int hid_driver_reset_resume(struct hid_device *hdev) +{ + if (hdev->driver && hdev->driver->reset_resume) + return hdev->driver->reset_resume(hdev); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_reset_resume); + +int hid_driver_resume(struct hid_device *hdev) +{ + if (hdev->driver && hdev->driver->resume) + return hdev->driver->resume(hdev); + + return 0; +} +EXPORT_SYMBOL_GPL(hid_driver_resume); +#endif /* CONFIG_PM */ + struct hid_dynid { struct list_head list; struct hid_device_id id; diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 517141138b007..4cdd862ca1cb6 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -1063,11 +1063,9 @@ static int i2c_hid_core_suspend(struct device *dev) int ret; int wake_status; - if (hid->driver && hid->driver->suspend) { - ret = hid->driver->suspend(hid, PMSG_SUSPEND); - if (ret < 0) - return ret; - } + ret = hid_driver_suspend(hid, PMSG_SUSPEND); + if (ret < 0) + return ret; /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); @@ -1125,12 +1123,7 @@ static int i2c_hid_core_resume(struct device *dev) if (ret) return ret; - if (hid->driver && hid->driver->reset_resume) { - ret = hid->driver->reset_resume(hid); - return ret; - } - - return 0; + return hid_driver_reset_resume(hid); } #endif diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c index 5571e74abe91b..e46330b2e561a 100644 --- a/drivers/hid/surface-hid/surface_hid_core.c +++ b/drivers/hid/surface-hid/surface_hid_core.c @@ -204,50 +204,35 @@ static int surface_hid_suspend(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_SUSPEND); - - return 0; + return hid_driver_suspend(d->hid, PMSG_SUSPEND); } static int surface_hid_resume(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->resume) - return d->hid->driver->resume(d->hid); - - return 0; + return hid_driver_resume(d->hid); } static int surface_hid_freeze(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_FREEZE); - - return 0; + return hid_driver_suspend(d->hid, PMSG_FREEZE); } static int surface_hid_poweroff(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->suspend) - return d->hid->driver->suspend(d->hid, PMSG_HIBERNATE); - - return 0; + return hid_driver_suspend(d->hid, PMSG_HIBERNATE); } static int surface_hid_restore(struct device *dev) { struct surface_hid_device *d = dev_get_drvdata(dev); - if (d->hid->driver && d->hid->driver->reset_resume) - return d->hid->driver->reset_resume(d->hid); - - return 0; + return hid_driver_reset_resume(d->hid); } const struct dev_pm_ops surface_hid_pm_ops = { diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 2dcaf31eb9cdf..54752c85604b1 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1563,8 +1563,8 @@ static int hid_resume_common(struct hid_device *hid, bool driver_suspended) int status = 0; hid_restart_io(hid); - if (driver_suspended && hid->driver && hid->driver->resume) - status = hid->driver->resume(hid); + if (driver_suspended) + status = hid_driver_resume(hid); return status; } @@ -1588,11 +1588,9 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) { set_bit(HID_SUSPENDED, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); - if (hid->driver && hid->driver->suspend) { - status = hid->driver->suspend(hid, message); - if (status < 0) - goto failed; - } + status = hid_driver_suspend(hid, message); + if (status < 0) + goto failed; driver_suspended = true; } else { usbhid_mark_busy(usbhid); @@ -1602,8 +1600,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } else { /* TODO: resume() might need to handle suspend failure */ - if (hid->driver && hid->driver->suspend) - status = hid->driver->suspend(hid, message); + status = hid_driver_suspend(hid, message); driver_suspended = true; spin_lock_irq(&usbhid->lock); set_bit(HID_SUSPENDED, &usbhid->iofl); @@ -1644,8 +1641,8 @@ static int hid_reset_resume(struct usb_interface *intf) int status; status = hid_post_reset(intf); - if (status >= 0 && hid->driver && hid->driver->reset_resume) { - int ret = hid->driver->reset_resume(hid); + if (status >= 0) { + int ret = hid_driver_reset_resume(hid); if (ret < 0) status = ret; } diff --git a/include/linux/hid.h b/include/linux/hid.h index 9e067f937dbc2..ebe3ec98db6b6 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -923,6 +923,16 @@ s32 hid_snto32(__u32 value, unsigned n); __u32 hid_field_extract(const struct hid_device *hid, __u8 *report, unsigned offset, unsigned n); +#ifdef CONFIG_PM +int hid_driver_suspend(struct hid_device *hdev, pm_message_t state); +int hid_driver_reset_resume(struct hid_device *hdev); +int hid_driver_resume(struct hid_device *hdev); +#else +static inline int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) { return 0; } +static inline int hid_driver_reset_resume(struct hid_device *hdev) { return 0; } +static inline int hid_driver_resume(struct hid_device *hdev) { return 0; } +#endif + /** * hid_device_io_start - enable HID input during probe, remove * From f65a0b1f3e79444bba9ac56435eeb32db85ab2c9 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Dec 2021 10:53:34 +0100 Subject: [PATCH 08/32] HID: do not inline some hid_hw_ functions We don't gain much by having them as inline, and it actually prevents us to attach a probe to those helpers. Signed-off-by: Benjamin Tissoires Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20211202095334.14399-5-benjamin.tissoires@redhat.com --- drivers/hid/hid-core.c | 64 +++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 68 ++++-------------------------------------- 2 files changed, 70 insertions(+), 62 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5402329d6eca6..f1aed5bbd0008 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2126,6 +2126,70 @@ void hid_hw_close(struct hid_device *hdev) } EXPORT_SYMBOL_GPL(hid_hw_close); +/** + * hid_hw_request - send report request to device + * + * @hdev: hid device + * @report: report to send + * @reqtype: hid request type + */ +void hid_hw_request(struct hid_device *hdev, + struct hid_report *report, int reqtype) +{ + if (hdev->ll_driver->request) + return hdev->ll_driver->request(hdev, report, reqtype); + + __hid_request(hdev, report, reqtype); +} +EXPORT_SYMBOL_GPL(hid_hw_request); + +/** + * hid_hw_raw_request - send report request to device + * + * @hdev: hid device + * @reportnum: report ID + * @buf: in/out data to transfer + * @len: length of buf + * @rtype: HID report type + * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT + * + * Return: count of data transferred, negative if error + * + * Same behavior as hid_hw_request, but with raw buffers instead. + */ +int hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, unsigned char rtype, int reqtype) +{ + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) + return -EINVAL; + + return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, + rtype, reqtype); +} +EXPORT_SYMBOL_GPL(hid_hw_raw_request); + +/** + * hid_hw_output_report - send output report to device + * + * @hdev: hid device + * @buf: raw data to transfer + * @len: length of buf + * + * Return: count of data transferred, negative if error + */ +int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) +{ + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) + return -EINVAL; + + if (hdev->ll_driver->output_report) + return hdev->ll_driver->output_report(hdev, buf, len); + + return -ENOSYS; +} +EXPORT_SYMBOL_GPL(hid_hw_output_report); + #ifdef CONFIG_PM int hid_driver_suspend(struct hid_device *hdev, pm_message_t state) { diff --git a/include/linux/hid.h b/include/linux/hid.h index ebe3ec98db6b6..b2fea7fc54a1f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1066,6 +1066,12 @@ int __must_check hid_hw_start(struct hid_device *hdev, void hid_hw_stop(struct hid_device *hdev); int __must_check hid_hw_open(struct hid_device *hdev); void hid_hw_close(struct hid_device *hdev); +void hid_hw_request(struct hid_device *hdev, + struct hid_report *report, int reqtype); +int hid_hw_raw_request(struct hid_device *hdev, + unsigned char reportnum, __u8 *buf, + size_t len, unsigned char rtype, int reqtype); +int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len); /** * hid_hw_power - requests underlying HW to go into given power mode @@ -1083,68 +1089,6 @@ static inline int hid_hw_power(struct hid_device *hdev, int level) } -/** - * hid_hw_request - send report request to device - * - * @hdev: hid device - * @report: report to send - * @reqtype: hid request type - */ -static inline void hid_hw_request(struct hid_device *hdev, - struct hid_report *report, int reqtype) -{ - if (hdev->ll_driver->request) - return hdev->ll_driver->request(hdev, report, reqtype); - - __hid_request(hdev, report, reqtype); -} - -/** - * hid_hw_raw_request - send report request to device - * - * @hdev: hid device - * @reportnum: report ID - * @buf: in/out data to transfer - * @len: length of buf - * @rtype: HID report type - * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT - * - * Return: count of data transferred, negative if error - * - * Same behavior as hid_hw_request, but with raw buffers instead. - */ -static inline int hid_hw_raw_request(struct hid_device *hdev, - unsigned char reportnum, __u8 *buf, - size_t len, unsigned char rtype, int reqtype) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, - rtype, reqtype); -} - -/** - * hid_hw_output_report - send output report to device - * - * @hdev: hid device - * @buf: raw data to transfer - * @len: length of buf - * - * Return: count of data transferred, negative if error - */ -static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, - size_t len) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - if (hdev->ll_driver->output_report) - return hdev->ll_driver->output_report(hdev, buf, len); - - return -ENOSYS; -} - /** * hid_hw_idle - send idle request to device * From 8aa45b544db9788b0fcc7a300eba8a3ade5d3d50 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 10 Dec 2021 13:11:34 +0200 Subject: [PATCH 09/32] HID: Add map_msc() to avoid boilerplate code Since we are going to have more MSC events too, add map_msc() that can be used to fill in necessary fields and avoid boilerplate code. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Tero Kristo Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211210111138.1248187-2-tero.kristo@linux.intel.com --- drivers/hid/hid-input.c | 6 ++---- include/linux/hid.h | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 217f2d1b91c56..fbbb82f658420 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -52,6 +52,7 @@ static const struct { #define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c)) #define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c)) #define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c)) +#define map_msc(c) hid_map_usage(hidinput, usage, &bit, &max, EV_MSC, (c)) #define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ &max, EV_ABS, (c)) @@ -874,10 +875,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x5b: /* TransducerSerialNumber */ case 0x6e: /* TransducerSerialNumber2 */ - usage->type = EV_MSC; - usage->code = MSC_SERIAL; - bit = input->mscbit; - max = MSC_MAX; + map_msc(MSC_SERIAL); break; default: goto unknown; diff --git a/include/linux/hid.h b/include/linux/hid.h index b2fea7fc54a1f..f18e2cf5d74d3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1010,6 +1010,10 @@ static inline void hid_map_usage(struct hid_input *hidinput, bmap = input->ledbit; limit = LED_MAX; break; + case EV_MSC: + bmap = input->mscbit; + limit = MSC_MAX; + break; } if (unlikely(c > limit || !bmap)) { From c0ee1d571626d659535becdc3d9f2583be3b9208 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 10 Dec 2021 13:11:35 +0200 Subject: [PATCH 10/32] HID: hid-input: Add suffix also for HID_DG_PEN This and HID_DG_STYLUS are pretty much the same thing so add suffix for HID_DG_PEN too. This makes the input device name look better. While doing this, remove the suffix override from hid-multitouch, as it is now handled by hid-input. Also, the suffix override done by hid-multitouch was wrong, as it mapped HID_DG_PEN => "Stylus" and HID_DG_STYLUS => "Pen". Signed-off-by: Mika Westerberg Signed-off-by: Tero Kristo [bentiss: amended to keep the same name for hid-multitouch devices] Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211210111138.1248187-3-tero.kristo@linux.intel.com --- drivers/hid/hid-input.c | 10 ++++++++++ drivers/hid/hid-multitouch.c | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index fbbb82f658420..93bbc33da3c37 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1739,6 +1739,16 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, case HID_GD_MOUSE: suffix = "Mouse"; break; + case HID_DG_PEN: + /* + * yes, there is an issue here: + * DG_PEN -> "Stylus" + * DG_STYLUS -> "Pen" + * But changing this now means users with config snippets + * will have to change it and the test suite will not be happy. + */ + suffix = "Stylus"; + break; case HID_DG_STYLUS: suffix = "Pen"; break; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 082376a6cb3d7..99eabfb4145b5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1606,9 +1606,6 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) case HID_DG_STYLUS: /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); - fallthrough; - case HID_DG_PEN: - suffix = "Stylus"; break; default: suffix = "UNKNOWN"; From ae7fafa6896ae762ff489a5e71c8e5fabfeb61ee Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 10 Dec 2021 13:11:36 +0200 Subject: [PATCH 11/32] HID: Add hid usages for USI style pens Add usage codes for USI style pens, based on the USB-HID usage table: https://usb.org/document-library/hid-usage-tables-122 See chapter 16, Digitizers Page (0x0D) Signed-off-by: Tero Kristo Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211210111138.1248187-4-tero.kristo@linux.intel.com --- include/linux/hid.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/hid.h b/include/linux/hid.h index f18e2cf5d74d3..fa2ddda84a535 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -241,6 +241,7 @@ struct hid_item { #define HID_DG_TOUCH 0x000d0033 #define HID_DG_UNTOUCH 0x000d0034 #define HID_DG_TAP 0x000d0035 +#define HID_DG_TRANSDUCER_INDEX 0x000d0038 #define HID_DG_TABLETFUNCTIONKEY 0x000d0039 #define HID_DG_PROGRAMCHANGEKEY 0x000d003a #define HID_DG_BATTERYSTRENGTH 0x000d003b @@ -253,6 +254,15 @@ struct hid_item { #define HID_DG_BARRELSWITCH 0x000d0044 #define HID_DG_ERASER 0x000d0045 #define HID_DG_TABLETPICK 0x000d0046 +#define HID_DG_PEN_COLOR 0x000d005c +#define HID_DG_PEN_LINE_WIDTH 0x000d005e +#define HID_DG_PEN_LINE_STYLE 0x000d0070 +#define HID_DG_PEN_LINE_STYLE_INK 0x000d0072 +#define HID_DG_PEN_LINE_STYLE_PENCIL 0x000d0073 +#define HID_DG_PEN_LINE_STYLE_HIGHLIGHTER 0x000d0074 +#define HID_DG_PEN_LINE_STYLE_CHISEL_MARKER 0x000d0075 +#define HID_DG_PEN_LINE_STYLE_BRUSH 0x000d0076 +#define HID_DG_PEN_LINE_STYLE_NO_PREFERENCE 0x000d0077 #define HID_CP_CONSUMERCONTROL 0x000c0001 #define HID_CP_NUMERICKEYPAD 0x000c0002 From 5904a3f9d756f108279f8c5b8f17ca6ddfb28d24 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 10 Dec 2021 13:11:37 +0200 Subject: [PATCH 12/32] HID: input: Make hidinput_find_field() static This function is not called outside of hid-input.c so we can make it static. Signed-off-by: Mika Westerberg Reviewed-by: Benjamin Tissoires Signed-off-by: Tero Kristo Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211210111138.1248187-5-tero.kristo@linux.intel.com --- drivers/hid/hid-input.c | 4 ++-- include/linux/hid.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 93bbc33da3c37..4186143da7c6e 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1461,7 +1461,8 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report) } EXPORT_SYMBOL_GPL(hidinput_report_event); -int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) +static int hidinput_find_field(struct hid_device *hid, unsigned int type, + unsigned int code, struct hid_field **field) { struct hid_report *report; int i, j; @@ -1476,7 +1477,6 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int } return -1; } -EXPORT_SYMBOL_GPL(hidinput_find_field); struct hid_field *hidinput_get_led_field(struct hid_device *hid) { diff --git a/include/linux/hid.h b/include/linux/hid.h index fa2ddda84a535..ff8b6973022ab 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -899,7 +899,6 @@ extern void hidinput_disconnect(struct hid_device *); int hid_set_field(struct hid_field *, unsigned, __s32); int hid_input_report(struct hid_device *, int type, u8 *, u32, int); -int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); struct hid_field *hidinput_get_led_field(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid); __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code); From 9ea1b35f63dde3c8ff7f1fd8fee3a46c3d5583a9 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 10 Dec 2021 13:11:38 +0200 Subject: [PATCH 13/32] HID: debug: Add USI usages Add USI defined usages to the HID debug code. Signed-off-by: Mika Westerberg Signed-off-by: Tero Kristo Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211210111138.1248187-6-tero.kristo@linux.intel.com --- drivers/hid/hid-debug.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 7a92e2a04a09d..26c31d759914b 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -141,8 +141,10 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x33, "Touch"}, {0, 0x34, "UnTouch"}, {0, 0x35, "Tap"}, + {0, 0x38, "Transducer Index"}, {0, 0x39, "TabletFunctionKey"}, {0, 0x3a, "ProgramChangeKey"}, + {0, 0x3B, "Battery Strength"}, {0, 0x3c, "Invert"}, {0, 0x42, "TipSwitch"}, {0, 0x43, "SecondaryTipSwitch"}, @@ -160,7 +162,40 @@ static const struct hid_usage_entry hid_usage_table[] = { {0, 0x59, "ButtonType"}, {0, 0x5A, "SecondaryBarrelSwitch"}, {0, 0x5B, "TransducerSerialNumber"}, + {0, 0x5C, "Preferred Color"}, + {0, 0x5D, "Preferred Color is Locked"}, + {0, 0x5E, "Preferred Line Width"}, + {0, 0x5F, "Preferred Line Width is Locked"}, {0, 0x6e, "TransducerSerialNumber2"}, + {0, 0x70, "Preferred Line Style"}, + {0, 0x71, "Preferred Line Style is Locked"}, + {0, 0x72, "Ink"}, + {0, 0x73, "Pencil"}, + {0, 0x74, "Highlighter"}, + {0, 0x75, "Chisel Marker"}, + {0, 0x76, "Brush"}, + {0, 0x77, "No Preference"}, + {0, 0x80, "Digitizer Diagnostic"}, + {0, 0x81, "Digitizer Error"}, + {0, 0x82, "Err Normal Status"}, + {0, 0x83, "Err Transducers Exceeded"}, + {0, 0x84, "Err Full Trans Features Unavailable"}, + {0, 0x85, "Err Charge Low"}, + {0, 0x90, "Transducer Software Info"}, + {0, 0x91, "Transducer Vendor Id"}, + {0, 0x92, "Transducer Product Id"}, + {0, 0x93, "Device Supported Protocols"}, + {0, 0x94, "Transducer Supported Protocols"}, + {0, 0x95, "No Protocol"}, + {0, 0x96, "Wacom AES Protocol"}, + {0, 0x97, "USI Protocol"}, + {0, 0x98, "Microsoft Pen Protocol"}, + {0, 0xA0, "Supported Report Rates"}, + {0, 0xA1, "Report Rate"}, + {0, 0xA2, "Transducer Connected"}, + {0, 0xA3, "Switch Disabled"}, + {0, 0xA4, "Switch Unimplemented"}, + {0, 0xA5, "Transducer Switches"}, { 15, 0, "PhysicalInterfaceDevice" }, {0, 0x00, "Undefined"}, {0, 0x01, "Physical_Interface_Device"}, From 415e701cee5228f168049881624e343d9a3d97bb Mon Sep 17 00:00:00 2001 From: chiminghao Date: Tue, 9 Nov 2021 08:26:10 +0000 Subject: [PATCH 14/32] HID: thrustmaster use swap() to make code cleaner Fix the following coccicheck REVIEW: Use swap() instead of reimplementing it. Reported-by: Zeal Robot Signed-off-by: chiminghao [bentiss: rewrote commit title] Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211109082610.131341-1-chi.minghao@zte.com.cn --- drivers/hid/hid-tmff.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index 90acef3045369..4040cd98dafed 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -78,7 +78,6 @@ static int tmff_play(struct input_dev *dev, void *data, struct hid_field *ff_field = tmff->ff_field; int x, y; int left, right; /* Rumbling */ - int motor_swap; switch (effect->type) { case FF_CONSTANT: @@ -104,11 +103,8 @@ static int tmff_play(struct input_dev *dev, void *data, ff_field->logical_maximum); /* 2-in-1 strong motor is left */ - if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) { - motor_swap = left; - left = right; - right = motor_swap; - } + if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) + swap(left, right); dbg_hid("(left,right)=(%08x, %08x)\n", left, right); ff_field->value[0] = left; From 8590222e4b021054a7167a4dd35b152a8ed7018e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Tue, 30 Nov 2021 10:29:57 -0300 Subject: [PATCH 15/32] HID: hidraw: Replace hidraw device table mutex with a rwsem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the table that stores information about the connected hidraw devices has a mutex to prevent concurrent hidraw users to manipulate the hidraw table (e.g. delete an entry) while someone is trying to use the table (e.g. issuing an ioctl to the device), preventing the kernel to referencing a NULL pointer. However, since that every user that wants to access the table for both manipulating it and reading it content, this prevents concurrent access to the table for read-only operations for different or the same device (e.g. two hidraw ioctls can't happen at the same time, even if they are completely unrelated). This proves to be a bottleneck and gives performance issues when using multiple HID devices at same time, like VR kits where one can have two controllers, the headset and some tracking sensors. To improve the performance, replace the table mutex with a read-write semaphore, enabling multiple threads to issue parallel syscalls to multiple devices at the same time while protecting the table for concurrent modifications. Signed-off-by: André Almeida Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211130132957.8480-2-andrealmeid@collabora.com --- drivers/hid/hidraw.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 79faac87a06ff..681614a8302a5 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -34,7 +34,7 @@ static int hidraw_major; static struct cdev hidraw_cdev; static struct class *hidraw_class; static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; -static DEFINE_MUTEX(minors_lock); +static DECLARE_RWSEM(minors_rwsem); static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -107,7 +107,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, __u8 *buf; int ret = 0; - lockdep_assert_held(&minors_lock); + lockdep_assert_held(&minors_rwsem); if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { ret = -ENODEV; @@ -160,9 +160,9 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { ssize_t ret; - mutex_lock(&minors_lock); + down_read(&minors_rwsem); ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT); - mutex_unlock(&minors_lock); + up_read(&minors_rwsem); return ret; } @@ -182,7 +182,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t int ret = 0, len; unsigned char report_number; - lockdep_assert_held(&minors_lock); + lockdep_assert_held(&minors_rwsem); if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { ret = -ENODEV; @@ -272,7 +272,7 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; } - mutex_lock(&minors_lock); + down_read(&minors_rwsem); if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { err = -ENODEV; goto out_unlock; @@ -301,7 +301,7 @@ static int hidraw_open(struct inode *inode, struct file *file) spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags); file->private_data = list; out_unlock: - mutex_unlock(&minors_lock); + up_read(&minors_rwsem); out: if (err < 0) kfree(list); @@ -347,7 +347,7 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw_list *list = file->private_data; unsigned long flags; - mutex_lock(&minors_lock); + down_write(&minors_rwsem); spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags); list_del(&list->node); @@ -356,7 +356,7 @@ static int hidraw_release(struct inode * inode, struct file * file) drop_ref(hidraw_table[minor], 0); - mutex_unlock(&minors_lock); + up_write(&minors_rwsem); return 0; } @@ -369,7 +369,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, struct hidraw *dev; void __user *user_arg = (void __user*) arg; - mutex_lock(&minors_lock); + down_read(&minors_rwsem); dev = hidraw_table[minor]; if (!dev || !dev->exist) { ret = -ENODEV; @@ -487,7 +487,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ret = -ENOTTY; } out: - mutex_unlock(&minors_lock); + up_read(&minors_rwsem); return ret; } @@ -546,7 +546,7 @@ int hidraw_connect(struct hid_device *hid) result = -EINVAL; - mutex_lock(&minors_lock); + down_write(&minors_rwsem); for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { if (hidraw_table[minor]) @@ -557,7 +557,7 @@ int hidraw_connect(struct hid_device *hid) } if (result) { - mutex_unlock(&minors_lock); + up_write(&minors_rwsem); kfree(dev); goto out; } @@ -567,7 +567,7 @@ int hidraw_connect(struct hid_device *hid) if (IS_ERR(dev->dev)) { hidraw_table[minor] = NULL; - mutex_unlock(&minors_lock); + up_write(&minors_rwsem); result = PTR_ERR(dev->dev); kfree(dev); goto out; @@ -583,7 +583,7 @@ int hidraw_connect(struct hid_device *hid) dev->exist = 1; hid->hidraw = dev; - mutex_unlock(&minors_lock); + up_write(&minors_rwsem); out: return result; @@ -594,11 +594,11 @@ void hidraw_disconnect(struct hid_device *hid) { struct hidraw *hidraw = hid->hidraw; - mutex_lock(&minors_lock); + down_write(&minors_rwsem); drop_ref(hidraw, 1); - mutex_unlock(&minors_lock); + up_write(&minors_rwsem); } EXPORT_SYMBOL_GPL(hidraw_disconnect); From fd8d135b2c5e88662f2729e034913f183455a667 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 8 Dec 2021 22:40:43 +1000 Subject: [PATCH 16/32] HID: quirks: Allow inverting the absolute X/Y values Add a HID_QUIRK_X_INVERT/HID_QUIRK_Y_INVERT quirk that can be used to invert the X/Y values. Signed-off-by: Alistair Francis [bentiss: silence checkpatch warning] Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211208124045.61815-2-alistair@alistair23.me --- drivers/hid/hid-input.c | 6 ++++++ include/linux/hid.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 4186143da7c6e..5f357dddcc018 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1329,6 +1329,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input = field->hidinput->input; + if (usage->type == EV_ABS && + (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) || + ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) { + value = field->logical_maximum - value; + } + if (usage->hat_min < usage->hat_max || usage->hat_dir) { int hat_dir = usage->hat_dir; if (!hat_dir) diff --git a/include/linux/hid.h b/include/linux/hid.h index ff8b6973022ab..a14c089eb0c1b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -359,6 +359,8 @@ struct hid_item { /* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ #define HID_QUIRK_ALWAYS_POLL BIT(10) #define HID_QUIRK_INPUT_PER_APP BIT(11) +#define HID_QUIRK_X_INVERT BIT(12) +#define HID_QUIRK_Y_INVERT BIT(13) #define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16) #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17) #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) From b60d3c803d7603432a08aeaf988aff53b3a5ec64 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 8 Dec 2021 22:40:44 +1000 Subject: [PATCH 17/32] HID: i2c-hid-of: Expose the touchscreen-inverted properties Allow the touchscreen-inverted-x/y device tree properties to control the HID_QUIRK_X_INVERT/HID_QUIRK_Y_INVERT quirks for the hid-input device. Signed-off-by: Alistair Francis Acked-by: Rob Herring [bentiss: silence checkpatch warnings] Signed-off-by: Benjamin Tissoires Link: https://lore.kernel.org/r/20211208124045.61815-3-alistair@alistair23.me --- .../devicetree/bindings/input/hid-over-i2c.txt | 2 ++ drivers/hid/i2c-hid/i2c-hid-acpi.c | 2 +- drivers/hid/i2c-hid/i2c-hid-core.c | 4 +++- drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 2 +- drivers/hid/i2c-hid/i2c-hid-of.c | 10 +++++++++- drivers/hid/i2c-hid/i2c-hid.h | 2 +- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt index c76bafaf98d2f..34c43d3bddfd1 100644 --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt @@ -32,6 +32,8 @@ device-specific compatible properties, which should be used in addition to the - vdd-supply: phandle of the regulator that provides the supply voltage. - post-power-on-delay-ms: time required by the device after enabling its regulators or powering it on, before it is ready for communication. +- touchscreen-inverted-x: See touchscreen.txt +- touchscreen-inverted-y: See touchscreen.txt Example: diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c index a6f0257a26de3..b96ae15e0ad91 100644 --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -111,7 +111,7 @@ static int i2c_hid_acpi_probe(struct i2c_client *client) } return i2c_hid_core_probe(client, &ihid_acpi->ops, - hid_descriptor_address); + hid_descriptor_address, 0); } static const struct acpi_device_id i2c_hid_acpi_match[] = { diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 4cdd862ca1cb6..be00e07df06c8 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -912,7 +912,7 @@ static void i2c_hid_core_shutdown_tail(struct i2c_hid *ihid) } int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, - u16 hid_descriptor_address) + u16 hid_descriptor_address, u32 quirks) { int ret; struct i2c_hid *ihid; @@ -1009,6 +1009,8 @@ 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: diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c index 52674149a2750..b4dad66fa954d 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c +++ b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c @@ -150,7 +150,7 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client, goodix_i2c_hid_deassert_reset(ihid_goodix, true); mutex_unlock(&ihid_goodix->regulator_mutex); - return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001); + return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0); } static const struct goodix_i2c_hid_timing_data goodix_gt7375p_timing_data = { diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c index 4bf7cea926379..97a27a803f58d 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of.c +++ b/drivers/hid/i2c-hid/i2c-hid-of.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,7 @@ static int i2c_hid_of_probe(struct i2c_client *client, struct device *dev = &client->dev; struct i2c_hid_of *ihid_of; u16 hid_descriptor_address; + u32 quirks = 0; int ret; u32 val; @@ -105,8 +107,14 @@ static int i2c_hid_of_probe(struct i2c_client *client, if (ret) return ret; + if (device_property_read_bool(dev, "touchscreen-inverted-x")) + quirks |= HID_QUIRK_X_INVERT; + + if (device_property_read_bool(dev, "touchscreen-inverted-y")) + quirks |= HID_QUIRK_Y_INVERT; + return i2c_hid_core_probe(client, &ihid_of->ops, - hid_descriptor_address); + hid_descriptor_address, quirks); } static const struct of_device_id i2c_hid_of_match[] = { diff --git a/drivers/hid/i2c-hid/i2c-hid.h b/drivers/hid/i2c-hid/i2c-hid.h index 05a7827d211af..236cc062d5ef8 100644 --- a/drivers/hid/i2c-hid/i2c-hid.h +++ b/drivers/hid/i2c-hid/i2c-hid.h @@ -32,7 +32,7 @@ struct i2chid_ops { }; int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, - u16 hid_descriptor_address); + u16 hid_descriptor_address, u32 quirks); int i2c_hid_core_remove(struct i2c_client *client); void i2c_hid_core_shutdown(struct i2c_client *client); From 9f92d61f01dd31305e53d3d6c036e93269070167 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Wed, 1 Dec 2021 23:16:50 -0700 Subject: [PATCH 18/32] HID: apple: Add 2021 Magic Keyboard with fingerprint reader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Henrie Tested-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 4 ++++ drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 3 files changed, 6 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2bd8276411e07..0111d64c74848 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -722,6 +722,10 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 95037a3e2e6ef..f045a3d6a8dbe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -175,6 +175,7 @@ #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 #define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c +#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a #define USB_VENDOR_ID_ASUS 0x0486 #define USB_DEVICE_ID_ASUS_T91MT 0x0185 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 06b7908c874c1..319bbae7ff62e 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -303,6 +303,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021) }, #endif #if IS_ENABLED(CONFIG_HID_APPLEIR) { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, From b2dcadef207719a9b3520cb9f1c9237c320d3ccd Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Wed, 1 Dec 2021 23:16:51 -0700 Subject: [PATCH 19/32] HID: apple: Add 2021 Magic Keyboard with number pad Signed-off-by: Alex Henrie Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 4 ++++ drivers/hid/hid-ids.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 0111d64c74848..e40cd17c7f405 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -726,6 +726,10 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021), .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021), + .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f045a3d6a8dbe..242bd96d14d2d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -176,6 +176,7 @@ #define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a +#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021 0x029f #define USB_VENDOR_ID_ASUS 0x0486 #define USB_DEVICE_ID_ASUS_T91MT 0x0185 From 0aa45fcc42d82753a257abbc7138922d8250e06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sun, 12 Dec 2021 19:20:59 +0100 Subject: [PATCH 20/32] HID: magicmouse: set device name when it has been personalized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the Apple Magic Trackpad 2 has been connected to a Mac, the name is automatically personalized showing its owner name. For example: "José Expósito's Trackpad". When connected through Bluetooth, the personalized name is reported, however, when connected through USB the generic name is reported. Set the device name correctly to ensure the same driver settings are loaded, whether connected via Bluetooth or USB. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 686788ebf3e1e..3e483dd32873b 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -535,10 +535,18 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(REL_HWHEEL_HI_RES, input->relbit); } } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { - /* setting the device name to ensure the same driver settings - * get loaded, whether connected through bluetooth or USB + /* If the trackpad has been connected to a Mac, the name is + * automatically personalized, e.g., "José Expósito's Trackpad". + * When connected through Bluetooth, the personalized name is + * reported, however, when connected through USB the generic + * name is reported. + * Set the device name to ensure the same driver settings get + * loaded, whether connected through bluetooth or USB. */ - input->name = "Apple Inc. Magic Trackpad 2"; + if (hdev->vendor == BT_VENDOR_ID_APPLE) + input->name = "Apple Inc. Magic Trackpad 2"; + else /* USB_VENDOR_ID_APPLE */ + input->name = hdev->name; __clear_bit(EV_MSC, input->evbit); __clear_bit(BTN_0, input->keybit); From 5768701edcb7d7ff8abaa085996a5c1cb30d765e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sun, 12 Dec 2021 19:21:00 +0100 Subject: [PATCH 21/32] HID: magicmouse: set Magic Trackpad 2021 name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Apple Magic Trackpad 2021 (3rd generation) has the same product ID as the 2nd generation. However, when connected through Bluetooth, the version has changed from 0x107 to 0x110. The other meaningful change is that the name has dropped the generation number and now it is just "Apple Inc. Magic Trackpad", like the first generation model. Set the device name correctly to ensure the same driver settings are loaded, whether connected via Bluetooth or USB. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 3e483dd32873b..d688610af2482 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -51,6 +51,8 @@ static bool report_undeciphered; module_param(report_undeciphered, bool, 0644); MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); +#define TRACKPAD2_2021_BT_VERSION 0x110 + #define TRACKPAD_REPORT_ID 0x28 #define TRACKPAD2_USB_REPORT_ID 0x02 #define TRACKPAD2_BT_REPORT_ID 0x31 @@ -543,10 +545,14 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd * Set the device name to ensure the same driver settings get * loaded, whether connected through bluetooth or USB. */ - if (hdev->vendor == BT_VENDOR_ID_APPLE) - input->name = "Apple Inc. Magic Trackpad 2"; - else /* USB_VENDOR_ID_APPLE */ + if (hdev->vendor == BT_VENDOR_ID_APPLE) { + if (input->id.version == TRACKPAD2_2021_BT_VERSION) + input->name = "Apple Inc. Magic Trackpad"; + else + input->name = "Apple Inc. Magic Trackpad 2"; + } else { /* USB_VENDOR_ID_APPLE */ input->name = hdev->name; + } __clear_bit(EV_MSC, input->evbit); __clear_bit(BTN_0, input->keybit); From 531cb56972f2773c941499fcfb639cd5128dfb27 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Nov 2021 13:50:38 +0100 Subject: [PATCH 22/32] HID: apple: Add 2021 magic keyboard FN key mapping The new 2021 apple models have a different FN key assignment. Add a new translation table and use that for the 2021 magic keyboard. Signed-off-by: Benjamin Berg Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index e40cd17c7f405..8fcbac7f50ce9 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -76,6 +76,28 @@ struct apple_key_translation { u8 flags; }; +static const struct apple_key_translation apple2021_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_SEARCH, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_MICMUTE, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_SLEEP, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + static const struct apple_key_translation macbookair_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -220,7 +242,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode) { - if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && + if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) + table = apple2021_fn_keys; + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) @@ -443,6 +467,9 @@ static void apple_setup_input(struct input_dev *input) for (trans = apple_iso_keyboard; trans->from; trans++) set_bit(trans->to, input->keybit); + for (trans = apple2021_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + if (swap_fn_leftctrl) { for (trans = swapped_fn_leftctrl_keys; trans->from; trans++) set_bit(trans->to, input->keybit); From 7f84e2439ed2e2c7afdced9564dda1220e932704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sun, 2 Jan 2022 18:51:13 +0100 Subject: [PATCH 23/32] HID: apple: Add Magic Keyboard 2021 with fingerprint reader FN key mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the function key table introduced for the Magic Keyboard 2021 without fingerprint reader in the models with fingerprint reader and/or numpad. Tested with the ANSI variant of the keyboard with and without numpad. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 8fcbac7f50ce9..24802a4a636ee 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -242,7 +242,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode) { - if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021) + if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 || + hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021) table = apple2021_fn_keys; else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) From 33a5c2793451770cb6dcf0cc35c76cfd4b045513 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 12 Dec 2021 22:23:33 +0100 Subject: [PATCH 24/32] HID: Add new Letsketch tablet driver Add a new driver for the LetSketch / VSON WP9620N drawing tablet. This drawing tablet is also sold under other brand names such as Case U, presumably this driver will work for all of them. But it has only been tested with a LetSketch WP9620N model. These tablets also work without a special HID driver, but then only part of the active area works and both the pad and stylus buttons are hardwired to special key-combos. E.g. the 2 stylus buttons send right mouse clicks / resp. "e" key presses. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=2005575 BugLink: https://github.com/DIGImend/digimend-kernel-drivers/issues/528 Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- MAINTAINERS | 7 + drivers/hid/Kconfig | 14 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-ids.h | 3 + drivers/hid/hid-letsketch.c | 322 ++++++++++++++++++++++++++++++++++++ 5 files changed, 347 insertions(+) create mode 100644 drivers/hid/hid-letsketch.c diff --git a/MAINTAINERS b/MAINTAINERS index 8912b2c1260ca..eea4cdec77fe4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10745,6 +10745,13 @@ S: Maintained W: http://legousb.sourceforge.net/ F: drivers/usb/misc/legousbtower.c +LETSKETCH HID TABLET DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git +F: drivers/hid/hid-letsketch.c + LG LAPTOP EXTRAS M: Matan Ziv-Av L: platform-driver-x86@vger.kernel.org diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a7c78ac96270d..f5544157576c9 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -558,6 +558,20 @@ config HID_LENOVO - ThinkPad Compact Bluetooth Keyboard with TrackPoint (supports Fn keys) - ThinkPad Compact USB Keyboard with TrackPoint (supports Fn keys) +config HID_LETSKETCH + tristate "Letsketch WP9620N tablets" + depends on USB_HID + help + Driver for the LetSketch / VSON WP9620N drawing tablet. This + drawing tablet is also sold under other brand names such as Case U, + presumably this driver will work for all of them. But it has only been + tested with a LetSketch WP9620N model. + + These tablets also work without a special HID driver, but then only + part of the active area works and both the pad and stylus buttons are + hardwired to special key-combos. E.g. the 2 stylus buttons send right + mouse clicks / resp. "e" key presses. + config HID_LOGITECH tristate "Logitech devices" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 55a6fa3eca5a6..6d3e630e81af5 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o +obj-$(CONFIG_HID_LETSKETCH) += hid-letsketch.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH) += hid-lg-g15.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 19da07777d628..43095763535eb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -763,6 +763,9 @@ #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093 +#define USB_VENDOR_ID_LETSKETCH 0x6161 +#define USB_DEVICE_ID_WP9620N 0x4d15 + #define USB_VENDOR_ID_LG 0x1fd2 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 #define USB_DEVICE_ID_LG_MELFAS_MT 0x6007 diff --git a/drivers/hid/hid-letsketch.c b/drivers/hid/hid-letsketch.c new file mode 100644 index 0000000000000..74d17cf518ba1 --- /dev/null +++ b/drivers/hid/hid-letsketch.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021 Hans de Goede + * + * Driver for the LetSketch / VSON WP9620N drawing tablet. + * This drawing tablet is also sold under other brand names such as Case U, + * presumably this driver will work for all of them. But it has only been + * tested with a LetSketch WP9620N model. + * + * These tablets also work without a special HID driver, but then only part + * of the active area works and both the pad and stylus buttons are hardwired + * to special key-combos. E.g. the 2 stylus buttons send right mouse clicks / + * resp. "e" key presses. + * + * This device has 4 USB interfaces: + * + * Interface 0 EP 0x81 bootclass mouse, rdesc len 18, report id 0x08, + * Application(ff00.0001) + * This interface sends raw event input reports in a custom format, but only + * after doing the special dance from letsketch_probe(). After enabling this + * interface the other 3 interfaces are disabled. + * + * Interface 1 EP 0x82 bootclass mouse, rdesc len 83, report id 0x0a, Tablet + * This interface sends absolute events for the pen, including pressure, + * but only for some part of the active area due to special "aspect ratio" + * correction and only half by default since it assumes it will be used + * with a phone in portraid mode, while using the tablet in landscape mode. + * Also stylus + pad button events are not reported here. + * + * Interface 2 EP 0x83 bootclass keybd, rdesc len 64, report id none, Std Kbd + * This interfaces send various hard-coded key-combos for the pad buttons + * and "e" keypresses for the 2nd stylus button + * + * Interface 3 EP 0x84 bootclass mouse, rdesc len 75, report id 0x01, Std Mouse + * This reports right-click mouse-button events for the 1st stylus button + */ +#include +#include +#include +#include +#include +#include + +#include + +#include "hid-ids.h" + +#define LETSKETCH_RAW_IF 0 + +#define LETSKETCH_RAW_DATA_LEN 12 +#define LETSKETCH_RAW_REPORT_ID 8 + +#define LETSKETCH_PAD_BUTTONS 5 + +#define LETSKETCH_INFO_STR_IDX_BEGIN 0xc8 +#define LETSKETCH_INFO_STR_IDX_END 0xca + +#define LETSKETCH_GET_STRING_RETRIES 5 + +struct letsketch_data { + struct hid_device *hdev; + struct input_dev *input_tablet; + struct input_dev *input_tablet_pad; + struct timer_list inrange_timer; +}; + +static int letsketch_open(struct input_dev *dev) +{ + struct letsketch_data *data = input_get_drvdata(dev); + + return hid_hw_open(data->hdev); +} + +static void letsketch_close(struct input_dev *dev) +{ + struct letsketch_data *data = input_get_drvdata(dev); + + hid_hw_close(data->hdev); +} + +static struct input_dev *letsketch_alloc_input_dev(struct letsketch_data *data) +{ + struct input_dev *input; + + input = devm_input_allocate_device(&data->hdev->dev); + if (!input) + return NULL; + + input->id.bustype = data->hdev->bus; + input->id.vendor = data->hdev->vendor; + input->id.product = data->hdev->product; + input->id.version = data->hdev->bus; + input->phys = data->hdev->phys; + input->uniq = data->hdev->uniq; + input->open = letsketch_open; + input->close = letsketch_close; + + input_set_drvdata(input, data); + + return input; +} + +static int letsketch_setup_input_tablet(struct letsketch_data *data) +{ + struct input_dev *input; + + input = letsketch_alloc_input_dev(data); + if (!input) + return -ENOMEM; + + input_set_abs_params(input, ABS_X, 0, 50800, 0, 0); + input_set_abs_params(input, ABS_Y, 0, 31750, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 8192, 0, 0); + input_abs_set_res(input, ABS_X, 240); + input_abs_set_res(input, ABS_Y, 225); + input_set_capability(input, EV_KEY, BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOOL_PEN); + input_set_capability(input, EV_KEY, BTN_STYLUS); + input_set_capability(input, EV_KEY, BTN_STYLUS2); + + /* All known brands selling this tablet use WP9620[N] as model name */ + input->name = "WP9620 Tablet"; + + data->input_tablet = input; + + return input_register_device(data->input_tablet); +} + +static int letsketch_setup_input_tablet_pad(struct letsketch_data *data) +{ + struct input_dev *input; + int i; + + input = letsketch_alloc_input_dev(data); + if (!input) + return -ENOMEM; + + for (i = 0; i < LETSKETCH_PAD_BUTTONS; i++) + input_set_capability(input, EV_KEY, BTN_0 + i); + + /* + * These are never send on the pad input_dev, but must be set + * on the Pad to make udev / libwacom happy. + */ + input_set_abs_params(input, ABS_X, 0, 1, 0, 0); + input_set_abs_params(input, ABS_Y, 0, 1, 0, 0); + input_set_capability(input, EV_KEY, BTN_STYLUS); + + input->name = "WP9620 Pad"; + + data->input_tablet_pad = input; + + return input_register_device(data->input_tablet_pad); +} + +static void letsketch_inrange_timeout(struct timer_list *t) +{ + struct letsketch_data *data = from_timer(data, t, inrange_timer); + struct input_dev *input = data->input_tablet; + + input_report_key(input, BTN_TOOL_PEN, 0); + input_sync(input); +} + +static int letsketch_raw_event(struct hid_device *hdev, + struct hid_report *report, + u8 *raw_data, int size) +{ + struct letsketch_data *data = hid_get_drvdata(hdev); + struct input_dev *input; + int i; + + if (size != LETSKETCH_RAW_DATA_LEN || raw_data[0] != LETSKETCH_RAW_REPORT_ID) + return 0; + + switch (raw_data[1] & 0xf0) { + case 0x80: /* Pen data */ + input = data->input_tablet; + input_report_key(input, BTN_TOOL_PEN, 1); + input_report_key(input, BTN_TOUCH, raw_data[1] & 0x01); + input_report_key(input, BTN_STYLUS, raw_data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, raw_data[1] & 0x04); + input_report_abs(input, ABS_X, + get_unaligned_le16(raw_data + 2)); + input_report_abs(input, ABS_Y, + get_unaligned_le16(raw_data + 4)); + input_report_abs(input, ABS_PRESSURE, + get_unaligned_le16(raw_data + 6)); + /* + * There is no out of range event, so use a timer for this + * when in range we get an event approx. every 8 ms. + */ + mod_timer(&data->inrange_timer, jiffies + msecs_to_jiffies(100)); + break; + case 0xe0: /* Pad data */ + input = data->input_tablet_pad; + for (i = 0; i < LETSKETCH_PAD_BUTTONS; i++) + input_report_key(input, BTN_0 + i, raw_data[4] == (i + 1)); + break; + default: + hid_warn(data->hdev, "Warning unknown data header: 0x%02x\n", + raw_data[0]); + return 0; + } + + input_sync(input); + return 0; +} + +/* + * The tablets magic handshake to put it in raw mode relies on getting + * string descriptors. But the firmware is buggy and does not like it if + * we do this too fast. Even if we go slow sometimes the usb_string() call + * fails. Ignore errors and retry it a couple of times if necessary. + */ +static int letsketch_get_string(struct usb_device *udev, int index, char *buf, int size) +{ + int i, ret; + + for (i = 0; i < LETSKETCH_GET_STRING_RETRIES; i++) { + usleep_range(5000, 7000); + ret = usb_string(udev, index, buf, size); + if (ret > 0) + return 0; + } + + dev_err(&udev->dev, "Max retries (%d) exceeded reading string descriptor %d\n", + LETSKETCH_GET_STRING_RETRIES, index); + return ret ? ret : -EIO; +} + +static int letsketch_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct device *dev = &hdev->dev; + struct letsketch_data *data; + struct usb_interface *intf; + struct usb_device *udev; + char buf[256]; + int i, ret; + + if (!hid_is_using_ll_driver(hdev, &usb_hid_driver)) + return -ENODEV; + + intf = to_usb_interface(hdev->dev.parent); + if (intf->altsetting->desc.bInterfaceNumber != LETSKETCH_RAW_IF) + return -ENODEV; /* Ignore the other interfaces */ + + udev = interface_to_usbdev(intf); + + /* + * Instead of using a set-feature request, or even a custom USB ctrl + * message the tablet needs this elaborate magic reading of USB + * string descriptors to kick it into raw mode. This is what the + * Windows drivers are seen doing in an USB trace under Windows. + */ + for (i = LETSKETCH_INFO_STR_IDX_BEGIN; i <= LETSKETCH_INFO_STR_IDX_END; i++) { + ret = letsketch_get_string(udev, i, buf, sizeof(buf)); + if (ret) + return ret; + + hid_info(hdev, "Device info: %s\n", buf); + } + + for (i = 1; i <= 250; i++) { + ret = letsketch_get_string(udev, i, buf, sizeof(buf)); + if (ret) + return ret; + } + + ret = letsketch_get_string(udev, 0x64, buf, sizeof(buf)); + if (ret) + return ret; + + ret = letsketch_get_string(udev, LETSKETCH_INFO_STR_IDX_BEGIN, buf, sizeof(buf)); + if (ret) + return ret; + + /* + * The tablet should be in raw mode now, end with a final delay before + * doing further IO to the device. + */ + usleep_range(5000, 7000); + + ret = hid_parse(hdev); + if (ret) + return ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->hdev = hdev; + timer_setup(&data->inrange_timer, letsketch_inrange_timeout, 0); + hid_set_drvdata(hdev, data); + + ret = letsketch_setup_input_tablet(data); + if (ret) + return ret; + + ret = letsketch_setup_input_tablet_pad(data); + if (ret) + return ret; + + return hid_hw_start(hdev, HID_CONNECT_HIDRAW); +} + +static const struct hid_device_id letsketch_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LETSKETCH, USB_DEVICE_ID_WP9620N) }, + { } +}; +MODULE_DEVICE_TABLE(hid, letsketch_devices); + +static struct hid_driver letsketch_driver = { + .name = "letsketch", + .id_table = letsketch_devices, + .probe = letsketch_probe, + .raw_event = letsketch_raw_event, +}; +module_hid_driver(letsketch_driver); + +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); From f364c571a5c77e96de2d32062ff019d6b8d2e2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 5 Jan 2022 18:29:12 +0100 Subject: [PATCH 25/32] HID: hid-uclogic-params: Invalid parameter check in uclogic_params_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function performs a check on its input parameters, however, the hdev parameter is used before the check. Initialize the stack variables after checking the input parameters to avoid a possible NULL pointer dereference. Fixes: 9614219e9310e ("HID: uclogic: Extract tablet parameter discovery into a module") Addresses-Coverity-ID: 1443831 ("Null pointer dereference") Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index adff1bd68d9f8..3c10b858cf74c 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -834,10 +834,10 @@ int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev) { int rc; - struct usb_device *udev = hid_to_usb_dev(hdev); - __u8 bNumInterfaces = udev->config->desc.bNumInterfaces; - struct usb_interface *iface = to_usb_interface(hdev->dev.parent); - __u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + struct usb_device *udev; + __u8 bNumInterfaces; + struct usb_interface *iface; + __u8 bInterfaceNumber; bool found; /* The resulting parameters (noop) */ struct uclogic_params p = {0, }; @@ -848,6 +848,11 @@ int uclogic_params_init(struct uclogic_params *params, goto cleanup; } + udev = hid_to_usb_dev(hdev); + bNumInterfaces = udev->config->desc.bNumInterfaces; + iface = to_usb_interface(hdev->dev.parent); + bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + /* * Set replacement report descriptor if the original matches the * specified size. Otherwise keep interface unchanged. From 0a94131d6920916ccb6a357037c535533af08819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 5 Jan 2022 18:29:13 +0100 Subject: [PATCH 26/32] HID: hid-uclogic-params: Invalid parameter check in uclogic_params_get_str_desc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function performs a check on the hdev input parameters, however, it is used before the check. Initialize the udev variable after the sanity check to avoid a possible NULL pointer dereference. Fixes: 9614219e9310e ("HID: uclogic: Extract tablet parameter discovery into a module") Addresses-Coverity-ID: 1443827 ("Null pointer dereference") Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 3c10b858cf74c..3a83e2c39b4fb 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -66,7 +66,7 @@ static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev, __u8 idx, size_t len) { int rc; - struct usb_device *udev = hid_to_usb_dev(hdev); + struct usb_device *udev; __u8 *buf = NULL; /* Check arguments */ @@ -75,6 +75,8 @@ static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev, goto cleanup; } + udev = hid_to_usb_dev(hdev); + buf = kmalloc(len, GFP_KERNEL); if (buf == NULL) { rc = -ENOMEM; From ff6b548afe4d9d1ff3a0f6ef79e8cbca25d8f905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 5 Jan 2022 18:29:14 +0100 Subject: [PATCH 27/32] HID: hid-uclogic-params: Invalid parameter check in uclogic_params_huion_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function performs a check on its input parameters, however, the hdev parameter is used before the check. Initialize the stack variables after checking the input parameters to avoid a possible NULL pointer dereference. Fixes: 9614219e9310e ("HID: uclogic: Extract tablet parameter discovery into a module") Addresses-Coverity-ID: 1443804 ("Null pointer dereference") Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 3a83e2c39b4fb..4136837e4d158 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -709,9 +709,9 @@ static int uclogic_params_huion_init(struct uclogic_params *params, struct hid_device *hdev) { int rc; - struct usb_device *udev = hid_to_usb_dev(hdev); - struct usb_interface *iface = to_usb_interface(hdev->dev.parent); - __u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + struct usb_device *udev; + struct usb_interface *iface; + __u8 bInterfaceNumber; bool found; /* The resulting parameters (noop) */ struct uclogic_params p = {0, }; @@ -725,6 +725,10 @@ static int uclogic_params_huion_init(struct uclogic_params *params, goto cleanup; } + udev = hid_to_usb_dev(hdev); + iface = to_usb_interface(hdev->dev.parent); + bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + /* If it's not a pen interface */ if (bInterfaceNumber != 0) { /* TODO: Consider marking the interface invalid */ From aa320fdbbbb482c19100f51461bd0069753ce3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 5 Jan 2022 18:29:15 +0100 Subject: [PATCH 28/32] HID: hid-uclogic-params: Invalid parameter check in uclogic_params_frame_init_v1_buttonpad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function performs a check on the hdev input parameters, however, it is used before the check. Initialize the udev variable after the sanity check to avoid a possible NULL pointer dereference. Fixes: 9614219e9310e ("HID: uclogic: Extract tablet parameter discovery into a module") Addresses-Coverity-ID: 1443763 ("Null pointer dereference") Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 4136837e4d158..3e70f969fb849 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -452,7 +452,7 @@ static int uclogic_params_frame_init_v1_buttonpad( { int rc; bool found = false; - struct usb_device *usb_dev = hid_to_usb_dev(hdev); + struct usb_device *usb_dev; char *str_buf = NULL; const size_t str_len = 16; @@ -462,6 +462,8 @@ static int uclogic_params_frame_init_v1_buttonpad( goto cleanup; } + usb_dev = hid_to_usb_dev(hdev); + /* * Enable generic button mode */ From bcad6d1bd9177740176ea79f6d0fc9f5b07e0c43 Mon Sep 17 00:00:00 2001 From: Ye Xiang Date: Fri, 17 Dec 2021 15:45:41 +0800 Subject: [PATCH 29/32] HID: intel-ish-hid: ipc: Specify no cache snooping on TGL and ADL Specify that both TGL and ADL don't support DMA cache snooping. Signed-off-by: Ye Xiang Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/ipc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 45e0c7b1c9ec6..8ccb246b0114a 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -909,7 +909,11 @@ static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length, */ static bool _dma_no_cache_snooping(struct ishtp_device *dev) { - return dev->pdev->device == EHL_Ax_DEVICE_ID; + return (dev->pdev->device == EHL_Ax_DEVICE_ID || + dev->pdev->device == TGL_LP_DEVICE_ID || + dev->pdev->device == TGL_H_DEVICE_ID || + dev->pdev->device == ADL_S_DEVICE_ID || + dev->pdev->device == ADL_P_DEVICE_ID); } static const struct ishtp_hw_ops ish_hw_ops = { From 98b6b62cd5569a158868b62dc7866b5aae5d9a38 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 16 Dec 2021 12:01:46 +0800 Subject: [PATCH 30/32] HID: intel-ish-hid: ishtp-fw-loader: Fix a kernel-doc formatting issue This function had kernel-doc that not used a hash to separate the function name from the one line description. The warning was found by running scripts/kernel-doc, which is caused by using 'make W=1'. drivers/hid/intel-ish-hid/ishtp-fw-loader.c:271: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-fw-loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index 0e1183e961471..e24988586710d 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -268,7 +268,8 @@ static int get_firmware_variant(struct ishtp_cl_data *client_data, } /** - * loader_cl_send() Send message from host to firmware + * loader_cl_send() - Send message from host to firmware + * * @client_data: Client data instance * @out_msg: Message buffer to be sent to firmware * @out_size: Size of out going message From 3809fe479861194e310c23ed48b010c7c0f72d22 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 16 Dec 2021 10:21:57 +0100 Subject: [PATCH 31/32] HID: address kernel-doc warnings The command ./scripts/kernel-doc -none include/linux/hid.h reports: include/linux/hid.h:818: warning: cannot understand function prototype: 'struct hid_ll_driver ' include/linux/hid.h:1135: warning: expecting prototype for hid_may_wakeup(). Prototype was for hid_hw_may_wakeup() instead Address those kernel-doc warnings. Signed-off-by: Lukas Bulwahn Signed-off-by: Jiri Kosina --- include/linux/hid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index f453be385bd47..aaf89a8a836cf 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -788,7 +788,7 @@ struct hid_driver { container_of(pdrv, struct hid_driver, driver) /** - * hid_ll_driver - low level driver callbacks + * struct hid_ll_driver - low level driver callbacks * @start: called on probe to start the device * @stop: called on remove * @open: called by input layer on open @@ -1158,7 +1158,7 @@ static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle, } /** - * hid_may_wakeup - return if the hid device may act as a wakeup source during system-suspend + * hid_hw_may_wakeup - return if the hid device may act as a wakeup source during system-suspend * * @hdev: hid device */ From 33812fc7c8d77a43b7e2bf36a0d5a57c277a4b0c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 28 Dec 2021 22:09:17 +0100 Subject: [PATCH 32/32] HID: magicmouse: Fix an error handling path in magicmouse_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the timer introduced by the commit below is started, then it must be deleted in the error handling of the probe. Otherwise it would trigger once the driver is no more. Fixes: 0b91b4e4dae6 ("HID: magicmouse: Report battery level over USB") Signed-off-by: Christophe JAILLET Tested-by: José Expósito Reported-by: Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 167b6a5dd226a..39d7956066cfd 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -870,6 +870,7 @@ static int magicmouse_probe(struct hid_device *hdev, return 0; err_stop_hw: + del_timer_sync(&msc->battery_timer); hid_hw_stop(hdev); return ret; }