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

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

- support for Deck IMU in hid-steam (Max Maisel)
parents 47846941 3347e165
Loading
Loading
Loading
Loading
+147 −8
Original line number Diff line number Diff line
@@ -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: