Skip to content

Commit 4fd2313

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.10/playstation' into for-linus
- fixes for better support of 3rd party playstation DS4 controllers (Max Staudt)
2 parents ffff77d + 947992c commit 4fd2313

File tree

1 file changed

+93
-45
lines changed

1 file changed

+93
-45
lines changed

drivers/hid/hid-playstation.c

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ static DEFINE_IDA(ps_player_id_allocator);
2727

2828
#define HID_PLAYSTATION_VERSION_PATCH 0x8000
2929

30+
enum PS_TYPE {
31+
PS_TYPE_PS4_DUALSHOCK4,
32+
PS_TYPE_PS5_DUALSENSE,
33+
};
34+
3035
/* Base class for playstation devices. */
3136
struct ps_device {
3237
struct list_head list;
@@ -287,6 +292,8 @@ struct dualsense_output_report {
287292

288293
#define DS4_INPUT_REPORT_USB 0x01
289294
#define DS4_INPUT_REPORT_USB_SIZE 64
295+
#define DS4_INPUT_REPORT_BT_MINIMAL 0x01
296+
#define DS4_INPUT_REPORT_BT_MINIMAL_SIZE 10
290297
#define DS4_INPUT_REPORT_BT 0x11
291298
#define DS4_INPUT_REPORT_BT_SIZE 78
292299
#define DS4_OUTPUT_REPORT_USB 0x05
@@ -1778,8 +1785,10 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
17781785
int retries;
17791786

17801787
buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL);
1781-
if (!buf)
1782-
return -ENOMEM;
1788+
if (!buf) {
1789+
ret = -ENOMEM;
1790+
goto transfer_failed;
1791+
}
17831792

17841793
/* We should normally receive the feature report data we asked
17851794
* for, but hidraw applications such as Steam can issue feature
@@ -1796,26 +1805,30 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
17961805
continue;
17971806
}
17981807

1799-
hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
1808+
hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
18001809
ret = -EILSEQ;
1801-
goto err_free;
1810+
goto transfer_failed;
18021811
} else {
18031812
break;
18041813
}
18051814
}
18061815
} else { /* Bluetooth */
18071816
buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, GFP_KERNEL);
1808-
if (!buf)
1809-
return -ENOMEM;
1817+
if (!buf) {
1818+
ret = -ENOMEM;
1819+
goto transfer_failed;
1820+
}
18101821

18111822
ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf,
18121823
DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true);
1824+
18131825
if (ret) {
1814-
hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
1815-
goto err_free;
1826+
hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
1827+
goto transfer_failed;
18161828
}
18171829
}
18181830

1831+
/* Transfer succeeded - parse the calibration data received. */
18191832
gyro_pitch_bias = get_unaligned_le16(&buf[1]);
18201833
gyro_yaw_bias = get_unaligned_le16(&buf[3]);
18211834
gyro_roll_bias = get_unaligned_le16(&buf[5]);
@@ -1844,6 +1857,9 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
18441857
acc_z_plus = get_unaligned_le16(&buf[31]);
18451858
acc_z_minus = get_unaligned_le16(&buf[33]);
18461859

1860+
/* Done parsing the buffer, so let's free it. */
1861+
kfree(buf);
1862+
18471863
/*
18481864
* Set gyroscope calibration and normalization parameters.
18491865
* Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s.
@@ -1867,21 +1883,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
18671883
ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) +
18681884
abs(gyro_roll_minus - gyro_roll_bias);
18691885

1870-
/*
1871-
* Sanity check gyro calibration data. This is needed to prevent crashes
1872-
* during report handling of virtual, clone or broken devices not implementing
1873-
* calibration data properly.
1874-
*/
1875-
for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) {
1876-
if (ds4->gyro_calib_data[i].sens_denom == 0) {
1877-
hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
1878-
ds4->gyro_calib_data[i].abs_code);
1879-
ds4->gyro_calib_data[i].bias = 0;
1880-
ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE;
1881-
ds4->gyro_calib_data[i].sens_denom = S16_MAX;
1882-
}
1883-
}
1884-
18851886
/*
18861887
* Set accelerometer calibration and normalization parameters.
18871888
* Data values will be normalized to 1/DS4_ACC_RES_PER_G g.
@@ -1904,13 +1905,31 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
19041905
ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G;
19051906
ds4->accel_calib_data[2].sens_denom = range_2g;
19061907

1908+
transfer_failed:
1909+
/*
1910+
* Sanity check gyro calibration data. This is needed to prevent crashes
1911+
* during report handling of virtual, clone or broken devices not implementing
1912+
* calibration data properly.
1913+
*/
1914+
for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) {
1915+
if (ds4->gyro_calib_data[i].sens_denom == 0) {
1916+
ds4->gyro_calib_data[i].abs_code = ABS_RX + i;
1917+
hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
1918+
ds4->gyro_calib_data[i].abs_code);
1919+
ds4->gyro_calib_data[i].bias = 0;
1920+
ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE;
1921+
ds4->gyro_calib_data[i].sens_denom = S16_MAX;
1922+
}
1923+
}
1924+
19071925
/*
19081926
* Sanity check accelerometer calibration data. This is needed to prevent crashes
19091927
* during report handling of virtual, clone or broken devices not implementing calibration
19101928
* data properly.
19111929
*/
19121930
for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) {
19131931
if (ds4->accel_calib_data[i].sens_denom == 0) {
1932+
ds4->accel_calib_data[i].abs_code = ABS_X + i;
19141933
hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.",
19151934
ds4->accel_calib_data[i].abs_code);
19161935
ds4->accel_calib_data[i].bias = 0;
@@ -1919,8 +1938,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
19191938
}
19201939
}
19211940

1922-
err_free:
1923-
kfree(buf);
19241941
return ret;
19251942
}
19261943

@@ -2037,8 +2054,9 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del
20372054

20382055
dualshock4_schedule_work(ds4);
20392056

2040-
*delay_on = ds4->lightbar_blink_on;
2041-
*delay_off = ds4->lightbar_blink_off;
2057+
/* Report scaled values back to LED subsystem */
2058+
*delay_on = ds4->lightbar_blink_on * 10;
2059+
*delay_off = ds4->lightbar_blink_off * 10;
20422060

20432061
return 0;
20442062
}
@@ -2065,6 +2083,13 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig
20652083
break;
20662084
case 3:
20672085
ds4->lightbar_enabled = !!value;
2086+
2087+
/* brightness = 0 also cancels blinking in Linux. */
2088+
if (!ds4->lightbar_enabled) {
2089+
ds4->lightbar_blink_off = 0;
2090+
ds4->lightbar_blink_on = 0;
2091+
ds4->update_lightbar_blink = true;
2092+
}
20682093
}
20692094

20702095
ds4->update_lightbar = true;
@@ -2182,6 +2207,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
21822207
int battery_status, i, j;
21832208
uint16_t sensor_timestamp;
21842209
unsigned long flags;
2210+
bool is_minimal = false;
21852211

