@@ -108,6 +108,9 @@ struct ps_led_info {
108108#define DS_STATUS_CHARGING GENMASK(7, 4)
109109#define DS_STATUS_CHARGING_SHIFT 4
110110
111+ /* Feature version from DualSense Firmware Info report. */
112+ #define DS_FEATURE_VERSION (major , minor ) ((major & 0xff) << 8 | (minor & 0xff))
113+
111114/*
112115 * Status of a DualSense touch point contact.
113116 * Contact IDs, with highest bit set are 'inactive'
@@ -126,6 +129,7 @@ struct ps_led_info {
126129#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
127130#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4)
128131#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
132+ #define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2)
129133#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4)
130134#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
131135
@@ -143,6 +147,9 @@ struct dualsense {
143147 struct input_dev * sensors ;
144148 struct input_dev * touchpad ;
145149
150+ /* Update version is used as a feature/capability version. */
151+ uint16_t update_version ;
152+
146153 /* Calibration data for accelerometer and gyroscope. */
147154 struct ps_calibration_data accel_calib_data [3 ];
148155 struct ps_calibration_data gyro_calib_data [3 ];
@@ -153,6 +160,7 @@ struct dualsense {
153160 uint32_t sensor_timestamp_us ;
154161
155162 /* Compatible rumble state */
163+ bool use_vibration_v2 ;
156164 bool update_rumble ;
157165 uint8_t motor_left ;
158166 uint8_t motor_right ;
@@ -812,6 +820,15 @@ static int dualsense_get_firmware_info(struct dualsense *ds)
812820 ds -> base .hw_version = get_unaligned_le32 (& buf [24 ]);
813821 ds -> base .fw_version = get_unaligned_le32 (& buf [28 ]);
814822
823+ /* Update version is some kind of feature version. It is distinct from
824+ * the firmware version as there can be many different variations of a
825+ * controller over time with the same physical shell, but with different
826+ * PCBs and other internal changes. The update version (internal name) is
827+ * used as a means to detect what features are available and change behavior.
828+ * Note: the version is different between DualSense and DualSense Edge.
829+ */
830+ ds -> update_version = get_unaligned_le16 (& buf [44 ]);
831+
815832err_free :
816833 kfree (buf );
817834 return ret ;
@@ -974,7 +991,10 @@ static void dualsense_output_worker(struct work_struct *work)
974991 if (ds -> update_rumble ) {
975992 /* Select classic rumble style haptics and enable it. */
976993 common -> valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT ;
977- common -> valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION ;
994+ if (ds -> use_vibration_v2 )
995+ common -> valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 ;
996+ else
997+ common -> valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION ;
978998 common -> motor_left = ds -> motor_left ;
979999 common -> motor_right = ds -> motor_right ;
9801000 ds -> update_rumble = false;
@@ -1348,6 +1368,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
13481368 return ERR_PTR (ret );
13491369 }
13501370
1371+ /* Original DualSense firmware simulated classic controller rumble through
1372+ * its new haptics hardware. It felt different from classic rumble users
1373+ * were used to. Since then new firmwares were introduced to change behavior
1374+ * and make this new 'v2' behavior default on PlayStation and other platforms.
1375+ * The original DualSense requires a new enough firmware as bundled with PS5
1376+ * software released in 2021. DualSense edge supports it out of the box.
1377+ * Both devices also support the old mode, but it is not really used.
1378+ */
1379+ if (hdev -> product == USB_DEVICE_ID_SONY_PS5_CONTROLLER ) {
1380+ /* Feature version 2.21 introduced new vibration method. */
1381+ ds -> use_vibration_v2 = ds -> update_version >= DS_FEATURE_VERSION (2 , 21 );
1382+ } else if (hdev -> product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2 ) {
1383+ ds -> use_vibration_v2 = true;
1384+ }
1385+
13511386 ret = ps_devices_list_add (ps_dev );
13521387 if (ret )
13531388 return ERR_PTR (ret );
0 commit comments