]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
HID: pidff: Add MISSING_DELAY quirk and its detection
authorTomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Sat, 1 Feb 2025 11:38:48 +0000 (12:38 +0100)
committerJiri Kosina <jkosina@suse.com>
Mon, 3 Feb 2025 14:16:56 +0000 (15:16 +0100)
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>
drivers/hid/usbhid/hid-pidff.c
include/linux/hid.h

index 488e6a6a14a652360045b829d84f4da5966b67d1..e2e431dec936a1e52ce4dbfce643c87a9c49e1d5 100644 (file)
@@ -184,6 +184,8 @@ struct pidff_device {
        int operation_id[sizeof(pidff_effect_operation_status)];
 
        int pid_id[PID_EFFECTS_MAX];
+
+       u32 quirks;
 };
 
 /*
@@ -338,7 +340,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);
@@ -761,7 +766,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);
@@ -784,6 +792,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;
@@ -808,12 +817,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;
 }
 
 /*
@@ -1088,11 +1102,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) {
@@ -1336,6 +1358,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);
 
index cdc0dc13c87fed201a3a348d1e8c8ff34bcf40dc..9c3a728786c3e1422901e4aadd5638eadc700af6 100644 (file)
@@ -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, ...)                         \