mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-15 06:55:13 +08:00
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 <vi@endrift.com> Reviewed-by: Lyude Paul <lyude@redhat.com> Link: https://lore.kernel.org/r/20230126030126.895670-3-vi@endrift.com Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
This commit is contained in:
parent
9ba9498bff
commit
9cd61c8179
@ -1025,6 +1025,14 @@ config HID_STEAM
|
||||
without running the Steam Client. It supports both the wired and
|
||||
the wireless adaptor.
|
||||
|
||||
config STEAM_FF
|
||||
bool "Steam Deck force feedback support"
|
||||
depends on HID_STEAM
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
Say Y here if you want to enable force feedback support for the Steam
|
||||
Deck.
|
||||
|
||||
config HID_STEELSERIES
|
||||
tristate "Steelseries SRW-S1 steering wheel support"
|
||||
help
|
||||
|
@ -91,6 +91,7 @@ static LIST_HEAD(steam_devices);
|
||||
#define STEAM_CMD_FORCEFEEDBAK 0x8f
|
||||
#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
|
||||
#define STEAM_CMD_GET_SERIAL 0xae
|
||||
#define STEAM_CMD_HAPTIC_RUMBLE 0xeb
|
||||
|
||||
/* Some useful register ids */
|
||||
#define STEAM_REG_LPAD_MODE 0x07
|
||||
@ -134,6 +135,9 @@ struct steam_device {
|
||||
u8 battery_charge;
|
||||
u16 voltage;
|
||||
struct delayed_work heartbeat;
|
||||
struct work_struct rumble_work;
|
||||
u16 rumble_left;
|
||||
u16 rumble_right;
|
||||
};
|
||||
|
||||
static int steam_recv_report(struct steam_device *steam,
|
||||
@ -290,6 +294,45 @@ static inline int steam_request_conn_status(struct steam_device *steam)
|
||||
return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS);
|
||||
}
|
||||
|
||||
static inline int steam_haptic_rumble(struct steam_device *steam,
|
||||
u16 intensity, u16 left_speed, u16 right_speed,
|
||||
u8 left_gain, u8 right_gain)
|
||||
{
|
||||
u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9};
|
||||
|
||||
report[3] = intensity & 0xFF;
|
||||
report[4] = intensity >> 8;
|
||||
report[5] = left_speed & 0xFF;
|
||||
report[6] = left_speed >> 8;
|
||||
report[7] = right_speed & 0xFF;
|
||||
report[8] = right_speed >> 8;
|
||||
report[9] = left_gain;
|
||||
report[10] = right_gain;
|
||||
|
||||
return steam_send_report(steam, report, sizeof(report));
|
||||
}
|
||||
|
||||
static void steam_haptic_rumble_cb(struct work_struct *work)
|
||||
{
|
||||
struct steam_device *steam = container_of(work, struct steam_device,
|
||||
rumble_work);
|
||||
steam_haptic_rumble(steam, 0, steam->rumble_left,
|
||||
steam->rumble_right, 2, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STEAM_FF
|
||||
static int steam_play_effect(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct steam_device *steam = input_get_drvdata(dev);
|
||||
|
||||
steam->rumble_left = effect->u.rumble.strong_magnitude;
|
||||
steam->rumble_right = effect->u.rumble.weak_magnitude;
|
||||
|
||||
return schedule_work(&steam->rumble_work);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
@ -540,6 +583,15 @@ static int steam_input_register(struct steam_device *steam)
|
||||
input_abs_set_res(input, ABS_HAT0X, STEAM_PAD_RESOLUTION);
|
||||
input_abs_set_res(input, ABS_HAT0Y, STEAM_PAD_RESOLUTION);
|
||||
|
||||
#ifdef CONFIG_STEAM_FF
|
||||
if (steam->quirks & STEAM_QUIRK_DECK) {
|
||||
input_set_capability(input, EV_FF, FF_RUMBLE);
|
||||
ret = input_ff_create_memless(input, NULL, steam_play_effect);
|
||||
if (ret)
|
||||
goto input_register_fail;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = input_register_device(input);
|
||||
if (ret)
|
||||
goto input_register_fail;
|
||||
@ -841,6 +893,7 @@ static int steam_probe(struct hid_device *hdev,
|
||||
INIT_WORK(&steam->work_connect, steam_work_connect_cb);
|
||||
INIT_LIST_HEAD(&steam->list);
|
||||
INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
|
||||
INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
|
||||
|
||||
steam->client_hdev = steam_create_client_hid(hdev);
|
||||
if (IS_ERR(steam->client_hdev)) {
|
||||
@ -897,6 +950,7 @@ hid_hw_start_fail:
|
||||
client_hdev_fail:
|
||||
cancel_work_sync(&steam->work_connect);
|
||||
cancel_delayed_work_sync(&steam->heartbeat);
|
||||
cancel_work_sync(&steam->rumble_work);
|
||||
steam_alloc_fail:
|
||||
hid_err(hdev, "%s: failed with error %d\n",
|
||||
__func__, ret);
|
||||
|
Loading…
Reference in New Issue
Block a user