Skip to content

Commit 9cd61c8

Browse files
endriftbentiss
authored andcommitted
HID: hid-steam: Add rumble on Deck
The Steam Deck includes a new report that allows for emulating XInput-style rumble motors with the Deck's actuators. This adds support for passing these values directly to the Deck. Signed-off-by: Vicki Pfau <[email protected]> Reviewed-by: Lyude Paul <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 9ba9498 commit 9cd61c8

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

drivers/hid/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,14 @@ config HID_STEAM
10251025
without running the Steam Client. It supports both the wired and
10261026
the wireless adaptor.
10271027

1028+
config STEAM_FF
1029+
bool "Steam Deck force feedback support"
1030+
depends on HID_STEAM
1031+
select INPUT_FF_MEMLESS
1032+
help
1033+
Say Y here if you want to enable force feedback support for the Steam
1034+
Deck.
1035+
10281036
config HID_STEELSERIES
10291037
tristate "Steelseries SRW-S1 steering wheel support"
10301038
help

drivers/hid/hid-steam.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static LIST_HEAD(steam_devices);
9191
#define STEAM_CMD_FORCEFEEDBAK 0x8f
9292
#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
9393
#define STEAM_CMD_GET_SERIAL 0xae
94+
#define STEAM_CMD_HAPTIC_RUMBLE 0xeb
9495

9596
/* Some useful register ids */
9697
#define STEAM_REG_LPAD_MODE 0x07
@@ -134,6 +135,9 @@ struct steam_device {
134135
u8 battery_charge;
135136
u16 voltage;
136137
struct delayed_work heartbeat;
138+
struct work_struct rumble_work;
139+
u16 rumble_left;
140+
u16 rumble_right;
137141
};
138142

139143
static int steam_recv_report(struct steam_device *steam,
@@ -290,6 +294,45 @@ static inline int steam_request_conn_status(struct steam_device *steam)
290294
return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS);
291295
}
292296

297+
static inline int steam_haptic_rumble(struct steam_device *steam,
298+
u16 intensity, u16 left_speed, u16 right_speed,
299+
u8 left_gain, u8 right_gain)
300+
{
301+
u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9};
302+
303+
report[3] = intensity & 0xFF;
304+
report[4] = intensity >> 8;
305+
report[5] = left_speed & 0xFF;
306+
report[6] = left_speed >> 8;
307+
report[7] = right_speed & 0xFF;
308+
report[8] = right_speed >> 8;
309+
report[9] = left_gain;
310+
report[10] = right_gain;
311+
312+
return steam_send_report(steam, report, sizeof(report));
313+
}
314+
315+
static void steam_haptic_rumble_cb(struct work_struct *work)
316+
{
317+
struct steam_device *steam = container_of(work, struct steam_device,
318+
rumble_work);
319+
steam_haptic_rumble(steam, 0, steam->rumble_left,
320+
steam->rumble_right, 2, 0);
321+
}
322+
323+
#ifdef CONFIG_STEAM_FF
324+
static int steam_play_effect(struct input_dev *dev, void *data,
325+
struct ff_effect *effect)
326+
{
327+
struct steam_device *steam = input_get_drvdata(dev);
328+
329+
steam->rumble_left = effect->u.rumble.strong_magnitude;
330+
steam->rumble_right = effect->u.rumble.weak_magnitude;
331+
332+
return schedule_work(&steam->rumble_work);
333+
}
334+
#endif
335+
293336
static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
294337
{
295338
if (enable) {
@@ -540,6 +583,15 @@ static int steam_input_register(struct steam_device *steam)
540583
input_abs_set_res(input, ABS_HAT0X, STEAM_PAD_RESOLUTION);
541584
input_abs_set_res(input, ABS_HAT0Y, STEAM_PAD_RESOLUTION);
542585

586+
#ifdef CONFIG_STEAM_FF
587+
if (steam->quirks & STEAM_QUIRK_DECK) {
588+
input_set_capability(input, EV_FF, FF_RUMBLE);
589+
ret = input_ff_create_memless(input, NULL, steam_play_effect);
590+
if (ret)
591+
goto input_register_fail;
592+
}
593+
#endif
594+
543595
ret = input_register_device(input);
544596
if (ret)
545597
goto input_register_fail;
@@ -841,6 +893,7 @@ static int steam_probe(struct hid_device *hdev,
841893
INIT_WORK(&steam->work_connect, steam_work_connect_cb);
842894
INIT_LIST_HEAD(&steam->list);
843895
INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
896+
INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
844897

845898
steam->client_hdev = steam_create_client_hid(hdev);
846899
if (IS_ERR(steam->client_hdev)) {
@@ -897,6 +950,7 @@ static int steam_probe(struct hid_device *hdev,
897950
client_hdev_fail:
898951
cancel_work_sync(&steam->work_connect);
899952
cancel_delayed_work_sync(&steam->heartbeat);
953+
cancel_work_sync(&steam->rumble_work);
900954
steam_alloc_fail:
901955
hid_err(hdev, "%s: failed with error %d\n",
902956
__func__, ret);

0 commit comments

Comments
 (0)