From: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com
[ Upstream commit c2dc9f0b368c08c34674311cf78407718d5715a7 ]
Fixes force feedback for devices built with MMOS firmware and many more not yet detected devices.
Update quirks mask debug message to always contain all 32 bits of data.
Signed-off-by: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com Signed-off-by: Jiri Kosina jkosina@suse.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
Why this is a good stable backport - Fixes real user-visible breakage: enables force feedback on devices with MMOS firmware and other devices misreporting PID_DEVICE_CONTROL’s logical_minimum (previously failed to initialize FF). - Small, contained change in HID PID FF driver; no architectural changes or cross‑subsystem impacts. - Risk is low: the new behavior only relaxes a check if the strict path fails, and only for the specific Device Control field; otherwise behavior remains identical. - Improves diagnostics (full 32‑bit quirks mask) without functional side effects. - Aligns with stable rules: important bugfix, minimal risk, confined to HID/PIDFF.
What changes, concretely - Autodetect and set PERMISSIVE_CONTROL only when needed: - Before: Device Control lookup was strict unless the quirk was pre- specified (e.g., via device ID). If logical_minimum != 1, driver failed with “device control field not found”. - After: Try strict lookup first; if not found, set `HID_PIDFF_QUIRK_PERMISSIVE_CONTROL` and retry without enforcing min==1. This allows devices with non‑conforming descriptors to work without hardcoding IDs. - Debug formatting improvement: print all 32 bits of the quirks mask.
Relevant code references (current tree) - Device Control lookup currently enforces min==1 unless the quirk is already set: - drivers/hid/usbhid/hid-pidff.c:1135 - `pidff->device_control = pidff_find_special_field(..., PID_DEVICE_CONTROL_ARRAY, !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL));` - The change will: - First call with `enforce_min=1`, then if null: - `pr_debug("Setting PERMISSIVE_CONTROL quirk");` - `pidff->quirks |= HID_PIDFF_QUIRK_PERMISSIVE_CONTROL;` - Retry with `enforce_min=0`. - Safety: If the usage isn’t present at all, the second lookup still returns NULL and the function returns error exactly as before. - Quirk definition already exists: - drivers/hid/usbhid/hid-pidff.h:16 - `#define HID_PIDFF_QUIRK_PERMISSIVE_CONTROL BIT(2)` - Quirks debug formatting to widen to 8 hex digits: - drivers/hid/usbhid/hid-pidff.c:1477 - Currently: `hid_dbg(dev, "Active quirks mask: 0x%x\n", pidff->quirks);` - Change to: `0x%08x` (formatting only, no logic impact).
Compatibility and dependencies - Depends on the existing quirk bit and infrastructure (already present since “HID: pidff: Add PERMISSIVE_CONTROL quirk”; this is in-tree with Signed-off-by: Sasha Levin, so it has been flowing into stable). - Interacts safely with the more recent fix to Device Control handling: - “HID: pidff: Fix set_device_control()” ensures correct 1‑based indexing and guards against missing fields; the autodetection does not invalidate those fixes.
Regression risk assessment - Previously working devices (strict path succeeds) are unchanged. - Previously non-working devices (strict path fails) now work via a guarded fallback; without the usage present, behavior remains identical (fail). - The quirk only changes acceptance of the Device Control field; no other code paths are altered.
Conclusion - This is a targeted, low-risk fix that unlocks FF functionality for a notable set of devices without broad side effects. It’s well-suited for backporting to stable trees that already carry the PERMISSIVE_CONTROL quirk.
drivers/hid/usbhid/hid-pidff.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index c6b4f61e535d5..711eefff853bb 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1151,8 +1151,16 @@ static int pidff_find_special_fields(struct pidff_device *pidff) PID_DIRECTION, 0); pidff->device_control = pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], - PID_DEVICE_CONTROL_ARRAY, - !(pidff->quirks & HID_PIDFF_QUIRK_PERMISSIVE_CONTROL)); + PID_DEVICE_CONTROL_ARRAY, 1); + + /* Detect and set permissive control quirk */ + if (!pidff->device_control) { + pr_debug("Setting PERMISSIVE_CONTROL quirk\n"); + pidff->quirks |= HID_PIDFF_QUIRK_PERMISSIVE_CONTROL; + pidff->device_control = pidff_find_special_field( + pidff->reports[PID_DEVICE_CONTROL], + PID_DEVICE_CONTROL_ARRAY, 0); + }
pidff->block_load_status = pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], @@ -1492,7 +1500,7 @@ int hid_pidff_init_with_quirks(struct hid_device *hid, u32 initial_quirks) 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_dbg(dev, "Active quirks mask: 0x%08x\n", pidff->quirks);
hid_device_io_stop(hid);