]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
HID: pidff: Clamp PERIODIC effect period to device's logical range
authorTomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Sat, 1 Feb 2025 11:38:47 +0000 (12:38 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 20 Apr 2025 08:17:54 +0000 (10:17 +0200)
[ Upstream commit f538183e997a9fb6087e94e71e372de967b9e56a ]

This ensures the effect can actually be played on the connected force
feedback device. Adds clamping functions used instead of rescaling, as we
don't want to change the characteristics of the periodic effects.

Fixes edge cases found on Moza Racing and some other hardware where
the effects would not play if the period is outside the defined
logical range.

Changes in v6:
- Use in-kernel clamp macro instead of a custom solution

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

index 25dbed076f530467293f3a9a228e0e2ef8ba036b..6b55345ce75ac44be1b6c2b927d5c86e76c290db 100644 (file)
 #include <linux/input.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
-
 #include <linux/hid.h>
+#include <linux/minmax.h>
 
-#include "usbhid.h"
 
 #define        PID_EFFECTS_MAX         64
 #define        PID_INFINITE            0xffff
@@ -192,6 +191,16 @@ struct pidff_device {
        u32 quirks;
 };
 
+/*
+ * Clamp value for a given field
+ */
+static s32 pidff_clamp(s32 i, struct hid_field *field)
+{
+       s32 clamped = clamp(i, field->logical_minimum, field->logical_maximum);
+       pr_debug("clamped from %d to %d", i, clamped);
+       return clamped;
+}
+
 /*
  * Scale an unsigned value with range 0..max for the given field
  */
@@ -372,7 +381,11 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
        pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
                         effect->u.periodic.offset);
        pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
-       pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
+
+       /* Clamp period to ensure the device can play the effect */
+       pidff->set_periodic[PID_PERIOD].value[0] =
+               pidff_clamp(effect->u.periodic.period,
+                       pidff->set_periodic[PID_PERIOD].field);
 
        hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
                        HID_REQ_SET_REPORT);