* [PATCH AUTOSEL 6.13 03/24] HID: pidff: Convert infinite length from Linux API to PID standard
[not found] <20250331145404.1705141-1-sashal@kernel.org>
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 04/24] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
` (8 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Makarenko Oleg, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 37e0591fe44dce39d1ebc7a82d5b6e4dba1582eb ]
Software uses 0 as de-facto infinite lenght on Linux FF apis (SDL),
Linux doesn't actually define anythi as of now, while USB PID defines
NULL (0xffff). Most PID devices do not expect a 0-length effect and
can't interpret it as infinite. This change fixes Force Feedback for
most PID compliant devices.
As most games depend on updating the values of already playing infinite
effects, this is crucial to ensure they will actually work.
Previously, users had to rely on third-party software to do this conversion
and make their PID devices usable.
Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 3b4ee21cd8111..5fe4422bb5bad 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -21,6 +21,7 @@
#include "usbhid.h"
#define PID_EFFECTS_MAX 64
+#define PID_INFINITE 0xffff
/* Report usage table used to put reports into an array */
@@ -301,7 +302,12 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
pidff->set_effect_type->value[0] =
pidff->create_new_effect_type->value[0];
- pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
+
+ /* Convert infinite length from Linux API (0)
+ to PID standard (NULL) if needed */
+ pidff->set_effect[PID_DURATION].value[0] =
+ effect->replay.length == 0 ? PID_INFINITE : effect->replay.length;
+
pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
effect->trigger.interval;
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 04/24] HID: pidff: Do not send effect envelope if it's empty
[not found] <20250331145404.1705141-1-sashal@kernel.org>
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 03/24] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 05/24] HID: pidff: Add MISSING_DELAY quirk and its detection Sasha Levin
` (7 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Michał Kopeć, Paul Dino Jones,
Cristóferson Bueno, Pablo Cisneros, Jiri Kosina, Sasha Levin,
jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 8876fc1884f5b39550c8387ff3176396c988541d ]
Envelope struct is always initialized, but the envelope itself is
optional as described in USB PID Device class definition 1.0.
5.1.1.1 Type Specific Block Offsets
...
4) Effects that do not use Condition Blocks use 1 Parameter Block and
an *optional* Envelope Block.
Sending out "empty" envelope breaks force feedback on some devices with
games that use SINE effect + offset to emulate constant force effect, as
well as generally breaking Constant/Periodic effects. One of the affected
brands is Moza Racing.
This change prevents the envelope from being sent if it contains all
0 values while keeping the old behavior of only sending it, if it differs
from the old one.
Changes in v6:
- Simplify the checks to make them clearer
- Fix possible null pointer dereference while calling
pidff_needs_set_envelope
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 42 +++++++++++++++++++---------------
1 file changed, 24 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 5fe4422bb5bad..a01c1b2ab2f4c 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -262,10 +262,22 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
static int pidff_needs_set_envelope(struct ff_envelope *envelope,
struct ff_envelope *old)
{
- return envelope->attack_level != old->attack_level ||
- envelope->fade_level != old->fade_level ||
+ bool needs_new_envelope;
+ needs_new_envelope = envelope->attack_level != 0 ||
+ envelope->fade_level != 0 ||
+ envelope->attack_length != 0 ||
+ envelope->fade_length != 0;
+
+ if (!needs_new_envelope)
+ return false;
+
+ if (!old)
+ return needs_new_envelope;
+
+ return envelope->attack_level != old->attack_level ||
+ envelope->fade_level != old->fade_level ||
envelope->attack_length != old->attack_length ||
- envelope->fade_length != old->fade_length;
+ envelope->fade_length != old->fade_length;
}
/*
@@ -580,11 +592,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_constant(effect, old))
pidff_set_constant_force_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.constant.envelope,
- &old->u.constant.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.constant.envelope);
+ if (pidff_needs_set_envelope(&effect->u.constant.envelope,
+ old ? &old->u.constant.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.constant.envelope);
break;
case FF_PERIODIC:
@@ -619,11 +629,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_periodic(effect, old))
pidff_set_periodic_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.periodic.envelope,
- &old->u.periodic.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.periodic.envelope);
+ if (pidff_needs_set_envelope(&effect->u.periodic.envelope,
+ old ? &old->u.periodic.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.periodic.envelope);
break;
case FF_RAMP:
@@ -637,11 +645,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_ramp(effect, old))
pidff_set_ramp_force_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.ramp.envelope,
- &old->u.ramp.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.ramp.envelope);
+ if (pidff_needs_set_envelope(&effect->u.ramp.envelope,
+ old ? &old->u.ramp.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.ramp.envelope);
break;
case FF_SPRING:
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 05/24] HID: pidff: Add MISSING_DELAY quirk and its detection
[not found] <20250331145404.1705141-1-sashal@kernel.org>
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 03/24] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 04/24] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 06/24] HID: pidff: Add MISSING_PBO " Sasha Levin
` (6 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Makarenko Oleg, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 2d5c7ce5bf4cc27db41632f357f682d0ee4518e7 ]
A lot of devices do not include this field, and it's seldom used in force
feedback implementations. I tested about three dozen applications and
none of them make use of the delay.
This fixes initialization of a lot of PID wheels like Cammus, VRS, FFBeast
This change has no effect on fully compliant devices
Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 33 ++++++++++++++++++++++++++++-----
include/linux/hid.h | 3 +++
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index a01c1b2ab2f4c..929f5967e7cb1 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -185,6 +185,8 @@ struct pidff_device {
int operation_id[sizeof(pidff_effect_operation_status)];
int pid_id[PID_EFFECTS_MAX];
+
+ u32 quirks;
};
/*
@@ -329,7 +331,10 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction->value[0] =
pidff_rescale(effect->direction, 0xffff,
pidff->effect_direction);
- pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
+
+ /* Omit setting delay field if it's missing */
+ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
+ pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
HID_REQ_SET_REPORT);
@@ -748,7 +753,10 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
- pidff->set_effect[PID_START_DELAY].value[0] = 0;
+
+ /* Omit setting delay field if it's missing */
+ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
+ pidff->set_effect[PID_START_DELAY].value[0] = 0;
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
HID_REQ_SET_REPORT);
@@ -771,6 +779,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
struct hid_report *report, int count, int strict)
{
int i, j, k, found;
+ int return_value = 0;
for (k = 0; k < count; k++) {
found = 0;
@@ -795,12 +804,17 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
if (found)
break;
}
- if (!found && strict) {
+ if (!found && table[k] == pidff_set_effect[PID_START_DELAY]) {
+ pr_debug("Delay field not found, but that's OK\n");
+ pr_debug("Setting MISSING_DELAY quirk\n");
+ return_value |= HID_PIDFF_QUIRK_MISSING_DELAY;
+ }
+ else if (!found && strict) {
pr_debug("failed to locate %d\n", k);
return -1;
}
}
- return 0;
+ return return_value;
}
/*
@@ -1075,11 +1089,19 @@ static int pidff_find_effects(struct pidff_device *pidff,
static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
{
int envelope_ok = 0;
+ int status = 0;
- if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
+ /* Save info about the device not having the DELAY ffb field. */
+ status = PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1);
+ if (status == -1) {
hid_err(pidff->hid, "unknown set_effect report layout\n");
return -ENODEV;
}
+ pidff->quirks |= status;
+
+ if (status & HID_PIDFF_QUIRK_MISSING_DELAY)
+ hid_dbg(pidff->hid, "Adding MISSING_DELAY quirk\n");
+
PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
@@ -1323,6 +1345,7 @@ int hid_pidff_init(struct hid_device *hid)
ff->playback = pidff_playback;
hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_dbg(dev, "Active quirks mask: 0x%x\n", pidff->quirks);
hid_device_io_stop(hid);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index cdc0dc13c87fe..9c3a728786c3e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1228,6 +1228,9 @@ int hid_pidff_init(struct hid_device *hid);
#define hid_pidff_init NULL
#endif
+/* HID PIDFF quirks */
+#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
+
#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__)
#define hid_err(hid, fmt, ...) \
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 06/24] HID: pidff: Add MISSING_PBO quirk and its detection
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (2 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 05/24] HID: pidff: Add MISSING_DELAY quirk and its detection Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 07/24] HID: pidff: Add PERMISSIVE_CONTROL quirk Sasha Levin
` (5 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Makarenko Oleg, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit fc7c154e9bb3c2b98875cfc565406f4787e3b7a4 ]
Some devices with only one axis are missing PARAMETER_BLOCK_OFFSET field
for conditional effects. They can only have one axis, so we're limiting
the max_axis when setting the report for those effects.
Automatic detection ensures compatibility even if such device won't be
explicitly defined in the kernel.
Fixes initialization of VRS DirectForce PRO and possibly other devices.
Changes in v6:
- Fixed NULL pointer dereference. When PBO is missing, make sure not
to set it anyway
Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 47 +++++++++++++++++++++-------------
include/linux/hid.h | 1 +
2 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 929f5967e7cb1..503b22feacdbb 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -391,13 +391,19 @@ static int pidff_needs_set_periodic(struct ff_effect *effect,
static void pidff_set_condition_report(struct pidff_device *pidff,
struct ff_effect *effect)
{
- int i;
+ int i, max_axis;
+
+ /* Devices missing Parameter Block Offset can only have one axis */
+ max_axis = pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO ? 1 : 2;
pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
- for (i = 0; i < 2; i++) {
- pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
+ for (i = 0; i < max_axis; i++) {
+ /* Omit Parameter Block Offset if missing */
+ if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_PBO))
+ pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
+
pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
effect->u.condition[i].center);
pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
@@ -809,6 +815,11 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
pr_debug("Setting MISSING_DELAY quirk\n");
return_value |= HID_PIDFF_QUIRK_MISSING_DELAY;
}
+ else if (!found && table[k] == pidff_set_condition[PID_PARAM_BLOCK_OFFSET]) {
+ pr_debug("PBO field not found, but that's OK\n");
+ pr_debug("Setting MISSING_PBO quirk\n");
+ return_value |= HID_PIDFF_QUIRK_MISSING_PBO;
+ }
else if (!found && strict) {
pr_debug("failed to locate %d\n", k);
return -1;
@@ -1088,7 +1099,6 @@ static int pidff_find_effects(struct pidff_device *pidff,
*/
static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
{
- int envelope_ok = 0;
int status = 0;
/* Save info about the device not having the DELAY ffb field. */
@@ -1119,13 +1129,10 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
return -ENODEV;
}
- if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
- envelope_ok = 1;
-
if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
return -ENODEV;
- if (!envelope_ok) {
+ if (PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) {
if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
hid_warn(pidff->hid,
"has constant effect but no envelope\n");
@@ -1150,16 +1157,20 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
clear_bit(FF_RAMP, dev->ffbit);
}
- if ((test_bit(FF_SPRING, dev->ffbit) ||
- test_bit(FF_DAMPER, dev->ffbit) ||
- test_bit(FF_FRICTION, dev->ffbit) ||
- test_bit(FF_INERTIA, dev->ffbit)) &&
- PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- hid_warn(pidff->hid, "unknown condition effect layout\n");
- clear_bit(FF_SPRING, dev->ffbit);
- clear_bit(FF_DAMPER, dev->ffbit);
- clear_bit(FF_FRICTION, dev->ffbit);
- clear_bit(FF_INERTIA, dev->ffbit);
+ if (test_bit(FF_SPRING, dev->ffbit) ||
+ test_bit(FF_DAMPER, dev->ffbit) ||
+ test_bit(FF_FRICTION, dev->ffbit) ||
+ test_bit(FF_INERTIA, dev->ffbit)) {
+ status = PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1);
+
+ if (status < 0) {
+ hid_warn(pidff->hid, "unknown condition effect layout\n");
+ clear_bit(FF_SPRING, dev->ffbit);
+ clear_bit(FF_DAMPER, dev->ffbit);
+ clear_bit(FF_FRICTION, dev->ffbit);
+ clear_bit(FF_INERTIA, dev->ffbit);
+ }
+ pidff->quirks |= status;
}
if (test_bit(FF_PERIODIC, dev->ffbit) &&
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 9c3a728786c3e..ea7ba8e4bfe49 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1230,6 +1230,7 @@ int hid_pidff_init(struct hid_device *hid);
/* HID PIDFF quirks */
#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
+#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 07/24] HID: pidff: Add PERMISSIVE_CONTROL quirk
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (3 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 06/24] HID: pidff: Add MISSING_PBO " Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 08/24] HID: pidff: Add hid_pidff_init_with_quirks and export as GPL symbol Sasha Levin
` (4 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Makarenko Oleg, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit a4119108d2530747e61c7cbf52e2affd089cb1f6 ]
With this quirk, a PID device isn't required to have a strict
logical_minimum of 1 for the the PID_DEVICE_CONTROL usage page.
Some devices come with weird values in their device descriptors and
this quirk enables their initialization even if the logical minimum
of the DEVICE_CONTROL page is not 1.
Fixes initialization of VRS Direct Force Pro
Changes in v6:
- Change quirk name to better reflect it's intention
Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 3 ++-
include/linux/hid.h | 5 +++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 503b22feacdbb..5a57ba0d7026a 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -969,7 +969,8 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
0x57, 0);
pidff->device_control =
pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
- 0x96, 1);
+ 0x96, !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL));
+
pidff->block_load_status =
pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
0x8b, 1);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ea7ba8e4bfe49..89a4dee377292 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1229,8 +1229,9 @@ int hid_pidff_init(struct hid_device *hid);
#endif
/* HID PIDFF quirks */
-#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
-#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
+#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
+#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
+#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2)
#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 08/24] HID: pidff: Add hid_pidff_init_with_quirks and export as GPL symbol
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (4 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 07/24] HID: pidff: Add PERMISSIVE_CONTROL quirk Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 09/24] HID: pidff: Add FIX_WHEEL_DIRECTION quirk Sasha Levin
` (3 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Michał Kopeć, Paul Dino Jones,
Cristóferson Bueno, Pablo Cisneros, Jiri Kosina, Sasha Levin,
jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 36de0164bbaff1484288e84ac5df5cff00580263 ]
This lays out a way to provide an initial set of quirks to enable before
device initialization takes place. GPL symbol export needed for the
possibility of building HID drivers which use this function as modules.
Adding a wrapper function to ensure compatibility with the old behavior
of hid_pidff_init.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 15 ++++++++++++++-
include/linux/hid.h | 2 ++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 5a57ba0d7026a..b8c2ba0a930c2 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -1268,8 +1268,9 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
/*
* Check if the device is PID and initialize it
+ * Set initial quirks
*/
-int hid_pidff_init(struct hid_device *hid)
+int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks)
{
struct pidff_device *pidff;
struct hid_input *hidinput = list_entry(hid->inputs.next,
@@ -1291,6 +1292,7 @@ int hid_pidff_init(struct hid_device *hid)
return -ENOMEM;
pidff->hid = hid;
+ pidff->quirks = initial_quirks;
hid_device_io_start(hid);
@@ -1369,3 +1371,14 @@ int hid_pidff_init(struct hid_device *hid)
kfree(pidff);
return error;
}
+EXPORT_SYMBOL_GPL(hid_pidff_init_with_quirks);
+
+/*
+ * Check if the device is PID and initialize it
+ * Wrapper made to keep the compatibility with old
+ * init function
+ */
+int hid_pidff_init(struct hid_device *hid)
+{
+ return hid_pidff_init_with_quirks(hid, 0);
+}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 89a4dee377292..31dfe9ed5394b 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1224,8 +1224,10 @@ void hid_quirks_exit(__u16 bus);
#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);
#else
#define hid_pidff_init NULL
+#define hid_pidff_init_with_quirks NULL
#endif
/* HID PIDFF quirks */
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 09/24] HID: pidff: Add FIX_WHEEL_DIRECTION quirk
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (5 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 08/24] HID: pidff: Add hid_pidff_init_with_quirks and export as GPL symbol Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 10/24] HID: Add hid-universal-pidff driver and supported device ids Sasha Levin
` (2 subsequent siblings)
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Michał Kopeć, Paul Dino Jones,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 3051bf5ec773b803c474ea556b57d678a8885be3 ]
Most steering wheels simply ignore DIRECTION field, but some try to be
compliant with the PID standard and use it in force calculations. Games
often ignore setting this field properly and/or there can be issues with
dinput8 -> wine -> SDL -> Linux API translation, and this value can be
incorrect. This can lead to partial/complete loss of Force Feedback or
even unexpected force reversal.
Sadly, this quirk can't be detected automatically without sending out
effects that would move an axis.
This fixes FFB on Moza Racing devices and others where effect direction
is not simply ignored.
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 12 +++++++++---
include/linux/hid.h | 1 +
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index b8c2ba0a930c2..a37cf852a2836 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -137,6 +137,9 @@ static const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
#define PID_EFFECT_STOP 1
static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
+/* Polar direction 90 degrees (North) */
+#define PIDFF_FIXED_WHEEL_DIRECTION 0x4000
+
struct pidff_usage {
struct hid_field *field;
s32 *value;
@@ -328,9 +331,12 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->set_effect[PID_GAIN].value[0] =
pidff->set_effect[PID_GAIN].field->logical_maximum;
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
- pidff->effect_direction->value[0] =
- pidff_rescale(effect->direction, 0xffff,
- pidff->effect_direction);
+
+ /* Use fixed direction if needed */
+ pidff->effect_direction->value[0] = pidff_rescale(
+ pidff->quirks & HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION ?
+ PIDFF_FIXED_WHEEL_DIRECTION : effect->direction,
+ 0xffff, pidff->effect_direction);
/* Omit setting delay field if it's missing */
if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY))
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 31dfe9ed5394b..7a55accf689e0 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1234,6 +1234,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks);
#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0)
#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2)
+#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3)
#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 10/24] HID: Add hid-universal-pidff driver and supported device ids
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (6 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 09/24] HID: pidff: Add FIX_WHEEL_DIRECTION quirk Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 11/24] HID: pidff: Add PERIODIC_SINE_ONLY quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 12/24] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Makarenko Oleg, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit f06bf8d94fffbb544b1cb5402c92e0a075f0d420 ]
Extend pidff compatibility, usable button range, manage pidff quirks and
set improved fuzz/flat default for high precision devices. Possibility
of fixing device descriptors in the future if such needs arises.
As many of PID devices are quite similar and not dependent on
custom drivers, this one can handle all of PID devices which
need special care.
Numerous sim racing/sim flight bases report a lot of buttons
in excess of 100. Moza Racing exposes 128 of them and thus
the need to extend the available range.
All the included devices were tested and confirmed working
with the help of the sim racing community.
Changes in v6:
- Support "split" devices with a separate "input device" for buttons
- Fixed comment styling
Co-developed-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Makarenko Oleg <oleg@makarenk.ooo>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/Kconfig | 14 +++
drivers/hid/Makefile | 1 +
drivers/hid/hid-ids.h | 31 +++++
drivers/hid/hid-universal-pidff.c | 192 ++++++++++++++++++++++++++++++
4 files changed, 238 insertions(+)
create mode 100644 drivers/hid/hid-universal-pidff.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 363c860835d35..84a757da4fb63 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1218,6 +1218,20 @@ config HID_U2FZERO
allow setting the brightness to anything but 1, which will
trigger a single blink and immediately reset back to 0.
+config HID_UNIVERSAL_PIDFF
+ tristate "universal-pidff: extended USB PID driver compatibility and usage"
+ depends on USB_HID
+ depends on HID_PID
+ help
+ Extended PID support for selected devices.
+
+ Contains report fixups, extended usable button range and
+ pidff quirk management to extend compatibility with slightly
+ non-compliant USB PID devices and better fuzz/flat values for
+ high precision direct drive devices.
+
+ Supports Moza Racing, Cammus, VRS, FFBeast and more.
+
config HID_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 24de45f3677d1..919d6a1460770 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -140,6 +140,7 @@ hid-uclogic-objs := hid-uclogic-core.o \
hid-uclogic-params.o
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o
+obj-$(CONFIG_HID_UNIVERSAL_PIDFF) += hid-universal-pidff.o
obj-$(CONFIG_HID_LED) += hid-led.o
obj-$(CONFIG_HID_XIAOMI) += hid-xiaomi.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index c4ca7a579e3d4..e1e002df64de2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -262,6 +262,10 @@
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
+#define USB_VENDOR_ID_CAMMUS 0x3416
+#define USB_DEVICE_ID_CAMMUS_C5 0x0301
+#define USB_DEVICE_ID_CAMMUS_C12 0x0302
+
#define USB_VENDOR_ID_CANDO 0x2087
#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
@@ -453,6 +457,11 @@
#define USB_VENDOR_ID_EVISION 0x320f
#define USB_DEVICE_ID_EVISION_ICL01 0x5041
+#define USB_VENDOR_ID_FFBEAST 0x045b
+#define USB_DEVICE_ID_FFBEAST_JOYSTICK 0x58f9
+#define USB_DEVICE_ID_FFBEAST_RUDDER 0x5968
+#define USB_DEVICE_ID_FFBEAST_WHEEL 0x59d7
+
#define USB_VENDOR_ID_FLATFROG 0x25b5
#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002
@@ -817,6 +826,13 @@
#define I2C_DEVICE_ID_LG_8001 0x8001
#define I2C_DEVICE_ID_LG_7010 0x7010
+#define USB_VENDOR_ID_LITE_STAR 0x11ff
+#define USB_DEVICE_ID_PXN_V10 0x3245
+#define USB_DEVICE_ID_PXN_V12 0x1212
+#define USB_DEVICE_ID_PXN_V12_LITE 0x1112
+#define USB_DEVICE_ID_PXN_V12_LITE_2 0x1211
+#define USB_DEVICE_LITE_STAR_GT987_FF 0x2141
+
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
@@ -964,6 +980,18 @@
#define USB_VENDOR_ID_MONTEREY 0x0566
#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
+#define USB_VENDOR_ID_MOZA 0x346e
+#define USB_DEVICE_ID_MOZA_R3 0x0005
+#define USB_DEVICE_ID_MOZA_R3_2 0x0015
+#define USB_DEVICE_ID_MOZA_R5 0x0004
+#define USB_DEVICE_ID_MOZA_R5_2 0x0014
+#define USB_DEVICE_ID_MOZA_R9 0x0002
+#define USB_DEVICE_ID_MOZA_R9_2 0x0012
+#define USB_DEVICE_ID_MOZA_R12 0x0006
+#define USB_DEVICE_ID_MOZA_R12_2 0x0016
+#define USB_DEVICE_ID_MOZA_R16_R21 0x0000
+#define USB_DEVICE_ID_MOZA_R16_R21_2 0x0010
+
#define USB_VENDOR_ID_MSI 0x1770
#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00
@@ -1375,6 +1403,9 @@
#define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061
#define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068
+#define USB_VENDOR_ID_VRS 0x0483
+#define USB_DEVICE_ID_VRS_DFP 0xa355
+
#define USB_VENDOR_ID_VTL 0x0306
#define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f
diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c
new file mode 100644
index 0000000000000..55aad2e4ac1b8
--- /dev/null
+++ b/drivers/hid/hid-universal-pidff.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HID UNIVERSAL PIDFF
+ * hid-pidff wrapper for PID-enabled devices
+ * Handles device reports, quirks and extends usable button range
+ *
+ * Copyright (c) 2024, 2025 Makarenko Oleg
+ * Copyright (c) 2024, 2025 Tomasz Pakuła
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/input-event-codes.h>
+#include "hid-ids.h"
+
+#define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1)
+
+/*
+ * Map buttons manually to extend the default joystick button limit
+ */
+static int universal_pidff_input_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)
+ return 0;
+
+ if (field->application != HID_GD_JOYSTICK)
+ return 0;
+
+ int button = ((usage->hid - 1) & HID_USAGE);
+ int code = button + BTN_JOYSTICK;
+
+ /* Detect the end of JOYSTICK buttons range */
+ if (code > BTN_DEAD)
+ code = button + KEY_NEXT_FAVORITE - JOY_RANGE;
+
+ /*
+ * Map overflowing buttons to KEY_RESERVED to not ignore
+ * them and let them still trigger MSC_SCAN
+ */
+ if (code > KEY_MAX)
+ code = KEY_RESERVED;
+
+ hid_map_usage(hi, usage, bit, max, EV_KEY, code);
+ hid_dbg(hdev, "Button %d: usage %d", button, code);
+ return 1;
+}
+
+/*
+ * Check if the device is PID and initialize it
+ * Add quirks after initialisation
+ */
+static int universal_pidff_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int i, error;
+ error = hid_parse(hdev);
+ if (error) {
+ hid_err(hdev, "HID parse failed\n");
+ goto err;
+ }
+
+ error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (error) {
+ hid_err(hdev, "HID hw start failed\n");
+ goto err;
+ }
+
+ /* Check if device contains PID usage page */
+ error = 1;
+ for (i = 0; i < hdev->collection_size; i++)
+ if ((hdev->collection[i].usage & HID_USAGE_PAGE) == HID_UP_PID) {
+ error = 0;
+ hid_dbg(hdev, "PID usage page found\n");
+ break;
+ }
+
+ /*
+ * Do not fail as this might be the second "device"
+ * just for additional buttons/axes. Exit cleanly if force
+ * feedback usage page wasn't found (included devices were
+ * tested and confirmed to be USB PID after all).
+ */
+ if (error) {
+ hid_dbg(hdev, "PID usage page not found in the descriptor\n");
+ return 0;
+ }
+
+ /* Check if HID_PID support is enabled */
+ int (*init_function)(struct hid_device *, __u32);
+ init_function = hid_pidff_init_with_quirks;
+
+ if (!init_function) {
+ hid_warn(hdev, "HID_PID support not enabled!\n");
+ return 0;
+ }
+
+ error = init_function(hdev, id->driver_data);
+ if (error) {
+ hid_warn(hdev, "Error initialising force feedback\n");
+ goto err;
+ }
+
+ hid_info(hdev, "Universal pidff driver loaded sucesfully!");
+
+ return 0;
+err:
+ return error;
+}
+
+static int universal_pidff_input_configured(struct hid_device *hdev,
+ struct hid_input *hidinput)
+{
+ int axis;
+ struct input_dev *input = hidinput->input;
+
+ if (!input->absinfo)
+ return 0;
+
+ /* Decrease fuzz and deadzone on available axes */
+ for (axis = ABS_X; axis <= ABS_BRAKE; axis++) {
+ if (!test_bit(axis, input->absbit))
+ continue;
+
+ input_set_abs_params(input, axis,
+ input->absinfo[axis].minimum,
+ input->absinfo[axis].maximum,
+ axis == ABS_X ? 0 : 8, 0);
+ }
+
+ /* Remove fuzz and deadzone from the second joystick axis */
+ if (hdev->vendor == USB_VENDOR_ID_FFBEAST &&
+ hdev->product == USB_DEVICE_ID_FFBEAST_JOYSTICK)
+ input_set_abs_params(input, ABS_Y,
+ input->absinfo[ABS_Y].minimum,
+ input->absinfo[ABS_Y].maximum, 0, 0);
+
+ return 0;
+}
+
+static const struct hid_device_id universal_pidff_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R3_2),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R5_2),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R9_2),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R12_2),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MOZA, USB_DEVICE_ID_MOZA_R16_R21_2),
+ .driver_data = HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C5) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CAMMUS, USB_DEVICE_ID_CAMMUS_C12) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VRS, USB_DEVICE_ID_VRS_DFP),
+ .driver_data = HID_PIDFF_QUIRK_PERMISSIVE_CONTROL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_JOYSTICK), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_RUDDER), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, universal_pidff_devices);
+
+static struct hid_driver universal_pidff = {
+ .name = "hid-universal-pidff",
+ .id_table = universal_pidff_devices,
+ .input_mapping = universal_pidff_input_mapping,
+ .probe = universal_pidff_probe,
+ .input_configured = universal_pidff_input_configured
+};
+module_hid_driver(universal_pidff);
+
+MODULE_DESCRIPTION("Universal driver for USB PID Force Feedback devices");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Makarenko Oleg <oleg@makarenk.ooo>");
+MODULE_AUTHOR("Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>");
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 11/24] HID: pidff: Add PERIODIC_SINE_ONLY quirk
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (7 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 10/24] HID: Add hid-universal-pidff driver and supported device ids Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 12/24] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Michał Kopeć, Paul Dino Jones,
Cristóferson Bueno, Jiri Kosina, Sasha Levin, oleg, jikos,
bentiss, linux-input, linux-usb
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit abdbf8764f4962af2a910abb3a213ecf304a73d3 ]
Some devices only support SINE periodic effect although they advertise
support for all PERIODIC effect in their HID descriptor. Some just do
nothing when trying to play such an effect (upload goes fine), some express
undefined behavior like turning to one side.
This quirk forces all the periodic effects to be uploaded as SINE. This is
acceptable as all these effects are similar in nature and are mostly used as
rumble. SINE is the most popular with others seldom used (especially SAW_UP
and SAW_DOWN).
Fixes periodic effects for PXN and LITE STAR wheels
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/hid-universal-pidff.c | 15 ++++++++++-----
drivers/hid/usbhid/hid-pidff.c | 3 +++
include/linux/hid.h | 1 +
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c
index 55aad2e4ac1b8..7ef5ab9146b1c 100644
--- a/drivers/hid/hid-universal-pidff.c
+++ b/drivers/hid/hid-universal-pidff.c
@@ -168,11 +168,16 @@ static const struct hid_device_id universal_pidff_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_JOYSTICK), },
{ HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_RUDDER), },
{ HID_USB_DEVICE(USB_VENDOR_ID_FFBEAST, USB_DEVICE_ID_FFBEAST_WHEEL) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V10),
+ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12),
+ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE),
+ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_ID_PXN_V12_LITE_2),
+ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LITE_STAR, USB_DEVICE_LITE_STAR_GT987_FF),
+ .driver_data = HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY },
{ }
};
MODULE_DEVICE_TABLE(hid, universal_pidff_devices);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index a37cf852a2836..4c94d8cbac43a 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -637,6 +637,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
return -EINVAL;
}
+ if (pidff->quirks & HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY)
+ type_id = PID_SINE;
+
error = pidff_request_effect_upload(pidff,
pidff->type_id[type_id]);
if (error)
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 7a55accf689e0..e180679ab284c 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1235,6 +1235,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks);
#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1)
#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2)
#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3)
+#define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4)
#define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH AUTOSEL 6.13 12/24] HID: pidff: Fix null pointer dereference in pidff_find_fields
[not found] <20250331145404.1705141-1-sashal@kernel.org>
` (8 preceding siblings ...)
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 11/24] HID: pidff: Add PERIODIC_SINE_ONLY quirk Sasha Levin
@ 2025-03-31 14:53 ` Sasha Levin
9 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2025-03-31 14:53 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Nolan Nicholson, Tomasz Pakuła,
Michał Kopeć, Paul Dino Jones, Cristóferson Bueno,
Pablo Cisneros, Jiri Kosina, Sasha Levin, jikos, bentiss,
linux-usb, linux-input
From: Tomasz Pakuła <forest10pl@gmail.com>
[ Upstream commit 22a05462c3d0eee15154faf8d13c49e6295270a5 ]
This function triggered a null pointer dereference if used to search for
a report that isn't implemented on the device. This happened both for
optional and required reports alike.
The same logic was applied to pidff_find_special_field and although
pidff_init_fields should return an error earlier if one of the required
reports is missing, future modifications could change this logic and
resurface this possible null pointer dereference again.
LKML bug report:
https://lore.kernel.org/all/CAL-gK7f5=R0nrrQdPtaZZr1fd-cdAMbDMuZ_NLA8vM0SX+nGSw@mail.gmail.com
Reported-by: Nolan Nicholson <nolananicholson@gmail.com>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 4c94d8cbac43a..25dbed076f530 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -793,6 +793,11 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
struct hid_report *report, int count, int strict)
{
+ if (!report) {
+ pr_debug("pidff_find_fields, null report\n");
+ return -1;
+ }
+
int i, j, k, found;
int return_value = 0;
@@ -917,6 +922,11 @@ static int pidff_reports_ok(struct pidff_device *pidff)
static struct hid_field *pidff_find_special_field(struct hid_report *report,
int usage, int enforce_min)
{
+ if (!report) {
+ pr_debug("pidff_find_special_field, null report\n");
+ return NULL;
+ }
+
int i;
for (i = 0; i < report->maxfield; i++) {
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-03-31 14:54 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20250331145404.1705141-1-sashal@kernel.org>
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 03/24] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 04/24] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 05/24] HID: pidff: Add MISSING_DELAY quirk and its detection Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 06/24] HID: pidff: Add MISSING_PBO " Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 07/24] HID: pidff: Add PERMISSIVE_CONTROL quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 08/24] HID: pidff: Add hid_pidff_init_with_quirks and export as GPL symbol Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 09/24] HID: pidff: Add FIX_WHEEL_DIRECTION quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 10/24] HID: Add hid-universal-pidff driver and supported device ids Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 11/24] HID: pidff: Add PERIODIC_SINE_ONLY quirk Sasha Levin
2025-03-31 14:53 ` [PATCH AUTOSEL 6.13 12/24] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).