From 9335051c1e06dc87ec8a6aa8edc424d99bf60684 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Wed, 16 Apr 2025 12:38:29 -0400 Subject: [PATCH] Fixes for 6.13 Signed-off-by: Sasha Levin --- ...l-pidff-add-asetek-wheelbases-suppor.patch | 92 +++++++ ...amp-effect-playback-loop_count-value.patch | 42 +++ ...periodic-effect-period-to-device-s-l.patch | 84 ++++++ ...-pidff-comment-and-code-style-update.patch | 193 +++++++++++++ ...tely-rework-and-fix-pidff_reset-func.patch | 259 ++++++++++++++++++ ...e-infinite-value-instead-of-using-ha.patch | 45 +++ ...-values-used-in-pidff_find_special_f.patch | 79 ++++++ ...dff-factor-out-code-for-setting-gain.patch | 83 ++++++ ...-out-pool-report-fetch-and-remove-ex.patch | 117 ++++++++ ...90-degrees-direction-name-north-east.patch | 34 +++ .../hid-pidff-fix-set_device_control.patch | 79 ++++++ ...ure-to-fetch-pool-before-checking-si.patch | 76 +++++ ...ll-hid-pidff-definitions-to-a-dedica.patch | 154 +++++++++++ ...-redundant-call-to-pidff_find_specia.patch | 39 +++ ...-two-functions-to-align-them-with-na.patch | 68 +++++ ...ale-time-values-to-match-field-units.patch | 167 +++++++++++ ...-pidff-simplify-pidff_rescale_signed.patch | 47 ++++ ...implify-pidff_upload_effect-function.patch | 100 +++++++ ...ll-effects-before-enabling-actuators.patch | 63 +++++ ...t-device-error-response-from-pid_blo.patch | 54 ++++ ...cros-instead-of-hardcoded-min-max-va.patch | 122 +++++++++ queue-6.13/series | 21 ++ 22 files changed, 2018 insertions(+) create mode 100644 queue-6.13/hid-hid-universal-pidff-add-asetek-wheelbases-suppor.patch create mode 100644 queue-6.13/hid-pidff-clamp-effect-playback-loop_count-value.patch create mode 100644 queue-6.13/hid-pidff-clamp-periodic-effect-period-to-device-s-l.patch create mode 100644 queue-6.13/hid-pidff-comment-and-code-style-update.patch create mode 100644 queue-6.13/hid-pidff-completely-rework-and-fix-pidff_reset-func.patch create mode 100644 queue-6.13/hid-pidff-compute-infinite-value-instead-of-using-ha.patch create mode 100644 queue-6.13/hid-pidff-define-values-used-in-pidff_find_special_f.patch create mode 100644 queue-6.13/hid-pidff-factor-out-code-for-setting-gain.patch create mode 100644 queue-6.13/hid-pidff-factor-out-pool-report-fetch-and-remove-ex.patch create mode 100644 queue-6.13/hid-pidff-fix-90-degrees-direction-name-north-east.patch create mode 100644 queue-6.13/hid-pidff-fix-set_device_control.patch create mode 100644 queue-6.13/hid-pidff-make-sure-to-fetch-pool-before-checking-si.patch create mode 100644 queue-6.13/hid-pidff-move-all-hid-pidff-definitions-to-a-dedica.patch create mode 100644 queue-6.13/hid-pidff-remove-redundant-call-to-pidff_find_specia.patch create mode 100644 queue-6.13/hid-pidff-rename-two-functions-to-align-them-with-na.patch create mode 100644 queue-6.13/hid-pidff-rescale-time-values-to-match-field-units.patch create mode 100644 queue-6.13/hid-pidff-simplify-pidff_rescale_signed.patch create mode 100644 queue-6.13/hid-pidff-simplify-pidff_upload_effect-function.patch create mode 100644 queue-6.13/hid-pidff-stop-all-effects-before-enabling-actuators.patch create mode 100644 queue-6.13/hid-pidff-support-device-error-response-from-pid_blo.patch create mode 100644 queue-6.13/hid-pidff-use-macros-instead-of-hardcoded-min-max-va.patch diff --git a/queue-6.13/hid-hid-universal-pidff-add-asetek-wheelbases-suppor.patch b/queue-6.13/hid-hid-universal-pidff-add-asetek-wheelbases-suppor.patch new file mode 100644 index 0000000000..951bcc26e6 --- /dev/null +++ b/queue-6.13/hid-hid-universal-pidff-add-asetek-wheelbases-suppor.patch @@ -0,0 +1,92 @@ +From 0a0b38afee0e82901b62c98c5510aca5d79b2d0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Feb 2025 15:35:09 +0100 +Subject: HID: hid-universal-pidff: Add Asetek wheelbases support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit c385f61108d403633e8cfbdae15b35ccf7cee686 ] + +Adds Asetek vendor id and product ids for: +- Invicta +- Forte +- La Prima +- Tony Kanaan + +v2: +- Misc spelling fix in driver loaded info + +v3: +- Chanage Oleg's name order + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-ids.h | 6 ++++++ + drivers/hid/hid-universal-pidff.c | 10 +++++++--- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index e1e002df64de2..db88831633466 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -190,6 +190,12 @@ + #define USB_DEVICE_ID_APPLE_TOUCHBAR_BACKLIGHT 0x8102 + #define USB_DEVICE_ID_APPLE_TOUCHBAR_DISPLAY 0x8302 + ++#define USB_VENDOR_ID_ASETEK 0x2433 ++#define USB_DEVICE_ID_ASETEK_INVICTA 0xf300 ++#define USB_DEVICE_ID_ASETEK_FORTE 0xf301 ++#define USB_DEVICE_ID_ASETEK_LA_PRIMA 0xf303 ++#define USB_DEVICE_ID_ASETEK_TONY_KANAAN 0xf306 ++ + #define USB_VENDOR_ID_ASUS 0x0486 + #define USB_DEVICE_ID_ASUS_T91MT 0x0185 + #define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186 +diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c +index 1b713b741d192..5b89ec7b5c26c 100644 +--- a/drivers/hid/hid-universal-pidff.c ++++ b/drivers/hid/hid-universal-pidff.c +@@ -4,7 +4,7 @@ + * 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 Oleg Makarenko + * Copyright (c) 2024, 2025 Tomasz Pakuła + */ + +@@ -104,7 +104,7 @@ static int universal_pidff_probe(struct hid_device *hdev, + goto err; + } + +- hid_info(hdev, "Universal pidff driver loaded sucesfully!"); ++ hid_info(hdev, "Universal pidff driver loaded sucessfully!"); + + return 0; + err: +@@ -179,6 +179,10 @@ static const struct hid_device_id universal_pidff_devices[] = { + .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 }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_INVICTA) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_FORTE) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_LA_PRIMA) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_ASETEK, USB_DEVICE_ID_ASETEK_TONY_KANAAN) }, + { } + }; + MODULE_DEVICE_TABLE(hid, universal_pidff_devices); +@@ -194,5 +198,5 @@ module_hid_driver(universal_pidff); + + MODULE_DESCRIPTION("Universal driver for USB PID Force Feedback devices"); + MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("Makarenko Oleg "); ++MODULE_AUTHOR("Oleg Makarenko "); + MODULE_AUTHOR("Tomasz Pakuła "); +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-clamp-effect-playback-loop_count-value.patch b/queue-6.13/hid-pidff-clamp-effect-playback-loop_count-value.patch new file mode 100644 index 0000000000..3dcab8774b --- /dev/null +++ b/queue-6.13/hid-pidff-clamp-effect-playback-loop_count-value.patch @@ -0,0 +1,42 @@ +From 18c55e3e5b2c33a02da7b212a4c2976409f8e90c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 23:30:01 +0100 +Subject: HID: pidff: Clamp effect playback LOOP_COUNT value +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 0c6673e3d17b258b8c5c7331d28bf6c49f25ed30 ] + +Ensures the loop count will never exceed the logical_maximum. + +Fixes implementation errors happening when applications use the max +value of int32/DWORD as the effect iterations. This could be observed +when running software both native and in wine. + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index ffecc712be003..74b033a4ac1b8 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -690,7 +690,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) + } else { + pidff->effect_operation_status->value[0] = + pidff->operation_id[PID_EFFECT_START]; +- pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; ++ pidff->effect_operation[PID_LOOP_COUNT].value[0] = ++ pidff_clamp(n, pidff->effect_operation[PID_LOOP_COUNT].field); + } + + hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-clamp-periodic-effect-period-to-device-s-l.patch b/queue-6.13/hid-pidff-clamp-periodic-effect-period-to-device-s-l.patch new file mode 100644 index 0000000000..22c0238039 --- /dev/null +++ b/queue-6.13/hid-pidff-clamp-periodic-effect-period-to-device-s-l.patch @@ -0,0 +1,84 @@ +From 302108835bbf1426dc34238367aa6867b9364e7f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:38:47 +0100 +Subject: HID: pidff: Clamp PERIODIC effect period to device's logical range +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ 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 +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 25dbed076f530..6b55345ce75ac 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -15,10 +15,9 @@ + #include + #include + #include +- + #include ++#include + +-#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); +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-comment-and-code-style-update.patch b/queue-6.13/hid-pidff-comment-and-code-style-update.patch new file mode 100644 index 0000000000..564d90d5f6 --- /dev/null +++ b/queue-6.13/hid-pidff-comment-and-code-style-update.patch @@ -0,0 +1,193 @@ +From 18fb9bbc8cd16f86addce464172b451415e2fa2e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Feb 2025 15:35:10 +0100 +Subject: HID: pidff: Comment and code style update +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit e19675c2477491401b236ed939ad5a43ddc339af ] + +Update comments to fully conform to the Linux comment styling. +Define Linux infinite effect duration (0) as FF_INFINITE + +Chanage Oleg's name order + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 57 +++++++++++++++------------------- + 1 file changed, 25 insertions(+), 32 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 503f643b59cad..e2508a4d754d3 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -3,13 +3,9 @@ + * Force feedback driver for USB HID PID compliant devices + * + * Copyright (c) 2005, 2006 Anssi Hannula ++ * Upgraded 2025 by Oleg Makarenko and Tomasz Pakuła + */ + +-/* +- */ +- +-/* #define DEBUG */ +- + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include "hid-pidff.h" +@@ -25,9 +21,9 @@ + + /* Linux Force Feedback API uses miliseconds as time unit */ + #define FF_TIME_EXPONENT -3 ++#define FF_INFINITE 0 + + /* Report usage table used to put reports into an array */ +- + #define PID_SET_EFFECT 0 + #define PID_EFFECT_OPERATION 1 + #define PID_DEVICE_GAIN 2 +@@ -48,12 +44,12 @@ static const u8 pidff_reports[] = { + 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab, + 0x5a, 0x5f, 0x6e, 0x73, 0x74 + }; +- +-/* device_control is really 0x95, but 0x96 specified as it is the usage of +-the only field in that report */ ++/* ++ * device_control is really 0x95, but 0x96 specified ++ * as it is the usage of the only field in that report. ++ */ + + /* PID special fields */ +- + #define PID_EFFECT_TYPE 0x25 + #define PID_DIRECTION 0x57 + #define PID_EFFECT_OPERATION_ARRAY 0x78 +@@ -61,7 +57,6 @@ the only field in that report */ + #define PID_DEVICE_CONTROL_ARRAY 0x96 + + /* Value usage tables used to put fields and values into arrays */ +- + #define PID_EFFECT_BLOCK_INDEX 0 + + #define PID_DURATION 1 +@@ -119,7 +114,6 @@ static const u8 pidff_device_gain[] = { 0x7e }; + static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; + + /* Special field key tables used to put special field keys into arrays */ +- + #define PID_ENABLE_ACTUATORS 0 + #define PID_DISABLE_ACTUATORS 1 + #define PID_STOP_ALL_EFFECTS 2 +@@ -176,8 +170,10 @@ struct pidff_device { + struct pidff_usage effect_operation[sizeof(pidff_effect_operation)]; + struct pidff_usage block_free[sizeof(pidff_block_free)]; + +- /* Special field is a field that is not composed of +- usage<->value pairs that pidff_usage values are */ ++ /* ++ * Special field is a field that is not composed of ++ * usage<->value pairs that pidff_usage values are ++ */ + + /* Special field in create_new_effect */ + struct hid_field *create_new_effect_type; +@@ -222,7 +218,7 @@ static s32 pidff_clamp(s32 i, struct hid_field *field) + static int pidff_rescale(int i, int max, struct hid_field *field) + { + return i * (field->logical_maximum - field->logical_minimum) / max + +- field->logical_minimum; ++ field->logical_minimum; + } + + /* +@@ -282,9 +278,8 @@ static void pidff_set_time(struct pidff_usage *usage, u16 time) + + static void pidff_set_duration(struct pidff_usage *usage, u16 duration) + { +- /* Convert infinite length from Linux API (0) +- to PID standard (NULL) if needed */ +- if (duration == 0) ++ /* Infinite value conversion from Linux API -> PID */ ++ if (duration == FF_INFINITE) + duration = PID_INFINITE; + + if (duration == PID_INFINITE) { +@@ -302,16 +297,16 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, + struct ff_envelope *envelope) + { + pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] = +- pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; ++ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; + + pidff->set_envelope[PID_ATTACK_LEVEL].value[0] = +- pidff_rescale(envelope->attack_level > +- S16_MAX ? S16_MAX : envelope->attack_level, S16_MAX, +- pidff->set_envelope[PID_ATTACK_LEVEL].field); ++ pidff_rescale(envelope->attack_level > ++ S16_MAX ? S16_MAX : envelope->attack_level, S16_MAX, ++ pidff->set_envelope[PID_ATTACK_LEVEL].field); + pidff->set_envelope[PID_FADE_LEVEL].value[0] = +- pidff_rescale(envelope->fade_level > +- S16_MAX ? S16_MAX : envelope->fade_level, S16_MAX, +- pidff->set_envelope[PID_FADE_LEVEL].field); ++ pidff_rescale(envelope->fade_level > ++ S16_MAX ? S16_MAX : envelope->fade_level, S16_MAX, ++ pidff->set_envelope[PID_FADE_LEVEL].field); + + pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME], + envelope->attack_length); +@@ -702,9 +697,7 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) + static int pidff_playback(struct input_dev *dev, int effect_id, int value) + { + struct pidff_device *pidff = dev->ff->private; +- + pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); +- + return 0; + } + +@@ -732,8 +725,11 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id) + + hid_dbg(pidff->hid, "starting to erase %d/%d\n", + effect_id, pidff->pid_id[effect_id]); +- /* Wait for the queue to clear. We do not want a full fifo to +- prevent the effect removal. */ ++ ++ /* ++ * Wait for the queue to clear. We do not want ++ * a full fifo to prevent the effect removal. ++ */ + hid_hw_wait(pidff->hid); + pidff_playback_pid(pidff, pid_id, 0); + pidff_erase_pid(pidff, pid_id); +@@ -1239,7 +1235,6 @@ static int pidff_find_effects(struct pidff_device *pidff, + set_bit(FF_FRICTION, dev->ffbit); + + return 0; +- + } + + #define PIDFF_FIND_FIELDS(name, report, strict) \ +@@ -1370,12 +1365,10 @@ static int pidff_check_autocenter(struct pidff_device *pidff, + hid_notice(pidff->hid, + "device has unknown autocenter control method\n"); + } +- + pidff_erase_pid(pidff, + pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]); + + return 0; +- + } + + /* +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-completely-rework-and-fix-pidff_reset-func.patch b/queue-6.13/hid-pidff-completely-rework-and-fix-pidff_reset-func.patch new file mode 100644 index 0000000000..61a616a0fc --- /dev/null +++ b/queue-6.13/hid-pidff-completely-rework-and-fix-pidff_reset-func.patch @@ -0,0 +1,259 @@ +From c3a3eb88636b587ca89edfa209e5d19c7ec6b14b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:38:57 +0100 +Subject: HID: pidff: Completely rework and fix pidff_reset function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit cb3fd788e3fa5358602a49809c4eb4911539c9d0 ] + +Previously, it was assumed that DEVICE_CONTROL usage is always an array +but a lot of devices implements it as a bitmask variable. This led to +the pidff_reset function not working and causing errors in such cases. + +Selectors can come in three types. One selection of a set, N selections +and Any selection in form of bitmask as from USB Hid Usage Tables v1.5, +subsection 3.4.2.1 + +Added pidff_send_device_control which handles usage flag check which +decides whether DEVICE_CONTROL should be handled as "One selection of a +set" or "Any selection of a set". + +Reset was triggered once, on device initialization. Now, it's triggered +every time when uploading an effect to an empty device (no currently +stored effects), tracked by pidff->effect_count variable. + +Co-developed-by: Makarenko Oleg +Signed-off-by: Makarenko Oleg +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 138 +++++++++++++++++++++------------ + 1 file changed, 89 insertions(+), 49 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 635596a57c75d..99b5d3deb40d0 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -109,9 +109,10 @@ static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; + /* Special field key tables used to put special field keys into arrays */ + + #define PID_ENABLE_ACTUATORS 0 +-#define PID_STOP_ALL_EFFECTS 1 +-#define PID_RESET 2 +-static const u8 pidff_device_control[] = { 0x97, 0x99, 0x9a }; ++#define PID_DISABLE_ACTUATORS 1 ++#define PID_STOP_ALL_EFFECTS 2 ++#define PID_RESET 3 ++static const u8 pidff_device_control[] = { 0x97, 0x98, 0x99, 0x9a }; + + #define PID_CONSTANT 0 + #define PID_RAMP 1 +@@ -190,6 +191,7 @@ struct pidff_device { + int pid_id[PID_EFFECTS_MAX]; + + u32 quirks; ++ u8 effect_count; + }; + + /* +@@ -490,9 +492,83 @@ static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old) + effect->u.ramp.end_level != old->u.ramp.end_level; + } + ++/* ++ * Clear device control report ++ */ ++static void pidff_send_device_control(struct pidff_device *pidff, int field) ++{ ++ int i, tmp; ++ int field_index = pidff->control_id[field]; ++ ++ /* Detect if the field is a bitmask variable or an array */ ++ if (pidff->device_control->flags & HID_MAIN_ITEM_VARIABLE) { ++ hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n"); ++ /* Clear current bitmask */ ++ for(i = 0; i < sizeof(pidff_device_control); i++) { ++ tmp = pidff->control_id[i]; ++ pidff->device_control->value[tmp] = 0; ++ } ++ pidff->device_control->value[field_index - 1] = 1; ++ } else { ++ hid_dbg(pidff->hid, "DEVICE_CONTROL is an array\n"); ++ pidff->device_control->value[0] = field_index; ++ } ++ ++ hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); ++ hid_hw_wait(pidff->hid); ++} ++ ++/* ++ * Modify actuators state ++ */ ++static void pidff_modify_actuators_state(struct pidff_device *pidff, bool enable) ++{ ++ hid_dbg(pidff->hid, "%s actuators\n", enable ? "Enable" : "Disable"); ++ pidff_send_device_control(pidff, ++ enable ? PID_ENABLE_ACTUATORS : PID_DISABLE_ACTUATORS); ++} ++ ++/* ++ * Reset the device, stop all effects, enable actuators ++ * Refetch pool report ++ */ ++static void pidff_reset(struct pidff_device *pidff) ++{ ++ int i = 0; ++ ++ /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ ++ pidff_send_device_control(pidff, PID_RESET); ++ pidff_send_device_control(pidff, PID_RESET); ++ pidff->effect_count = 0; ++ ++ pidff_send_device_control(pidff, PID_STOP_ALL_EFFECTS); ++ pidff_modify_actuators_state(pidff, 1); ++ ++ /* pool report is sometimes messed up, refetch it */ ++ hid_hw_request(pidff->hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); ++ hid_hw_wait(pidff->hid); ++ ++ if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { ++ while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { ++ if (i++ > 20) { ++ hid_warn(pidff->hid, ++ "device reports %d simultaneous effects\n", ++ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); ++ break; ++ } ++ hid_dbg(pidff->hid, "pid_pool requested again\n"); ++ hid_hw_request(pidff->hid, pidff->reports[PID_POOL], ++ HID_REQ_GET_REPORT); ++ hid_hw_wait(pidff->hid); ++ } ++ } ++} ++ + /* + * Send a request for effect upload to the device + * ++ * Reset and enable actuators if no effects were present on the device ++ * + * Returns 0 if device reported success, -ENOSPC if the device reported memory + * is full. Upon unknown response the function will retry for 60 times, if + * still unsuccessful -EIO is returned. +@@ -501,6 +577,9 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) + { + int j; + ++ if (!pidff->effect_count) ++ pidff_reset(pidff); ++ + pidff->create_new_effect_type->value[0] = efnum; + hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], + HID_REQ_SET_REPORT); +@@ -520,6 +599,8 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) + hid_dbg(pidff->hid, "device reported free memory: %d bytes\n", + pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? + pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); ++ ++ pidff->effect_count++; + return 0; + } + if (pidff->block_load_status->value[0] == +@@ -568,12 +649,16 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) + + /* + * Erase effect with PID id ++ * Decrease the device effect counter + */ + static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) + { + pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; + hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE], + HID_REQ_SET_REPORT); ++ ++ if (pidff->effect_count > 0) ++ pidff->effect_count--; + } + + /* +@@ -1221,50 +1306,6 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) + return 0; + } + +-/* +- * Reset the device +- */ +-static void pidff_reset(struct pidff_device *pidff) +-{ +- struct hid_device *hid = pidff->hid; +- int i = 0; +- +- pidff->device_control->value[0] = pidff->control_id[PID_RESET]; +- /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ +- hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); +- hid_hw_wait(hid); +- hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); +- hid_hw_wait(hid); +- +- pidff->device_control->value[0] = pidff->control_id[PID_STOP_ALL_EFFECTS]; +- hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); +- hid_hw_wait(hid); +- +- pidff->device_control->value[0] = +- pidff->control_id[PID_ENABLE_ACTUATORS]; +- hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); +- hid_hw_wait(hid); +- +- /* pool report is sometimes messed up, refetch it */ +- hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); +- hid_hw_wait(hid); +- +- if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { +- while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { +- if (i++ > 20) { +- hid_warn(pidff->hid, +- "device reports %d simultaneous effects\n", +- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); +- break; +- } +- hid_dbg(pidff->hid, "pid_pool requested again\n"); +- hid_hw_request(hid, pidff->reports[PID_POOL], +- HID_REQ_GET_REPORT); +- hid_hw_wait(hid); +- } +- } +-} +- + /* + * Test if autocenter modification is using the supported method + */ +@@ -1330,6 +1371,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks) + + pidff->hid = hid; + pidff->quirks = initial_quirks; ++ pidff->effect_count = 0; + + hid_device_io_start(hid); + +@@ -1346,8 +1388,6 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks) + if (error) + goto fail; + +- pidff_reset(pidff); +- + if (test_bit(FF_GAIN, dev->ffbit)) { + pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); + hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN], +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-compute-infinite-value-instead-of-using-ha.patch b/queue-6.13/hid-pidff-compute-infinite-value-instead-of-using-ha.patch new file mode 100644 index 0000000000..8849343416 --- /dev/null +++ b/queue-6.13/hid-pidff-compute-infinite-value-instead-of-using-ha.patch @@ -0,0 +1,45 @@ +From 7cd7fbc41bfea5e4f94a4e0a233bc46c0f66e151 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 23:30:02 +0100 +Subject: HID: pidff: Compute INFINITE value instead of using hardcoded 0xffff +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 1a575044d516972a1d036d54c0180b9085e21dc6 ] + +As per USB PID standard: +INFINITE - Referrers to the maximum value of a range. i.e. if in an 8 +bit unsigned field the value of 255 would indicate INFINITE. + +Detecting 0xffff (U16_MAX) is still important as we MIGHT get this value +as infinite from some native software as 0 was never actually defined +in Linux' FF api as the infinite value. I'm working on it though. + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 74b033a4ac1b8..a614438e43bd8 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -283,8 +283,9 @@ static void pidff_set_duration(struct pidff_usage *usage, u16 duration) + if (duration == FF_INFINITE) + duration = PID_INFINITE; + ++ /* PID defines INFINITE as the max possible value for duration field */ + if (duration == PID_INFINITE) { +- usage->value[0] = PID_INFINITE; ++ usage->value[0] = (1U << usage->field->report_size) - 1; + return; + } + +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-define-values-used-in-pidff_find_special_f.patch b/queue-6.13/hid-pidff-define-values-used-in-pidff_find_special_f.patch new file mode 100644 index 0000000000..e2856976cc --- /dev/null +++ b/queue-6.13/hid-pidff-define-values-used-in-pidff_find_special_f.patch @@ -0,0 +1,79 @@ +From 2ff0ff4d3df8e2b26d32cd4ee5761c22f0369f26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:38:59 +0100 +Subject: HID: pidff: Define values used in pidff_find_special_fields +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 1c12f136891cf4d2d4e6aa202d671a9d2171a716 ] + +Makes it clear where did these values came from + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 42c951a1d65bf..bd913d57e4d75 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -48,6 +48,14 @@ static const u8 pidff_reports[] = { + /* device_control is really 0x95, but 0x96 specified as it is the usage of + the only field in that report */ + ++/* PID special fields */ ++ ++#define PID_EFFECT_TYPE 0x25 ++#define PID_DIRECTION 0x57 ++#define PID_EFFECT_OPERATION_ARRAY 0x78 ++#define PID_BLOCK_LOAD_STATUS 0x8b ++#define PID_DEVICE_CONTROL_ARRAY 0x96 ++ + /* Value usage tables used to put fields and values into arrays */ + + #define PID_EFFECT_BLOCK_INDEX 0 +@@ -1056,23 +1064,24 @@ static int pidff_find_special_fields(struct pidff_device *pidff) + + pidff->create_new_effect_type = + pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT], +- 0x25, 1); ++ PID_EFFECT_TYPE, 1); + pidff->set_effect_type = + pidff_find_special_field(pidff->reports[PID_SET_EFFECT], +- 0x25, 1); ++ PID_EFFECT_TYPE, 1); + pidff->effect_direction = + pidff_find_special_field(pidff->reports[PID_SET_EFFECT], +- 0x57, 0); ++ PID_DIRECTION, 0); + pidff->device_control = + pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], +- 0x96, !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); ++ PID_DEVICE_CONTROL_ARRAY, ++ !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); + + pidff->block_load_status = + pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], +- 0x8b, 1); ++ PID_BLOCK_LOAD_STATUS, 1); + pidff->effect_operation_status = + pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION], +- 0x78, 1); ++ PID_EFFECT_OPERATION_ARRAY, 1); + + hid_dbg(pidff->hid, "search done\n"); + +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-factor-out-code-for-setting-gain.patch b/queue-6.13/hid-pidff-factor-out-code-for-setting-gain.patch new file mode 100644 index 0000000000..8420164fd8 --- /dev/null +++ b/queue-6.13/hid-pidff-factor-out-code-for-setting-gain.patch @@ -0,0 +1,83 @@ +From 159ce5f3d0e9462a48955532fbf2352cd6fa377e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:01 +0100 +Subject: HID: pidff: Factor out code for setting gain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit f7ebf0b11b9e04bf59c438ad14f0115b12aa2f44 ] + +Makes it possible to easily set gain from inside hid-pidff.c + +Changes in v7: +- Check if device gain field exists before setting device gain + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 180b2cf66e4c7..ac6f940abd901 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -539,6 +539,19 @@ static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old) + effect->u.ramp.end_level != old->u.ramp.end_level; + } + ++/* ++ * Set device gain ++ */ ++static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) ++{ ++ if (!pidff->device_gain[PID_DEVICE_GAIN_FIELD].field) ++ return; ++ ++ pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); ++ hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN], ++ HID_REQ_SET_REPORT); ++} ++ + /* + * Clear device control report + */ +@@ -865,11 +878,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + */ + static void pidff_set_gain(struct input_dev *dev, u16 gain) + { +- struct pidff_device *pidff = dev->ff->private; +- +- pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); +- hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN], +- HID_REQ_SET_REPORT); ++ pidff_set_gain_report(dev->ff->private, gain); + } + + static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) +@@ -1414,12 +1423,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, __u32 initial_quirks) + if (error) + goto fail; + +- if (test_bit(FF_GAIN, dev->ffbit)) { +- pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); +- hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN], +- HID_REQ_SET_REPORT); +- } +- ++ pidff_set_gain_report(pidff, 0xffff); + error = pidff_check_autocenter(pidff, dev); + if (error) + goto fail; +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-factor-out-pool-report-fetch-and-remove-ex.patch b/queue-6.13/hid-pidff-factor-out-pool-report-fetch-and-remove-ex.patch new file mode 100644 index 0000000000..ee8069e011 --- /dev/null +++ b/queue-6.13/hid-pidff-factor-out-pool-report-fetch-and-remove-ex.patch @@ -0,0 +1,117 @@ +From 56cfa0759e801c5bcad99a3849bd2b1524b5a90b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:06 +0100 +Subject: HID: pidff: Factor out pool report fetch and remove excess + declaration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 5d98079b2d0186e1f586301a9c00144a669416a8 ] + +We only want to refetch the pool report during device init. Reset +function is now called when uploading effects to an empty device so +extract pool fetch to separate function and call it from init before +autocenter check (autocenter check triggered reset during init). + +Remove a superfluous pointer declaration and assigment as well. + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 45 ++++++++++++++++++---------------- + 1 file changed, 24 insertions(+), 21 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index b21e844f5f3a3..f23381b6e3447 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -591,12 +591,9 @@ static void pidff_modify_actuators_state(struct pidff_device *pidff, bool enable + + /* + * Reset the device, stop all effects, enable actuators +- * Refetch pool report + */ + static void pidff_reset(struct pidff_device *pidff) + { +- int i = 0; +- + /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ + pidff_send_device_control(pidff, PID_RESET); + pidff_send_device_control(pidff, PID_RESET); +@@ -604,23 +601,29 @@ static void pidff_reset(struct pidff_device *pidff) + + pidff_send_device_control(pidff, PID_STOP_ALL_EFFECTS); + pidff_modify_actuators_state(pidff, 1); ++} + +- /* pool report is sometimes messed up, refetch it */ +- hid_hw_request(pidff->hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); +- hid_hw_wait(pidff->hid); ++/* ++ * Refetch pool report ++ */ ++static void pidff_fetch_pool(struct pidff_device *pidff) ++{ ++ if (!pidff->pool[PID_SIMULTANEOUS_MAX].value) ++ return; + +- if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { +- while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { +- if (i++ > 20) { +- hid_warn(pidff->hid, +- "device reports %d simultaneous effects\n", +- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); +- break; +- } +- hid_dbg(pidff->hid, "pid_pool requested again\n"); +- hid_hw_request(pidff->hid, pidff->reports[PID_POOL], +- HID_REQ_GET_REPORT); +- hid_hw_wait(pidff->hid); ++ int i = 0; ++ while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { ++ hid_dbg(pidff->hid, "pid_pool requested again\n"); ++ hid_hw_request(pidff->hid, pidff->reports[PID_POOL], ++ HID_REQ_GET_REPORT); ++ hid_hw_wait(pidff->hid); ++ ++ /* break after 20 tries with SIMULTANEOUS_MAX < 2 */ ++ if (i++ > 20) { ++ hid_warn(pidff->hid, ++ "device reports %d simultaneous effects\n", ++ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); ++ break; + } + } + } +@@ -916,9 +919,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) + */ + static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) + { +- struct pidff_device *pidff = dev->ff->private; +- +- pidff_autocenter(pidff, magnitude); ++ pidff_autocenter(dev->ff->private, magnitude); + } + + /* +@@ -1424,6 +1425,8 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) + if (error) + goto fail; + ++ /* pool report is sometimes messed up, refetch it */ ++ pidff_fetch_pool(pidff); + pidff_set_gain_report(pidff, U16_MAX); + error = pidff_check_autocenter(pidff, dev); + if (error) +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-fix-90-degrees-direction-name-north-east.patch b/queue-6.13/hid-pidff-fix-90-degrees-direction-name-north-east.patch new file mode 100644 index 0000000000..9bbfb71eda --- /dev/null +++ b/queue-6.13/hid-pidff-fix-90-degrees-direction-name-north-east.patch @@ -0,0 +1,34 @@ +From 67be8f2859efa7abf3df4b1d446e02f05b6e9837 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 23:30:03 +0100 +Subject: HID: pidff: Fix 90 degrees direction name North -> East +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit f98ecedbeca34a8df1460c3a03cce32639c99a9d ] + +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index a614438e43bd8..6eb7934c8f53b 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -145,7 +145,7 @@ static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e}; + #define PID_EFFECT_STOP 1 + static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; + +-/* Polar direction 90 degrees (North) */ ++/* Polar direction 90 degrees (East) */ + #define PIDFF_FIXED_WHEEL_DIRECTION 0x4000 + + struct pidff_usage { +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-fix-set_device_control.patch b/queue-6.13/hid-pidff-fix-set_device_control.patch new file mode 100644 index 0000000000..b87fc4d3af --- /dev/null +++ b/queue-6.13/hid-pidff-fix-set_device_control.patch @@ -0,0 +1,79 @@ +From 7f7e1dc79ab8a02d52eac5a493699b30de646ea3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 23:30:04 +0100 +Subject: HID: pidff: Fix set_device_control() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit e2fa0bdf08a70623f24ed52f2037a330999d9800 ] + +As the search for Device Control report is permissive, make sure the +desired field was actually found, before trying to set it. + +Fix bitmask clearing as it was erronously using index instead of +index - 1 (HID arrays index is 1-based). + +Add last two missing Device Control usages to the defined array. +PID_PAUSE and PID_CONTINUE. + +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 20 +++++++++++++++----- + 1 file changed, 15 insertions(+), 5 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 6eb7934c8f53b..8dfd2c554a276 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -118,7 +118,9 @@ static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; + #define PID_DISABLE_ACTUATORS 1 + #define PID_STOP_ALL_EFFECTS 2 + #define PID_RESET 3 +-static const u8 pidff_device_control[] = { 0x97, 0x98, 0x99, 0x9a }; ++#define PID_PAUSE 4 ++#define PID_CONTINUE 5 ++static const u8 pidff_device_control[] = { 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c }; + + #define PID_CONSTANT 0 + #define PID_RAMP 1 +@@ -551,21 +553,29 @@ static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) + } + + /* +- * Clear device control report ++ * Send device control report to the device + */ + static void pidff_set_device_control(struct pidff_device *pidff, int field) + { +- int i, tmp; ++ int i, index; + int field_index = pidff->control_id[field]; + ++ if (field_index < 1) ++ return; ++ + /* Detect if the field is a bitmask variable or an array */ + if (pidff->device_control->flags & HID_MAIN_ITEM_VARIABLE) { + hid_dbg(pidff->hid, "DEVICE_CONTROL is a bitmask\n"); ++ + /* Clear current bitmask */ + for(i = 0; i < sizeof(pidff_device_control); i++) { +- tmp = pidff->control_id[i]; +- pidff->device_control->value[tmp] = 0; ++ index = pidff->control_id[i]; ++ if (index < 1) ++ continue; ++ ++ pidff->device_control->value[index - 1] = 0; + } ++ + pidff->device_control->value[field_index - 1] = 1; + } else { + hid_dbg(pidff->hid, "DEVICE_CONTROL is an array\n"); +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-make-sure-to-fetch-pool-before-checking-si.patch b/queue-6.13/hid-pidff-make-sure-to-fetch-pool-before-checking-si.patch new file mode 100644 index 0000000000..d105176797 --- /dev/null +++ b/queue-6.13/hid-pidff-make-sure-to-fetch-pool-before-checking-si.patch @@ -0,0 +1,76 @@ +From 9f1981ec1eaa69fb1d14e8d6c02bbed402ddd623 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Feb 2025 15:35:08 +0100 +Subject: HID: pidff: Make sure to fetch pool before checking SIMULTANEOUS_MAX +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 1f650dcec32d22deb1d6db12300a2b98483099a9 ] + +As noted by Anssi some 20 years ago, pool report is sometimes messed up. +This worked fine on many devices but casued oops on VRS DirectForce PRO. + +Here, we're making sure pool report is refetched before trying to access +any of it's fields. While loop was replaced with a for loop + exit +conditions were moved aroud to decrease the possibility of creating an +infinite loop scenario. + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 29 +++++++++++++---------------- + 1 file changed, 13 insertions(+), 16 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index f23381b6e3447..503f643b59cad 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -604,28 +604,25 @@ static void pidff_reset(struct pidff_device *pidff) + } + + /* +- * Refetch pool report ++ * Fetch pool report + */ + static void pidff_fetch_pool(struct pidff_device *pidff) + { +- if (!pidff->pool[PID_SIMULTANEOUS_MAX].value) +- return; ++ int i; ++ struct hid_device *hid = pidff->hid; + +- int i = 0; +- while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { +- hid_dbg(pidff->hid, "pid_pool requested again\n"); +- hid_hw_request(pidff->hid, pidff->reports[PID_POOL], +- HID_REQ_GET_REPORT); +- hid_hw_wait(pidff->hid); ++ /* Repeat if PID_SIMULTANEOUS_MAX < 2 to make sure it's correct */ ++ for(i = 0; i < 20; i++) { ++ hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT); ++ hid_hw_wait(hid); + +- /* break after 20 tries with SIMULTANEOUS_MAX < 2 */ +- if (i++ > 20) { +- hid_warn(pidff->hid, +- "device reports %d simultaneous effects\n", +- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); +- break; +- } ++ if (!pidff->pool[PID_SIMULTANEOUS_MAX].value) ++ return; ++ if (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] >= 2) ++ return; + } ++ hid_warn(hid, "device reports %d simultaneous effects\n", ++ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); + } + + /* +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-move-all-hid-pidff-definitions-to-a-dedica.patch b/queue-6.13/hid-pidff-move-all-hid-pidff-definitions-to-a-dedica.patch new file mode 100644 index 0000000000..16e39e8bd6 --- /dev/null +++ b/queue-6.13/hid-pidff-move-all-hid-pidff-definitions-to-a-dedica.patch @@ -0,0 +1,154 @@ +From 3365a9dc9e2fcb2e5293178b093467e5f4f6225f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:03 +0100 +Subject: HID: pidff: Move all hid-pidff definitions to a dedicated header +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 0d24d4b1da96df9fc5ff36966f40f980ef864d46 ] + +Do not clutter hid includes with stuff not needed outside of +the kernel. + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-universal-pidff.c | 3 ++- + drivers/hid/usbhid/hid-core.c | 1 + + drivers/hid/usbhid/hid-pidff.c | 3 ++- + drivers/hid/usbhid/hid-pidff.h | 33 +++++++++++++++++++++++++++++++ + include/linux/hid.h | 15 -------------- + 5 files changed, 38 insertions(+), 17 deletions(-) + create mode 100644 drivers/hid/usbhid/hid-pidff.h + +diff --git a/drivers/hid/hid-universal-pidff.c b/drivers/hid/hid-universal-pidff.c +index 7ef5ab9146b1c..1b713b741d192 100644 +--- a/drivers/hid/hid-universal-pidff.c ++++ b/drivers/hid/hid-universal-pidff.c +@@ -13,6 +13,7 @@ + #include + #include + #include "hid-ids.h" ++#include "usbhid/hid-pidff.h" + + #define JOY_RANGE (BTN_DEAD - BTN_JOYSTICK + 1) + +@@ -89,7 +90,7 @@ static int universal_pidff_probe(struct hid_device *hdev, + } + + /* Check if HID_PID support is enabled */ +- int (*init_function)(struct hid_device *, __u32); ++ int (*init_function)(struct hid_device *, u32); + init_function = hid_pidff_init_with_quirks; + + if (!init_function) { +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index a6eb6fe6130d1..44c2351b870fa 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -35,6 +35,7 @@ + #include + #include + #include "usbhid.h" ++#include "hid-pidff.h" + + /* + * Version Information +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index ac6f940abd901..a8eaa77e80be3 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -12,6 +12,7 @@ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + ++#include "hid-pidff.h" + #include + #include + #include +@@ -1383,7 +1384,7 @@ 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_with_quirks(struct hid_device *hid, __u32 initial_quirks) ++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, +diff --git a/drivers/hid/usbhid/hid-pidff.h b/drivers/hid/usbhid/hid-pidff.h +new file mode 100644 +index 0000000000000..dda571e0a5bd3 +--- /dev/null ++++ b/drivers/hid/usbhid/hid-pidff.h +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++#ifndef __HID_PIDFF_H ++#define __HID_PIDFF_H ++ ++#include ++ ++/* HID PIDFF quirks */ ++ ++/* Delay field (0xA7) missing. Skip it during set effect report upload */ ++#define HID_PIDFF_QUIRK_MISSING_DELAY BIT(0) ++ ++/* Missing Paramter block offset (0x23). Skip it during SET_CONDITION ++ report upload */ ++#define HID_PIDFF_QUIRK_MISSING_PBO BIT(1) ++ ++/* Initialise device control field even if logical_minimum != 1 */ ++#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2) ++ ++/* Use fixed 0x4000 direction during SET_EFFECT report upload */ ++#define HID_PIDFF_QUIRK_FIX_WHEEL_DIRECTION BIT(3) ++ ++/* Force all periodic effects to be uploaded as SINE */ ++#define HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) ++ ++#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 ++ ++#endif +diff --git a/include/linux/hid.h b/include/linux/hid.h +index e180679ab284c..9ca7e26ac4e92 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -1222,21 +1222,6 @@ unsigned long hid_lookup_quirk(const struct hid_device *hdev); + int hid_quirks_init(char **quirks_param, __u16 bus, int count); + 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 */ +-#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 HID_PIDFF_QUIRK_PERIODIC_SINE_ONLY BIT(4) +- + #define dbg_hid(fmt, ...) pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__) + + #define hid_err(hid, fmt, ...) \ +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-remove-redundant-call-to-pidff_find_specia.patch b/queue-6.13/hid-pidff-remove-redundant-call-to-pidff_find_specia.patch new file mode 100644 index 0000000000..47266ed776 --- /dev/null +++ b/queue-6.13/hid-pidff-remove-redundant-call-to-pidff_find_specia.patch @@ -0,0 +1,39 @@ +From 8b7b49c3973926eb82d92dd75ce5fabb4aeb81d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Feb 2025 15:35:12 +0100 +Subject: HID: pidff: Remove redundant call to pidff_find_special_keys +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 1bd55e79cbc0ea2d6a65f51e06c891806359c2f2 ] + +Probably left out as a mistake after Anssi created the helper macro + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index d5734cbf745d1..6f6c47bd57eaa 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -1159,10 +1159,6 @@ static int pidff_find_special_fields(struct pidff_device *pidff) + return -1; + } + +- pidff_find_special_keys(pidff->control_id, pidff->device_control, +- pidff_device_control, +- sizeof(pidff_device_control)); +- + PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control); + + if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type, +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-rename-two-functions-to-align-them-with-na.patch b/queue-6.13/hid-pidff-rename-two-functions-to-align-them-with-na.patch new file mode 100644 index 0000000000..2866e63390 --- /dev/null +++ b/queue-6.13/hid-pidff-rename-two-functions-to-align-them-with-na.patch @@ -0,0 +1,68 @@ +From 39fae9c77f9df0a2513dc84357780918ba952cc9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 23:30:00 +0100 +Subject: HID: pidff: Rename two functions to align them with naming convention +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit bbeface1051142bcb0473fdcc89102ea5b31607d ] + +Driver uses "set" everywhere to indicate setting report values and +requesting HID_REQ_SET_REPORT + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 6f6c47bd57eaa..ffecc712be003 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -552,7 +552,7 @@ static void pidff_set_gain_report(struct pidff_device *pidff, u16 gain) + /* + * Clear device control report + */ +-static void pidff_send_device_control(struct pidff_device *pidff, int field) ++static void pidff_set_device_control(struct pidff_device *pidff, int field) + { + int i, tmp; + int field_index = pidff->control_id[field]; +@@ -578,10 +578,10 @@ static void pidff_send_device_control(struct pidff_device *pidff, int field) + /* + * Modify actuators state + */ +-static void pidff_modify_actuators_state(struct pidff_device *pidff, bool enable) ++static void pidff_set_actuators(struct pidff_device *pidff, bool enable) + { + hid_dbg(pidff->hid, "%s actuators\n", enable ? "Enable" : "Disable"); +- pidff_send_device_control(pidff, ++ pidff_set_device_control(pidff, + enable ? PID_ENABLE_ACTUATORS : PID_DISABLE_ACTUATORS); + } + +@@ -591,12 +591,12 @@ static void pidff_modify_actuators_state(struct pidff_device *pidff, bool enable + static void pidff_reset(struct pidff_device *pidff) + { + /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ +- pidff_send_device_control(pidff, PID_RESET); +- pidff_send_device_control(pidff, PID_RESET); ++ pidff_set_device_control(pidff, PID_RESET); ++ pidff_set_device_control(pidff, PID_RESET); + pidff->effect_count = 0; + +- pidff_send_device_control(pidff, PID_STOP_ALL_EFFECTS); +- pidff_modify_actuators_state(pidff, 1); ++ pidff_set_device_control(pidff, PID_STOP_ALL_EFFECTS); ++ pidff_set_actuators(pidff, 1); + } + + /* +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-rescale-time-values-to-match-field-units.patch b/queue-6.13/hid-pidff-rescale-time-values-to-match-field-units.patch new file mode 100644 index 0000000000..d61dfe6fbf --- /dev/null +++ b/queue-6.13/hid-pidff-rescale-time-values-to-match-field-units.patch @@ -0,0 +1,167 @@ +From 9e39fc1bd5b565a5404006bc53e73915edf33824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:00 +0100 +Subject: HID: pidff: Rescale time values to match field units +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 8713107221a8ce4021ec5fa12bb50ecc8165cf08 ] + +PID devices can use different exponents for time fields, while Linux +Force Feedback API only supports miliseconds. + +Read the exponent of a given time field and scale its value accordingly. + +Changes in v7: +- Rescale all time fields, not only period + +changes in v9: +- Properly assign fade_lenght, not attack_length to PID_FADE_TIME + +Co-developed-by: Makarenko Oleg +Signed-off-by: Makarenko Oleg +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 69 ++++++++++++++++++++++++++-------- + 1 file changed, 54 insertions(+), 15 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index bd913d57e4d75..180b2cf66e4c7 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -22,6 +22,9 @@ + #define PID_EFFECTS_MAX 64 + #define PID_INFINITE 0xffff + ++/* Linux Force Feedback API uses miliseconds as time unit */ ++#define FF_TIME_EXPONENT -3 ++ + /* Report usage table used to put reports into an array */ + + #define PID_SET_EFFECT 0 +@@ -231,6 +234,24 @@ static int pidff_rescale_signed(int i, struct hid_field *field) + field->logical_minimum / -0x8000; + } + ++/* ++ * Scale time value from Linux default (ms) to field units ++ */ ++static u32 pidff_rescale_time(u16 time, struct hid_field *field) ++{ ++ u32 scaled_time = time; ++ int exponent = field->unit_exponent; ++ pr_debug("time field exponent: %d\n", exponent); ++ ++ for (;exponent < FF_TIME_EXPONENT; exponent++) ++ scaled_time *= 10; ++ for (;exponent > FF_TIME_EXPONENT; exponent--) ++ scaled_time /= 10; ++ ++ pr_debug("time calculated from %d to %d\n", time, scaled_time); ++ return scaled_time; ++} ++ + static void pidff_set(struct pidff_usage *usage, u16 value) + { + usage->value[0] = pidff_rescale(value, 0xffff, usage->field); +@@ -252,6 +273,27 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value) + pr_debug("calculated from %d to %d\n", value, usage->value[0]); + } + ++static void pidff_set_time(struct pidff_usage *usage, u16 time) ++{ ++ u32 modified_time = pidff_rescale_time(time, usage->field); ++ usage->value[0] = pidff_clamp(modified_time, usage->field); ++} ++ ++static void pidff_set_duration(struct pidff_usage *usage, u16 duration) ++{ ++ /* Convert infinite length from Linux API (0) ++ to PID standard (NULL) if needed */ ++ if (duration == 0) ++ duration = PID_INFINITE; ++ ++ if (duration == PID_INFINITE) { ++ usage->value[0] = PID_INFINITE; ++ return; ++ } ++ ++ pidff_set_time(usage, duration); ++} ++ + /* + * Send envelope report to the device + */ +@@ -270,8 +312,10 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, + 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff, + pidff->set_envelope[PID_FADE_LEVEL].field); + +- pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length; +- pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; ++ pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME], ++ envelope->attack_length); ++ pidff_set_time(&pidff->set_envelope[PID_FADE_TIME], ++ envelope->fade_length); + + hid_dbg(pidff->hid, "attack %u => %d\n", + envelope->attack_level, +@@ -340,14 +384,12 @@ static void pidff_set_effect_report(struct pidff_device *pidff, + pidff->set_effect_type->value[0] = + pidff->create_new_effect_type->value[0]; + +- /* 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_duration(&pidff->set_effect[PID_DURATION], ++ 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; ++ pidff_set_time(&pidff->set_effect[PID_TRIGGER_REPEAT_INT], ++ effect->trigger.interval); + pidff->set_effect[PID_GAIN].value[0] = + pidff->set_effect[PID_GAIN].field->logical_maximum; + pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; +@@ -360,7 +402,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff, + + /* 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; ++ pidff_set_time(&pidff->set_effect[PID_START_DELAY], ++ effect->replay.delay); + + hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT], + HID_REQ_SET_REPORT); +@@ -392,15 +435,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); +- +- /* 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); ++ pidff_set_time(&pidff->set_periodic[PID_PERIOD], ++ effect->u.periodic.period); + + hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC], + HID_REQ_SET_REPORT); +- + } + + /* +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-simplify-pidff_rescale_signed.patch b/queue-6.13/hid-pidff-simplify-pidff_rescale_signed.patch new file mode 100644 index 0000000000..4138021989 --- /dev/null +++ b/queue-6.13/hid-pidff-simplify-pidff_rescale_signed.patch @@ -0,0 +1,47 @@ +From 04f6c98ddccd154c60d887dc27d8faa2820d8996 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:04 +0100 +Subject: HID: pidff: Simplify pidff_rescale_signed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 4eb9c2ee538b62dc5dcae192297c3a4044b7ade5 ] + +This function overrelies on ternary operators and makes it hard to parse +it mentally. New version makes it very easy to understand. + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index a8eaa77e80be3..8083eb7684e5e 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -230,9 +230,9 @@ static int pidff_rescale(int i, int max, struct hid_field *field) + */ + static int pidff_rescale_signed(int i, struct hid_field *field) + { +- return i == 0 ? 0 : i > +- 0 ? i * field->logical_maximum / 0x7fff : i * +- field->logical_minimum / -0x8000; ++ if (i > 0) return i * field->logical_maximum / 0x7fff; ++ if (i < 0) return i * field->logical_minimum / -0x8000; ++ return 0; + } + + /* +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-simplify-pidff_upload_effect-function.patch b/queue-6.13/hid-pidff-simplify-pidff_upload_effect-function.patch new file mode 100644 index 0000000000..16567ff4cc --- /dev/null +++ b/queue-6.13/hid-pidff-simplify-pidff_upload_effect-function.patch @@ -0,0 +1,100 @@ +From e2159f9fba9c9b937fcfacb7c4a5f5c16d9242ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:38:58 +0100 +Subject: HID: pidff: Simplify pidff_upload_effect function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit e4bdc80ef14272ef56c38d8ca2f365fdf59cd0ba ] + +Merge a bit of code that reqeusts conditional effects upload. +Makes it clear, that effect handling should be identical for +SPRING, DAMPER, INERTIA and FRICTION. + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 54 ++++++++++------------------------ + 1 file changed, 16 insertions(+), 38 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 99b5d3deb40d0..42c951a1d65bf 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -770,48 +770,26 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, + break; + + case FF_SPRING: +- if (!old) { +- error = pidff_request_effect_upload(pidff, +- pidff->type_id[PID_SPRING]); +- if (error) +- return error; +- } +- if (!old || pidff_needs_set_effect(effect, old)) +- pidff_set_effect_report(pidff, effect); +- if (!old || pidff_needs_set_condition(effect, old)) +- pidff_set_condition_report(pidff, effect); +- break; +- +- case FF_FRICTION: +- if (!old) { +- error = pidff_request_effect_upload(pidff, +- pidff->type_id[PID_FRICTION]); +- if (error) +- return error; +- } +- if (!old || pidff_needs_set_effect(effect, old)) +- pidff_set_effect_report(pidff, effect); +- if (!old || pidff_needs_set_condition(effect, old)) +- pidff_set_condition_report(pidff, effect); +- break; +- + case FF_DAMPER: +- if (!old) { +- error = pidff_request_effect_upload(pidff, +- pidff->type_id[PID_DAMPER]); +- if (error) +- return error; +- } +- if (!old || pidff_needs_set_effect(effect, old)) +- pidff_set_effect_report(pidff, effect); +- if (!old || pidff_needs_set_condition(effect, old)) +- pidff_set_condition_report(pidff, effect); +- break; +- + case FF_INERTIA: ++ case FF_FRICTION: + if (!old) { ++ switch(effect->type) { ++ case FF_SPRING: ++ type_id = PID_SPRING; ++ break; ++ case FF_DAMPER: ++ type_id = PID_DAMPER; ++ break; ++ case FF_INERTIA: ++ type_id = PID_INERTIA; ++ break; ++ case FF_FRICTION: ++ type_id = PID_FRICTION; ++ break; ++ } + error = pidff_request_effect_upload(pidff, +- pidff->type_id[PID_INERTIA]); ++ pidff->type_id[type_id]); + if (error) + return error; + } +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-stop-all-effects-before-enabling-actuators.patch b/queue-6.13/hid-pidff-stop-all-effects-before-enabling-actuators.patch new file mode 100644 index 0000000000..b84909d7b5 --- /dev/null +++ b/queue-6.13/hid-pidff-stop-all-effects-before-enabling-actuators.patch @@ -0,0 +1,63 @@ +From 0923ad51b20b53cb105f09473875a7431cc6c137 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:38:53 +0100 +Subject: HID: pidff: Stop all effects before enabling actuators +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit ce52c0c939fcb568d1abe454821d5623de38b424 ] + +Some PID compliant devices automatically play effects after boot (i.e. +autocenter spring) that prevent the rendering of other effects since +it is done outside the kernel driver. + +This makes sure all the effects currently played are stopped after +resetting the device. +It brings compatibility to the Brunner CLS-P joystick and others + +Reported-by: Jules Noirant +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/usbhid/hid-pidff.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c +index 6b55345ce75ac..635596a57c75d 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -109,8 +109,9 @@ static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; + /* Special field key tables used to put special field keys into arrays */ + + #define PID_ENABLE_ACTUATORS 0 +-#define PID_RESET 1 +-static const u8 pidff_device_control[] = { 0x97, 0x9a }; ++#define PID_STOP_ALL_EFFECTS 1 ++#define PID_RESET 2 ++static const u8 pidff_device_control[] = { 0x97, 0x99, 0x9a }; + + #define PID_CONSTANT 0 + #define PID_RAMP 1 +@@ -1235,6 +1236,10 @@ static void pidff_reset(struct pidff_device *pidff) + hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); + hid_hw_wait(hid); + ++ pidff->device_control->value[0] = pidff->control_id[PID_STOP_ALL_EFFECTS]; ++ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); ++ hid_hw_wait(hid); ++ + pidff->device_control->value[0] = + pidff->control_id[PID_ENABLE_ACTUATORS]; + hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT); +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-support-device-error-response-from-pid_blo.patch b/queue-6.13/hid-pidff-support-device-error-response-from-pid_blo.patch new file mode 100644 index 0000000000..f2396c7cd6 --- /dev/null +++ b/queue-6.13/hid-pidff-support-device-error-response-from-pid_blo.patch @@ -0,0 +1,54 @@ +From ba582ecdfdcc0dcd3faeb1504f9d0e913697a105 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Feb 2025 15:35:11 +0100 +Subject: HID: pidff: Support device error response from PID_BLOCK_LOAD +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 9d4174dc4a234408d91fd83725e1899766cd1731 ] + +If an error happens on the device, the driver will no longer fall +into the trap of reading this status 60 times before it decides that +this reply won't change to success/memory full. + +Greatly reduces communication overhead during device error situation. + +Signed-off-by: Tomasz Pakuła +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 e2508a4d754d3..d5734cbf745d1 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -138,7 +138,8 @@ static const u8 pidff_effect_types[] = { + + #define PID_BLOCK_LOAD_SUCCESS 0 + #define PID_BLOCK_LOAD_FULL 1 +-static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; ++#define PID_BLOCK_LOAD_ERROR 2 ++static const u8 pidff_block_load_status[] = { 0x8c, 0x8d, 0x8e}; + + #define PID_EFFECT_START 0 + #define PID_EFFECT_STOP 1 +@@ -666,6 +667,11 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) + pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); + return -ENOSPC; + } ++ if (pidff->block_load_status->value[0] == ++ pidff->status_id[PID_BLOCK_LOAD_ERROR]) { ++ hid_dbg(pidff->hid, "device error during effect creation\n"); ++ return -EREMOTEIO; ++ } + } + hid_err(pidff->hid, "pid_block_load failed 60 times\n"); + return -EIO; +-- +2.39.5 + diff --git a/queue-6.13/hid-pidff-use-macros-instead-of-hardcoded-min-max-va.patch b/queue-6.13/hid-pidff-use-macros-instead-of-hardcoded-min-max-va.patch new file mode 100644 index 0000000000..0eb9012c9a --- /dev/null +++ b/queue-6.13/hid-pidff-use-macros-instead-of-hardcoded-min-max-va.patch @@ -0,0 +1,122 @@ +From 52f5f2a790f36da96a3b05acd9e02c5f3cbd167c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 1 Feb 2025 12:39:05 +0100 +Subject: HID: pidff: Use macros instead of hardcoded min/max values for shorts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tomasz Pakuła + +[ Upstream commit 21755162456902998f8d9897086b8c980c540df5 ] + +Makes it obvious these magic values ARE in fact derived from min and +max values for s16 and u16 + +Signed-off-by: Tomasz Pakuła +Reviewed-by: Michał Kopeć +Reviewed-by: Paul Dino Jones +Tested-by: Paul Dino Jones +Tested-by: Cristóferson Bueno +Tested-by: Pablo Cisneros +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + 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 8083eb7684e5e..b21e844f5f3a3 100644 +--- a/drivers/hid/usbhid/hid-pidff.c ++++ b/drivers/hid/usbhid/hid-pidff.c +@@ -21,7 +21,7 @@ + + + #define PID_EFFECTS_MAX 64 +-#define PID_INFINITE 0xffff ++#define PID_INFINITE U16_MAX + + /* Linux Force Feedback API uses miliseconds as time unit */ + #define FF_TIME_EXPONENT -3 +@@ -226,12 +226,12 @@ static int pidff_rescale(int i, int max, struct hid_field *field) + } + + /* +- * Scale a signed value in range -0x8000..0x7fff for the given field ++ * Scale a signed value in range S16_MIN..S16_MAX for the given field + */ + static int pidff_rescale_signed(int i, struct hid_field *field) + { +- if (i > 0) return i * field->logical_maximum / 0x7fff; +- if (i < 0) return i * field->logical_minimum / -0x8000; ++ if (i > 0) return i * field->logical_maximum / S16_MAX; ++ if (i < 0) return i * field->logical_minimum / S16_MIN; + return 0; + } + +@@ -255,7 +255,7 @@ static u32 pidff_rescale_time(u16 time, struct hid_field *field) + + static void pidff_set(struct pidff_usage *usage, u16 value) + { +- usage->value[0] = pidff_rescale(value, 0xffff, usage->field); ++ usage->value[0] = pidff_rescale(value, U16_MAX, usage->field); + pr_debug("calculated from %d to %d\n", value, usage->value[0]); + } + +@@ -266,10 +266,10 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value) + else { + if (value < 0) + usage->value[0] = +- pidff_rescale(-value, 0x8000, usage->field); ++ pidff_rescale(-value, -S16_MIN, usage->field); + else + usage->value[0] = +- pidff_rescale(value, 0x7fff, usage->field); ++ pidff_rescale(value, S16_MAX, usage->field); + } + pr_debug("calculated from %d to %d\n", value, usage->value[0]); + } +@@ -306,11 +306,11 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, + + pidff->set_envelope[PID_ATTACK_LEVEL].value[0] = + pidff_rescale(envelope->attack_level > +- 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff, ++ S16_MAX ? S16_MAX : envelope->attack_level, S16_MAX, + pidff->set_envelope[PID_ATTACK_LEVEL].field); + pidff->set_envelope[PID_FADE_LEVEL].value[0] = + pidff_rescale(envelope->fade_level > +- 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff, ++ S16_MAX ? S16_MAX : envelope->fade_level, S16_MAX, + pidff->set_envelope[PID_FADE_LEVEL].field); + + pidff_set_time(&pidff->set_envelope[PID_ATTACK_TIME], +@@ -399,7 +399,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff, + 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); ++ U16_MAX, pidff->effect_direction); + + /* Omit setting delay field if it's missing */ + if (!(pidff->quirks & HID_PIDFF_QUIRK_MISSING_DELAY)) +@@ -1366,7 +1366,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff, + + if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] == + pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) { +- pidff_autocenter(pidff, 0xffff); ++ pidff_autocenter(pidff, U16_MAX); + set_bit(FF_AUTOCENTER, dev->ffbit); + } else { + hid_notice(pidff->hid, +@@ -1424,7 +1424,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) + if (error) + goto fail; + +- pidff_set_gain_report(pidff, 0xffff); ++ pidff_set_gain_report(pidff, U16_MAX); + error = pidff_check_autocenter(pidff, dev); + if (error) + goto fail; +-- +2.39.5 + diff --git a/queue-6.13/series b/queue-6.13/series index b14ca3630e..a9b2db167d 100644 --- a/queue-6.13/series +++ b/queue-6.13/series @@ -171,3 +171,24 @@ erofs-set-error-to-bio-if-file-backed-io-fails.patch bpf-support-skf_net_off-and-skf_ll_off-on-skb-frags.patch ext4-don-t-treat-fhandle-lookup-of-ea_inode-as-fs-co.patch s390-pci-fix-s390_mmio_read-write-syscall-page-fault.patch +hid-pidff-clamp-periodic-effect-period-to-device-s-l.patch +hid-pidff-stop-all-effects-before-enabling-actuators.patch +hid-pidff-completely-rework-and-fix-pidff_reset-func.patch +hid-pidff-simplify-pidff_upload_effect-function.patch +hid-pidff-define-values-used-in-pidff_find_special_f.patch +hid-pidff-rescale-time-values-to-match-field-units.patch +hid-pidff-factor-out-code-for-setting-gain.patch +hid-pidff-move-all-hid-pidff-definitions-to-a-dedica.patch +hid-pidff-simplify-pidff_rescale_signed.patch +hid-pidff-use-macros-instead-of-hardcoded-min-max-va.patch +hid-pidff-factor-out-pool-report-fetch-and-remove-ex.patch +hid-pidff-make-sure-to-fetch-pool-before-checking-si.patch +hid-hid-universal-pidff-add-asetek-wheelbases-suppor.patch +hid-pidff-comment-and-code-style-update.patch +hid-pidff-support-device-error-response-from-pid_blo.patch +hid-pidff-remove-redundant-call-to-pidff_find_specia.patch +hid-pidff-rename-two-functions-to-align-them-with-na.patch +hid-pidff-clamp-effect-playback-loop_count-value.patch +hid-pidff-compute-infinite-value-instead-of-using-ha.patch +hid-pidff-fix-90-degrees-direction-name-north-east.patch +hid-pidff-fix-set_device_control.patch -- 2.47.3