Commit 4fd2313d authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-6.10/playstation' into for-linus

- fixes for better support of 3rd party playstation DS4 controllers (Max Staudt)
parents ffff77dd 947992c7
...@@ -27,6 +27,11 @@ static DEFINE_IDA(ps_player_id_allocator); ...@@ -27,6 +27,11 @@ static DEFINE_IDA(ps_player_id_allocator);
#define HID_PLAYSTATION_VERSION_PATCH 0x8000 #define HID_PLAYSTATION_VERSION_PATCH 0x8000
enum PS_TYPE {
PS_TYPE_PS4_DUALSHOCK4,
PS_TYPE_PS5_DUALSENSE,
};
/* Base class for playstation devices. */ /* Base class for playstation devices. */
struct ps_device { struct ps_device {
struct list_head list; struct list_head list;
...@@ -287,6 +292,8 @@ struct dualsense_output_report { ...@@ -287,6 +292,8 @@ struct dualsense_output_report {
#define DS4_INPUT_REPORT_USB 0x01 #define DS4_INPUT_REPORT_USB 0x01
#define DS4_INPUT_REPORT_USB_SIZE 64 #define DS4_INPUT_REPORT_USB_SIZE 64
#define DS4_INPUT_REPORT_BT_MINIMAL 0x01
#define DS4_INPUT_REPORT_BT_MINIMAL_SIZE 10
#define DS4_INPUT_REPORT_BT 0x11 #define DS4_INPUT_REPORT_BT 0x11
#define DS4_INPUT_REPORT_BT_SIZE 78 #define DS4_INPUT_REPORT_BT_SIZE 78
#define DS4_OUTPUT_REPORT_USB 0x05 #define DS4_OUTPUT_REPORT_USB 0x05
...@@ -1778,8 +1785,10 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1778,8 +1785,10 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
int retries; int retries;
buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL);
if (!buf) if (!buf) {
return -ENOMEM; ret = -ENOMEM;
goto transfer_failed;
}
/* We should normally receive the feature report data we asked /* We should normally receive the feature report data we asked
* for, but hidraw applications such as Steam can issue feature * for, but hidraw applications such as Steam can issue feature
...@@ -1796,26 +1805,30 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1796,26 +1805,30 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
continue; continue;
} }
hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
ret = -EILSEQ; ret = -EILSEQ;
goto err_free; goto transfer_failed;
} else { } else {
break; break;
} }
} }
} else { /* Bluetooth */ } else { /* Bluetooth */
buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, GFP_KERNEL); buf = kzalloc(DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, GFP_KERNEL);
if (!buf) if (!buf) {
return -ENOMEM; ret = -ENOMEM;
goto transfer_failed;
}
ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf, ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION_BT, buf,
DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true); DS4_FEATURE_REPORT_CALIBRATION_BT_SIZE, true);
if (ret) { if (ret) {
hid_err(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret);
goto err_free; goto transfer_failed;
} }
} }
/* Transfer succeeded - parse the calibration data received. */
gyro_pitch_bias = get_unaligned_le16(&buf[1]); gyro_pitch_bias = get_unaligned_le16(&buf[1]);
gyro_yaw_bias = get_unaligned_le16(&buf[3]); gyro_yaw_bias = get_unaligned_le16(&buf[3]);
gyro_roll_bias = get_unaligned_le16(&buf[5]); gyro_roll_bias = get_unaligned_le16(&buf[5]);
...@@ -1844,6 +1857,9 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1844,6 +1857,9 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
acc_z_plus = get_unaligned_le16(&buf[31]); acc_z_plus = get_unaligned_le16(&buf[31]);
acc_z_minus = get_unaligned_le16(&buf[33]); acc_z_minus = get_unaligned_le16(&buf[33]);
/* Done parsing the buffer, so let's free it. */
kfree(buf);
/* /*
* Set gyroscope calibration and normalization parameters. * Set gyroscope calibration and normalization parameters.
* Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s. * 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) ...@@ -1867,21 +1883,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) +
abs(gyro_roll_minus - gyro_roll_bias); abs(gyro_roll_minus - gyro_roll_bias);
/*
* Sanity check gyro calibration data. This is needed to prevent crashes
* during report handling of virtual, clone or broken devices not implementing
* calibration data properly.
*/
for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) {
if (ds4->gyro_calib_data[i].sens_denom == 0) {
hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
ds4->gyro_calib_data[i].abs_code);
ds4->gyro_calib_data[i].bias = 0;
ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE;
ds4->gyro_calib_data[i].sens_denom = S16_MAX;
}
}
/* /*
* Set accelerometer calibration and normalization parameters. * Set accelerometer calibration and normalization parameters.
* Data values will be normalized to 1/DS4_ACC_RES_PER_G g. * Data values will be normalized to 1/DS4_ACC_RES_PER_G g.
...@@ -1904,6 +1905,23 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1904,6 +1905,23 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G; ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G;
ds4->accel_calib_data[2].sens_denom = range_2g; ds4->accel_calib_data[2].sens_denom = range_2g;
transfer_failed:
/*
* Sanity check gyro calibration data. This is needed to prevent crashes
* during report handling of virtual, clone or broken devices not implementing
* calibration data properly.
*/
for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) {
if (ds4->gyro_calib_data[i].sens_denom == 0) {
ds4->gyro_calib_data[i].abs_code = ABS_RX + i;
hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
ds4->gyro_calib_data[i].abs_code);
ds4->gyro_calib_data[i].bias = 0;
ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE;
ds4->gyro_calib_data[i].sens_denom = S16_MAX;
}
}
/* /*
* Sanity check accelerometer calibration data. This is needed to prevent crashes * Sanity check accelerometer calibration data. This is needed to prevent crashes
* during report handling of virtual, clone or broken devices not implementing calibration * during report handling of virtual, clone or broken devices not implementing calibration
...@@ -1911,6 +1929,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1911,6 +1929,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
*/ */
for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) { for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) {
if (ds4->accel_calib_data[i].sens_denom == 0) { if (ds4->accel_calib_data[i].sens_denom == 0) {
ds4->accel_calib_data[i].abs_code = ABS_X + i;
hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.",
ds4->accel_calib_data[i].abs_code); ds4->accel_calib_data[i].abs_code);
ds4->accel_calib_data[i].bias = 0; ds4->accel_calib_data[i].bias = 0;
...@@ -1919,8 +1938,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) ...@@ -1919,8 +1938,6 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
} }
} }
err_free:
kfree(buf);
return ret; return ret;
} }
...@@ -2037,8 +2054,9 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del ...@@ -2037,8 +2054,9 @@ static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *del
dualshock4_schedule_work(ds4); dualshock4_schedule_work(ds4);
*delay_on = ds4->lightbar_blink_on; /* Report scaled values back to LED subsystem */
*delay_off = ds4->lightbar_blink_off; *delay_on = ds4->lightbar_blink_on * 10;
*delay_off = ds4->lightbar_blink_off * 10;
return 0; return 0;
} }
...@@ -2065,6 +2083,13 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig ...@@ -2065,6 +2083,13 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig
break; break;
case 3: case 3:
ds4->lightbar_enabled = !!value; ds4->lightbar_enabled = !!value;
/* brightness = 0 also cancels blinking in Linux. */
if (!ds4->lightbar_enabled) {
ds4->lightbar_blink_off = 0;
ds4->lightbar_blink_on = 0;
ds4->update_lightbar_blink = true;
}
} }
ds4->update_lightbar = true; ds4->update_lightbar = true;
...@@ -2182,6 +2207,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * ...@@ -2182,6 +2207,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
int battery_status, i, j; int battery_status, i, j;
uint16_t sensor_timestamp; uint16_t sensor_timestamp;
unsigned long flags; unsigned long flags;
bool is_minimal = false;
/* /*
* DualShock4 in USB uses the full HID report for reportID 1, but * 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 * ...@@ -2209,6 +2235,18 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
ds4_report = &bt->common; ds4_report = &bt->common;
num_touch_reports = bt->num_touch_reports; num_touch_reports = bt->num_touch_reports;
touch_reports = bt->touch_reports; touch_reports = bt->touch_reports;
} else if (hdev->bus == BUS_BLUETOOTH &&
report->id == DS4_INPUT_REPORT_BT_MINIMAL &&
size == DS4_INPUT_REPORT_BT_MINIMAL_SIZE) {
/* Some third-party pads never switch to the full 0x11 report.
* The short 0x01 report is 10 bytes long:
* u8 report_id == 0x01
* u8 first_bytes_of_full_report[9]
* So let's reuse the full report parser, and stop it after
* parsing the buttons.
*/
ds4_report = (struct dualshock4_input_report_common *)&data[1];
is_minimal = true;
} else { } else {
hid_err(hdev, "Unhandled reportID=%d\n", report->id); hid_err(hdev, "Unhandled reportID=%d\n", report->id);
return -1; return -1;
...@@ -2242,6 +2280,9 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * ...@@ -2242,6 +2280,9 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
input_report_key(ds4->gamepad, BTN_MODE, ds4_report->buttons[2] & DS_BUTTONS2_PS_HOME); input_report_key(ds4->gamepad, BTN_MODE, ds4_report->buttons[2] & DS_BUTTONS2_PS_HOME);
input_sync(ds4->gamepad); input_sync(ds4->gamepad);
if (is_minimal)
return 0;
/* Parse and calibrate gyroscope data. */ /* Parse and calibrate gyroscope data. */
for (i = 0; i < ARRAY_SIZE(ds4_report->gyro); i++) { for (i = 0; i < ARRAY_SIZE(ds4_report->gyro); i++) {
int raw_data = (short)le16_to_cpu(ds4_report->gyro[i]); 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) ...@@ -2550,8 +2591,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
ret = dualshock4_get_firmware_info(ds4); ret = dualshock4_get_firmware_info(ds4);
if (ret) { if (ret) {
hid_err(hdev, "Failed to get firmware info from DualShock4\n"); hid_warn(hdev, "Failed to get firmware info from DualShock4\n");
return ERR_PTR(ret); hid_warn(hdev, "HW/FW version data in sysfs will be invalid.\n");
} }
ret = ps_devices_list_add(ps_dev); ret = ps_devices_list_add(ps_dev);
...@@ -2560,8 +2601,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) ...@@ -2560,8 +2601,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
ret = dualshock4_get_calibration_data(ds4); ret = dualshock4_get_calibration_data(ds4);
if (ret) { if (ret) {
hid_err(hdev, "Failed to get calibration data from DualShock4\n"); hid_warn(hdev, "Failed to get calibration data from DualShock4\n");
goto err; hid_warn(hdev, "Gyroscope and accelerometer will be inaccurate.\n");
} }
ds4->gamepad = ps_gamepad_create(hdev, dualshock4_play_effect); 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) ...@@ -2655,17 +2696,14 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop; goto err_stop;
} }
if (hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER || if (id->driver_data == PS_TYPE_PS4_DUALSHOCK4) {
hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 ||
hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) {
dev = dualshock4_create(hdev); dev = dualshock4_create(hdev);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
hid_err(hdev, "Failed to create dualshock4.\n"); hid_err(hdev, "Failed to create dualshock4.\n");
ret = PTR_ERR(dev); ret = PTR_ERR(dev);
goto err_close; goto err_close;
} }
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER || } else if (id->driver_data == PS_TYPE_PS5_DUALSENSE) {
hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
dev = dualsense_create(hdev); dev = dualsense_create(hdev);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
hid_err(hdev, "Failed to create dualsense.\n"); hid_err(hdev, "Failed to create dualsense.\n");
...@@ -2699,16 +2737,26 @@ static void ps_remove(struct hid_device *hdev) ...@@ -2699,16 +2737,26 @@ static void ps_remove(struct hid_device *hdev)
static const struct hid_device_id ps_devices[] = { static const struct hid_device_id ps_devices[] = {
/* Sony DualShock 4 controllers for PS4 */ /* Sony DualShock 4 controllers for PS4 */
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, .driver_data = PS_TYPE_PS4_DUALSHOCK4 },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) }, .driver_data = PS_TYPE_PS4_DUALSHOCK4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE),
.driver_data = PS_TYPE_PS4_DUALSHOCK4 },
/* Sony DualSense controllers for PS5 */ /* Sony DualSense controllers for PS5 */
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER),
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) }, .driver_data = PS_TYPE_PS5_DUALSENSE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER),
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) }, .driver_data = PS_TYPE_PS5_DUALSENSE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2),
.driver_data = PS_TYPE_PS5_DUALSENSE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2),
.driver_data = PS_TYPE_PS5_DUALSENSE },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, ps_devices); MODULE_DEVICE_TABLE(hid, ps_devices);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment