diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-11 11:28:10 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-11 11:28:10 -0800 |
| commit | a31980dba7b957df21fd99d158dd0be516825676 (patch) | |
| tree | ea9c41c91772c1696a809c9e9a6ddbbc531f00b6 | |
| parent | 532355a756103639816068b89f73cc7789b16275 (diff) | |
| parent | 33312c4d5ed81506d477bc55981fca0654cb7120 (diff) | |
Merge tag 'hid-for-linus-2026020901' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina:
- global switch of HID drivers to use pm_*ptr instead of #ifdef
CONFIG_PM* (Bastien Nocera)
- support for new firmware handling in intel-ish-hid (Vishnu Sankar)
- support for HID output reports in the Quicki2c in intel-thc (Even Xu)
- solidify register configuration updates in intel-thc (Even Xu)
- Support for Rock band 4 PS4 and PS5 guitars (Rosalie Wanders)
- fn lock and WMI fan control handling improvements in certain Asus
models (ROG, ProArt P16) (Ionut Nechita, Connor Belli)
- fix for potential NULL pointer dereference during warm reset in
intel-ish-hid (Ryan Lin)
- fix for potential NULL pointer derefence in probe error paths in
hid-pl (Oliver Neukum)
- various other small assorted fixes and new device ID additions /
device-specific quirks
* tag 'hid-for-linus-2026020901' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (41 commits)
HID: sony: add dongle device IDs for CRKD Gibson SG
HID: Intel-thc-hid: Intel-thc: Fix wrong register fields updating
HID: intel-ish-hid: fix NULL-ptr-deref in ishtp_bus_remove_all_clients
HID: logitech-hidpp: Add support for Logitech K980
HID: logitech-dj: Differentiate "invalid device index" error
HID: sony: Use pm_ptr instead of #ifdef CONFIG_PM
HID: wacom: Use pm_ptr instead of #ifdef CONFIG_PM
HID: uclogic: Use pm_ptr instead of #ifdef CONFIG_PM
HID: hid-sensor-hub: Use pm_ptr instead of #ifdef CONFIG_PM
HID: picolcd_core: Use pm_ptr instead of #ifdef CONFIG_PM
HID: nintendo: Use pm_ptr instead of #ifdef CONFIG_PM
HID: logitech-dj: Use pm_ptr instead of #ifdef CONFIG_PM
HID: lenovo: Use pm_ptr instead of #ifdef CONFIG_PM
HID: asus: Use pm_ptr instead of #ifdef CONFIG_PM
HID: appletb-kbd: Use pm_ptr instead of #ifdef CONFIG_PM
HID: hid-alps: Use pm_ptr instead of #ifdef CONFIG_PM
HID: multitouch: add eGalaxTouch EXC3188 support
HID: elecom: Add support for ELECOM HUGE Plus M-HT1MRBK
HID: sony: add support for bluetooth Rock Band 4 PS4 guitars
HID: logitech-hidpp: Check maxfield in hidpp_get_report_length()
...
35 files changed, 676 insertions, 132 deletions
diff --git a/Documentation/hid/intel-ish-hid.rst b/Documentation/hid/intel-ish-hid.rst index 2adc174fb576..068a5906b177 100644 --- a/Documentation/hid/intel-ish-hid.rst +++ b/Documentation/hid/intel-ish-hid.rst @@ -413,6 +413,10 @@ Vendors who wish to upstream their custom firmware should follow these guideline - The firmware filename should use one of the following patterns: + - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`` + - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_SKU_CRC32}.bin`` + - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_NAME_CRC32}.bin`` + - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}.bin`` - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`` - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin`` - ``ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin`` @@ -420,16 +424,21 @@ Vendors who wish to upstream their custom firmware should follow these guideline - ``${intel_plat_gen}`` indicates the Intel platform generation (e.g., ``lnlm`` for Lunar Lake) and must not exceed 8 characters in length. - ``${SYS_VENDOR_CRC32}`` is the CRC32 checksum of the ``sys_vendor`` value from the DMI field ``DMI_SYS_VENDOR``. +- ``${PRODUCT_FAMILY_CRC32}`` is the CRC32 checksum of the ``product_family`` value from the DMI field ``DMI_PRODUCT_FAMILY``. - ``${PRODUCT_NAME_CRC32}`` is the CRC32 checksum of the ``product_name`` value from the DMI field ``DMI_PRODUCT_NAME``. - ``${PRODUCT_SKU_CRC32}`` is the CRC32 checksum of the ``product_sku`` value from the DMI field ``DMI_PRODUCT_SKU``. During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns: -1. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`` -2. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin`` -3. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin`` -4. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin`` -5. ``intel/ish/ish_${intel_plat_gen}.bin`` +1. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`` +2. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_SKU_CRC32}.bin`` +3. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}_${PRODUCT_NAME_CRC32}.bin`` +4. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_FAMILY_CRC32}.bin`` +5. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin`` +6. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin`` +7. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin`` +8. ``intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin`` +9. ``intel/ish/ish_${intel_plat_gen}.bin`` The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded. diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 920a64b66b25..c1d9f7c6a5f2 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -369,6 +369,7 @@ config HID_ELECOM - EX-G Trackballs (M-XT3DRBK, M-XT3URBK) - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK) - HUGE Trackballs (M-HT1DRBK, M-HT1URBK) + - HUGE Plus Trackball (M-HT1MRBK) config HID_ELO tristate "ELO USB 4000/4500 touchscreen" @@ -1015,6 +1016,12 @@ config HID_PXRC To compile this driver as a module, choose M here: the module will be called hid-pxrc. +config HID_RAPOO + tristate "Rapoo non-fully HID-compliant devices" + help + Support for Rapoo devices that are not fully compliant with the + HID standard. + config HID_RAZER tristate "Razer non-fully HID-compliant devices" help @@ -1084,7 +1091,7 @@ config HID_SIGMAMICRO - Rapoo V500 config HID_SONY - tristate "Sony PS2/3/4 accessories" + tristate "Sony PS2/3/4/5 accessories" depends on USB_HID depends on NEW_LEDS depends on LEDS_CLASS @@ -1094,12 +1101,12 @@ config HID_SONY Support for * Sony PS3 6-axis controllers - * Sony PS4 DualShock 4 controllers * Buzz controllers * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) * Guitar Hero Live PS3, Wii U and PS4 guitar dongles * Guitar Hero PS3 and PC guitar dongles + * Rock Band 4 PS4 and PS5 guitars config SONY_FF bool "Sony PS2/3/4 accessories force feedback support" diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 361a7daedeb8..e01838239ae6 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_PXRC) += hid-pxrc.o +obj-$(CONFIG_HID_RAPOO) += hid-rapoo.o obj-$(CONFIG_HID_RAZER) += hid-razer.o obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o obj-$(CONFIG_HID_RETRODE) += hid-retrode.o diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index ba00f6e6324b..21e55f3d0d1b 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -840,10 +840,8 @@ static struct hid_driver alps_driver = { .raw_event = alps_raw_event, .input_mapping = alps_input_mapping, .input_configured = alps_input_configured, -#ifdef CONFIG_PM - .resume = alps_post_resume, - .reset_resume = alps_post_reset, -#endif + .resume = pm_ptr(alps_post_resume), + .reset_resume = pm_ptr(alps_post_reset), }; module_hid_driver(alps_driver); diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 57da4f86a9fa..233e367cce1d 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -354,6 +354,7 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { }; static const struct apple_non_apple_keyboard non_apple_keyboards[] = { + { "SONiX KN85 Keyboard" }, { "SONiX USB DEVICE" }, { "SONiX AK870 PRO" }, { "Keychron" }, diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c index b00687e67ce8..a1db3b3d0667 100644 --- a/drivers/hid/hid-appletb-kbd.c +++ b/drivers/hid/hid-appletb-kbd.c @@ -466,7 +466,6 @@ static void appletb_kbd_remove(struct hid_device *hdev) hid_hw_stop(hdev); } -#ifdef CONFIG_PM static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg) { struct appletb_kbd *kbd = hid_get_drvdata(hdev); @@ -485,7 +484,6 @@ static int appletb_kbd_reset_resume(struct hid_device *hdev) return 0; } -#endif static const struct hid_device_id appletb_kbd_hid_ids[] = { /* MacBook Pro's 2018, 2019, with T2 chip: iBridge Display */ @@ -501,10 +499,8 @@ static struct hid_driver appletb_kbd_hid_driver = { .remove = appletb_kbd_remove, .event = appletb_kbd_hid_event, .input_configured = appletb_kbd_input_configured, -#ifdef CONFIG_PM - .suspend = appletb_kbd_suspend, - .reset_resume = appletb_kbd_reset_resume, -#endif + .suspend = pm_ptr(appletb_kbd_suspend), + .reset_resume = pm_ptr(appletb_kbd_reset_resume), .driver.dev_groups = appletb_kbd_groups, }; module_hid_driver(appletb_kbd_hid_driver); diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 472bca54642b..df7c03dde67f 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -23,6 +23,7 @@ /* */ +#include <linux/acpi.h> #include <linux/dmi.h> #include <linux/hid.h> #include <linux/module.h> @@ -57,6 +58,16 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define ROG_ALLY_X_MIN_MCU 313 #define ROG_ALLY_MIN_MCU 319 +/* Spurious HID codes sent by QUIRK_ROG_NKEY_KEYBOARD devices */ +#define ASUS_SPURIOUS_CODE_0XEA 0xea +#define ASUS_SPURIOUS_CODE_0XEC 0xec +#define ASUS_SPURIOUS_CODE_0X02 0x02 +#define ASUS_SPURIOUS_CODE_0X8A 0x8a +#define ASUS_SPURIOUS_CODE_0X9E 0x9e + +/* Special key codes */ +#define ASUS_FAN_CTRL_KEY_CODE 0xae + #define SUPPORT_KBD_BACKLIGHT BIT(0) #define MAX_TOUCH_MAJOR 8 @@ -90,6 +101,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) #define QUIRK_ROG_ALLY_XPAD BIT(13) +#define QUIRK_HID_FN_LOCK BIT(14) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -133,6 +145,8 @@ struct asus_drvdata { int battery_stat; bool battery_in_query; unsigned long battery_next_query; + struct work_struct fn_lock_sync_work; + bool fn_lock; }; static int asus_report_battery(struct asus_drvdata *, u8 *, int); @@ -314,16 +328,47 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) return 0; } +/* + * Send events to asus-wmi driver for handling special keys + */ +static int asus_wmi_send_event(struct asus_drvdata *drvdata, u8 code) +{ + int err; + u32 retval; + + err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, + ASUS_WMI_METHODID_NOTIF, code, &retval); + if (err) { + pr_warn("Failed to notify asus-wmi: %d\n", err); + return err; + } + + if (retval != 0) { + pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval); + return -EIO; + } + + return 0; +} + static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { - if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 && + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR && (usage->hid & HID_USAGE) != 0x00 && (usage->hid & HID_USAGE) != 0xff && !usage->type) { hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n", usage->hid & HID_USAGE); } + if (drvdata->quirks & QUIRK_HID_FN_LOCK && + usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) { + drvdata->fn_lock = !drvdata->fn_lock; + schedule_work(&drvdata->fn_lock_sync_work); + } + return 0; } @@ -348,6 +393,43 @@ static int asus_raw_event(struct hid_device *hdev, if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2) return -1; if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + if (report->id == FEATURE_KBD_REPORT_ID) { + /* + * Fn+F5 fan control key - try to send WMI event to toggle fan mode. + * If successful, block the event from reaching userspace. + * If asus-wmi is unavailable or the call fails, let the event + * pass to userspace so it can implement its own fan control. + */ + if (data[1] == ASUS_FAN_CTRL_KEY_CODE) { + int ret = asus_wmi_send_event(drvdata, ASUS_FAN_CTRL_KEY_CODE); + + if (ret == 0) { + /* Successfully handled by asus-wmi, block event */ + return -1; + } + + /* + * Warn if asus-wmi failed (but not if it's unavailable). + * Let the event reach userspace in all failure cases. + */ + if (ret != -ENODEV) + hid_warn(hdev, "Failed to notify asus-wmi: %d\n", ret); + } + + /* + * ASUS ROG laptops send these codes during normal operation + * with no discernable reason. Filter them out to avoid + * unmapped warning messages. + */ + if (data[1] == ASUS_SPURIOUS_CODE_0XEA || + data[1] == ASUS_SPURIOUS_CODE_0XEC || + data[1] == ASUS_SPURIOUS_CODE_0X02 || + data[1] == ASUS_SPURIOUS_CODE_0X8A || + data[1] == ASUS_SPURIOUS_CODE_0X9E) { + return -1; + } + } + /* * G713 and G733 send these codes on some keypresses, depending on * the key pressed it can trigger a shutdown event if not caught. @@ -458,6 +540,21 @@ static int asus_kbd_disable_oobe(struct hid_device *hdev) return 0; } +static int asus_kbd_set_fn_lock(struct hid_device *hdev, bool enabled) +{ + u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xd0, 0x4e, !!enabled }; + + return asus_kbd_set_report(hdev, buf, sizeof(buf)); +} + +static void asus_sync_fn_lock(struct work_struct *work) +{ + struct asus_drvdata *drvdata = + container_of(work, struct asus_drvdata, fn_lock_sync_work); + + asus_kbd_set_fn_lock(drvdata->hdev, drvdata->fn_lock); +} + static void asus_schedule_work(struct asus_kbd_leds *led) { unsigned long flags; @@ -929,6 +1026,12 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) asus_kbd_register_leds(hdev)) hid_warn(hdev, "Failed to initialize backlight.\n"); + if (drvdata->quirks & QUIRK_HID_FN_LOCK) { + drvdata->fn_lock = true; + INIT_WORK(&drvdata->fn_lock_sync_work, asus_sync_fn_lock); + asus_kbd_set_fn_lock(hdev, true); + } + return 0; } @@ -1260,6 +1363,9 @@ static void asus_remove(struct hid_device *hdev) cancel_work_sync(&drvdata->kbd_backlight->work); } + if (drvdata->quirks & QUIRK_HID_FN_LOCK) + cancel_work_sync(&drvdata->fn_lock_sync_work); + hid_hw_stop(hdev); } @@ -1387,7 +1493,7 @@ static const struct hid_device_id asus_devices[] = { QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_HID_FN_LOCK }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, @@ -1434,10 +1540,8 @@ static struct hid_driver asus_driver = { .remove = asus_remove, .input_mapping = asus_input_mapping, .input_configured = asus_input_configured, -#ifdef CONFIG_PM - .reset_resume = asus_reset_resume, - .resume = asus_resume, -#endif + .reset_resume = pm_ptr(asus_reset_resume), + .resume = pm_ptr(asus_resume), .event = asus_event, .raw_event = asus_raw_event }; diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 2003d2dcda7c..37d88ce57f67 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -5,6 +5,7 @@ * - EX-G Trackballs (M-XT3DRBK, M-XT3URBK, M-XT4DRBK) * - DEFT Trackballs (M-DT1DRBK, M-DT1URBK, M-DT2DRBK, M-DT2URBK) * - HUGE Trackballs (M-HT1DRBK, M-HT1URBK) + * - HUGE Plus Trackball (M-HT1MRBK) * * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> @@ -123,12 +124,25 @@ static const __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, */ mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8); break; + case USB_DEVICE_ID_ELECOM_M_HT1MRBK: + case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB: + case USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC: + /* + * Report descriptor format: + * 24: button bit count + * 28: padding bit count + * 22: button report size + * 16: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 24, 28, 22, 16, 8); + break; } return rdesc; } static const struct hid_device_id elecom_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, @@ -142,6 +156,8 @@ static const struct hid_device_id elecom_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) }, { } }; MODULE_DEVICE_TABLE(hid, elecom_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9c2bf584d9f6..3e299a30dcde 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -364,6 +364,12 @@ #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 #define USB_DEVICE_ID_CREATIVE_SB0540 0x3100 +#define USB_VENDOR_ID_CRKD 0x3651 +#define USB_DEVICE_ID_CRKD_PS4_GIBSON_SG 0x1500 +#define USB_DEVICE_ID_CRKD_PS4_GIBSON_SG_DONGLE 0x5500 +#define USB_DEVICE_ID_CRKD_PS5_GIBSON_SG 0x1600 +#define USB_DEVICE_ID_CRKD_PS5_GIBSON_SG_DONGLE 0x5600 + #define USB_VENDOR_ID_CVTOUCH 0x1ff7 #define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013 @@ -437,6 +443,7 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000 0xc000 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002 0xc002 #define USB_VENDOR_ID_EDIFIER 0x2d99 @@ -465,6 +472,9 @@ #define USB_DEVICE_ID_ELECOM_M_HT1URBK_019B 0x019b #define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D 0x010d #define USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C 0x011c +#define USB_DEVICE_ID_ELECOM_M_HT1MRBK 0x01aa +#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB 0x01ab +#define USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC 0x01ac #define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 #define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004 @@ -841,6 +851,7 @@ #define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5 #define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe #define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae +#define USB_DEVICE_ID_LENOVO_YOGABOOK9I 0x6161 #define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 @@ -1102,6 +1113,11 @@ #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 #define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003 +#define USB_VENDOR_ID_PDP 0x0e6F +#define USB_DEVICE_ID_PDP_PS4_JAGUAR 0x0173 +#define USB_DEVICE_ID_PDP_PS4_RIFFMASTER 0x024a +#define USB_DEVICE_ID_PDP_PS5_RIFFMASTER 0x0249 + #define USB_VENDOR_ID_PLANTRONICS 0x047f #define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3210_SERIES 0xc055 #define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES 0xc056 @@ -1166,6 +1182,9 @@ #define I2C_PRODUCT_ID_RAYDIUM_4B33 0x4b33 #define I2C_PRODUCT_ID_RAYDIUM_3118 0x3118 +#define USB_VENDOR_ID_RAPOO 0x24ae +#define USB_DEVICE_ID_RAPOO_2_4G_RECEIVER 0x2015 + #define USB_VENDOR_ID_RAZER 0x1532 #define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE 0x010D #define USB_DEVICE_ID_RAZER_BLACKWIDOW 0x010e @@ -1536,6 +1555,9 @@ #define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */ #define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */ +#define USB_VENDOR_ID_MADCATZ 0x0738 +#define USB_DEVICE_ID_MADCATZ_PS4_STRATOCASTER 0x8261 + #define USB_VENDOR_ID_MULTIPLE_1781 0x1781 #define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a9d #define USB_DEVICE_ID_PHOENIXRC 0x0898 diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 9cc3e029e9f6..a6b73e03c16b 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -1422,7 +1422,6 @@ err: return ret; } -#ifdef CONFIG_PM static int lenovo_reset_resume(struct hid_device *hdev) { switch (hdev->product) { @@ -1438,7 +1437,6 @@ static int lenovo_reset_resume(struct hid_device *hdev) return 0; } -#endif static void lenovo_remove_tpkbd(struct hid_device *hdev) { @@ -1570,9 +1568,7 @@ static struct hid_driver lenovo_driver = { .raw_event = lenovo_raw_event, .event = lenovo_event, .report_fixup = lenovo_report_fixup, -#ifdef CONFIG_PM - .reset_resume = lenovo_reset_resume, -#endif + .reset_resume = pm_ptr(lenovo_reset_resume), }; module_hid_driver(lenovo_driver); diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 44b716697510..c41fded63f4b 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -1664,7 +1664,7 @@ static int logi_dj_dj_event(struct hid_device *hdev, * so ignore those reports too. */ if (dj_report->device_index != DJ_RECEIVER_INDEX) - hid_err(hdev, "%s: invalid device index:%d\n", + hid_err(hdev, "%s: invalid receiver index:%d\n", __func__, dj_report->device_index); return false; } @@ -1983,7 +1983,6 @@ hid_hw_start_fail: return retval; } -#ifdef CONFIG_PM static int logi_dj_reset_resume(struct hid_device *hdev) { struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); @@ -1994,7 +1993,6 @@ static int logi_dj_reset_resume(struct hid_device *hdev) logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); return 0; } -#endif static void logi_dj_remove(struct hid_device *hdev) { @@ -2150,9 +2148,7 @@ static struct hid_driver logi_djreceiver_driver = { .probe = logi_dj_probe, .remove = logi_dj_remove, .raw_event = logi_dj_raw_event, -#ifdef CONFIG_PM - .reset_resume = logi_dj_reset_resume, -#endif + .reset_resume = pm_ptr(logi_dj_reset_resume), }; module_hid_driver(logi_djreceiver_driver); diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index e871f1729d4b..02d83c3bd73d 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4314,7 +4314,7 @@ static int hidpp_get_report_length(struct hid_device *hdev, int id) re = &(hdev->report_enum[HID_OUTPUT_REPORT]); report = re->report_id_hash[id]; - if (!report) + if (!report || !report->maxfield) return 0; return report->field[0]->report_count + 1; @@ -4666,6 +4666,8 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb037) }, { /* MX Anywhere 3SB mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, + { /* Slim Solar+ K980 Keyboard over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb391) }, {} }; diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 7d4a25c6de0e..91f621ceb924 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -725,6 +725,11 @@ static int magicmouse_input_configured(struct hid_device *hdev, struct magicmouse_sc *msc = hid_get_drvdata(hdev); int ret; + if (!msc->input) { + hid_err(hdev, "magicmouse setup input failed (no input)"); + return -EINVAL; + } + ret = magicmouse_setup_input(msc->input, hdev); if (ret) { hid_err(hdev, "magicmouse setup input failed (%d)\n", ret); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index b1c3ef129058..7daa8f6d8187 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -76,6 +76,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_ORIENTATION_INVERT BIT(22) #define MT_QUIRK_APPLE_TOUCHBAR BIT(23) +#define MT_QUIRK_YOGABOOK9I BIT(24) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -231,6 +232,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_SMART_TECH 0x0113 #define MT_CLS_APPLE_TOUCHBAR 0x0114 +#define MT_CLS_YOGABOOK9I 0x0115 #define MT_CLS_SIS 0x0457 #define MT_DEFAULT_MAXCONTACT 10 @@ -428,6 +430,14 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, }, + { .name = MT_CLS_YOGABOOK9I, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_FORCE_MULTI_INPUT | + MT_QUIRK_SEPARATE_APP_REPORT | + MT_QUIRK_HOVERING | + MT_QUIRK_YOGABOOK9I, + .export_all_inputs = true + }, { } }; @@ -1576,6 +1586,38 @@ static void mt_report(struct hid_device *hid, struct hid_report *report) if (rdata && rdata->is_mt_collection) return mt_touch_report(hid, rdata); + /* Lenovo Yoga Book 9i requires consuming and dropping certain bogus reports */ + if (rdata && rdata->application && + (rdata->application->quirks & MT_QUIRK_YOGABOOK9I)) { + + bool all_zero_report = true; + + for (int f = 0; f < report->maxfield && all_zero_report; f++) { + struct hid_field *fld = report->field[f]; + + for (int i = 0; i < fld->report_count; i++) { + unsigned int usage = fld->usage[i].hid; + + if (usage == HID_DG_INRANGE || + usage == HID_DG_TIPSWITCH || + usage == HID_DG_BARRELSWITCH || + usage == HID_DG_BARRELSWITCH2 || + usage == HID_DG_CONTACTID || + usage == HID_DG_TILT_X || + usage == HID_DG_TILT_Y) { + + if (fld->value[i] != 0) { + all_zero_report = false; + break; + } + } + } + } + + if (all_zero_report) + return; + } + if (field && field->hidinput && field->hidinput->input) input_sync(field->hidinput->input); } @@ -1772,6 +1814,30 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) break; } + /* Lenovo Yoga Book 9i requires custom naming to allow differentiation in udev */ + if (hi->report && td->mtclass.quirks & MT_QUIRK_YOGABOOK9I) { + switch (hi->report->id) { + case 48: + suffix = "Touchscreen Top"; + break; + case 56: + suffix = "Touchscreen Bottom"; + break; + case 20: + suffix = "Stylus Top"; + break; + case 40: + suffix = "Stylus Bottom"; + break; + case 80: + suffix = "Emulated Touchpad"; + break; + default: + suffix = ""; + break; + } + } + if (suffix) { hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name, suffix); @@ -2146,6 +2212,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_EGALAX_SERIAL, MT_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, + { .driver_data = MT_CLS_EGALAX_SERIAL, + MT_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) }, { .driver_data = MT_CLS_EGALAX, MT_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) }, @@ -2277,6 +2346,12 @@ static const struct hid_device_id mt_devices[] = { USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB2) }, + /* Lenovo Yoga Book 9i */ + { .driver_data = MT_CLS_YOGABOOK9I, + HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_LENOVO, + USB_DEVICE_ID_LENOVO_YOGABOOK9I) }, + /* Logitech devices */ { .driver_data = MT_CLS_NSMU, HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH_WIN_8, diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 7ac9217d9096..29008c2cc530 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -2748,8 +2748,6 @@ static void nintendo_hid_remove(struct hid_device *hdev) hid_hw_stop(hdev); } -#ifdef CONFIG_PM - static int nintendo_hid_resume(struct hid_device *hdev) { struct joycon_ctlr *ctlr = hid_get_drvdata(hdev); @@ -2792,8 +2790,6 @@ static int nintendo_hid_suspend(struct hid_device *hdev, pm_message_t message) return 0; } -#endif - static const struct hid_device_id nintendo_hid_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_PROCON) }, @@ -2827,11 +2823,8 @@ static struct hid_driver nintendo_hid_driver = { .probe = nintendo_hid_probe, .remove = nintendo_hid_remove, .raw_event = nintendo_hid_event, - -#ifdef CONFIG_PM - .resume = nintendo_hid_resume, - .suspend = nintendo_hid_suspend, -#endif + .resume = pm_ptr(nintendo_hid_resume), + .suspend = pm_ptr(nintendo_hid_suspend), }; static int __init nintendo_init(void) { diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c index 297103be3381..6a88e6bc70f3 100644 --- a/drivers/hid/hid-picolcd_core.c +++ b/drivers/hid/hid-picolcd_core.c @@ -363,7 +363,6 @@ static int picolcd_raw_event(struct hid_device *hdev, return 1; } -#ifdef CONFIG_PM static int picolcd_suspend(struct hid_device *hdev, pm_message_t message) { if (PMSG_IS_AUTO(message)) @@ -401,7 +400,6 @@ static int picolcd_reset_resume(struct hid_device *hdev) picolcd_leds_set(hid_get_drvdata(hdev)); return 0; } -#endif /* initialize keypad input device */ static int picolcd_init_keys(struct picolcd_data *data, @@ -648,11 +646,9 @@ static struct hid_driver picolcd_driver = { .probe = picolcd_probe, .remove = picolcd_remove, .raw_event = picolcd_raw_event, -#ifdef CONFIG_PM - .suspend = picolcd_suspend, - .resume = picolcd_resume, - .reset_resume = picolcd_reset_resume, -#endif + .suspend = pm_ptr(picolcd_suspend), + .resume = pm_ptr(picolcd_resume), + .reset_resume = pm_ptr(picolcd_reset_resume), }; module_hid_driver(picolcd_driver); diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c index 3c8827081dea..dc11d5322fc0 100644 --- a/drivers/hid/hid-pl.c +++ b/drivers/hid/hid-pl.c @@ -194,9 +194,14 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err; } - plff_init(hdev); + ret = plff_init(hdev); + if (ret) + goto stop; return 0; + +stop: + hid_hw_stop(hdev); err: return ret; } diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index e4dfcf26b04e..2ec6d4445e84 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -774,7 +774,9 @@ ps_gamepad_create(struct hid_device *hdev, #if IS_ENABLED(CONFIG_PLAYSTATION_FF) if (play_effect) { input_set_capability(gamepad, EV_FF, FF_RUMBLE); - input_ff_create_memless(gamepad, NULL, play_effect); + ret = input_ff_create_memless(gamepad, NULL, play_effect); + if (ret) + return ERR_PTR(ret); } #endif diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 74bddb2c3e82..6e413df38358 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -378,6 +378,10 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data) bit_mask = (bit_mask << 8) | data[2]; bit_mask = (bit_mask << 8) | data[3]; + /* robustness in case input_mapping hook does not get called */ + if (!pm->input_ep82) + return 0; + /* break keys */ for (bit_index = 0; bit_index < 24; bit_index++) { if (!((0x01 << bit_index) & bit_mask)) { diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 11438039cdb7..3217e436c052 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -420,6 +420,7 @@ static const struct hid_device_id hid_have_special_driver[] = { #if IS_ENABLED(CONFIG_HID_ELECOM) { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AC) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_00FB) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK_018F) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK_00FC) }, @@ -432,6 +433,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK_019B) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1MRBK_01AB) }, #endif #if IS_ENABLED(CONFIG_HID_ELO) { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, diff --git a/drivers/hid/hid-rapoo.c b/drivers/hid/hid-rapoo.c new file mode 100644 index 000000000000..4c81f3086de4 --- /dev/null +++ b/drivers/hid/hid-rapoo.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <asm-generic/errno-base.h> +#include <asm-generic/int-ll64.h> +#include <linux/bitops.h> +#include <linux/input.h> +#include <linux/input-event-codes.h> +#include <linux/module.h> +#include <linux/hid.h> +#include <linux/usb.h> + +#include "hid-ids.h" + +#define RAPOO_BTN_BACK 0x08 +#define RAPOO_BTN_FORWARD 0x10 + +static const struct hid_device_id rapoo_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAPOO, USB_DEVICE_ID_RAPOO_2_4G_RECEIVER) }, + { } +}; +MODULE_DEVICE_TABLE(hid, rapoo_devices); + +static int rapoo_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct input_dev *input; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hdev, "start failed\n"); + return ret; + } + + if (hdev->bus == BUS_USB) { + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + if (intf->cur_altsetting->desc.bInterfaceNumber != 1) + return 0; + } + + input = devm_input_allocate_device(&hdev->dev); + if (!input) + return -ENOMEM; + + input->name = "Rapoo 2.4G Wireless Mouse"; + input->phys = "rapoo/input1"; + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + + __set_bit(EV_KEY, input->evbit); + __set_bit(KEY_BACK, input->keybit); + __set_bit(KEY_FORWARD, input->keybit); + + ret = input_register_device(input); + if (ret) + return ret; + + hid_set_drvdata(hdev, input); + + return ret; +} + +static int rapoo_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) +{ + struct input_dev *input = hid_get_drvdata(hdev); + + if (!input) + return 0; + + if (report->id == 1 && size >= 2) { + u8 btn = data[1]; + + input_report_key(input, KEY_BACK, btn & RAPOO_BTN_BACK); + input_report_key(input, KEY_FORWARD, btn & RAPOO_BTN_FORWARD); + input_sync(input); + return 1; + } + + return 0; +} + +static struct hid_driver rapoo_driver = { + .name = "hid-rapoo", + .id_table = rapoo_devices, + .probe = rapoo_probe, + .raw_event = rapoo_raw_event, +}; + +module_hid_driver(rapoo_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nguyen Dinh Dang Duong <dangduong31205@gmail.com>"); +MODULE_DESCRIPTION("RAPOO 2.4G Wireless Device Driver"); + diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 4c94c03cb573..0edec902be41 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -422,7 +422,6 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, } EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); -#ifdef CONFIG_PM static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) { struct sensor_hub_data *pdata = hid_get_drvdata(hdev); @@ -463,7 +462,6 @@ static int sensor_hub_reset_resume(struct hid_device *hdev) { return 0; } -#endif /* * Handle raw report as sent by device @@ -772,11 +770,9 @@ static struct hid_driver sensor_hub_driver = { .remove = sensor_hub_remove, .raw_event = sensor_hub_raw_event, .report_fixup = sensor_hub_report_fixup, -#ifdef CONFIG_PM - .suspend = sensor_hub_suspend, - .resume = sensor_hub_resume, - .reset_resume = sensor_hub_reset_resume, -#endif + .suspend = pm_ptr(sensor_hub_suspend), + .resume = pm_ptr(sensor_hub_resume), + .reset_resume = pm_ptr(sensor_hub_reset_resume), }; module_hid_driver(sensor_hub_driver); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b966e4044238..a89af14e4acc 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -14,6 +14,7 @@ * Copyright (c) 2020-2021 Pascal Giard <pascal.giard@etsmtl.ca> * Copyright (c) 2020 Sanjay Govind <sanjay.govind9@gmail.com> * Copyright (c) 2021 Daniel Nguyen <daniel.nguyen.1@ens.etsmtl.ca> + * Copyright (c) 2026 Rosalie Wanders <rosalie@mailbox.org> */ /* @@ -61,6 +62,9 @@ #define GH_GUITAR_CONTROLLER BIT(14) #define GHL_GUITAR_PS3WIIU BIT(15) #define GHL_GUITAR_PS4 BIT(16) +#define RB4_GUITAR_PS4_USB BIT(17) +#define RB4_GUITAR_PS4_BT BIT(18) +#define RB4_GUITAR_PS5 BIT(19) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -418,6 +422,27 @@ static const unsigned int sixaxis_keymap[] = { [0x11] = BTN_MODE, /* PS */ }; +static const unsigned int rb4_absmap[] = { + [0x30] = ABS_X, + [0x31] = ABS_Y, +}; + +static const unsigned int rb4_keymap[] = { + [0x1] = BTN_WEST, /* Square */ + [0x2] = BTN_SOUTH, /* Cross */ + [0x3] = BTN_EAST, /* Circle */ + [0x4] = BTN_NORTH, /* Triangle */ + [0x5] = BTN_TL, /* L1 */ + [0x6] = BTN_TR, /* R1 */ + [0x7] = BTN_TL2, /* L2 */ + [0x8] = BTN_TR2, /* R2 */ + [0x9] = BTN_SELECT, /* Share */ + [0xa] = BTN_START, /* Options */ + [0xb] = BTN_THUMBL, /* L3 */ + [0xc] = BTN_THUMBR, /* R3 */ + [0xd] = BTN_MODE, /* PS */ +}; + static enum power_supply_property sony_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, @@ -484,6 +509,7 @@ struct sony_sc { spinlock_t lock; struct list_head list_node; struct hid_device *hdev; + struct input_dev *input_dev; struct input_dev *touchpad; struct input_dev *sensor_dev; struct led_classdev *leds[MAX_LEDS]; @@ -584,7 +610,7 @@ static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev, return 0; } -static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi, +static int gh_guitar_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { @@ -599,6 +625,37 @@ static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi, return 0; } +static int rb4_guitar_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { + unsigned int key = usage->hid & HID_USAGE; + + if (key >= ARRAY_SIZE(rb4_keymap)) + return 0; + + key = rb4_keymap[key]; + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + return 1; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + /* Let the HID parser deal with the HAT. */ + if (usage->hid == HID_GD_HATSWITCH) + return 0; + + if (abs >= ARRAY_SIZE(rb4_absmap)) + return 0; + + abs = rb4_absmap[abs]; + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + return 1; + } + + return 0; +} + static const u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { @@ -915,6 +972,40 @@ static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size) input_sync(sc->touchpad); } +static void rb4_ps4_guitar_parse_report(struct sony_sc *sc, u8 *rd, int size) +{ + /* + * Rock Band 4 PS4 guitars have whammy and + * tilt functionality, they're located at + * byte 44 and 45 respectively. + * + * We will map these values to the triggers + * because the guitars don't have anything + * mapped there. + */ + input_report_abs(sc->input_dev, ABS_Z, rd[44]); + input_report_abs(sc->input_dev, ABS_RZ, rd[45]); + + input_sync(sc->input_dev); +} + +static void rb4_ps5_guitar_parse_report(struct sony_sc *sc, u8 *rd, int size) +{ + /* + * Rock Band 4 PS5 guitars have whammy and + * tilt functionality, they're located at + * byte 41 and 42 respectively. + * + * We will map these values to the triggers + * because the guitars don't have anything + * mapped there. + */ + input_report_abs(sc->input_dev, ABS_Z, rd[41]); + input_report_abs(sc->input_dev, ABS_RZ, rd[42]); + + input_sync(sc->input_dev); +} + static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size) { @@ -950,6 +1041,15 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, } else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) { nsg_mrxu_parse_report(sc, rd, size); return 1; + } else if ((sc->quirks & RB4_GUITAR_PS4_USB) && rd[0] == 0x01 && size == 64) { + rb4_ps4_guitar_parse_report(sc, rd, size); + return 1; + } else if ((sc->quirks & RB4_GUITAR_PS4_BT) && rd[0] == 0x01 && size == 78) { + rb4_ps4_guitar_parse_report(sc, rd, size); + return 1; + } else if ((sc->quirks & RB4_GUITAR_PS5) && rd[0] == 0x01 && size == 64) { + rb4_ps5_guitar_parse_report(sc, rd, size); + return 1; } if (sc->defer_initialization) { @@ -999,7 +1099,13 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, return sixaxis_mapping(hdev, hi, field, usage, bit, max); if (sc->quirks & GH_GUITAR_CONTROLLER) - return guitar_mapping(hdev, hi, field, usage, bit, max); + return gh_guitar_mapping(hdev, hi, field, usage, bit, max); + + if (sc->quirks & (RB4_GUITAR_PS4_USB | RB4_GUITAR_PS4_BT)) + return rb4_guitar_mapping(hdev, hi, field, usage, bit, max); + + if (sc->quirks & RB4_GUITAR_PS5) + return rb4_guitar_mapping(hdev, hi, field, usage, bit, max); /* Let hid-core decide for the others */ return 0; @@ -2043,6 +2149,7 @@ static int sony_input_configured(struct hid_device *hdev, goto err_close; } + sc->input_dev = hidinput->input; return 0; err_close: hid_hw_close(hdev); @@ -2179,7 +2286,6 @@ static void sony_remove(struct hid_device *hdev) hid_hw_stop(hdev); } -#ifdef CONFIG_PM static int sony_suspend(struct hid_device *hdev, pm_message_t message) { @@ -2214,8 +2320,6 @@ static int sony_resume(struct hid_device *hdev) return 0; } -#endif - static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, @@ -2271,6 +2375,24 @@ static const struct hid_device_id sony_devices[] = { /* Guitar Hero Live PS4 guitar dongles */ { HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_PS4_GHLIVE_DONGLE), .driver_data = GHL_GUITAR_PS4 | GH_GUITAR_CONTROLLER }, + /* Rock Band 4 PS4 guitars */ + { HID_USB_DEVICE(USB_VENDOR_ID_PDP, USB_DEVICE_ID_PDP_PS4_RIFFMASTER), + .driver_data = RB4_GUITAR_PS4_USB }, + { HID_USB_DEVICE(USB_VENDOR_ID_CRKD, USB_DEVICE_ID_CRKD_PS4_GIBSON_SG), + .driver_data = RB4_GUITAR_PS4_USB }, + { HID_USB_DEVICE(USB_VENDOR_ID_CRKD, USB_DEVICE_ID_CRKD_PS4_GIBSON_SG_DONGLE), + .driver_data = RB4_GUITAR_PS4_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_PDP, USB_DEVICE_ID_PDP_PS4_JAGUAR), + .driver_data = RB4_GUITAR_PS4_BT }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_PS4_STRATOCASTER), + .driver_data = RB4_GUITAR_PS4_BT }, + /* Rock Band 4 PS5 guitars */ + { HID_USB_DEVICE(USB_VENDOR_ID_PDP, USB_DEVICE_ID_PDP_PS5_RIFFMASTER), + .driver_data = RB4_GUITAR_PS5 }, + { HID_USB_DEVICE(USB_VENDOR_ID_CRKD, USB_DEVICE_ID_CRKD_PS5_GIBSON_SG), + .driver_data = RB4_GUITAR_PS5 }, + { HID_USB_DEVICE(USB_VENDOR_ID_CRKD, USB_DEVICE_ID_CRKD_PS5_GIBSON_SG_DONGLE), + .driver_data = RB4_GUITAR_PS5 }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); @@ -2284,12 +2406,9 @@ static struct hid_driver sony_driver = { .remove = sony_remove, .report_fixup = sony_report_fixup, .raw_event = sony_raw_event, - -#ifdef CONFIG_PM - .suspend = sony_suspend, - .resume = sony_resume, - .reset_resume = sony_resume, -#endif + .suspend = pm_ptr(sony_suspend), + .resume = pm_ptr(sony_resume), + .reset_resume = pm_ptr(sony_resume), }; static int __init sony_init(void) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 90ebb81041ea..bd7f93e96e4e 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -268,7 +268,6 @@ failure: return rc; } -#ifdef CONFIG_PM static int uclogic_resume(struct hid_device *hdev) { int rc; @@ -283,7 +282,6 @@ static int uclogic_resume(struct hid_device *hdev) return rc; } -#endif /** * uclogic_exec_event_hook - if the received event is hooked schedules the @@ -636,10 +634,8 @@ static struct hid_driver uclogic_driver = { .raw_event = uclogic_raw_event, .input_mapping = uclogic_input_mapping, .input_configured = uclogic_input_configured, -#ifdef CONFIG_PM - .resume = uclogic_resume, - .reset_resume = uclogic_resume, -#endif + .resume = pm_ptr(uclogic_resume), + .reset_resume = pm_ptr(uclogic_resume), }; module_hid_driver(uclogic_driver); diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index c3915f3a060e..b890fbf97a75 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -730,7 +730,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags); list_for_each_entry(cl, &ishtp_dev->cl_list, link) { cl->state = ISHTP_CL_DISCONNECTED; - if (warm_reset && cl->device->reference_count) + if (warm_reset && cl->device && cl->device->reference_count) continue; /* diff --git a/drivers/hid/intel-ish-hid/ishtp/loader.c b/drivers/hid/intel-ish-hid/ishtp/loader.c index f34086b29cf0..ffa2042bb316 100644 --- a/drivers/hid/intel-ish-hid/ishtp/loader.c +++ b/drivers/hid/intel-ish-hid/ishtp/loader.c @@ -195,13 +195,19 @@ static int prepare_dma_bufs(struct ishtp_device *dev, return 0; } +/* Patterns with PRODUCT_FAMILY */ +#define ISH_FW_FILE_VENDOR_FAMILY_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x_%08x.bin" +#define ISH_FW_FILE_VENDOR_FAMILY_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin" +#define ISH_FW_FILE_VENDOR_FAMILY_NAME_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin" +#define ISH_FW_FILE_VENDOR_FAMILY_FMT "intel/ish/ish_%s_%08x_%08x.bin" + #define ISH_FW_FILE_VENDOR_NAME_SKU_FMT "intel/ish/ish_%s_%08x_%08x_%08x.bin" #define ISH_FW_FILE_VENDOR_SKU_FMT "intel/ish/ish_%s_%08x_%08x.bin" #define ISH_FW_FILE_VENDOR_NAME_FMT "intel/ish/ish_%s_%08x_%08x.bin" #define ISH_FW_FILE_VENDOR_FMT "intel/ish/ish_%s_%08x.bin" #define ISH_FW_FILE_DEFAULT_FMT "intel/ish/ish_%s.bin" -#define ISH_FW_FILENAME_LEN_MAX 56 +#define ISH_FW_FILENAME_LEN_MAX 72 #define ISH_CRC_INIT (~0u) #define ISH_CRC_XOROUT (~0u) @@ -228,6 +234,12 @@ static int _request_ish_firmware(const struct firmware **firmware_p, * for the given device in the following order, prioritizing custom firmware * with more precise matching patterns: * + * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32) + * _$(PRODUCT_NAME_CRC32)_${PRODUCT_SKU_CRC32}.bin + * + * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32)_${PRODUCT_SKU_CRC32}.bin + * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32)_$(PRODUCT_NAME_CRC32).bin + * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_FAMILY_CRC32).bin * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32)_${PRODUCT_SKU_CRC32}.bin * ish_${fw_generation}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin * ish_${fw_generation}_${SYS_VENDOR_CRC32}_$(PRODUCT_NAME_CRC32).bin @@ -256,8 +268,9 @@ static int request_ish_firmware(const struct firmware **firmware_p, struct device *dev) { const char *gen, *sys_vendor, *product_name, *product_sku; + const char *product_family; struct ishtp_device *ishtp = dev_get_drvdata(dev); - u32 vendor_crc, name_crc, sku_crc; + u32 vendor_crc, name_crc, sku_crc, family_crc; char filename[ISH_FW_FILENAME_LEN_MAX]; int ret; @@ -265,14 +278,55 @@ static int request_ish_firmware(const struct firmware **firmware_p, sys_vendor = dmi_get_system_info(DMI_SYS_VENDOR); product_name = dmi_get_system_info(DMI_PRODUCT_NAME); product_sku = dmi_get_system_info(DMI_PRODUCT_SKU); + product_family = dmi_get_system_info(DMI_PRODUCT_FAMILY); if (sys_vendor) vendor_crc = crc32(ISH_CRC_INIT, sys_vendor, strlen(sys_vendor)) ^ ISH_CRC_XOROUT; + if (product_family) + family_crc = crc32(ISH_CRC_INIT, product_family, + strlen(product_family)) ^ ISH_CRC_XOROUT; if (product_name) name_crc = crc32(ISH_CRC_INIT, product_name, strlen(product_name)) ^ ISH_CRC_XOROUT; if (product_sku) sku_crc = crc32(ISH_CRC_INIT, product_sku, strlen(product_sku)) ^ ISH_CRC_XOROUT; + /* PRODUCT_FAMILY-extended matching */ + if (sys_vendor && product_family && product_name && product_sku) { + snprintf(filename, sizeof(filename), + ISH_FW_FILE_VENDOR_FAMILY_NAME_SKU_FMT, + gen, vendor_crc, family_crc, name_crc, sku_crc); + ret = _request_ish_firmware(firmware_p, filename, dev); + if (!ret) + return 0; + } + + if (sys_vendor && product_family && product_sku) { + snprintf(filename, sizeof(filename), + ISH_FW_FILE_VENDOR_FAMILY_SKU_FMT, + gen, vendor_crc, family_crc, sku_crc); + ret = _request_ish_firmware(firmware_p, filename, dev); + if (!ret) + return 0; + } + + if (sys_vendor && product_family && product_name) { + snprintf(filename, sizeof(filename), + ISH_FW_FILE_VENDOR_FAMILY_NAME_FMT, + gen, vendor_crc, family_crc, name_crc); + ret = _request_ish_firmware(firmware_p, filename, dev); + if (!ret) + return 0; + } + + if (sys_vendor && product_family) { + snprintf(filename, sizeof(filename), + ISH_FW_FILE_VENDOR_FAMILY_FMT, + gen, vendor_crc, family_crc); + ret = _request_ish_firmware(firmware_p, filename, dev); + if (!ret) + return 0; +} + if (sys_vendor && product_name && product_sku) { snprintf(filename, sizeof(filename), ISH_FW_FILE_VENDOR_NAME_SKU_FMT, gen, vendor_crc, name_crc, sku_crc); diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c index cfda66ee4895..f178017352ba 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c @@ -807,6 +807,12 @@ static int quicki2c_suspend(struct device *device) if (!qcdev) return -ENODEV; + if (!device_may_wakeup(qcdev->dev)) { + ret = quicki2c_set_power(qcdev, HIDI2C_SLEEP); + if (ret) + return ret; + } + /* * As I2C is THC subsystem, no register auto save/restore support, * need driver to do that explicitly for every D3 case. @@ -856,6 +862,9 @@ static int quicki2c_resume(struct device *device) if (ret) return ret; + if (!device_may_wakeup(qcdev->dev)) + return quicki2c_set_power(qcdev, HIDI2C_ON); + return 0; } @@ -913,6 +922,9 @@ static int quicki2c_poweroff(struct device *device) if (!qcdev) return -ENODEV; + /* Ignore the return value as platform will be poweroff soon */ + quicki2c_set_power(qcdev, HIDI2C_SLEEP); + ret = thc_interrupt_quiesce(qcdev->thc_hw, true); if (ret) return ret; @@ -966,7 +978,7 @@ static int quicki2c_restore(struct device *device) thc_change_ltr_mode(qcdev->thc_hw, THC_LTR_MODE_ACTIVE); - return 0; + return quicki2c_set_power(qcdev, HIDI2C_ON); } static int quicki2c_runtime_suspend(struct device *device) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h index 2cb5471a8133..33a1e3db1cb2 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-dev.h @@ -213,7 +213,7 @@ struct quicki2c_device { u8 *report_descriptor; u8 *input_buf; u8 *report_buf; - u32 report_len; + size_t report_len; wait_queue_head_t reset_ack_wq; bool reset_ack; diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c index 834a537b6780..f9fcb398673b 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-hid.c @@ -82,6 +82,13 @@ static int quicki2c_hid_power(struct hid_device *hid, int lvl) return 0; } +static int quicki2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count) +{ + struct quicki2c_device *qcdev = hid->driver_data; + + return quicki2c_output_report(qcdev, buf, count); +} + static struct hid_ll_driver quicki2c_hid_ll_driver = { .parse = quicki2c_hid_parse, .start = quicki2c_hid_start, @@ -90,6 +97,7 @@ static struct hid_ll_driver quicki2c_hid_ll_driver = { .close = quicki2c_hid_close, .power = quicki2c_hid_power, .raw_request = quicki2c_hid_raw_request, + .output_report = quicki2c_hid_output_report, }; /** diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c index a63f8c833252..41271301215a 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.c @@ -13,11 +13,11 @@ #include "quicki2c-hid.h" #include "quicki2c-protocol.h" -static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int cmd_len, - bool append_data_reg, u8 *data, int data_len, - u8 *write_buf, int write_buf_len) +static ssize_t quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, size_t cmd_len, + bool append_data_reg, u8 *data, size_t data_len, + u8 *write_buf, size_t write_buf_len) { - int buf_len, offset = 0; + size_t buf_len, offset = 0; buf_len = HIDI2C_REG_LEN + cmd_len; @@ -30,20 +30,23 @@ static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int c if (buf_len > write_buf_len) return -EINVAL; - memcpy(write_buf, &qcdev->dev_desc.cmd_reg, HIDI2C_REG_LEN); - offset += HIDI2C_REG_LEN; - memcpy(write_buf + offset, &cmd, cmd_len); - offset += cmd_len; + if (cmd_len) { + memcpy(write_buf, &qcdev->dev_desc.cmd_reg, HIDI2C_REG_LEN); + offset += HIDI2C_REG_LEN; + memcpy(write_buf + offset, &cmd, cmd_len); + offset += cmd_len; - if (append_data_reg) { - memcpy(write_buf + offset, &qcdev->dev_desc.data_reg, HIDI2C_REG_LEN); + if (append_data_reg) { + memcpy(write_buf + offset, &qcdev->dev_desc.data_reg, HIDI2C_REG_LEN); + offset += HIDI2C_REG_LEN; + } + } else { + memcpy(write_buf, &qcdev->dev_desc.output_reg, HIDI2C_REG_LEN); offset += HIDI2C_REG_LEN; } if (data && data_len) { - __le16 len = cpu_to_le16(data_len + HIDI2C_LENGTH_LEN); - - memcpy(write_buf + offset, &len, HIDI2C_LENGTH_LEN); + put_unaligned_le16(data_len + HIDI2C_LENGTH_LEN, write_buf + offset); offset += HIDI2C_LENGTH_LEN; memcpy(write_buf + offset, data, data_len); } @@ -51,10 +54,10 @@ static int quicki2c_init_write_buf(struct quicki2c_device *qcdev, u32 cmd, int c return buf_len; } -static int quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf, - u8 opcode, u8 report_type, u8 report_id) +static size_t quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf, + u8 opcode, u8 report_type, u8 report_id) { - int cmd_len; + size_t cmd_len; *cmd_buf = FIELD_PREP(HIDI2C_CMD_OPCODE, opcode) | FIELD_PREP(HIDI2C_CMD_REPORT_TYPE, report_type); @@ -72,22 +75,20 @@ static int quicki2c_encode_cmd(struct quicki2c_device *qcdev, u32 *cmd_buf, } static int write_cmd_to_txdma(struct quicki2c_device *qcdev, int opcode, - int report_type, int report_id, u8 *buf, int buf_len) + int report_type, int report_id, u8 *buf, size_t buf_len) { - size_t write_buf_len; - int cmd_len, ret; + size_t cmd_len; + ssize_t len; u32 cmd; cmd_len = quicki2c_encode_cmd(qcdev, &cmd, opcode, report_type, report_id); - ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf, + len = quicki2c_init_write_buf(qcdev, cmd, cmd_len, buf ? true : false, buf, buf_len, qcdev->report_buf, qcdev->report_len); - if (ret < 0) - return ret; - - write_buf_len = ret; + if (len < 0) + return len; - return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, write_buf_len); + return thc_dma_write(qcdev->thc_hw, qcdev->report_buf, len); } int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state) @@ -126,13 +127,13 @@ int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev) } int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type, - unsigned int reportnum, void *buf, u32 buf_len) + unsigned int reportnum, void *buf, size_t buf_len) { struct hidi2c_report_packet *rpt; - size_t write_buf_len, read_len = 0; - int cmd_len, rep_type; + size_t cmd_len, read_len = 0; + int rep_type, ret; + ssize_t len; u32 cmd; - int ret; if (report_type == HID_INPUT_REPORT) { rep_type = HIDI2C_INPUT; @@ -145,25 +146,22 @@ int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type, cmd_len = quicki2c_encode_cmd(qcdev, &cmd, HIDI2C_GET_REPORT, rep_type, reportnum); - ret = quicki2c_init_write_buf(qcdev, cmd, cmd_len, true, NULL, 0, + len = quicki2c_init_write_buf(qcdev, cmd, cmd_len, true, NULL, 0, qcdev->report_buf, qcdev->report_len); - if (ret < 0) - return ret; - - write_buf_len = ret; + if (len < 0) + return len; rpt = (struct hidi2c_report_packet *)qcdev->input_buf; - ret = thc_swdma_read(qcdev->thc_hw, qcdev->report_buf, write_buf_len, - NULL, rpt, &read_len); + ret = thc_swdma_read(qcdev->thc_hw, qcdev->report_buf, len, NULL, rpt, &read_len); if (ret) { - dev_err_once(qcdev->dev, "Get report failed, ret %d, read len (%zu vs %d)\n", + dev_err_once(qcdev->dev, "Get report failed, ret %d, read len (%zu vs %zu)\n", ret, read_len, buf_len); return ret; } if (HIDI2C_DATA_LEN(le16_to_cpu(rpt->len)) != buf_len || rpt->data[0] != reportnum) { - dev_err_once(qcdev->dev, "Invalid packet, len (%d vs %d) report id (%d vs %d)\n", + dev_err_once(qcdev->dev, "Invalid packet, len (%d vs %zu) report id (%d vs %d)\n", le16_to_cpu(rpt->len), buf_len, rpt->data[0], reportnum); return -EINVAL; } @@ -174,7 +172,7 @@ int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type, } int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type, - unsigned int reportnum, void *buf, u32 buf_len) + unsigned int reportnum, void *buf, size_t buf_len) { int rep_type; int ret; @@ -197,6 +195,25 @@ int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type, return buf_len; } +int quicki2c_output_report(struct quicki2c_device *qcdev, void *buf, size_t buf_len) +{ + ssize_t len; + int ret; + + len = quicki2c_init_write_buf(qcdev, 0, 0, false, buf, buf_len, + qcdev->report_buf, qcdev->report_len); + if (len < 0) + return -EINVAL; + + ret = thc_dma_write(qcdev->thc_hw, qcdev->report_buf, len); + if (ret) { + dev_err(qcdev->dev, "Output Report failed, ret %d\n", ret); + return ret; + } + + return buf_len; +} + #define HIDI2C_RESET_TIMEOUT 5 int quicki2c_reset(struct quicki2c_device *qcdev) diff --git a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h index bf4908cce59c..6642cefb8a67 100644 --- a/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h +++ b/drivers/hid/intel-thc-hid/intel-quicki2c/quicki2c-protocol.h @@ -10,9 +10,10 @@ struct quicki2c_device; int quicki2c_set_power(struct quicki2c_device *qcdev, enum hidi2c_power_state power_state); int quicki2c_get_report(struct quicki2c_device *qcdev, u8 report_type, - unsigned int reportnum, void *buf, u32 buf_len); + unsigned int reportnum, void *buf, size_t buf_len); int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type, - unsigned int reportnum, void *buf, u32 buf_len); + unsigned int reportnum, void *buf, size_t buf_len); +int quicki2c_output_report(struct quicki2c_device *qcdev, void *buf, size_t buf_len); int quicki2c_get_device_descriptor(struct quicki2c_device *qcdev); int quicki2c_get_report_descriptor(struct quicki2c_device *qcdev); int quicki2c_reset(struct quicki2c_device *qcdev); diff --git a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c index 7e220a4c5ded..d8e195189e4b 100644 --- a/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c +++ b/drivers/hid/intel-thc-hid/intel-thc/intel-thc-dev.c @@ -1597,6 +1597,7 @@ int thc_i2c_set_rx_max_size(struct thc_device *dev, u32 max_rx_size) if (ret) return ret; + val = val & ~THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE; val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_MAX_SIZE, max_rx_size); ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val); @@ -1667,6 +1668,7 @@ int thc_i2c_set_rx_int_delay(struct thc_device *dev, u32 delay_us) return ret; /* THC hardware counts at 10us unit */ + val = val & ~THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL; val |= FIELD_PREP(THC_M_PRT_SPI_ICRRD_OPCODE_I2C_INTERVAL, DIV_ROUND_UP(delay_us, 10)); ret = regmap_write(dev->thc_regmap, THC_M_PRT_SPI_ICRRD_OPCODE_OFFSET, val); diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 95377c5f6335..a4e700b40ba9 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -523,9 +523,19 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff_set_duration(&pidff->set_effect[PID_DURATION], effect->replay.length); - pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; - pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT], - effect->trigger.interval); + /* Some games set this to random values that can be out of range */ + s32 trigger_button_max = + pidff->set_effect[PID_TRIGGER_BUTTON].field->logical_maximum; + if (effect->trigger.button <= trigger_button_max) { + pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = + effect->trigger.button; + pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT], + effect->trigger.interval); + } else { + pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0; + pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; + } + pidff->set_effect[PID_GAIN].value[0] = pidff->set_effect[PID_GAIN].field->logical_maximum; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 9a57504e51a1..afc900560706 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2921,7 +2921,6 @@ static void wacom_remove(struct hid_device *hdev) wacom_release_resources(wacom); } -#ifdef CONFIG_PM static int wacom_resume(struct hid_device *hdev) { struct wacom *wacom = hid_get_drvdata(hdev); @@ -2941,7 +2940,6 @@ static int wacom_reset_resume(struct hid_device *hdev) { return wacom_resume(hdev); } -#endif /* CONFIG_PM */ static struct hid_driver wacom_driver = { .name = "wacom", @@ -2949,10 +2947,8 @@ static struct hid_driver wacom_driver = { .probe = wacom_probe, .remove = wacom_remove, .report = wacom_wac_report, -#ifdef CONFIG_PM - .resume = wacom_resume, - .reset_resume = wacom_reset_resume, -#endif + .resume = pm_ptr(wacom_resume), + .reset_resume = pm_ptr(wacom_reset_resume), .raw_event = wacom_raw_event, }; module_hid_driver(wacom_driver); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 419491d4abca..516538b5a527 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -29,6 +29,7 @@ #define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ #define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ #define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ +#define ASUS_WMI_METHODID_NOTIF 0x00100021 /* Notify method */ #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE |
