99#include <linux/crc32.h>
1010#include <linux/device.h>
1111#include <linux/hid.h>
12+ #include <linux/idr.h>
1213#include <linux/input/mt.h>
1314#include <linux/module.h>
1415
2021static DEFINE_MUTEX (ps_devices_lock );
2122static LIST_HEAD (ps_devices_list );
2223
24+ static DEFINE_IDA (ps_player_id_allocator );
25+
2326#define HID_PLAYSTATION_VERSION_PATCH 0x8000
2427
2528/* Base class for playstation devices. */
@@ -28,6 +31,8 @@ struct ps_device {
2831 struct hid_device * hdev ;
2932 spinlock_t lock ;
3033
34+ uint32_t player_id ;
35+
3136 struct power_supply_desc battery_desc ;
3237 struct power_supply * battery ;
3338 uint8_t battery_capacity ;
@@ -108,6 +113,7 @@ struct ps_calibration_data {
108113#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1)
109114#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2)
110115#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
116+ #define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4)
111117#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
112118#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4)
113119#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
@@ -151,6 +157,11 @@ struct dualsense {
151157 bool mic_muted ;
152158 bool last_btn_mic_state ;
153159
160+ /* Player leds */
161+ bool update_player_leds ;
162+ uint8_t player_leds_state ;
163+ struct led_classdev player_leds [5 ];
164+
154165 struct work_struct output_worker ;
155166 void * output_report_dmabuf ;
156167 uint8_t output_seq ; /* Sequence number for output report. */
@@ -309,6 +320,24 @@ static int ps_devices_list_remove(struct ps_device *dev)
309320 return 0 ;
310321}
311322
323+ static int ps_device_set_player_id (struct ps_device * dev )
324+ {
325+ int ret = ida_alloc (& ps_player_id_allocator , GFP_KERNEL );
326+
327+ if (ret < 0 )
328+ return ret ;
329+
330+ dev -> player_id = ret ;
331+ return 0 ;
332+ }
333+
334+ static void ps_device_release_player_id (struct ps_device * dev )
335+ {
336+ ida_free (& ps_player_id_allocator , dev -> player_id );
337+
338+ dev -> player_id = U32_MAX ;
339+ }
340+
312341static struct input_dev * ps_allocate_input_dev (struct hid_device * hdev , const char * name_suffix )
313342{
314343 struct input_dev * input_dev ;
@@ -824,6 +853,13 @@ static void dualsense_output_worker(struct work_struct *work)
824853 ds -> update_lightbar = false;
825854 }
826855
856+ if (ds -> update_player_leds ) {
857+ common -> valid_flag1 |= DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE ;
858+ common -> player_leds = ds -> player_leds_state ;
859+
860+ ds -> update_player_leds = false;
861+ }
862+
827863 if (ds -> update_mic_mute ) {
828864 common -> valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE ;
829865 common -> mute_button_led = ds -> mic_muted ;
@@ -1078,6 +1114,29 @@ static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t gr
10781114 schedule_work (& ds -> output_worker );
10791115}
10801116
1117+ static void dualsense_set_player_leds (struct dualsense * ds )
1118+ {
1119+ /*
1120+ * The DualSense controller has a row of 5 LEDs used for player ids.
1121+ * Behavior on the PlayStation 5 console is to center the player id
1122+ * across the LEDs, so e.g. player 1 would be "--x--" with x being 'on'.
1123+ * Follow a similar mapping here.
1124+ */
1125+ static const int player_ids [5 ] = {
1126+ BIT (2 ),
1127+ BIT (3 ) | BIT (1 ),
1128+ BIT (4 ) | BIT (2 ) | BIT (0 ),
1129+ BIT (4 ) | BIT (3 ) | BIT (1 ) | BIT (0 ),
1130+ BIT (4 ) | BIT (3 ) | BIT (2 ) | BIT (1 ) | BIT (0 )
1131+ };
1132+
1133+ uint8_t player_id = ds -> base .player_id % ARRAY_SIZE (player_ids );
1134+
1135+ ds -> update_player_leds = true;
1136+ ds -> player_leds_state = player_ids [player_id ];
1137+ schedule_work (& ds -> output_worker );
1138+ }
1139+
10811140static struct ps_device * dualsense_create (struct hid_device * hdev )
10821141{
10831142 struct dualsense * ds ;
@@ -1166,6 +1225,15 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
11661225
11671226 dualsense_set_lightbar (ds , 0 , 0 , 128 ); /* blue */
11681227
1228+ ret = ps_device_set_player_id (ps_dev );
1229+ if (ret ) {
1230+ hid_err (hdev , "Failed to assign player id for DualSense: %d\n" , ret );
1231+ goto err ;
1232+ }
1233+
1234+ /* Set player LEDs to our player id. */
1235+ dualsense_set_player_leds (ds );
1236+
11691237 /*
11701238 * Reporting hardware and firmware is important as there are frequent updates, which
11711239 * can change behavior.
@@ -1243,6 +1311,7 @@ static void ps_remove(struct hid_device *hdev)
12431311 struct ps_device * dev = hid_get_drvdata (hdev );
12441312
12451313 ps_devices_list_remove (dev );
1314+ ps_device_release_player_id (dev );
12461315
12471316 hid_hw_close (hdev );
12481317 hid_hw_stop (hdev );
@@ -1263,7 +1332,19 @@ static struct hid_driver ps_driver = {
12631332 .raw_event = ps_raw_event ,
12641333};
12651334
1266- module_hid_driver (ps_driver );
1335+ static int __init ps_init (void )
1336+ {
1337+ return hid_register_driver (& ps_driver );
1338+ }
1339+
1340+ static void __exit ps_exit (void )
1341+ {
1342+ hid_unregister_driver (& ps_driver );
1343+ ida_destroy (& ps_player_id_allocator );
1344+ }
1345+
1346+ module_init (ps_init );
1347+ module_exit (ps_exit );
12671348
12681349MODULE_AUTHOR ("Sony Interactive Entertainment" );
12691350MODULE_DESCRIPTION ("HID Driver for PlayStation peripherals." );
0 commit comments