summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorVicki Pfau <vi@endrift.com>2026-08-11 18:13:57 -0700
committerJiri Kosina <jkosina@suse.com>2026-08-14 15:11:16 +0200
commitcfe8ee25fe1223d6a14000d7837b8bdee5c9eb21 (patch)
tree0ce900dc8d424d701f2d2ab04e5a464d998b5314 /drivers/hid
parentde1d341b9b3ec9655f31fb8b44f784cca5e670ad (diff)
HID: steam: Zero out inputs when disabling gamepad mode
When gamepad mode is disabled the gamepad input devices will stop receiving updates. However, in the case where there are buttons still pressed this will appear as an indefinitely-held button. Instead we should zero out the inputs to make it look like things are all released. We do the same thing for gyroscope inputs to make sure it doesn't look like it's endlessly rotating, but we freeze the accelerometer input since zero isn't a neutral input on the surface of the Earth. Signed-off-by: Vicki Pfau <vi@endrift.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-steam.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index 7bb892972447..ac08cb2d0368 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -1501,13 +1501,83 @@ static void steam_mode_switch_cb(struct work_struct *work)
client_opened = steam->client_opened;
spin_unlock_irqrestore(&steam->lock, flags);
- guard(mutex)(&steam->report_mutex);
hid_dbg(steam->hdev, "%s: switching gamepad mode to %i\n", __func__, gamepad_mode);
- if (gamepad_mode)
+ if (gamepad_mode) {
+ guard(mutex)(&steam->report_mutex);
steam_set_lizard_mode(steam, false);
- else if (!client_opened)
- steam_set_lizard_mode(steam, lizard_mode);
+ } else {
+ struct input_dev *input;
+ struct input_dev *sensors;
+
+ if (!client_opened) {
+ guard(mutex)(&steam->report_mutex);
+ steam_set_lizard_mode(steam, lizard_mode);
+ }
+
+ /*
+ * Zero out inputs so it doesn't look like we're holding
+ * anything indefinitely.
+ */
+ guard(spinlock_irqsave)(&steam->lock);
+ rcu_read_lock();
+ input = rcu_dereference(steam->input);
+ if (likely(input)) {
+ input_report_key(input, BTN_TR2, 0);
+ input_report_key(input, BTN_TL2, 0);
+ input_report_key(input, BTN_TR, 0);
+ input_report_key(input, BTN_TL, 0);
+ input_report_key(input, BTN_Y, 0);
+ input_report_key(input, BTN_B, 0);
+ input_report_key(input, BTN_X, 0);
+ input_report_key(input, BTN_A, 0);
+ input_report_key(input, BTN_DPAD_UP, 0);
+ input_report_key(input, BTN_DPAD_RIGHT, 0);
+ input_report_key(input, BTN_DPAD_LEFT, 0);
+ input_report_key(input, BTN_DPAD_DOWN, 0);
+ input_report_key(input, BTN_SELECT, 0);
+ input_report_key(input, BTN_MODE, 0);
+ input_report_key(input, BTN_START, 0);
+ input_report_key(input, BTN_THUMBR, 0);
+ input_report_key(input, BTN_THUMBL, 0);
+ input_report_key(input, BTN_THUMB, 0);
+ input_report_key(input, BTN_THUMB2, 0);
+ input_report_key(input, BTN_GRIPL, 0);
+ input_report_key(input, BTN_GRIPR, 0);
+
+ input_report_abs(input, ABS_X, 0);
+ input_report_abs(input, ABS_Y, 0);
+ input_report_abs(input, ABS_RX, 0);
+ input_report_abs(input, ABS_RY, 0);
+ input_report_abs(input, ABS_HAT0X, 0);
+ input_report_abs(input, ABS_HAT0Y, 0);
+ input_report_abs(input, ABS_HAT2Y, 0);
+ input_report_abs(input, ABS_HAT2X, 0);
+
+ if (steam->quirks & (STEAM_QUIRK_DECK | STEAM_QUIRK_IBEX)) {
+ input_report_key(input, BTN_BASE, 0);
+ input_report_key(input, BTN_GRIPL2, 0);
+ input_report_key(input, BTN_GRIPR2, 0);
+
+ input_report_abs(input, ABS_HAT1X, 0);
+ input_report_abs(input, ABS_HAT1Y, 0);
+ }
+
+ input_sync(input);
+ }
+ sensors = rcu_dereference(steam->sensors);
+ if (likely(sensors)) {
+ /* Skip accelerometers since 0 isn't a neutral input */
+ input_report_abs(sensors, ABS_RX, 0);
+ input_report_abs(sensors, ABS_RY, 0);
+ input_report_abs(sensors, ABS_RZ, 0);
+
+ input_sync(sensors);
+ }
+ rcu_read_unlock();
+ }
+
+ guard(mutex)(&steam->report_mutex);
steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0);
if (gamepad_mode) {
steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x14D, 0x14D, 0x2D, 0);