linux/drivers/hid/hid-steam.c

// 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();