// SPDX-License-Identifier: GPL-2.0+ /* * HID driver for Valve Steam Controller * * Copyright (c) 2018 Rodrigo Rivas Costa <[email protected]> * Copyright (c) 2022 Valve Software * * Supports both the wired and wireless interfaces. * * This controller has a builtin emulation of mouse and keyboard: the right pad * can be used as a mouse, the shoulder buttons are mouse buttons, A and B * buttons are ENTER and ESCAPE, and so on. This is implemented as additional * HID interfaces. * * This is known as the "lizard mode", because apparently lizards like to use * the computer from the coach, without a proper mouse and keyboard. * * This driver will disable the lizard mode when the input device is opened * and re-enable it when the input device is closed, so as not to break user * mode behaviour. The lizard_mode parameter can be used to change that. * * There are a few user space applications (notably Steam Client) that use * the hidraw interface directly to create input devices (XTest, uinput...). * In order to avoid breaking them this driver creates a layered hidraw device, * so it can detect when the client is running and then: * - it will not send any command to the controller. * - this input device will be removed, to avoid double input of the same * user action. * When the client is closed, this input device will be created again. * * For additional functions, such as changing the right-pad margin or switching * the led, you can use the user-space tool at: * * https://github.com/rodrigorc/steamctrl */ #include <linux/device.h> #include <linux/input.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/workqueue.h> #include <linux/mutex.h> #include <linux/rcupdate.h> #include <linux/delay.h> #include <linux/power_supply.h> #include "hid-ids.h" MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…) …; static bool lizard_mode = …; static DEFINE_MUTEX(steam_devices_lock); static LIST_HEAD(steam_devices); #define STEAM_QUIRK_WIRELESS … #define STEAM_QUIRK_DECK … /* Touch pads are 40 mm in diameter and 65535 units */ #define STEAM_PAD_RESOLUTION … /* Trigger runs are about 5 mm and 256 units */ #define STEAM_TRIGGER_RESOLUTION … /* Joystick runs are about 5 mm and 256 units */ #define STEAM_JOYSTICK_RESOLUTION … /* Trigger runs are about 6 mm and 32768 units */ #define STEAM_DECK_TRIGGER_RESOLUTION … /* Joystick runs are about 5 mm and 32768 units */ #define STEAM_DECK_JOYSTICK_RESOLUTION … /* Accelerometer has 16 bit resolution and a range of +/- 2g */ #define STEAM_DECK_ACCEL_RES_PER_G … #define STEAM_DECK_ACCEL_RANGE … #define STEAM_DECK_ACCEL_FUZZ … /* Gyroscope has 16 bit resolution and a range of +/- 2000 dps */ #define STEAM_DECK_GYRO_RES_PER_DPS … #define STEAM_DECK_GYRO_RANGE … #define STEAM_DECK_GYRO_FUZZ … #define STEAM_PAD_FUZZ … /* * Commands that can be sent in a feature report. * Thanks to Valve and SDL for the names. */ enum { … }; /* Settings IDs */ enum { … }; /* Input report identifiers */ enum { … }; /* String attribute idenitifiers */ enum { … }; /* Values for GYRO_MODE (bitmask) */ enum { … }; /* Trackpad modes */ enum { … }; /* Pad identifiers for the deck */ #define STEAM_PAD_LEFT … #define STEAM_PAD_RIGHT … #define STEAM_PAD_BOTH … /* Other random constants */ #define STEAM_SERIAL_LEN … struct steam_device { … }; static int steam_recv_report(struct steam_device *steam, u8 *data, int size) { … } static int steam_send_report(struct steam_device *steam, u8 *cmd, int size) { … } static inline int steam_send_report_byte(struct steam_device *steam, u8 cmd) { … } static int steam_write_settings(struct steam_device *steam, /* u8 reg, u16 val */...) { … } static int steam_get_serial(struct steam_device *steam) { … } /* * This command requests the wireless adaptor to post an event * with the connection status. Useful if this driver is loaded when * the controller is already connected. */ static inline int steam_request_conn_status(struct steam_device *steam) { … } /* * Send a haptic pulse to the trackpads * Duration and interval are measured in microseconds, count is the number * of pulses to send for duration time with interval microseconds between them * and gain is measured in decibels, ranging from -24 to +6 */ static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad, u16 duration, u16 interval, u16 count, u8 gain) { … } static inline int steam_haptic_rumble(struct steam_device *steam, u16 intensity, u16 left_speed, u16 right_speed, u8 left_gain, u8 right_gain) { … } static void steam_haptic_rumble_cb(struct work_struct *work) { … } #ifdef CONFIG_STEAM_FF static int steam_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { … } #endif static void steam_set_lizard_mode(struct steam_device *steam, bool enable) { … } static int steam_input_open(struct input_dev *dev) { … } static void steam_input_close(struct input_dev *dev) { … } static enum power_supply_property steam_battery_props[] = …; static int steam_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { … } static int steam_battery_register(struct steam_device *steam) { … } static int steam_input_register(struct steam_device *steam) { … } static int steam_sensors_register(struct steam_device *steam) { … } static void steam_input_unregister(struct steam_device *steam) { … } static void steam_sensors_unregister(struct steam_device *steam) { … } static void steam_battery_unregister(struct steam_device *steam) { … } static int steam_register(struct steam_device *steam) { … } static void steam_unregister(struct steam_device *steam) { … } static void steam_work_connect_cb(struct work_struct *work) { … } static void steam_mode_switch_cb(struct work_struct *work) { … } static bool steam_is_valve_interface(struct hid_device *hdev) { … } static int steam_client_ll_parse(struct hid_device *hdev) { … } static int steam_client_ll_start(struct hid_device *hdev) { … } static void steam_client_ll_stop(struct hid_device *hdev) { … } static int steam_client_ll_open(struct hid_device *hdev) { … } static void steam_client_ll_close(struct hid_device *hdev) { … } static int steam_client_ll_raw_request(struct hid_device *hdev, unsigned char reportnum, u8 *buf, size_t count, unsigned char report_type, int reqtype) { … } static const struct hid_ll_driver steam_client_ll_driver = …; static struct hid_device *steam_create_client_hid(struct hid_device *hdev) { … } static int steam_probe(struct hid_device *hdev, const struct hid_device_id *id) { … } static void steam_remove(struct hid_device *hdev) { … } static void steam_do_connect_event(struct steam_device *steam, bool connected) { … } /* * Some input data in the protocol has the opposite sign. * Clamp the values to 32767..-32767 so that the range is * symmetrical and can be negated safely. */ static inline s16 steam_le16(u8 *data) { … } /* * The size for this message payload is 60. * The known values are: * (* values are not sent through wireless) * (* accelerator/gyro is disabled by default) * Offset| Type | Mapped to |Meaning * -------+-------+-----------+-------------------------- * 4-7 | u32 | -- | sequence number * 8-10 | 24bit | see below | buttons * 11 | u8 | ABS_HAT2Y | left trigger * 12 | u8 | ABS_HAT2X | right trigger * 13-15 | -- | -- | always 0 * 16-17 | s16 | ABS_X/ABS_HAT0X | X value * 18-19 | s16 | ABS_Y/ABS_HAT0Y | Y value * 20-21 | s16 | ABS_RX | right-pad X value * 22-23 | s16 | ABS_RY | right-pad Y value * 24-25 | s16 | -- | * left trigger * 26-27 | s16 | -- | * right trigger * 28-29 | s16 | -- | * accelerometer X value * 30-31 | s16 | -- | * accelerometer Y value * 32-33 | s16 | -- | * accelerometer Z value * 34-35 | s16 | -- | gyro X value * 36-36 | s16 | -- | gyro Y value * 38-39 | s16 | -- | gyro Z value * 40-41 | s16 | -- | quaternion W value * 42-43 | s16 | -- | quaternion X value * 44-45 | s16 | -- | quaternion Y value * 46-47 | s16 | -- | quaternion Z value * 48-49 | -- | -- | always 0 * 50-51 | s16 | -- | * left trigger (uncalibrated) * 52-53 | s16 | -- | * right trigger (uncalibrated) * 54-55 | s16 | -- | * joystick X value (uncalibrated) * 56-57 | s16 | -- | * joystick Y value (uncalibrated) * 58-59 | s16 | -- | * left-pad X value * 60-61 | s16 | -- | * left-pad Y value * 62-63 | u16 | -- | * battery voltage * * The buttons are: * Bit | Mapped to | Description * ------+------------+-------------------------------- * 8.0 | BTN_TR2 | right trigger fully pressed * 8.1 | BTN_TL2 | left trigger fully pressed * 8.2 | BTN_TR | right shoulder * 8.3 | BTN_TL | left shoulder * 8.4 | BTN_Y | button Y * 8.5 | BTN_B | button B * 8.6 | BTN_X | button X * 8.7 | BTN_A | button A * 9.0 | BTN_DPAD_UP | left-pad up * 9.1 | BTN_DPAD_RIGHT | left-pad right * 9.2 | BTN_DPAD_LEFT | left-pad left * 9.3 | BTN_DPAD_DOWN | left-pad down * 9.4 | BTN_SELECT | menu left * 9.5 | BTN_MODE | steam logo * 9.6 | BTN_START | menu right * 9.7 | BTN_GEAR_DOWN | left back lever * 10.0 | BTN_GEAR_UP | right back lever * 10.1 | -- | left-pad clicked * 10.2 | BTN_THUMBR | right-pad clicked * 10.3 | BTN_THUMB | left-pad touched (but see explanation below) * 10.4 | BTN_THUMB2 | right-pad touched * 10.5 | -- | unknown * 10.6 | BTN_THUMBL | joystick clicked * 10.7 | -- | lpad_and_joy */ static void steam_do_input_event(struct steam_device *steam, struct input_dev *input, u8 *data) { … } /* * The size for this message payload is 56. * The known values are: * Offset| Type | Mapped to |Meaning * -------+-------+-----------+-------------------------- * 4-7 | u32 | -- | sequence number * 8-15 | u64 | see below | buttons * 16-17 | s16 | ABS_HAT0X | left-pad X value * 18-19 | s16 | ABS_HAT0Y | left-pad Y value * 20-21 | s16 | ABS_HAT1X | right-pad X value * 22-23 | s16 | ABS_HAT1Y | right-pad Y value * 24-25 | s16 | IMU ABS_X | accelerometer X value * 26-27 | s16 | IMU ABS_Z | accelerometer Y value * 28-29 | s16 | IMU ABS_Y | accelerometer Z value * 30-31 | s16 | IMU ABS_RX | gyro X value * 32-33 | s16 | IMU ABS_RZ | gyro Y value * 34-35 | s16 | IMU ABS_RY | gyro Z value * 36-37 | s16 | -- | quaternion W value * 38-39 | s16 | -- | quaternion X value * 40-41 | s16 | -- | quaternion Y value * 42-43 | s16 | -- | quaternion Z value * 44-45 | u16 | ABS_HAT2Y | left trigger (uncalibrated) * 46-47 | u16 | ABS_HAT2X | right trigger (uncalibrated) * 48-49 | s16 | ABS_X | left joystick X * 50-51 | s16 | ABS_Y | left joystick Y * 52-53 | s16 | ABS_RX | right joystick X * 54-55 | s16 | ABS_RY | right joystick Y * 56-57 | u16 | -- | left pad pressure * 58-59 | u16 | -- | right pad pressure * * The buttons are: * Bit | Mapped to | Description * ------+------------+-------------------------------- * 8.0 | BTN_TR2 | right trigger fully pressed * 8.1 | BTN_TL2 | left trigger fully pressed * 8.2 | BTN_TR | right shoulder * 8.3 | BTN_TL | left shoulder * 8.4 | BTN_Y | button Y * 8.5 | BTN_B | button B * 8.6 | BTN_X | button X * 8.7 | BTN_A | button A * 9.0 | BTN_DPAD_UP | left-pad up * 9.1 | BTN_DPAD_RIGHT | left-pad right * 9.2 | BTN_DPAD_LEFT | left-pad left * 9.3 | BTN_DPAD_DOWN | left-pad down * 9.4 | BTN_SELECT | menu left * 9.5 | BTN_MODE | steam logo * 9.6 | BTN_START | menu right * 9.7 | BTN_TRIGGER_HAPPY3 | left bottom grip button * 10.0 | BTN_TRIGGER_HAPPY4 | right bottom grip button * 10.1 | BTN_THUMB | left pad pressed * 10.2 | BTN_THUMB2 | right pad pressed * 10.3 | -- | left pad touched * 10.4 | -- | right pad touched * 10.5 | -- | unknown * 10.6 | BTN_THUMBL | left joystick clicked * 10.7 | -- | unknown * 11.0 | -- | unknown * 11.1 | -- | unknown * 11.2 | BTN_THUMBR | right joystick clicked * 11.3 | -- | unknown * 11.4 | -- | unknown * 11.5 | -- | unknown * 11.6 | -- | unknown * 11.7 | -- | unknown * 12.0 | -- | unknown * 12.1 | -- | unknown * 12.2 | -- | unknown * 12.3 | -- | unknown * 12.4 | -- | unknown * 12.5 | -- | unknown * 12.6 | -- | unknown * 12.7 | -- | unknown * 13.0 | -- | unknown * 13.1 | BTN_TRIGGER_HAPPY1 | left top grip button * 13.2 | BTN_TRIGGER_HAPPY2 | right top grip button * 13.3 | -- | unknown * 13.4 | -- | unknown * 13.5 | -- | unknown * 13.6 | -- | left joystick touched * 13.7 | -- | right joystick touched * 14.0 | -- | unknown * 14.1 | -- | unknown * 14.2 | BTN_BASE | quick access button * 14.3 | -- | unknown * 14.4 | -- | unknown * 14.5 | -- | unknown * 14.6 | -- | unknown * 14.7 | -- | unknown * 15.0 | -- | unknown * 15.1 | -- | unknown * 15.2 | -- | unknown * 15.3 | -- | unknown * 15.4 | -- | unknown * 15.5 | -- | unknown * 15.6 | -- | unknown * 15.7 | -- | unknown */ static void steam_do_deck_input_event(struct steam_device *steam, struct input_dev *input, u8 *data) { … } static void steam_do_deck_sensors_event(struct steam_device *steam, struct input_dev *sensors, u8 *data) { … } /* * The size for this message payload is 11. * The known values are: * Offset| Type | Meaning * -------+-------+--------------------------- * 4-7 | u32 | sequence number * 8-11 | -- | always 0 * 12-13 | u16 | voltage (mV) * 14 | u8 | battery percent */ static void steam_do_battery_event(struct steam_device *steam, struct power_supply *battery, u8 *data) { … } static int steam_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { … } static int steam_param_set_lizard_mode(const char *val, const struct kernel_param *kp) { … } static const struct kernel_param_ops steam_lizard_mode_ops = …; module_param_cb(…); MODULE_PARM_DESC(…) …; static const struct hid_device_id steam_controllers[] = …; MODULE_DEVICE_TABLE(hid, steam_controllers); static struct hid_driver steam_controller_driver = …; module_hid_driver(…) …;