[PATCH v2 00/33] HID: logitech-hidpp: G920 force-feedback fixes, rework, and cleanups

From: Dmitry Torokhov

Date: Wed Nov 11 2026 - 02:03:11 EST


This series starts from Gideon Heinz's report of Logitech G920
force-feedback initialization timing out in v7.3 and addresses several
additional pre-existing bugs, lifetime races, and cleanup opportunities
found while auditing hid-logitech-hidpp.

The first 14 patches carry Fixes and stable tags. They fix the v7.3
G920 force-feedback initialization timeout by temporarily enabling
device I/O around g920_get_config() in hidpp_input_configured(), switch
hidpp_ff_queue_work() to GFP_ATOMIC since playback, gain, and autocenter
callbacks run under the input event spinlock, drain the G920 FF
workqueue before closing the HID transport on input close so queued
commands still receive their USB interrupt IN replies, synchronously
disable driver work items and disconnect input devices with device I/O
enabled before stopping the transport on removal and probe failure,
avoid storing an ERR_PTR in battery->ps on registration failure, avoid
NULL pointer subtraction in the HID++ 1.0 consumer keys report fixup,
and fix an off-by-one in G920 slot tracking that made the 63rd user
effect in hardware slot 64 unusable and leaked it across reopen.

Additionally in the bug fix section, hidpp_send_message_sync() is
updated to stop retrying non-busy errors (timeouts and transport
failures) so failed commands fail promptly without 15-second stalls,
and response buffers are initialized before publishing send_receive_buf
to eliminate races with concurrent or spurious packets. Battery fixes
correct HID++ 1.0 battery mileage event parsing to read capacity from
the correct report byte and update state, properly propagate negative
transport and timeout errors in ADC measurement (0x1f20) queries, mark
devices online when receiving unified battery (0x1004) events, fix K750
solar battery feature lookup and reconnect handling, and expose the
charge_type property for the battery voltage (0x1001) feature.

The next section prepares transport handling and reworks G920 force
feedback for next. Connect-event work is kept disabled in probe until
hid_connect() completes successfully. Transport error codes are
preserved in __hidpp_send_report(), and hidpp_send_message_sync()
is switched to return standard negative error codes on failure.
G920 capability discovery moves back into hidpp_probe() while device
I/O is active (keeping force feedback optional on failure and
excluding generic USB PID force feedback), device-level wheel settings
are separated from the input FF queue lifetime, the G920 range sysfs
attribute moves to driver dev_groups, and FF workqueue teardown moves
into ff->stop so open evdev handles across USB disconnect or unbind
no longer cause use-after-free.

Furthermore, G920 range store, effect upload, and effect erase are
converted to execute synchronously with proper transport lifetime
handling, avoiding asynchronous command queueing and work flushing
during device close and teardown. Effect slot lookup is streamlined by
indexing slot arrays directly by effect ID instead of performing linear
scans.

The final section modernizes the driver. Multi-byte packet fields are
switched to unaligned accessors, the device serial is stored as a byte
array, and resource management is updated to use guard(mutex),
__free(kfree), alloc_ordered_workqueue(), devm_mutex_init(), and
devm_device_add_group(). Lastly, unused kfifo fields and helpers
are removed.

Note that device removal teardown still has limitations due to how HID
core's hid_device_io_start() and hid_device_io_stop() (via
driver_input_lock) gate both driver raw command/response I/O and
subdriver event forwarding, disabling I/O before .remove() and
hid_disconnect(). For instance, HIDPP_QUIRK_DELAYED_INIT devm-managed
input devices are still unregistered after hid_hw_stop(), and
hidpp_connect_event() publishes hidpp->input before input registration
completes. Resolving these teardown edge cases cleanly will require
follow-up work in HID core and driver input registration.

