From 446e303982a616f5cd48beabd236f0e6a17ec0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 3 Feb 2026 18:45:27 +0100 Subject: [PATCH 1/5] HID: pidff: Refactor field quirks detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for additional quirks Co-developed-by: Oleg Makarenko Signed-off-by: Oleg Makarenko Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index a4e700b40ba9..68049d5d76b3 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #define PID_EFFECTS_MAX 64 @@ -1053,6 +1054,11 @@ static int pidff_find_field_with_usage(int *usage_index, return -1; } +#define PIDFF_MISSING_FIELD(name, quirks) \ + ({ pr_debug("%s field not found, but that's OK\n", __stringify(name)); \ + pr_debug("Setting MISSING_%s quirk\n", __stringify(name)); \ + *quirks |= HID_PIDFF_QUIRK_MISSING_ ## name; }) + /* * Find fields from a report and fill a pidff_usage */ @@ -1060,9 +1066,6 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, struct hid_report *report, int count, int strict, u32 *quirks) { - const u8 block_offset = pidff_set_condition[PID_PARAM_BLOCK_OFFSET]; - const u8 delay = pidff_set_effect[PID_START_DELAY]; - if (!report) { pr_debug("%s, null report\n", __func__); return -1; @@ -1080,17 +1083,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, continue; } - if (table[i] == delay) { - pr_debug("Delay field not found, but that's OK\n"); - pr_debug("Setting MISSING_DELAY quirk\n"); - *quirks |= HID_PIDFF_QUIRK_MISSING_DELAY; + /* Field quirks auto-detection */ + if (table[i] == pidff_set_effect[PID_START_DELAY]) + PIDFF_MISSING_FIELD(DELAY, quirks); - } else if (table[i] == block_offset) { - pr_debug("PBO field not found, but that's OK\n"); - pr_debug("Setting MISSING_PBO quirk\n"); - *quirks |= HID_PIDFF_QUIRK_MISSING_PBO; + else if (table[i] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) + PIDFF_MISSING_FIELD(PBO, quirks); - } else if (strict) { + else if (strict) { pr_debug("failed to locate %d\n", i); return -1; } From cf3bf7ad4e7722735d085b5fd5ab90a01be831d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 3 Feb 2026 18:45:28 +0100 Subject: [PATCH 2/5] HID: pidff: Add MISSING_NEG_COEFFICIENT quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows/Directinput allows devices with missing negative coefficient for conditional effects. Negative coefficient is ignored in such cases. Donot fail set_condition usage search if negative coefficient is missing. Fixes conditional effect playback on Asetek wheelbases. https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416601(v=vs.85) Co-developed-by: Oleg Makarenko Signed-off-by: Oleg Makarenko Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 11 +++++++++-- drivers/hid/usbhid/hid-pidff.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 68049d5d76b3..aebf6c89643f 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -619,8 +619,12 @@ static void pidff_set_condition_report(struct pidff_device *pidff, effect->u.condition[i].center); pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], effect->u.condition[i].right_coeff); - pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT], - effect->u.condition[i].left_coeff); + + /* Omit Negative Coefficient if missing */ + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_NEG_COEFFICIENT)) + pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT], + effect->u.condition[i].left_coeff); + pidff_set(&pidff->set_condition[PID_POS_SATURATION], effect->u.condition[i].right_saturation); pidff_set(&pidff->set_condition[PID_NEG_SATURATION], @@ -1090,6 +1094,9 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, else if (table[i] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) PIDFF_MISSING_FIELD(PBO, quirks); + else if (table[i] == pidff_set_condition[PID_NEG_COEFFICIENT]) + PIDFF_MISSING_FIELD(NEG_COEFFICIENT, quirks); + else if (strict) { pr_debug("failed to locate %d\n", i); return -1; diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h index f321f675e131..5bf54e981543 100644 --- a/drivers/hid/usbhid/hid-pidff.h +++ b/drivers/hid/usbhid/hid-pidff.h @@ -21,6 +21,9 @@ /* Force all periodic effects to be uploaded as SINE */ #define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) +/* Allow devices with missing negative coefficient in the set condition usage */ +#define HID_PIDFF_QUIRK_MISSING_NEG_COEFFICIENT BIT(5) + #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks); From d9cef0989ace79582dac90a2915c100144460e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 3 Feb 2026 18:45:29 +0100 Subject: [PATCH 3/5] HID: pidff: Add MISSING_NEG_SATURATION quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the same case as the previous MISSING_NEG_COEFFICIENT quirk Co-developed-by: Oleg Makarenko Signed-off-by: Oleg Makarenko Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 14 ++++++++++---- drivers/hid/usbhid/hid-pidff.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index aebf6c89643f..17bdc36d1908 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -619,16 +619,19 @@ static void pidff_set_condition_report(struct pidff_device *pidff, effect->u.condition[i].center); pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], effect->u.condition[i].right_coeff); + pidff_set(&pidff->set_condition[PID_POS_SATURATION], + effect->u.condition[i].right_saturation); /* Omit Negative Coefficient if missing */ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_NEG_COEFFICIENT)) pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT], effect->u.condition[i].left_coeff); - pidff_set(&pidff->set_condition[PID_POS_SATURATION], - effect->u.condition[i].right_saturation); - pidff_set(&pidff->set_condition[PID_NEG_SATURATION], - effect->u.condition[i].left_saturation); + /* Omit Negative Saturation if missing */ + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_NEG_SATURATION)) + pidff_set_signed(&pidff->set_condition[PID_NEG_SATURATION], + effect->u.condition[i].left_saturation); + pidff_set(&pidff->set_condition[PID_DEAD_BAND], effect->u.condition[i].deadband); hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION], @@ -1097,6 +1100,9 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, else if (table[i] == pidff_set_condition[PID_NEG_COEFFICIENT]) PIDFF_MISSING_FIELD(NEG_COEFFICIENT, quirks); + else if (table[i] == pidff_set_condition[PID_NEG_SATURATION]) + PIDFF_MISSING_FIELD(NEG_SATURATION, quirks); + else if (strict) { pr_debug("failed to locate %d\n", i); return -1; diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h index 5bf54e981543..8d879067718f 100644 --- a/drivers/hid/usbhid/hid-pidff.h +++ b/drivers/hid/usbhid/hid-pidff.h @@ -24,6 +24,9 @@ /* Allow devices with missing negative coefficient in the set condition usage */ #define HID_PIDFF_QUIRK_MISSING_NEG_COEFFICIENT BIT(5) +/* Allow devices with missing negative saturation in the set condition usage */ +#define HID_PIDFF_QUIRK_MISSING_NEG_SATURATION BIT(6) + #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks); From 7daaa0fc44f47882e7b2efff7b95c5f72bb08c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 3 Feb 2026 18:45:30 +0100 Subject: [PATCH 4/5] HID: pidff: Add MISSING_DEADBAND quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices (mainly Asetek) do not have deadband field in set conditional usage. Do not fail set conditional usage search if it's missing. Allows conditional effect playback on Asetek wheelbases. Deadband is practically never used in simracing anyway. Align property name in the whole driver to use 'deadband' without space. Co-developed-by: Oleg Makarenko Signed-off-by: Oleg Makarenko Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-pidff.c | 12 +++++++++--- drivers/hid/usbhid/hid-pidff.h | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 17bdc36d1908..8106b045a8f7 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -82,7 +82,7 @@ static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e }; #define PID_NEG_COEFFICIENT 4 #define PID_POS_SATURATION 5 #define PID_NEG_SATURATION 6 -#define PID_DEAD_BAND 7 +#define PID_DEADBAND 7 static const u8 pidff_set_condition[] = { 0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65 }; @@ -632,8 +632,11 @@ static void pidff_set_condition_report(struct pidff_device *pidff, pidff_set_signed(&pidff->set_condition[PID_NEG_SATURATION], effect->u.condition[i].left_saturation); - pidff_set(&pidff->set_condition[PID_DEAD_BAND], - effect->u.condition[i].deadband); + /* Omit Deadband field if missing */ + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DEADBAND)) + pidff_set(&pidff->set_condition[PID_DEADBAND], + effect->u.condition[i].deadband); + hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION], HID_REQ_SET_REPORT); } @@ -1103,6 +1106,9 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, else if (table[i] == pidff_set_condition[PID_NEG_SATURATION]) PIDFF_MISSING_FIELD(NEG_SATURATION, quirks); + else if (table[i] == pidff_set_condition[PID_DEADBAND]) + PIDFF_MISSING_FIELD(DEADBAND, quirks); + else if (strict) { pr_debug("failed to locate %d\n", i); return -1; diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h index 8d879067718f..c413aa732842 100644 --- a/drivers/hid/usbhid/hid-pidff.h +++ b/drivers/hid/usbhid/hid-pidff.h @@ -27,6 +27,9 @@ /* Allow devices with missing negative saturation in the set condition usage */ #define HID_PIDFF_QUIRK_MISSING_NEG_SATURATION BIT(6) +/* Allow devices with missing deadband in the set condition usage */ +#define HID_PIDFF_QUIRK_MISSING_DEADBAND BIT(7) + #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks); From f8d379460bd088753e47505eebe6a76beecc48c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Paku=C5=82a?= Date: Tue, 3 Feb 2026 18:45:31 +0100 Subject: [PATCH 5/5] HID: Update MAINTAINERS for USB HID PID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take de-facto ownership of core hid-pidff driver Signed-off-by: Tomasz Pakuła Signed-off-by: Jiri Kosina --- MAINTAINERS | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index bacaec38aaf1..aa5877d2de52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11298,14 +11298,6 @@ F: drivers/hid/hid-sensor-* F: drivers/iio/*/hid-* F: include/linux/hid-sensor-* -HID UNIVERSAL PIDFF DRIVER -M: Tomasz Pakuła -M: Oleg Makarenko -L: linux-input@vger.kernel.org -S: Maintained -B: https://github.com/JacKeTUs/universal-pidff/issues -F: drivers/hid/hid-universal-pidff.c - HID VRC-2 CAR CONTROLLER DRIVER M: Marcus Folkesson L: linux-input@vger.kernel.org @@ -27176,6 +27168,15 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git F: Documentation/hid/hiddev.rst F: drivers/hid/usbhid/ +USB HID PID DRIVERS (USB WHEELBASES, JOYSTICKS, RUDDERS, ...) +M: Tomasz Pakuła +M: Oleg Makarenko +L: linux-input@vger.kernel.org +S: Maintained +B: https://github.com/JacKeTUs/universal-pidff/issues +F: drivers/hid/usbhid/hid-pidff* +F: drivers/hid/hid-universal-pidff.c + USB INTEL XHCI ROLE MUX DRIVER M: Hans de Goede L: linux-usb@vger.kernel.org