Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 85f00312 authored by Roderick Colenbrander's avatar Roderick Colenbrander Committed by Kishor Krishna Bhat
Browse files

UPSTREAM: HID: playstation: Add initial DualSense lightbar support



Provide initial support for the DualSense lightbar and configure it
with a default Playstation blue color.

Bug: 167947264
CRs-fixed: 2971837
Change-Id: I4f5a78e20b2e11c68e67c539b9c21197e42a722f
Signed-off-by: default avatarRoderick Colenbrander <roderick.colenbrander@sony.com>
Reviewed-by: default avatarBarnabás Pőcze <pobrn@protonmail.com>
Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarFarid Chahla <farid.chahla@sony.com>
Signed-off-by: default avatarSiarhei Vishniakou <svv@google.com>
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git


Git-commit: 8e5198a12d6416f0a1e9393bdb3a533854ed577b
Signed-off-by: default avatarKishor Krishna Bhat <kishkris@codeaurora.org>
parent 3f3217de
Loading
Loading
Loading
Loading
+66 −0
Original line number Diff line number Diff line
@@ -102,6 +102,10 @@ struct ps_calibration_data {
/* Flags for DualSense output report. */
#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0)
#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1)
#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2)
#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)

#define DS_ACC_RES_PER_G       8192
#define DS_ACC_RANGE           (4*DS_ACC_RES_PER_G)
@@ -130,6 +134,13 @@ struct dualsense {
	bool update_rumble;
	uint8_t motor_left;
	uint8_t motor_right;

	/* RGB lightbar */
	bool update_lightbar;
	uint8_t lightbar_red;
	uint8_t lightbar_green;
	uint8_t lightbar_blue;

	struct work_struct output_worker;
	void *output_report_dmabuf;
	uint8_t output_seq; /* Sequence number for output report. */
@@ -797,6 +808,15 @@ static void dualsense_output_worker(struct work_struct *work)
		ds->update_rumble = false;
	}

	if (ds->update_lightbar) {
		common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE;
		common->lightbar_red = ds->lightbar_red;
		common->lightbar_green = ds->lightbar_green;
		common->lightbar_blue = ds->lightbar_blue;

		ds->update_lightbar = false;
	}

	spin_unlock_irqrestore(&ds->base.lock, flags);

	dualsense_send_output_report(ds, &report);
@@ -990,6 +1010,41 @@ static int dualsense_play_effect(struct input_dev *dev,
	return 0;
}

static int dualsense_reset_leds(struct dualsense *ds)
{
	struct dualsense_output_report report;
	uint8_t *buf;

	buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	dualsense_init_output_report(ds, &report, buf);
	/*
	 * On Bluetooth the DualSense outputs an animation on the lightbar
	 * during startup and maintains a color afterwards. We need to explicitly
	 * reconfigure the lightbar before we can do any programming later on.
	 * In USB the lightbar is not on by default, but redoing the setup there
	 * doesn't hurt.
	 */
	report.common->valid_flag2 = DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE;
	report.common->lightbar_setup = DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT; /* Fade light out. */
	dualsense_send_output_report(ds, &report);

	kfree(buf);
	return 0;
}

static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue)
{
	ds->update_lightbar = true;
	ds->lightbar_red = red;
	ds->lightbar_green = green;
	ds->lightbar_blue = blue;

	schedule_work(&ds->output_worker);
}

static struct ps_device *dualsense_create(struct hid_device *hdev)
{
	struct dualsense *ds;
@@ -1069,6 +1124,17 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
	if (ret)
		goto err;

	/*
	 * The hardware may have control over the LEDs (e.g. in Bluetooth on startup).
	 * Reset the LEDs (lightbar, mute, player leds), so we can control them
	 * from software.
	 */
	ret = dualsense_reset_leds(ds);
	if (ret)
		goto err;

	dualsense_set_lightbar(ds, 0, 0, 128); /* blue */

	/*
	 * Reporting hardware and firmware is important as there are frequent updates, which
	 * can change behavior.