summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-playstation.c
diff options
context:
space:
mode:
authorRoderick Colenbrander <roderick.colenbrander@sony.com>2021-02-16 14:26:35 -0800
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2021-02-18 17:41:51 +0100
commit8e5198a12d6416f0a1e9393bdb3a533854ed577b (patch)
treeec6b2958b1a16a940fb85df3ec6d227a1a4b3f43 /drivers/hid/hid-playstation.c
parent50ab1ffd7c41c5c7759b62fb42d3006b751bb12b (diff)
HID: playstation: add initial DualSense lightbar support.
Provide initial support for the DualSense lightbar and configure it with a default PlayStation blue color. Signed-off-by: Roderick Colenbrander <roderick.colenbrander@sony.com> Reviewed-by: Barnabás Pőcze <pobrn@protonmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Diffstat (limited to 'drivers/hid/hid-playstation.c')
-rw-r--r--drivers/hid/hid-playstation.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index 3b6f42155e21..cbd5da28de63 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -103,6 +103,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)
/* DualSense hardware limits */
#define DS_ACC_RES_PER_G 8192
@@ -132,6 +136,12 @@ struct dualsense {
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. */
@@ -796,6 +806,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);
@@ -980,6 +999,41 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
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;
@@ -1058,6 +1112,17 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
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.
*/