// SPDX-License-Identifier: GPL-2.0+
/*
* HID driver for Valve Steam Controller
*
* Copyright (c) 2018 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
*
* 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_LICENSE("GPL");
MODULE_AUTHOR("Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>");
static bool lizard_mode = true;
static DEFINE_MUTEX(steam_devices_lock);
static LIST_HEAD(steam_devices);
#define STEAM_QUIRK_WIRELESS BIT(0)
/* Touch pads are 40 mm in diameter and 65535 units */
#define STEAM_PAD_RESOLUTION 1638
/* Trigger runs are about 5 mm and 256 units */
#define STEAM_TRIGGER_RESOLUTION 51
/* Joystick runs are about 5 mm and 256 units */
#define STEAM_JOYSTICK_RESOLUTION 51
#define STEAM_PAD_FUZZ 256
/*
* Commands that can be sent in a feature report.
* Thanks to Valve for some valuable hints.
*/
#define STEAM_CMD_SET_MAPPINGS 0x80
#define STEAM_CMD_CLEAR_MAPPINGS 0x81
#define STEAM_CMD_GET_MAPPINGS 0x82
#define STEAM_CMD_GET_ATTRIB 0x83
#define STEAM_CMD_GET_ATTRIB_LABEL 0x84
#define STEAM_CMD_DEFAULT_MAPPINGS 0x85
#define STEAM_CMD_FACTORY_RESET 0x86
#define STEAM_CMD_WRITE_REGISTER 0x87
#define STEAM_CMD_CLEAR_REGISTER 0x88
#define STEAM_CMD_READ_REGISTER 0x89
#define STEAM_CMD_GET_REGISTER_LABEL 0x8a
#define STEAM_CMD_GET_REGISTER_MAX 0x8b
#define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c
#define STEAM_CMD_SET_MODE 0x8d
#define STEAM_CMD_DEFAULT_MOUSE 0x8e
#define STEAM_CMD_FORCEFEEDBAK 0x8f
#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
#define STEAM_CMD_GET_SERIAL 0xae
/* Some useful register ids */
#define STEAM_REG_LPAD_MODE 0x07
#define STEAM_REG_RPAD_MODE 0x08
#define STEAM_REG_RPAD_MARGIN 0x18
#define STEAM_REG_LED 0x2d
#define STEAM_REG_GYRO_MODE 0x30
/* Raw event identifiers */
#define STEAM_EV_INPUT_DATA 0x01
#define STEAM_EV_CONNECT 0x03
#define STEAM_EV_BATTERY 0x04
/* Values for GYRO_MODE (bitmask) */
#define STEAM_GYRO_MODE_OFF 0x0000
#define STEAM_GYRO_MODE_STEERING 0x0001
#define STEAM_GYRO_MODE_TILT 0x0002
#define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004
#define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008
#define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010
/* Other random constants */
#define STEAM_SERIAL_LEN 10
struct steam_device {
struct list_head list;
spinlock_t lock;
struct hid_device *hdev, *client_hdev;
struct mutex mutex;
bool client_opened;
struct input_dev __rcu *input;
unsigned long quirks;
struct work_struct work_connect;
bool connected;
char serial_no[STEAM_SERIAL_LEN + 1];
struct power_supply_desc battery_desc;
struct power_supply __rcu *battery;
u8 battery_charge;
u16 voltage;
};
static int steam_recv_report(struct steam_device *steam,
u8 *data, int size)
{
struct hid_report *r;
u8 *buf;
int ret;
r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
if (hid_report_len(r) < 64)
return -EINVAL;
buf = hid_alloc_report_buf(r, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/*
* The report ID is always 0, so strip the first byte from the output.
* hid_report_len() is not counting the report ID, so +1 to the length
* or else we get a EOVERFLOW. We are safe from a buffer overflow
* because hid_alloc_report_buf() allocates +7 bytes.
*/
ret = hid_hw_raw_request(steam->hdev, 0x00,
buf, hid_report_len(r) + 1,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret > 0)
memcpy(data, buf + 1, min(size, ret - 1));
kfree(buf);
return ret;
}
static int steam_send_report(struct steam_device *steam,
u8 *cmd, int size)
{
struct hid_report *r;
u8 *buf;
unsigned int retries = 50;
int ret;
r = steam->hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0];
if (hid_report_len(r) < 64)
return -EINVAL;
buf = hid_alloc_report_buf(r, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* The report ID is always 0 */
memcpy(buf + 1, cmd, size);
/*
* Sometimes the wireless controller fails with EPIPE
* when sending a feature report.
* Doing a HID_REQ_GET_REPORT and waiting for a while
* seems to fix that.
*/
do {
ret = hid_hw_raw_request(steam->hdev, 0,
buf, size + 1,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EPIPE)
break;
msleep(20);
} while (--retries);
kfree(buf);
if (ret < 0)
hid_err(steam->hdev, "%s: error %d (%*ph)\n", __func__,
ret, size, cmd);
return ret;
}
static