@@ -56,6 +56,13 @@ struct ps_calibration_data {
5656 int sens_denom ;
5757};
5858
59+ struct ps_led_info {
60+ const char * name ;
61+ const char * color ;
62+ enum led_brightness (* brightness_get )(struct led_classdev * cdev );
63+ int (* brightness_set )(struct led_classdev * cdev , enum led_brightness );
64+ };
65+
5966/* Seed values for DualShock4 / DualSense CRC32 for different report types. */
6067#define PS_INPUT_CRC32_SEED 0xA1
6168#define PS_OUTPUT_CRC32_SEED 0xA2
@@ -531,6 +538,32 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu
531538 return 0 ;
532539}
533540
541+ static int ps_led_register (struct ps_device * ps_dev , struct led_classdev * led ,
542+ const struct ps_led_info * led_info )
543+ {
544+ int ret ;
545+
546+ led -> name = devm_kasprintf (& ps_dev -> hdev -> dev , GFP_KERNEL ,
547+ "%s:%s:%s" , ps_dev -> input_dev_name , led_info -> color , led_info -> name );
548+
549+ if (!led -> name )
550+ return - ENOMEM ;
551+
552+ led -> brightness = 0 ;
553+ led -> max_brightness = 1 ;
554+ led -> flags = LED_CORE_SUSPENDRESUME ;
555+ led -> brightness_get = led_info -> brightness_get ;
556+ led -> brightness_set_blocking = led_info -> brightness_set ;
557+
558+ ret = devm_led_classdev_register (& ps_dev -> hdev -> dev , led );
559+ if (ret ) {
560+ hid_err (ps_dev -> hdev , "Failed to register LED %s: %d\n" , led_info -> name , ret );
561+ return ret ;
562+ }
563+
564+ return 0 ;
565+ }
566+
534567/* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */
535568static int ps_lightbar_register (struct ps_device * ps_dev , struct led_classdev_mc * lightbar_mc_dev ,
536569 int (* brightness_set )(struct led_classdev * , enum led_brightness ))
@@ -822,6 +855,35 @@ static int dualsense_lightbar_set_brightness(struct led_classdev *cdev,
822855 return 0 ;
823856}
824857
858+ static enum led_brightness dualsense_player_led_get_brightness (struct led_classdev * led )
859+ {
860+ struct hid_device * hdev = to_hid_device (led -> dev -> parent );
861+ struct dualsense * ds = hid_get_drvdata (hdev );
862+
863+ return !!(ds -> player_leds_state & BIT (led - ds -> player_leds ));
864+ }
865+
866+ static int dualsense_player_led_set_brightness (struct led_classdev * led , enum led_brightness value )
867+ {
868+ struct hid_device * hdev = to_hid_device (led -> dev -> parent );
869+ struct dualsense * ds = hid_get_drvdata (hdev );
870+ unsigned long flags ;
871+ unsigned int led_index ;
872+
873+ spin_lock_irqsave (& ds -> base .lock , flags );
874+
875+ led_index = led - ds -> player_leds ;
876+ if (value == LED_OFF )
877+ ds -> player_leds_state &= ~BIT (led_index );
878+ else
879+ ds -> player_leds_state |= BIT (led_index );
880+
881+ ds -> update_player_leds = true;
882+ spin_unlock_irqrestore (& ds -> base .lock , flags );
883+
884+ schedule_work (& ds -> output_worker );
885+ }
886+
825887static void dualsense_init_output_report (struct dualsense * ds , struct dualsense_output_report * rp ,
826888 void * buf )
827889{
@@ -1207,7 +1269,20 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
12071269 struct dualsense * ds ;
12081270 struct ps_device * ps_dev ;
12091271 uint8_t max_output_report_size ;
1210- int ret ;
1272+ int i , ret ;
1273+
1274+ static const struct ps_led_info player_leds_info [] = {
1275+ { LED_FUNCTION_PLAYER1 , "white" , dualsense_player_led_get_brightness ,
1276+ dualsense_player_led_set_brightness },
1277+ { LED_FUNCTION_PLAYER2 , "white" , dualsense_player_led_get_brightness ,
1278+ dualsense_player_led_set_brightness },
1279+ { LED_FUNCTION_PLAYER3 , "white" , dualsense_player_led_get_brightness ,
1280+ dualsense_player_led_set_brightness },
1281+ { LED_FUNCTION_PLAYER4 , "white" , dualsense_player_led_get_brightness ,
1282+ dualsense_player_led_set_brightness },
1283+ { LED_FUNCTION_PLAYER5 , "white" , dualsense_player_led_get_brightness ,
1284+ dualsense_player_led_set_brightness }
1285+ };
12111286
12121287 ds = devm_kzalloc (& hdev -> dev , sizeof (* ds ), GFP_KERNEL );
12131288 if (!ds )
@@ -1297,6 +1372,14 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
12971372 /* Set default lightbar color. */
12981373 dualsense_set_lightbar (ds , 0 , 0 , 128 ); /* blue */
12991374
1375+ for (i = 0 ; i < ARRAY_SIZE (player_leds_info ); i ++ ) {
1376+ const struct ps_led_info * led_info = & player_leds_info [i ];
1377+
1378+ ret = ps_led_register (ps_dev , & ds -> player_leds [i ], led_info );
1379+ if (ret < 0 )
1380+ goto err ;
1381+ }
1382+
13001383 ret = ps_device_set_player_id (ps_dev );
13011384 if (ret ) {
13021385 hid_err (hdev , "Failed to assign player id for DualSense: %d\n" , ret );
0 commit comments