mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 10:26:09 +00:00
Merge branch 'for-6.10/steam' into for-linus
- support for Deck IMU in hid-steam (Max Maisel)
This commit is contained in:
commit
55b04252dc
@ -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 @@ input_register_fail:
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user