Commit 55b04252 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-6.10/steam' into for-linus

- support for Deck IMU in hid-steam (Max Maisel)
parents 47846941 3347e165
......@@ -66,6 +66,14 @@ static LIST_HEAD(steam_devices);
#define STEAM_DECK_TRIGGER_RESOLUTION 5461
/* Joystick runs are about 5 mm and 32768 units */
#define STEAM_DECK_JOYSTICK_RESOLUTION 6553
/* Accelerometer has 16 bit resolution and a range of +/- 2g */
#define STEAM_DECK_ACCEL_RES_PER_G 16384
#define STEAM_DECK_ACCEL_RANGE 32768
#define STEAM_DECK_ACCEL_FUZZ 32
/* Gyroscope has 16 bit resolution and a range of +/- 2000 dps */
#define STEAM_DECK_GYRO_RES_PER_DPS 16
#define STEAM_DECK_GYRO_RANGE 32768
#define STEAM_DECK_GYRO_FUZZ 1
#define STEAM_PAD_FUZZ 256
......@@ -288,6 +296,7 @@ struct steam_device {
struct mutex report_mutex;
unsigned long client_opened;
struct input_dev __rcu *input;
struct input_dev __rcu *sensors;
unsigned long quirks;
struct work_struct work_connect;
bool connected;
......@@ -302,6 +311,7 @@ struct steam_device {
struct work_struct rumble_work;
u16 rumble_left;
u16 rumble_right;
unsigned int sensor_timestamp_us;
};
static int steam_recv_report(struct steam_device *steam,
......@@ -825,6 +835,74 @@ static int steam_input_register(struct steam_device *steam)
return ret;
}
static int steam_sensors_register(struct steam_device *steam)
{
struct hid_device *hdev = steam->hdev;
struct input_dev *sensors;
int ret;
if (!(steam->quirks & STEAM_QUIRK_DECK))
return 0;
rcu_read_lock();
sensors = rcu_dereference(steam->sensors);
rcu_read_unlock();
if (sensors) {
dbg_hid("%s: already connected\n", __func__);
return 0;
}
sensors = input_allocate_device();
if (!sensors)
return -ENOMEM;
input_set_drvdata(sensors, steam);
sensors->dev.parent = &hdev->dev;
sensors->name = "Steam Deck Motion Sensors";
sensors->phys = hdev->phys;
sensors->uniq = steam->serial_no;
sensors->id.bustype = hdev->bus;
sensors->id.vendor = hdev->vendor;
sensors->id.product = hdev->product;
sensors->id.version = hdev->version;
__set_bit(INPUT_PROP_ACCELEROMETER, sensors->propbit);
__set_bit(EV_MSC, sensors->evbit);
__set_bit(MSC_TIMESTAMP, sensors->mscbit);
input_set_abs_params(sensors, ABS_X, -STEAM_DECK_ACCEL_RANGE,
STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0);
input_set_abs_params(sensors, ABS_Y, -STEAM_DECK_ACCEL_RANGE,
STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0);
input_set_abs_params(sensors, ABS_Z, -STEAM_DECK_ACCEL_RANGE,
STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0);
input_abs_set_res(sensors, ABS_X, STEAM_DECK_ACCEL_RES_PER_G);
input_abs_set_res(sensors, ABS_Y, STEAM_DECK_ACCEL_RES_PER_G);
input_abs_set_res(sensors, ABS_Z, STEAM_DECK_ACCEL_RES_PER_G);
input_set_abs_params(sensors, ABS_RX, -STEAM_DECK_GYRO_RANGE,
STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0);
input_set_abs_params(sensors, ABS_RY, -STEAM_DECK_GYRO_RANGE,
STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0);
input_set_abs_params(sensors, ABS_RZ, -STEAM_DECK_GYRO_RANGE,
STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0);
input_abs_set_res(sensors, ABS_RX, STEAM_DECK_GYRO_RES_PER_DPS);
input_abs_set_res(sensors, ABS_RY, STEAM_DECK_GYRO_RES_PER_DPS);
input_abs_set_res(sensors, ABS_RZ, STEAM_DECK_GYRO_RES_PER_DPS);
ret = input_register_device(sensors);
if (ret)
goto sensors_register_fail;
rcu_assign_pointer(steam->sensors, sensors);
return 0;
sensors_register_fail:
input_free_device(sensors);
return ret;
}
static void steam_input_unregister(struct steam_device *steam)
{
struct input_dev *input;
......@@ -838,6 +916,24 @@ static void steam_input_unregister(struct steam_device *steam)
input_unregister_device(input);
}
static void steam_sensors_unregister(struct steam_device *steam)
{
struct input_dev *sensors;
if (!(steam->quirks & STEAM_QUIRK_DECK))
return;
rcu_read_lock();
sensors = rcu_dereference(steam->sensors);
rcu_read_unlock();
if (!sensors)
return;
RCU_INIT_POINTER(steam->sensors, NULL);
synchronize_rcu();
input_unregister_device(sensors);
}
static void steam_battery_unregister(struct steam_device *steam)
{
struct power_supply *battery;
......@@ -890,18 +986,28 @@ static int steam_register(struct steam_device *steam)
spin_lock_irqsave(&steam->lock, flags);
client_opened = steam->client_opened;
spin_unlock_irqrestore(&steam->lock, flags);
if (!client_opened) {
steam_set_lizard_mode(steam, lizard_mode);
ret = steam_input_register(steam);
} else
ret = 0;
if (ret != 0)
goto steam_register_input_fail;
ret = steam_sensors_register(steam);
if (ret != 0)
goto steam_register_sensors_fail;
}
return 0;
steam_register_sensors_fail:
steam_input_unregister(steam);
steam_register_input_fail:
return ret;
}
static void steam_unregister(struct steam_device *steam)
{
steam_battery_unregister(steam);
steam_sensors_unregister(steam);
steam_input_unregister(steam);
if (steam->serial_no[0]) {
hid_info(steam->hdev, "Steam Controller '%s' disconnected",
......@@ -1010,6 +1116,7 @@ static int steam_client_ll_open(struct hid_device *hdev)
steam->client_opened++;
spin_unlock_irqrestore(&steam->lock, flags);
steam_sensors_unregister(steam);
steam_input_unregister(steam);
return 0;
......@@ -1030,6 +1137,7 @@ static void steam_client_ll_close(struct hid_device *hdev)
if (connected) {
steam_set_lizard_mode(steam, lizard_mode);
steam_input_register(steam);
steam_sensors_register(steam);
}
}
......@@ -1121,6 +1229,7 @@ static int steam_probe(struct hid_device *hdev,
INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb);
INIT_LIST_HEAD(&steam->list);
INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
steam->sensor_timestamp_us = 0;
/*
* With the real steam controller interface, do not connect hidraw.
......@@ -1380,12 +1489,12 @@ static void steam_do_input_event(struct steam_device *steam,
* 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 | -- | accelerometer X value
* 26-27 | s16 | -- | accelerometer Y value
* 28-29 | s16 | -- | accelerometer Z value
* 30-31 | s16 | -- | gyro X value
* 32-33 | s16 | -- | gyro Y value
* 34-35 | s16 | -- | gyro Z 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
......@@ -1546,6 +1655,32 @@ static void steam_do_deck_input_event(struct steam_device *steam,
input_sync(input);
}
static void steam_do_deck_sensors_event(struct steam_device *steam,
struct input_dev *sensors, u8 *data)
{
/*
* The deck input report is received every 4 ms on average,
* with a jitter of +/- 4 ms even though the USB descriptor claims
* that it uses 1 kHz.
* Since the HID report does not include a sensor timestamp,
* use a fixed increment here.
*/
steam->sensor_timestamp_us += 4000;
if (!steam->gamepad_mode)
return;
input_event(sensors, EV_MSC, MSC_TIMESTAMP, steam->sensor_timestamp_us);
input_report_abs(sensors, ABS_X, steam_le16(data + 24));
input_report_abs(sensors, ABS_Z, -steam_le16(data + 26));
input_report_abs(sensors, ABS_Y, steam_le16(data + 28));
input_report_abs(sensors, ABS_RX, steam_le16(data + 30));
input_report_abs(sensors, ABS_RZ, -steam_le16(data + 32));
input_report_abs(sensors, ABS_RY, steam_le16(data + 34));
input_sync(sensors);
}
/*
* The size for this message payload is 11.
* The known values are:
......@@ -1583,6 +1718,7 @@ static int steam_raw_event(struct hid_device *hdev,
{
struct steam_device *steam = hid_get_drvdata(hdev);
struct input_dev *input;
struct input_dev *sensors;
struct power_supply *battery;
if (!steam)
......@@ -1628,6 +1764,9 @@ static int steam_raw_event(struct hid_device *hdev,
input = rcu_dereference(steam->input);
if (likely(input))
steam_do_deck_input_event(steam, input, data);
sensors = rcu_dereference(steam->sensors);
if (likely(sensors))
steam_do_deck_sensors_event(steam, sensors, data);
rcu_read_unlock();
break;
case ID_CONTROLLER_WIRELESS:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment