@@ -103,6 +103,10 @@ struct ps_calibration_data {
103103/* Flags for DualSense output report. */
104104#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0)
105105#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1)
106+ #define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2)
107+ #define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
108+ #define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
109+ #define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
106110
107111/* DualSense hardware limits */
108112#define DS_ACC_RES_PER_G 8192
@@ -132,6 +136,12 @@ struct dualsense {
132136 uint8_t motor_left ;
133137 uint8_t motor_right ;
134138
139+ /* RGB lightbar */
140+ bool update_lightbar ;
141+ uint8_t lightbar_red ;
142+ uint8_t lightbar_green ;
143+ uint8_t lightbar_blue ;
144+
135145 struct work_struct output_worker ;
136146 void * output_report_dmabuf ;
137147 uint8_t output_seq ; /* Sequence number for output report. */
@@ -796,6 +806,15 @@ static void dualsense_output_worker(struct work_struct *work)
796806 ds -> update_rumble = false;
797807 }
798808
809+ if (ds -> update_lightbar ) {
810+ common -> valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE ;
811+ common -> lightbar_red = ds -> lightbar_red ;
812+ common -> lightbar_green = ds -> lightbar_green ;
813+ common -> lightbar_blue = ds -> lightbar_blue ;
814+
815+ ds -> update_lightbar = false;
816+ }
817+
799818 spin_unlock_irqrestore (& ds -> base .lock , flags );
800819
801820 dualsense_send_output_report (ds , & report );
@@ -980,6 +999,41 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
980999 return 0 ;
9811000}
9821001
1002+ static int dualsense_reset_leds (struct dualsense * ds )
1003+ {
1004+ struct dualsense_output_report report ;
1005+ uint8_t * buf ;
1006+
1007+ buf = kzalloc (sizeof (struct dualsense_output_report_bt ), GFP_KERNEL );
1008+ if (!buf )
1009+ return - ENOMEM ;
1010+
1011+ dualsense_init_output_report (ds , & report , buf );
1012+ /*
1013+ * On Bluetooth the DualSense outputs an animation on the lightbar
1014+ * during startup and maintains a color afterwards. We need to explicitly
1015+ * reconfigure the lightbar before we can do any programming later on.
1016+ * In USB the lightbar is not on by default, but redoing the setup there
1017+ * doesn't hurt.
1018+ */
1019+ report .common -> valid_flag2 = DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE ;
1020+ report .common -> lightbar_setup = DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT ; /* Fade light out. */
1021+ dualsense_send_output_report (ds , & report );
1022+
1023+ kfree (buf );
1024+ return 0 ;
1025+ }
1026+
1027+ static void dualsense_set_lightbar (struct dualsense * ds , uint8_t red , uint8_t green , uint8_t blue )
1028+ {
1029+ ds -> update_lightbar = true;
1030+ ds -> lightbar_red = red ;
1031+ ds -> lightbar_green = green ;
1032+ ds -> lightbar_blue = blue ;
1033+
1034+ schedule_work (& ds -> output_worker );
1035+ }
1036+
9831037static struct ps_device * dualsense_create (struct hid_device * hdev )
9841038{
9851039 struct dualsense * ds ;
@@ -1057,6 +1111,17 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
10571111 if (ret )
10581112 goto err ;
10591113
1114+ /*
1115+ * The hardware may have control over the LEDs (e.g. in Bluetooth on startup).
1116+ * Reset the LEDs (lightbar, mute, player leds), so we can control them
1117+ * from software.
1118+ */
1119+ ret = dualsense_reset_leds (ds );
1120+ if (ret )
1121+ goto err ;
1122+
1123+ dualsense_set_lightbar (ds , 0 , 0 , 128 ); /* blue */
1124+
10601125 /*
10611126 * Reporting hardware and firmware is important as there are frequent updates, which
10621127 * can change behavior.
0 commit comments