21862212
/*
21872213
* DualShock4 in USB uses the full HID report for reportID 1, but
@@ -2209,6 +2235,18 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
22092235
ds4_report = &bt->common;
22102236
num_touch_reports = bt->num_touch_reports;
22112237
touch_reports = bt->touch_reports;
2238+
} else if (hdev->bus == BUS_BLUETOOTH &&
2239+
report->id == DS4_INPUT_REPORT_BT_MINIMAL &&
2240+
size == DS4_INPUT_REPORT_BT_MINIMAL_SIZE) {
2241+
/* Some third-party pads never switch to the full 0x11 report.
2242+
* The short 0x01 report is 10 bytes long:
2243+
* u8 report_id == 0x01
2244+
* u8 first_bytes_of_full_report[9]
2245+
* So let's reuse the full report parser, and stop it after
2246+
* parsing the buttons.
2247+
*/
2248+
ds4_report = (struct dualshock4_input_report_common *)&data[1];
2249+
is_minimal = true;
22122250
} else {
22132251
hid_err(hdev, "Unhandled reportID=%d\n", report->id);
22142252
return -1;
@@ -2242,6 +2280,9 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
22422280
input_report_key(ds4->gamepad, BTN_MODE, ds4_report->buttons[2] & DS_BUTTONS2_PS_HOME);
22432281
input_sync(ds4->gamepad);
22442282

2283+
if (is_minimal)
2284+
return 0;
2285+
22452286
/* Parse and calibrate gyroscope data. */
22462287
for (i = 0; i < ARRAY_SIZE(ds4_report->gyro); i++) {
22472288
int raw_data = (short)le16_to_cpu(ds4_report->gyro[i]);
@@ -2550,8 +2591,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
25502591

25512592
ret = dualshock4_get_firmware_info(ds4);
25522593
if (ret) {
2553-
hid_err(hdev, "Failed to get firmware info from DualShock4\n");
2554-
return ERR_PTR(ret);
2594+
hid_warn(hdev, "Failed to get firmware info from DualShock4\n");
2595+
hid_warn(hdev, "HW/FW version data in sysfs will be invalid.\n");
25552596
}
25562597

25572598
ret = ps_devices_list_add(ps_dev);
@@ -2560,8 +2601,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
25602601

25612602
ret = dualshock4_get_calibration_data(ds4);
25622603
if (ret) {
2563-
hid_err(hdev, "Failed to get calibration data from DualShock4\n");
2564-
goto err;
2604+
hid_warn(hdev, "Failed to get calibration data from DualShock4\n");
2605+
hid_warn(hdev, "Gyroscope and accelerometer will be inaccurate.\n");
25652606
}
25662607

25672608
ds4->gamepad = ps_gamepad_create(hdev, dualshock4_play_effect);
@@ -2655,17 +2696,14 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
26552696
goto err_stop;
26562697
}
26572698

2658-
if (hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER ||
2659-
hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 ||
2660-
hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) {
2699+
if (id->driver_data == PS_TYPE_PS4_DUALSHOCK4) {
26612700
dev = dualshock4_create(hdev);
26622701
if (IS_ERR(dev)) {
26632702
hid_err(hdev, "Failed to create dualshock4.\n");
26642703
ret = PTR_ERR(dev);
26652704
goto err_close;
26662705
}
2667-
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER ||
2668-
hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
2706+
} else if (id->driver_data == PS_TYPE_PS5_DUALSENSE) {
26692707
dev = dualsense_create(hdev);
26702708
if (IS_ERR(dev)) {
26712709
hid_err(hdev, "Failed to create dualsense.\n");
@@ -2699,16 +2737,26 @@ static void ps_remove(struct hid_device *hdev)
26992737

27002738
static const struct hid_device_id ps_devices[] = {
27012739
/* Sony DualShock 4 controllers for PS4 */
2702-
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
2703-
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
2704-
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
2705-
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
2706-
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) },
2740+
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
2741+
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
2742+
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
2743+
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
2744+
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
2745+
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
2746+
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
2747+
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
2748+
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE),
2749+
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
2750+
27072751
/* Sony DualSense controllers for PS5 */
2708-
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
2709-
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
2710-
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
2711-
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
2752+
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER),
2753+
.driver_data = PS_TYPE_PS5_DUALSENSE },
2754+
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER),
2755+
.driver_data = PS_TYPE_PS5_DUALSENSE },
2756+
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2),
2757+
.driver_data = PS_TYPE_PS5_DUALSENSE },
2758+
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2),
2759+
.driver_data = PS_TYPE_PS5_DUALSENSE },
27122760
{ }
27132761
};
27142762
MODULE_DEVICE_TABLE(hid, ps_devices);

0 commit comments

Comments
 (0)