diff --git a/MAINTAINERS b/MAINTAINERS index 65dd8fc47008..af476d65bfb8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6614,12 +6614,6 @@ F: drivers/hid/ F: include/linux/hid* F: include/uapi/linux/hid* -HID PLAYSTATION DRIVER -M: Roderick Colenbrander -L: linux-input@vger.kernel.org -S: Supported -F: drivers/hid/hid-playstation.c - HID SENSOR HUB DRIVERS M: Jiri Kosina M: Jonathan Cameron diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index e7b15f396877..6bf06d541b5a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -798,27 +798,6 @@ config HID_PLANTRONICS Say M here if you may ever plug in a Plantronics USB audio device. -config HID_PLAYSTATION - tristate "PlayStation HID Driver" - depends on HID - select CRC32 - select POWER_SUPPLY - ---help--- - Provides support for Sony PS5 controllers including support for - its special functionalities e.g. touchpad, lights and motion - sensors. - -config PLAYSTATION_FF - bool "PlayStation force feedback support" - depends on HID_PLAYSTATION - select INPUT_FF_MEMLESS - help - Provides the force feedback support for Playstation game - controllers. - - Say Y here if you would like to enable force feedback support for - PlayStation game controllers. - config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 0ea94cbe0de1..3fb5a1b73a87 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -87,7 +87,6 @@ hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o -obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o obj-$(CONFIG_HID_RETRODE) += hid-retrode.o diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ae3dceb6a9d0..0ef51d1d2de2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1055,7 +1055,6 @@ #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc #define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0 -#define USB_DEVICE_ID_SONY_PS5_CONTROLLER 0x0ce6 #define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c deleted file mode 100644 index 4532d6b57174..000000000000 --- a/drivers/hid/hid-playstation.c +++ /dev/null @@ -1,1370 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * HID driver for Sony DualSense(TM) controller. - * - * Copyright (c) 2020 Sony Interactive Entertainment - */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "hid-ids.h" - -/* List of connected playstation devices. */ -static DEFINE_MUTEX(ps_devices_lock); -static LIST_HEAD(ps_devices_list); - -static DEFINE_IDA(ps_player_id_allocator); - -#define HID_PLAYSTATION_VERSION_PATCH 0x8000 - -/* Base class for playstation devices. */ -struct ps_device { - struct list_head list; - struct hid_device *hdev; - spinlock_t lock; - - uint32_t player_id; - - struct power_supply_desc battery_desc; - struct power_supply *battery; - uint8_t battery_capacity; - int battery_status; - uint8_t mac_address[6]; /* Note: stored in little endian order. */ - int32_t hw_version; - int32_t fw_version; - int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size); -}; - -/* Seed values for DualShock4 / DualSense CRC32 for different report types. */ -#define PS_INPUT_CRC32_SEED 0xA1 -#define PS_OUTPUT_CRC32_SEED 0xA2 -#define PS_FEATURE_CRC32_SEED 0xA3 - -struct ps_calibration_data { - int abs_code; - short bias; - int sens_numer; - int sens_denom; -}; - -#define DS_INPUT_REPORT_USB 0x01 -#define DS_INPUT_REPORT_USB_SIZE 64 - -#define DS_FEATURE_REPORT_CALIBRATION 0x05 -#define DS_FEATURE_REPORT_CALIBRATION_SIZE 41 - -#define DS_INPUT_REPORT_BT 0x31 -#define DS_INPUT_REPORT_BT_SIZE 78 -#define DS_OUTPUT_REPORT_USB 0x02 -#define DS_OUTPUT_REPORT_USB_SIZE 63 -#define DS_OUTPUT_REPORT_BT 0x31 -#define DS_OUTPUT_REPORT_BT_SIZE 78 - -#define DS_FEATURE_REPORT_PAIRING_INFO 0x09 -#define DS_FEATURE_REPORT_PAIRING_INFO_SIZE 20 - -#define DS_FEATURE_REPORT_FIRMWARE_INFO 0x20 -#define DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE 64 - -/* Button masks for DualSense input report. */ -#define DS_BUTTONS0_HAT_SWITCH GENMASK(3, 0) -#define DS_BUTTONS0_SQUARE BIT(4) -#define DS_BUTTONS0_CROSS BIT(5) -#define DS_BUTTONS0_CIRCLE BIT(6) -#define DS_BUTTONS0_TRIANGLE BIT(7) -#define DS_BUTTONS1_L1 BIT(0) -#define DS_BUTTONS1_R1 BIT(1) -#define DS_BUTTONS1_L2 BIT(2) -#define DS_BUTTONS1_R2 BIT(3) -#define DS_BUTTONS1_CREATE BIT(4) -#define DS_BUTTONS1_OPTIONS BIT(5) -#define DS_BUTTONS1_L3 BIT(6) -#define DS_BUTTONS1_R3 BIT(7) -#define DS_BUTTONS2_PS_HOME BIT(0) -#define DS_BUTTONS2_TOUCHPAD BIT(1) -#define DS_BUTTONS2_MIC_MUTE BIT(2) - -/* Status field of DualSense input report. */ -#define DS_STATUS_BATTERY_CAPACITY GENMASK(3, 0) -#define DS_STATUS_CHARGING GENMASK(7, 4) -#define DS_STATUS_CHARGING_SHIFT 4 - -/* -+ * Status of a DualSense touch point contact. -+ * Contact IDs, with highest bit set are 'inactive' -+ * and any associated data is then invalid. -+ */ -#define DS_TOUCH_POINT_INACTIVE BIT(7) - -/* Magic value required in tag field of Bluetooth output report. */ -#define DS_OUTPUT_TAG 0x10 -/* Flags for DualSense output report. */ -#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) -#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) -#define DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE BIT(0) -#define DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE BIT(1) -#define DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE BIT(2) -#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3) -#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4) -#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) -#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) -#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) - -#define DS_ACC_RES_PER_G 8192 -#define DS_ACC_RANGE (4*DS_ACC_RES_PER_G) -#define DS_GYRO_RES_PER_DEG_S 1024 -#define DS_GYRO_RANGE (2048*DS_GYRO_RES_PER_DEG_S) - -/* DualSense hardware limits */ -#define DS_TOUCHPAD_WIDTH 1920 -#define DS_TOUCHPAD_HEIGHT 1080 - -struct dualsense { - struct ps_device base; - struct input_dev *gamepad; - struct input_dev *sensors; - struct input_dev *touchpad; - - /* Calibration data for accelerometer and gyroscope. */ - struct ps_calibration_data accel_calib_data[3]; - struct ps_calibration_data gyro_calib_data[3]; - /* Timestamp for sensor data */ - bool sensor_timestamp_initialized; - uint32_t prev_sensor_timestamp; - uint32_t sensor_timestamp_us; - - /* Compatible rumble state */ - bool update_rumble; - uint8_t motor_left; - uint8_t motor_right; - - /* RGB lightbar */ - bool update_lightbar; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; - - /* Microphone */ - bool update_mic_mute; - bool mic_muted; - bool last_btn_mic_state; - - /* Player leds */ - bool update_player_leds; - uint8_t player_leds_state; - struct led_classdev player_leds[5]; - - struct work_struct output_worker; - void *output_report_dmabuf; - uint8_t output_seq; /* Sequence number for output report. */ -}; - -struct dualsense_touch_point { - uint8_t contact; - uint8_t x_lo; - uint8_t x_hi:4, y_lo:4; - uint8_t y_hi; -} __packed; - -/* Common data between DualSense BT/USB main output report. */ -struct dualsense_output_report_common { - uint8_t valid_flag0; - uint8_t valid_flag1; - - /* For DualShock 4 compatibility mode. */ - uint8_t motor_right; - uint8_t motor_left; - - /* Audio controls */ - uint8_t reserved[4]; - uint8_t mute_button_led; - - uint8_t power_save_control; - uint8_t reserved2[28]; - - /* LEDs and lightbar */ - uint8_t valid_flag2; - uint8_t reserved3[2]; - uint8_t lightbar_setup; - uint8_t led_brightness; - uint8_t player_leds; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; -} __packed; - -struct dualsense_output_report_bt { - uint8_t report_id; /* 0x31 */ - uint8_t seq_tag; - uint8_t tag; - struct dualsense_output_report_common common; - uint8_t reserved[24]; - __le32 crc32; -} __packed; - -struct dualsense_output_report_usb { - uint8_t report_id; /* 0x02 */ - struct dualsense_output_report_common common; - uint8_t reserved[15]; -} __packed; - -/* - * The DualSense has a main output report used to control most features. - * It is largely the same between Bluetooth and USB except for different - * headers and CRC. This structure hide the differences between the two to - * simplify sending output reports. - */ -struct dualsense_output_report { - uint8_t *data; /* Start of data */ - uint8_t len; /* Size of output report */ - - /* Points to Bluetooth data payload - * in case for a Bluetooth report else NULL. - */ - struct dualsense_output_report_bt *bt; - /* Points to USB data payload in case for a USB report else NULL. */ - struct dualsense_output_report_usb *usb; - /* Points to common section of report, so past any headers. */ - struct dualsense_output_report_common *common; -}; - -/* Main DualSense input report excluding any BT/USB specific headers. */ -struct dualsense_input_report { - uint8_t x, y; - uint8_t rx, ry; - uint8_t z, rz; - uint8_t seq_number; - uint8_t buttons[4]; - uint8_t reserved[4]; - - /* Motion sensors */ - __le16 gyro[3]; /* x, y, z */ - __le16 accel[3]; /* x, y, z */ - __le32 sensor_timestamp; - uint8_t reserved2; - - /* Touchpad */ - struct dualsense_touch_point points[2]; - - uint8_t reserved3[12]; - uint8_t status; - uint8_t reserved4[10]; -} __packed; - -/* - * Common gamepad buttons across DualShock 3 / 4 and DualSense. - * Note: for device with a touchpad, touchpad button is not included - * as it will be part of the touchpad device. - */ -static const int ps_gamepad_buttons[] = { - BTN_WEST, /* Square */ - BTN_NORTH, /* Triangle */ - BTN_EAST, /* Circle */ - BTN_SOUTH, /* Cross */ - BTN_TL, /* L1 */ - BTN_TR, /* R1 */ - BTN_TL2, /* L2 */ - BTN_TR2, /* R2 */ - BTN_SELECT, /* Create (PS5) / Share (PS4) */ - BTN_START, /* Option */ - BTN_THUMBL, /* L3 */ - BTN_THUMBR, /* R3 */ - BTN_MODE, /* PS Home */ -}; - -static const struct {int x; int y; } ps_gamepad_hat_mapping[] = { - {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, - {0, 0}, -}; - -/* - * Add a new ps_device to ps_devices if it doesn't exist. - * Return error on duplicate device, which can happen if the same - * device is connected using both Bluetooth and USB. - */ -static int ps_devices_list_add(struct ps_device *dev) -{ - struct ps_device *entry; - - mutex_lock(&ps_devices_lock); - list_for_each_entry(entry, &ps_devices_list, list) { - if (!memcmp(entry->mac_address, dev->mac_address, sizeof(dev->mac_address))) { - hid_err(dev->hdev, "Duplicate device found for MAC address %pMR.\n", - dev->mac_address); - mutex_unlock(&ps_devices_lock); - return -EEXIST; - } - } - - list_add_tail(&dev->list, &ps_devices_list); - mutex_unlock(&ps_devices_lock); - return 0; -} - -static int ps_devices_list_remove(struct ps_device *dev) -{ - mutex_lock(&ps_devices_lock); - list_del(&dev->list); - mutex_unlock(&ps_devices_lock); - return 0; -} - -static int ps_device_set_player_id(struct ps_device *dev) -{ - int ret = ida_alloc(&ps_player_id_allocator, GFP_KERNEL); - - if (ret < 0) - return ret; - - dev->player_id = ret; - return 0; -} - -static void ps_device_release_player_id(struct ps_device *dev) -{ - ida_free(&ps_player_id_allocator, dev->player_id); - - dev->player_id = U32_MAX; -} - -static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const char *name_suffix) -{ - struct input_dev *input_dev; - - input_dev = devm_input_allocate_device(&hdev->dev); - if (!input_dev) - return ERR_PTR(-ENOMEM); - - input_dev->id.bustype = hdev->bus; - input_dev->id.vendor = hdev->vendor; - input_dev->id.product = hdev->product; - input_dev->id.version = hdev->version; - input_dev->uniq = hdev->uniq; - - if (name_suffix) { - input_dev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name, - name_suffix); - if (!input_dev->name) - return ERR_PTR(-ENOMEM); - } else { - input_dev->name = hdev->name; - } - - input_set_drvdata(input_dev, hdev); - - return input_dev; -} - -/* Compute crc32 of HID data and compare against expected CRC. */ -static bool ps_check_crc32(uint8_t seed, uint8_t *data, size_t len, uint32_t report_crc) -{ - uint32_t crc; - - crc = crc32_le(0xFFFFFFFF, &seed, 1); - crc = ~crc32_le(crc, data, len); - - return crc == report_crc; -} - -static enum power_supply_property ps_power_supply_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_SCOPE, -}; - -static int ps_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct ps_device *dev = power_supply_get_drvdata(psy); - uint8_t battery_capacity; - int battery_status; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dev->lock, flags); - battery_capacity = dev->battery_capacity; - battery_status = dev->battery_status; - spin_unlock_irqrestore(&dev->lock, flags); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = battery_status; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = 1; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = battery_capacity; - break; - case POWER_SUPPLY_PROP_SCOPE: - val->intval = POWER_SUPPLY_SCOPE_DEVICE; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int ps_device_register_battery(struct ps_device *dev) -{ - struct power_supply *battery; - struct power_supply_config battery_cfg = { .drv_data = dev }; - int ret; - - dev->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; - dev->battery_desc.properties = ps_power_supply_props; - dev->battery_desc.num_properties = ARRAY_SIZE(ps_power_supply_props); - dev->battery_desc.get_property = ps_battery_get_property; - dev->battery_desc.name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL, - "ps-controller-battery-%pMR", dev->mac_address); - if (!dev->battery_desc.name) - return -ENOMEM; - - battery = devm_power_supply_register(&dev->hdev->dev, &dev->battery_desc, &battery_cfg); - if (IS_ERR(battery)) { - ret = PTR_ERR(battery); - hid_err(dev->hdev, "Unable to register battery device: %d\n", ret); - return ret; - } - dev->battery = battery; - - ret = power_supply_powers(dev->battery, &dev->hdev->dev); - if (ret) { - hid_err(dev->hdev, "Unable to activate battery device: %d\n", ret); - return ret; - } - - return 0; -} - -static struct input_dev *ps_gamepad_create(struct hid_device *hdev, - int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) -{ - struct input_dev *gamepad; - unsigned int i; - int ret; - - gamepad = ps_allocate_input_dev(hdev, NULL); - if (IS_ERR(gamepad)) - return ERR_CAST(gamepad); - - input_set_abs_params(gamepad, ABS_X, 0, 255, 0, 0); - input_set_abs_params(gamepad, ABS_Y, 0, 255, 0, 0); - input_set_abs_params(gamepad, ABS_Z, 0, 255, 0, 0); - input_set_abs_params(gamepad, ABS_RX, 0, 255, 0, 0); - input_set_abs_params(gamepad, ABS_RY, 0, 255, 0, 0); - input_set_abs_params(gamepad, ABS_RZ, 0, 255, 0, 0); - - input_set_abs_params(gamepad, ABS_HAT0X, -1, 1, 0, 0); - input_set_abs_params(gamepad, ABS_HAT0Y, -1, 1, 0, 0); - - for (i = 0; i < ARRAY_SIZE(ps_gamepad_buttons); i++) - input_set_capability(gamepad, EV_KEY, ps_gamepad_buttons[i]); - -#if IS_ENABLED(CONFIG_PLAYSTATION_FF) - if (play_effect) { - input_set_capability(gamepad, EV_FF, FF_RUMBLE); - input_ff_create_memless(gamepad, NULL, play_effect); - } -#endif - - ret = input_register_device(gamepad); - if (ret) - return ERR_PTR(ret); - - return gamepad; -} - -static int ps_get_report(struct hid_device *hdev, uint8_t report_id, - uint8_t *buf, size_t size) -{ - int ret; - - ret = hid_hw_raw_request(hdev, report_id, buf, size, HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); - if (ret < 0) { - hid_err(hdev, "Failed to retrieve: reportID %d: %d\n", report_id, ret); - return ret; - } - - if (ret != size) { - hid_err(hdev, "Invalid byte count, expected %zu got %d\n", size, ret); - return -EINVAL; - } - - if (buf[0] != report_id) { - hid_err(hdev, "Invalid reportID: expected %d got %d\n", report_id, buf[0]); - return -EINVAL; - } - - if (hdev->bus == BUS_BLUETOOTH) { - /* Last 4 bytes contains crc32. */ - uint8_t crc_offset = size - 4; - uint32_t report_crc = get_unaligned_le32(&buf[crc_offset]); - - if (!ps_check_crc32(PS_FEATURE_CRC32_SEED, buf, crc_offset, report_crc)) { - hid_err(hdev, "CRC check failed for reportID=%d\n", report_id); - return -EILSEQ; - } - } - - return 0; -} - -static struct input_dev *ps_sensors_create(struct hid_device *hdev, - int accel_range, int accel_res, int gyro_range, int gyro_res) -{ - struct input_dev *sensors; - int ret; - - sensors = ps_allocate_input_dev(hdev, "Motion Sensors"); - if (IS_ERR(sensors)) - return ERR_CAST(sensors); - - __set_bit(INPUT_PROP_ACCELEROMETER, sensors->propbit); - __set_bit(EV_MSC, sensors->evbit); - __set_bit(MSC_TIMESTAMP, sensors->mscbit); - - /* Accelerometer */ - input_set_abs_params(sensors, ABS_X, -accel_range, accel_range, 16, 0); - input_set_abs_params(sensors, ABS_Y, -accel_range, accel_range, 16, 0); - input_set_abs_params(sensors, ABS_Z, -accel_range, accel_range, 16, 0); - input_abs_set_res(sensors, ABS_X, accel_res); - input_abs_set_res(sensors, ABS_Y, accel_res); - input_abs_set_res(sensors, ABS_Z, accel_res); - - /* Gyroscope */ - input_set_abs_params(sensors, ABS_RX, -gyro_range, gyro_range, 16, 0); - input_set_abs_params(sensors, ABS_RY, -gyro_range, gyro_range, 16, 0); - input_set_abs_params(sensors, ABS_RZ, -gyro_range, gyro_range, 16, 0); - input_abs_set_res(sensors, ABS_RX, gyro_res); - input_abs_set_res(sensors, ABS_RY, gyro_res); - input_abs_set_res(sensors, ABS_RZ, gyro_res); - - ret = input_register_device(sensors); - if (ret) - return ERR_PTR(ret); - - return sensors; -} - -static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, int height, - unsigned int num_contacts) -{ - struct input_dev *touchpad; - int ret; - - touchpad = ps_allocate_input_dev(hdev, "Touchpad"); - if (IS_ERR(touchpad)) - return ERR_CAST(touchpad); - - /* Map button underneath touchpad to BTN_LEFT. */ - input_set_capability(touchpad, EV_KEY, BTN_LEFT); - __set_bit(INPUT_PROP_BUTTONPAD, touchpad->propbit); - - input_set_abs_params(touchpad, ABS_MT_POSITION_X, 0, width - 1, 0, 0); - input_set_abs_params(touchpad, ABS_MT_POSITION_Y, 0, height - 1, 0, 0); - - ret = input_mt_init_slots(touchpad, num_contacts, INPUT_MT_POINTER); - if (ret) - return ERR_PTR(ret); - - ret = input_register_device(touchpad); - if (ret) - return ERR_PTR(ret); - - return touchpad; -} - -static ssize_t firmware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - struct ps_device *ps_dev = hid_get_drvdata(hdev); - - return scnprintf(buf, PAGE_SIZE, "0x%08x\n", ps_dev->fw_version); -} - -static DEVICE_ATTR_RO(firmware_version); - -static ssize_t hardware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - struct ps_device *ps_dev = hid_get_drvdata(hdev); - - return scnprintf(buf, PAGE_SIZE, "0x%08x\n", ps_dev->hw_version); -} - -static DEVICE_ATTR_RO(hardware_version); - -static struct attribute *ps_device_attributes[] = { - &dev_attr_firmware_version.attr, - &dev_attr_hardware_version.attr, - NULL -}; - -static const struct attribute_group ps_device_attribute_group = { - .attrs = ps_device_attributes, -}; - -static int dualsense_get_calibration_data(struct dualsense *ds) -{ - short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; - short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus; - short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus; - short gyro_speed_plus, gyro_speed_minus; - short acc_x_plus, acc_x_minus; - short acc_y_plus, acc_y_minus; - short acc_z_plus, acc_z_minus; - int speed_2x; - int range_2g; - int ret = 0; - uint8_t *buf; - - buf = kzalloc(DS_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_CALIBRATION, buf, - DS_FEATURE_REPORT_CALIBRATION_SIZE); - if (ret) { - hid_err(ds->base.hdev, "Failed: DualSense cal info: %d\n", ret); - goto err_free; - } - - gyro_pitch_bias = get_unaligned_le16(&buf[1]); - gyro_yaw_bias = get_unaligned_le16(&buf[3]); - gyro_roll_bias = get_unaligned_le16(&buf[5]); - gyro_pitch_plus = get_unaligned_le16(&buf[7]); - gyro_pitch_minus = get_unaligned_le16(&buf[9]); - gyro_yaw_plus = get_unaligned_le16(&buf[11]); - gyro_yaw_minus = get_unaligned_le16(&buf[13]); - gyro_roll_plus = get_unaligned_le16(&buf[15]); - gyro_roll_minus = get_unaligned_le16(&buf[17]); - gyro_speed_plus = get_unaligned_le16(&buf[19]); - gyro_speed_minus = get_unaligned_le16(&buf[21]); - acc_x_plus = get_unaligned_le16(&buf[23]); - acc_x_minus = get_unaligned_le16(&buf[25]); - acc_y_plus = get_unaligned_le16(&buf[27]); - acc_y_minus = get_unaligned_le16(&buf[29]); - acc_z_plus = get_unaligned_le16(&buf[31]); - acc_z_minus = get_unaligned_le16(&buf[33]); - - /* - * Set gyroscope calibration and normalization parameters. - * Data values will be normalized to 1/DS_GYRO_RES_PER_DEG_S degree/s. - */ - speed_2x = (gyro_speed_plus + gyro_speed_minus); - ds->gyro_calib_data[0].abs_code = ABS_RX; - ds->gyro_calib_data[0].bias = gyro_pitch_bias; - ds->gyro_calib_data[0].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; - ds->gyro_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus; - - ds->gyro_calib_data[1].abs_code = ABS_RY; - ds->gyro_calib_data[1].bias = gyro_yaw_bias; - ds->gyro_calib_data[1].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; - ds->gyro_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus; - - ds->gyro_calib_data[2].abs_code = ABS_RZ; - ds->gyro_calib_data[2].bias = gyro_roll_bias; - ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; - ds->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; - - /* - * Set accelerometer calibration and normalization parameters. - * Data values will be normalized to 1/DS_ACC_RES_PER_G g. - */ - range_2g = acc_x_plus - acc_x_minus; - ds->accel_calib_data[0].abs_code = ABS_X; - ds->accel_calib_data[0].bias = acc_x_plus - range_2g / 2; - ds->accel_calib_data[0].sens_numer = 2*DS_ACC_RES_PER_G; - ds->accel_calib_data[0].sens_denom = range_2g; - - range_2g = acc_y_plus - acc_y_minus; - ds->accel_calib_data[1].abs_code = ABS_Y; - ds->accel_calib_data[1].bias = acc_y_plus - range_2g / 2; - ds->accel_calib_data[1].sens_numer = 2*DS_ACC_RES_PER_G; - ds->accel_calib_data[1].sens_denom = range_2g; - - range_2g = acc_z_plus - acc_z_minus; - ds->accel_calib_data[2].abs_code = ABS_Z; - ds->accel_calib_data[2].bias = acc_z_plus - range_2g / 2; - ds->accel_calib_data[2].sens_numer = 2*DS_ACC_RES_PER_G; - ds->accel_calib_data[2].sens_denom = range_2g; - -err_free: - kfree(buf); - return ret; -} - -static int dualsense_get_firmware_info(struct dualsense *ds) -{ - uint8_t *buf; - int ret; - - buf = kzalloc(DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_FIRMWARE_INFO, buf, - DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE); - if (ret) { - hid_err(ds->base.hdev, "Failed to retrieve DualSense firmware info: %d\n", ret); - goto err_free; - } - - ds->base.hw_version = get_unaligned_le32(&buf[24]); - ds->base.fw_version = get_unaligned_le32(&buf[28]); - -err_free: - kfree(buf); - return ret; -} - -static int dualsense_get_mac_address(struct dualsense *ds) -{ - uint8_t *buf; - int ret = 0; - - buf = kzalloc(DS_FEATURE_REPORT_PAIRING_INFO_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_PAIRING_INFO, buf, - DS_FEATURE_REPORT_PAIRING_INFO_SIZE); - if (ret) { - hid_err(ds->base.hdev, "Failed to retrieve DualSense pair: %d\n", ret); - goto err_free; - } - - memcpy(ds->base.mac_address, &buf[1], sizeof(ds->base.mac_address)); - -err_free: - kfree(buf); - return ret; -} - -static void dualsense_init_output_report(struct dualsense *ds, - struct dualsense_output_report *rp, void *buf) -{ - struct hid_device *hdev = ds->base.hdev; - - if (hdev->bus == BUS_BLUETOOTH) { - struct dualsense_output_report_bt *bt = buf; - - memset(bt, 0, sizeof(*bt)); - bt->report_id = DS_OUTPUT_REPORT_BT; - bt->tag = DS_OUTPUT_TAG; /* Tag to be set. It is unclear. */ - - /* - * Highest 4-bit is a sequence number, which needs to be - * increased every report. Lowest 4-bit is tag and can be - * zero for now. - */ - bt->seq_tag = (ds->output_seq << 4) | 0x0; - if (++ds->output_seq == 16) - ds->output_seq = 0; - - rp->data = buf; - rp->len = sizeof(*bt); - rp->bt = bt; - rp->usb = NULL; - rp->common = &bt->common; - } else { /* USB */ - struct dualsense_output_report_usb *usb = buf; - - memset(usb, 0, sizeof(*usb)); - usb->report_id = DS_OUTPUT_REPORT_USB; - - rp->data = buf; - rp->len = sizeof(*usb); - rp->bt = NULL; - rp->usb = usb; - rp->common = &usb->common; - } -} - -/* - * Helper function to send DualSense output reports. Applies a CRC - * at the end of a report for Bluetooth reports. - */ -static void dualsense_send_output_report(struct dualsense *ds, - struct dualsense_output_report *report) -{ - struct hid_device *hdev = ds->base.hdev; - - /* Bluetooth packets need to be signed - * with a CRC in the last 4 bytes. - */ - if (report->bt) { - uint32_t crc; - uint8_t seed = PS_OUTPUT_CRC32_SEED; - - crc = crc32_le(0xFFFFFFFF, &seed, 1); - crc = ~crc32_le(crc, report->data, report->len - 4); - - report->bt->crc32 = cpu_to_le32(crc); - } - - hid_hw_output_report(hdev, report->data, report->len); -} - -static void dualsense_output_worker(struct work_struct *work) -{ - struct dualsense *ds = container_of(work, struct dualsense, - output_worker); - struct dualsense_output_report report; - struct dualsense_output_report_common *common; - unsigned long flags; - - dualsense_init_output_report(ds, &report, ds->output_report_dmabuf); - common = report.common; - - spin_lock_irqsave(&ds->base.lock, flags); - - if (ds->update_rumble) { - /* Select classic rumble style haptics and enable it. */ - common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; - common->valid_flag0 |= - DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION; - common->motor_left = ds->motor_left; - common->motor_right = ds->motor_right; - ds->update_rumble = false; - } - - if (ds->update_lightbar) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE; - common->lightbar_red = ds->lightbar_red; - common->lightbar_green = ds->lightbar_green; - common->lightbar_blue = ds->lightbar_blue; - - ds->update_lightbar = false; - } - - if (ds->update_player_leds) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE; - common->player_leds = ds->player_leds_state; - - ds->update_player_leds = false; - } - - if (ds->update_mic_mute) { - common->valid_flag1 |= - DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; - common->mute_button_led = ds->mic_muted; - - if (ds->mic_muted) { - /* Disable microphone */ - common->valid_flag1 |= - DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; - common->power_save_control |= - DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; - } else { - /* Enable microphone */ - common->valid_flag1 |= - DS_OUTPUT_VALID_FLAG1_POWER_SAVE_CONTROL_ENABLE; - common->power_save_control &= - ~DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE; - } - - ds->update_mic_mute = false; - } - - spin_unlock_irqrestore(&ds->base.lock, flags); - - dualsense_send_output_report(ds, &report); -} - -static int dualsense_parse_report(struct ps_device *ps_dev, - struct hid_report *report, u8 *data, int size) -{ - struct hid_device *hdev = ps_dev->hdev; - struct dualsense *ds = container_of(ps_dev, struct dualsense, base); - struct dualsense_input_report *ds_report; - uint8_t battery_data, battery_capacity, charging_status, value; - int battery_status; - unsigned long flags; - bool btn_mic_state; - uint32_t sensor_timestamp; - int i; - - /* - * DualSense in USB uses the full HID report for reportID 1, but - * Bluetooth uses a minimal HID report for reportID 1 and reports - * the full report using reportID 49. - */ - if (hdev->bus == BUS_USB && report->id == DS_INPUT_REPORT_USB && - size == DS_INPUT_REPORT_USB_SIZE) { - ds_report = (struct dualsense_input_report *)&data[1]; - } else if (hdev->bus == BUS_BLUETOOTH && - report->id == DS_INPUT_REPORT_BT && - size == DS_INPUT_REPORT_BT_SIZE) { - /* Last 4 bytes of input report contain crc32 */ - uint32_t report_crc = get_unaligned_le32(&data[size - 4]); - - if (!ps_check_crc32(PS_INPUT_CRC32_SEED, data, size - 4, - report_crc)) { - hid_err(hdev, "DualSense input CRC's check failed\n"); - return -EILSEQ; - } - - ds_report = (struct dualsense_input_report *)&data[2]; - } else { - hid_err(hdev, "Unhandled reportID=%d\n", report->id); - return -1; - } - - input_report_abs(ds->gamepad, ABS_X, ds_report->x); - input_report_abs(ds->gamepad, ABS_Y, ds_report->y); - input_report_abs(ds->gamepad, ABS_RX, ds_report->rx); - input_report_abs(ds->gamepad, ABS_RY, ds_report->ry); - input_report_abs(ds->gamepad, ABS_Z, ds_report->z); - input_report_abs(ds->gamepad, ABS_RZ, ds_report->rz); - - value = ds_report->buttons[0] & DS_BUTTONS0_HAT_SWITCH; - if (value >= ARRAY_SIZE(ps_gamepad_hat_mapping)) - value = 8; /* center */ - input_report_abs(ds->gamepad, ABS_HAT0X, ps_gamepad_hat_mapping[value].x); - input_report_abs(ds->gamepad, ABS_HAT0Y, ps_gamepad_hat_mapping[value].y); - - input_report_key(ds->gamepad, BTN_WEST, ds_report->buttons[0] & DS_BUTTONS0_SQUARE); - input_report_key(ds->gamepad, BTN_SOUTH, ds_report->buttons[0] & DS_BUTTONS0_CROSS); - input_report_key(ds->gamepad, BTN_EAST, ds_report->buttons[0] & DS_BUTTONS0_CIRCLE); - input_report_key(ds->gamepad, BTN_NORTH, ds_report->buttons[0] & DS_BUTTONS0_TRIANGLE); - input_report_key(ds->gamepad, BTN_TL, ds_report->buttons[1] & DS_BUTTONS1_L1); - input_report_key(ds->gamepad, BTN_TR, ds_report->buttons[1] & DS_BUTTONS1_R1); - input_report_key(ds->gamepad, BTN_TL2, ds_report->buttons[1] & DS_BUTTONS1_L2); - input_report_key(ds->gamepad, BTN_TR2, ds_report->buttons[1] & DS_BUTTONS1_R2); - input_report_key(ds->gamepad, BTN_SELECT, ds_report->buttons[1] & DS_BUTTONS1_CREATE); - input_report_key(ds->gamepad, BTN_START, ds_report->buttons[1] & DS_BUTTONS1_OPTIONS); - input_report_key(ds->gamepad, BTN_THUMBL, ds_report->buttons[1] & DS_BUTTONS1_L3); - input_report_key(ds->gamepad, BTN_THUMBR, ds_report->buttons[1] & DS_BUTTONS1_R3); - input_report_key(ds->gamepad, BTN_MODE, ds_report->buttons[2] & DS_BUTTONS2_PS_HOME); - input_sync(ds->gamepad); - - /* - * The DualSense has an internal microphone, which can bemuted - * through a mute button on the device. The driver is expected - * to read the button state and program the device - * to mute/unmute audio at the hardware level. - */ - btn_mic_state = !!(ds_report->buttons[2] & DS_BUTTONS2_MIC_MUTE); - if (btn_mic_state && !ds->last_btn_mic_state) { - spin_lock_irqsave(&ps_dev->lock, flags); - ds->update_mic_mute = true; - ds->mic_muted = !ds->mic_muted; /* toggle */ - spin_unlock_irqrestore(&ps_dev->lock, flags); - - /* Schedule updating of microphone state at hardware level. */ - schedule_work(&ds->output_worker); - } - ds->last_btn_mic_state = btn_mic_state; - - /* Parse and calibrate gyroscope data. */ - for (i = 0; i < ARRAY_SIZE(ds_report->gyro); i++) { - int raw_data = (short)le16_to_cpu(ds_report->gyro[i]); - int calib_data = mult_frac(ds->gyro_calib_data[i].sens_numer, - raw_data - ds->gyro_calib_data[i].bias, - ds->gyro_calib_data[i].sens_denom); - - input_report_abs(ds->sensors, ds->gyro_calib_data[i].abs_code, - calib_data); - } - - /* Parse and calibrate accelerometer data. */ - for (i = 0; i < ARRAY_SIZE(ds_report->accel); i++) { - int raw_data = (short)le16_to_cpu(ds_report->accel[i]); - int calib_data = mult_frac(ds->accel_calib_data[i].sens_numer, - raw_data - ds->accel_calib_data[i].bias, - ds->accel_calib_data[i].sens_denom); - - input_report_abs(ds->sensors, ds->accel_calib_data[i].abs_code, - calib_data); - } - - /* Convert timestamp (in 0.33us unit) to timestamp_us */ - sensor_timestamp = le32_to_cpu(ds_report->sensor_timestamp); - if (!ds->sensor_timestamp_initialized) { - ds->sensor_timestamp_us = - DIV_ROUND_CLOSEST(sensor_timestamp, 3); - ds->sensor_timestamp_initialized = true; - } else { - uint32_t delta; - - if (ds->prev_sensor_timestamp > sensor_timestamp) - delta = (U32_MAX - ds->prev_sensor_timestamp + - sensor_timestamp + 1); - else - delta = sensor_timestamp - ds->prev_sensor_timestamp; - ds->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta, 3); - } - ds->prev_sensor_timestamp = sensor_timestamp; - input_event(ds->sensors, EV_MSC, MSC_TIMESTAMP, - ds->sensor_timestamp_us); - input_sync(ds->sensors); - - for (i = 0; i < ARRAY_SIZE(ds_report->points); i++) { - struct dualsense_touch_point *point = &ds_report->points[i]; - bool active = (point->contact & - DS_TOUCH_POINT_INACTIVE) ? false : true; - - input_mt_slot(ds->touchpad, i); - input_mt_report_slot_state(ds->touchpad, MT_TOOL_FINGER, active); - - if (active) { - int x = (point->x_hi << 8) | point->x_lo; - int y = (point->y_hi << 4) | point->y_lo; - - input_report_abs(ds->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, y); - } - } - input_mt_sync_frame(ds->touchpad); - input_report_key(ds->touchpad, BTN_LEFT, ds_report->buttons[2] & DS_BUTTONS2_TOUCHPAD); - input_sync(ds->touchpad); - - battery_data = ds_report->status & DS_STATUS_BATTERY_CAPACITY; - charging_status = (ds_report->status & DS_STATUS_CHARGING) >> DS_STATUS_CHARGING_SHIFT; - - switch (charging_status) { - case 0x0: - /* - * Each unit of battery data corresponds to 10% - * 0 = 0-9%, 1 = 10-19%, .. and 10 = 100% - */ - battery_capacity = min(battery_data * 10 + 5, 100); - battery_status = POWER_SUPPLY_STATUS_DISCHARGING; - break; - case 0x1: - battery_capacity = min(battery_data * 10 + 5, 100); - battery_status = POWER_SUPPLY_STATUS_CHARGING; - break; - case 0x2: - battery_capacity = 100; - battery_status = POWER_SUPPLY_STATUS_FULL; - break; - case 0xa: /* voltage or temperature out of range */ - case 0xb: /* temperature error */ - battery_capacity = 0; - battery_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - break; - case 0xf: /* charging error */ - default: - battery_capacity = 0; - battery_status = POWER_SUPPLY_STATUS_UNKNOWN; - } - - spin_lock_irqsave(&ps_dev->lock, flags); - ps_dev->battery_capacity = battery_capacity; - ps_dev->battery_status = battery_status; - spin_unlock_irqrestore(&ps_dev->lock, flags); - - return 0; -} - -static int dualsense_play_effect(struct input_dev *dev, - void *data, struct ff_effect *effect) -{ - struct hid_device *hdev = input_get_drvdata(dev); - struct dualsense *ds = hid_get_drvdata(hdev); - unsigned long flags; - - if (effect->type != FF_RUMBLE) - return 0; - - spin_lock_irqsave(&ds->base.lock, flags); - ds->update_rumble = true; - ds->motor_left = effect->u.rumble.strong_magnitude / 256; - ds->motor_right = effect->u.rumble.weak_magnitude / 256; - spin_unlock_irqrestore(&ds->base.lock, flags); - - schedule_work(&ds->output_worker); - return 0; -} - -static int dualsense_reset_leds(struct dualsense *ds) -{ - struct dualsense_output_report report; - uint8_t *buf; - - buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - dualsense_init_output_report(ds, &report, buf); - /* - * On Bluetooth the DualSense outputs an animation on the lightbar - * during startup and maintains a color afterwards. We need to explicitly - * reconfigure the lightbar before we can do any programming later on. - * In USB the lightbar is not on by default, but redoing the setup there - * doesn't hurt. - */ - report.common->valid_flag2 = DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE; - report.common->lightbar_setup = DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT; /* Fade light out. */ - dualsense_send_output_report(ds, &report); - - kfree(buf); - return 0; -} - -static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue) -{ - ds->update_lightbar = true; - ds->lightbar_red = red; - ds->lightbar_green = green; - ds->lightbar_blue = blue; - - schedule_work(&ds->output_worker); -} - -static void dualsense_set_player_leds(struct dualsense *ds) -{ - /* - * The DualSense controller has a row of 5 LEDs used for player ids. - * Behavior on the PlayStation 5 console is to center the player id - * across the LEDs, so e.g. player 1 would be "--x--" with x being 'on'. - * Follow a similar mapping here. - */ - static const int player_ids[5] = { - BIT(2), - BIT(3) | BIT(1), - BIT(4) | BIT(2) | BIT(0), - BIT(4) | BIT(3) | BIT(1) | BIT(0), - BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0) - }; - - uint8_t player_id = ds->base.player_id % ARRAY_SIZE(player_ids); - - ds->update_player_leds = true; - ds->player_leds_state = player_ids[player_id]; - schedule_work(&ds->output_worker); -} - -static struct ps_device *dualsense_create(struct hid_device *hdev) -{ - struct dualsense *ds; - struct ps_device *ps_dev; - uint8_t max_output_report_size; - int ret; - - ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL); - if (!ds) - return ERR_PTR(-ENOMEM); - - /* - * Patch version to allow userspace to distinguish between - * hid-generic vs hid-playstation axis and button mapping. - */ - hdev->version |= HID_PLAYSTATION_VERSION_PATCH; - - ps_dev = &ds->base; - ps_dev->hdev = hdev; - spin_lock_init(&ps_dev->lock); - ps_dev->battery_capacity = 100; /* initial value until parse_report. */ - ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN; - ps_dev->parse_report = dualsense_parse_report; - INIT_WORK(&ds->output_worker, dualsense_output_worker); - hid_set_drvdata(hdev, ds); - - max_output_report_size = sizeof(struct dualsense_output_report_bt); - ds->output_report_dmabuf = devm_kzalloc(&hdev->dev, - max_output_report_size, GFP_KERNEL); - if (!ds->output_report_dmabuf) - return ERR_PTR(-ENOMEM); - - ret = dualsense_get_mac_address(ds); - if (ret) { - hid_err(hdev, "Failed to get MAC address from DualSense\n"); - return ERR_PTR(ret); - } - snprintf(hdev->uniq, sizeof(hdev->uniq), "%pMR", ds->base.mac_address); - - ret = dualsense_get_firmware_info(ds); - if (ret) { - hid_err(hdev, "Failed to get firmware info from DualSense\n"); - return ERR_PTR(ret); - } - - ret = ps_devices_list_add(ps_dev); - if (ret) - return ERR_PTR(ret); - - ret = dualsense_get_calibration_data(ds); - if (ret) { - hid_err(hdev, "Failed to get calibration data from DualSense\n"); - goto err; - } - - ds->gamepad = ps_gamepad_create(hdev, dualsense_play_effect); - if (IS_ERR(ds->gamepad)) { - ret = PTR_ERR(ds->gamepad); - goto err; - } - - ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G, - DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); - if (IS_ERR(ds->sensors)) { - ret = PTR_ERR(ds->sensors); - goto err; - } - - ds->touchpad = ps_touchpad_create(hdev, DS_TOUCHPAD_WIDTH, - DS_TOUCHPAD_HEIGHT, 2); - if (IS_ERR(ds->touchpad)) { - ret = PTR_ERR(ds->touchpad); - goto err; - } - - ret = ps_device_register_battery(ps_dev); - if (ret) - goto err; - - /* - * The hardware may have control over the LEDs (e.g. in Bluetooth on startup). - * Reset the LEDs (lightbar, mute, player leds), so we can control them - * from software. - */ - ret = dualsense_reset_leds(ds); - if (ret) - goto err; - - dualsense_set_lightbar(ds, 0, 0, 128); /* blue */ - - ret = ps_device_set_player_id(ps_dev); - if (ret) { - hid_err(hdev, "Failed to assign player id for DualSense: %d\n", ret); - goto err; - } - - /* Set player LEDs to our player id. */ - dualsense_set_player_leds(ds); - - /* - * Reporting hardware and firmware is important as there are frequent updates, which - * can change behavior. - */ - hid_info(hdev, "Registered DualSense controller hw_version=0x%08x fw_version=0x%08x\n", - ds->base.hw_version, ds->base.fw_version); - - return &ds->base; - -err: - ps_devices_list_remove(ps_dev); - return ERR_PTR(ret); -} - -static int ps_raw_event(struct hid_device *hdev, struct hid_report *report, - u8 *data, int size) -{ - struct ps_device *dev = hid_get_drvdata(hdev); - - if (dev && dev->parse_report) - return dev->parse_report(dev, report, data, size); - - return 0; -} - -static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - struct ps_device *dev; - int ret; - - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "Parse failed\n"); - return ret; - } - - ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); - if (ret) { - hid_err(hdev, "Failed to start HID device\n"); - return ret; - } - - ret = hid_hw_open(hdev); - if (ret) { - hid_err(hdev, "Failed to open HID device\n"); - goto err_stop; - } - - if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) { - dev = dualsense_create(hdev); - if (IS_ERR(dev)) { - hid_err(hdev, "Failed to create dualsense.\n"); - ret = PTR_ERR(dev); - goto err_close; - } - } - - ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group); - if (ret) { - hid_err(hdev, "Failed to register sysfs nodes.\n"); - goto err_close; - } - - return ret; - -err_close: - hid_hw_close(hdev); -err_stop: - hid_hw_stop(hdev); - return ret; -} - -static void ps_remove(struct hid_device *hdev) -{ - struct ps_device *dev = hid_get_drvdata(hdev); - - ps_devices_list_remove(dev); - ps_device_release_player_id(dev); - - hid_hw_close(hdev); - hid_hw_stop(hdev); -} - -static const struct hid_device_id ps_devices[] = { - { 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) }, - { } -}; -MODULE_DEVICE_TABLE(hid, ps_devices); - -static struct hid_driver ps_driver = { - .name = "playstation", - .id_table = ps_devices, - .probe = ps_probe, - .remove = ps_remove, - .raw_event = ps_raw_event, -}; - -static int __init ps_init(void) -{ - return hid_register_driver(&ps_driver); -} - -static void __exit ps_exit(void) -{ - hid_unregister_driver(&ps_driver); - ida_destroy(&ps_player_id_allocator); -} - -module_init(ps_init); -module_exit(ps_exit); - -MODULE_AUTHOR("Sony Interactive Entertainment"); -MODULE_DESCRIPTION("HID Driver for PlayStation peripherals."); -MODULE_LICENSE("GPL v2");