@@ -34,6 +34,8 @@ struct ps_device {
3434 int battery_status ;
3535
3636 uint8_t mac_address [6 ]; /* Note: stored in little endian order. */
37+ uint32_t hw_version ;
38+ uint32_t fw_version ;
3739
3840 int (* parse_report )(struct ps_device * dev , struct hid_report * report , u8 * data , int size );
3941};
@@ -64,6 +66,8 @@ struct ps_calibration_data {
6466#define DS_FEATURE_REPORT_CALIBRATION_SIZE 41
6567#define DS_FEATURE_REPORT_PAIRING_INFO 0x09
6668#define DS_FEATURE_REPORT_PAIRING_INFO_SIZE 20
69+ #define DS_FEATURE_REPORT_FIRMWARE_INFO 0x20
70+ #define DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE 64
6771
6872/* Button masks for DualSense input report. */
6973#define DS_BUTTONS0_HAT_SWITCH GENMASK(3, 0)
@@ -538,6 +542,40 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width,
538542 return touchpad ;
539543}
540544
545+ static ssize_t firmware_version_show (struct device * dev ,
546+ struct device_attribute
547+ * attr , char * buf )
548+ {
549+ struct hid_device * hdev = to_hid_device (dev );
550+ struct ps_device * ps_dev = hid_get_drvdata (hdev );
551+
552+ return sysfs_emit (buf , "0x%08x\n" , ps_dev -> fw_version );
553+ }
554+
555+ static DEVICE_ATTR_RO (firmware_version );
556+
557+ static ssize_t hardware_version_show (struct device * dev ,
558+ struct device_attribute
559+ * attr , char * buf )
560+ {
561+ struct hid_device * hdev = to_hid_device (dev );
562+ struct ps_device * ps_dev = hid_get_drvdata (hdev );
563+
564+ return sysfs_emit (buf , "0x%08x\n" , ps_dev -> hw_version );
565+ }
566+
567+ static DEVICE_ATTR_RO (hardware_version );
568+
569+ static struct attribute * ps_device_attributes [] = {
570+ & dev_attr_firmware_version .attr ,
571+ & dev_attr_hardware_version .attr ,
572+ NULL
573+ };
574+
575+ static const struct attribute_group ps_device_attribute_group = {
576+ .attrs = ps_device_attributes ,
577+ };
578+
541579static int dualsense_get_calibration_data (struct dualsense * ds )
542580{
543581 short gyro_pitch_bias , gyro_pitch_plus , gyro_pitch_minus ;
@@ -628,6 +666,30 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
628666 return ret ;
629667}
630668
669+ static int dualsense_get_firmware_info (struct dualsense * ds )
670+ {
671+ uint8_t * buf ;
672+ int ret ;
673+
674+ buf = kzalloc (DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE , GFP_KERNEL );
675+ if (!buf )
676+ return - ENOMEM ;
677+
678+ ret = ps_get_report (ds -> base .hdev , DS_FEATURE_REPORT_FIRMWARE_INFO , buf ,
679+ DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE );
680+ if (ret ) {
681+ hid_err (ds -> base .hdev , "Failed to retrieve DualSense firmware info: %d\n" , ret );
682+ goto err_free ;
683+ }
684+
685+ ds -> base .hw_version = get_unaligned_le32 (& buf [24 ]);
686+ ds -> base .fw_version = get_unaligned_le32 (& buf [28 ]);
687+
688+ err_free :
689+ kfree (buf );
690+ return ret ;
691+ }
692+
631693static int dualsense_get_mac_address (struct dualsense * ds )
632694{
633695 uint8_t * buf ;
@@ -956,6 +1018,12 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
9561018 }
9571019 snprintf (hdev -> uniq , sizeof (hdev -> uniq ), "%pMR" , ds -> base .mac_address );
9581020
1021+ ret = dualsense_get_firmware_info (ds );
1022+ if (ret ) {
1023+ hid_err (hdev , "Failed to get firmware info from DualSense\n" );
1024+ return ERR_PTR (ret );
1025+ }
1026+
9591027 ret = ps_devices_list_add (ps_dev );
9601028 if (ret )
9611029 return ERR_PTR (ret );
@@ -989,6 +1057,13 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
9891057 if (ret )
9901058 goto err ;
9911059
1060+ /*
1061+ * Reporting hardware and firmware is important as there are frequent updates, which
1062+ * can change behavior.
1063+ */
1064+ hid_info (hdev , "Registered DualSense controller hw_version=0x%08x fw_version=0x%08x\n" ,
1065+ ds -> base .hw_version , ds -> base .fw_version );
1066+
9921067 return & ds -> base ;
9931068
9941069err :
@@ -1039,6 +1114,12 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
10391114 }
10401115 }
10411116
1117+ ret = devm_device_add_group (& hdev -> dev , & ps_device_attribute_group );
1118+ if (ret ) {
1119+ hid_err (hdev , "Failed to register sysfs nodes.\n" );
1120+ goto err_close ;
1121+ }
1122+
10421123 return ret ;
10431124
10441125err_close :
0 commit comments