diff options
author | Roderick Colenbrander | 2021-02-16 14:26:35 -0800 |
---|---|---|
committer | Benjamin Tissoires | 2021-02-18 17:41:51 +0100 |
commit | 8e5198a12d6416f0a1e9393bdb3a533854ed577b (patch) | |
tree | ec6b2958b1a16a940fb85df3ec6d227a1a4b3f43 /drivers/hid | |
parent | 50ab1ffd7c41c5c7759b62fb42d3006b751bb12b (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')
-rw-r--r-- | drivers/hid/hid-playstation.c | 65 |
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. */ |