Thanks.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
---
Changes in v2:
- Rebased the series on top of linux-next.
- Collected Tested-by tags from Gideon Heinz for 17 v1 patches (omitted
from patch 4 where hidpp_remove() was significantly altered).
- Reorganized the series to place all 14 stable bug fixes upfront,
followed by next refactorings and modernizations.
- Updated hidpp_remove() to enable device I/O while draining work
items and disconnecting hidinput so in-flight transfers and
force-feedback teardown can receive device replies (noting that
complete resolution of delayed-init and transport teardown ordering
requires follow-up work in HID core).
- Stopped retrying non-busy errors (timeouts and negative transport
failures) in hidpp_send_message_sync().
- Initialized response buffers before publishing send_receive_buf to
prevent stale response reads on concurrent or spurious events.
- Fixed HID++ 1.0 battery mileage event parsing to read capacity from
the correct report byte and update battery state.
- Handled negative transport and timeout errors properly in ADC
measurement (0x1f20) queries.
- Marked devices online when receiving unified battery (0x1004) events.
- Fixed K750 solar battery feature lookup and reconnect handling.
- Exposed charge_type property for battery voltage (0x1001) feature.
- Kept connect work disabled during probe until hid_connect() succeeds.
- Switched hidpp_send_message_sync() to translate RAP and FAP protocol
error codes into negative Linux error codes (-EBUSY, -EIO, -EPROTO)
instead of returning positive protocol values, and preserved transport
error codes in __hidpp_send_report().
- Converted G920 range store, effect upload, and effect erase to
synchronous execution with slot indexing by effect ID.
- Added G920 force-feedback helper cleanups, removed unused kfifo and
struct wtp_data fields, and cleaned up minor helpers.
- Link to v1: https://patch.msgid.link/20261109061103.2887636-1-dmitry.torokhov@xxxxxxxxx

---
Dmitry Torokhov (33):
HID: logitech-hidpp: fix G920 force-feedback initialization timeout
HID: logitech-hidpp: use GFP_ATOMIC in hidpp_ff_queue_work()
HID: logitech-hidpp: drain G920 FF workqueue before closing transport
HID: logitech-hidpp: disable works before stopping transport
HID: logitech-hidpp: do not store ERR_PTR in battery->ps
HID: logitech-hidpp: avoid NULL subtraction in consumer key report fixup
HID: logitech-hidpp: fix off-by-one in G920 force-feedback slot tracking
HID: logitech-hidpp: do not retry timeouts and transport errors in hidpp_send_message_sync()
HID: logitech-hidpp: initialize response buffer before publishing send_receive_buf
HID: logitech-hidpp: fix HID++ 1.0 battery mileage event parsing
HID: logitech-hidpp: handle negative errors in hidpp20_get_adc_measurement_1f20()
HID: logitech-hidpp: mark device online on unified battery 0x1004 events
HID: logitech-hidpp: fix K750 solar battery feature lookup and reconnect
HID: logitech-hidpp: expose charge_type property for battery voltage feature
HID: logitech-hidpp: keep connect work disabled until hid_connect() completes
HID: logitech-hidpp: preserve transport error codes in __hidpp_send_report()
HID: logitech-hidpp: return negative error codes from hidpp_send_message_sync()
HID: logitech-hidpp: rework G920 force-feedback initialization
HID: logitech-hidpp: use sysfs_emit() in hidpp_ff_range_show()
HID: logitech-hidpp: manage G920 range sysfs attribute via dev_groups
HID: logitech-hidpp: execute G920 range sysfs store synchronously
HID: logitech-hidpp: shut down G920 force feedback on input unregister
HID: logitech-hidpp: index G920 force-feedback slots by effect ID
HID: logitech-hidpp: execute G920 effect upload and erase synchronously
HID: logitech-hidpp: clean up G920 force-feedback helpers
HID: logitech-hidpp: use unaligned accessors for multi-byte values
HID: logitech-hidpp: store device serial as a byte array
HID: logitech-hidpp: use guard() for send_mutex
HID: logitech-hidpp: use __free(kfree) for temporary allocations
HID: logitech-hidpp: use alloc_ordered_workqueue() for FF queue
HID: logitech-hidpp: manage send_mutex with devm_mutex_init()
HID: logitech-hidpp: manage ps_attribute_group with devm_device_add_group()
HID: logitech-hidpp: remove unused kfifo and clean up minor helpers

drivers/hid/hid-logitech-hidpp.c | 897 ++++++++++++++++++---------------------
1 file changed, 411 insertions(+), 486 deletions(-)
---
base-commit: 630059a5a632377b9b7b487baccde92b7ae1dd47
change-id: 20261110-hid-logitech-hidpp-6884bfb6a348

Thanks.

--
Dmitry