diff options
Diffstat (limited to 'drivers/hid/hid-playstation.c')
-rw-r--r-- | drivers/hid/hid-playstation.c | 1073 |
1 files changed, 599 insertions, 474 deletions
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c index 1468fb11e39d..63f6eb9030d1 100644 --- a/drivers/hid/hid-playstation.c +++ b/drivers/hid/hid-playstation.c @@ -5,7 +5,9 @@ * Copyright (c) 2020-2022 Sony Interactive Entertainment */ +#include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/cleanup.h> #include <linux/crc32.h> #include <linux/device.h> #include <linux/hid.h> @@ -36,19 +38,19 @@ enum PS_TYPE { struct ps_device { struct list_head list; struct hid_device *hdev; - spinlock_t lock; + spinlock_t lock; /* Sync between event handler and workqueue */ - uint32_t player_id; + u32 player_id; struct power_supply_desc battery_desc; struct power_supply *battery; - uint8_t battery_capacity; + u8 battery_capacity; int battery_status; const char *input_dev_name; /* Name of primary input device. */ - uint8_t mac_address[6]; /* Note: stored in little endian order. */ - uint32_t hw_version; - uint32_t fw_version; + u8 mac_address[6]; /* Note: stored in little endian order. */ + u32 hw_version; + u32 fw_version; int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size); void (*remove)(struct ps_device *dev); @@ -110,41 +112,62 @@ struct ps_led_info { #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 fields of DualSense input report. */ +#define DS_STATUS0_BATTERY_CAPACITY GENMASK(3, 0) +#define DS_STATUS0_CHARGING GENMASK(7, 4) +#define DS_STATUS1_HP_DETECT BIT(0) +#define DS_STATUS1_MIC_DETECT BIT(1) +#define DS_STATUS1_JACK_DETECT (DS_STATUS1_HP_DETECT | DS_STATUS1_MIC_DETECT) +#define DS_STATUS1_MIC_MUTE BIT(2) /* Feature version from DualSense Firmware Info report. */ -#define DS_FEATURE_VERSION(major, minor) ((major & 0xff) << 8 | (minor & 0xff)) - +#define DS_FEATURE_VERSION_MINOR GENMASK(7, 0) +#define DS_FEATURE_VERSION_MAJOR GENMASK(15, 8) +#define DS_FEATURE_VERSION(major, minor) (FIELD_PREP(DS_FEATURE_VERSION_MAJOR, major) | \ + FIELD_PREP(DS_FEATURE_VERSION_MINOR, minor)) /* * 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) +#define DS_TOUCH_POINT_INACTIVE BIT(7) +#define DS_TOUCH_POINT_X_LO GENMASK(7, 0) +#define DS_TOUCH_POINT_X_HI GENMASK(11, 8) +#define DS_TOUCH_POINT_X(hi, lo) (FIELD_PREP(DS_TOUCH_POINT_X_HI, hi) | \ + FIELD_PREP(DS_TOUCH_POINT_X_LO, lo)) +#define DS_TOUCH_POINT_Y_LO GENMASK(3, 0) +#define DS_TOUCH_POINT_Y_HI GENMASK(11, 4) +#define DS_TOUCH_POINT_Y(hi, lo) (FIELD_PREP(DS_TOUCH_POINT_Y_HI, hi) | \ + FIELD_PREP(DS_TOUCH_POINT_Y_LO, lo)) /* Magic value required in tag field of Bluetooth output report. */ -#define DS_OUTPUT_TAG 0x10 +#define DS_OUTPUT_TAG 0x10 +#define DS_OUTPUT_SEQ_TAG GENMASK(3, 0) +#define DS_OUTPUT_SEQ_NO GENMASK(7, 4) /* 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_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2) -#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) -#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) +#define DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION BIT(0) +#define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT BIT(1) +#define DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE BIT(5) +#define DS_OUTPUT_VALID_FLAG0_MIC_VOLUME_ENABLE BIT(6) +#define DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE BIT(7) +#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_FLAG1_AUDIO_CONTROL2_ENABLE BIT(7) +#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1) +#define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2) +#define DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL GENMASK(5, 4) +#define DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN GENMASK(2, 0) +#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4) +#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1) /* DualSense hardware limits */ #define DS_ACC_RES_PER_G 8192 -#define DS_ACC_RANGE (4*DS_ACC_RES_PER_G) +#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) +#define DS_GYRO_RANGE (2048 * DS_GYRO_RES_PER_DEG_S) #define DS_TOUCHPAD_WIDTH 1920 #define DS_TOUCHPAD_HEIGHT 1080 @@ -153,9 +176,10 @@ struct dualsense { struct input_dev *gamepad; struct input_dev *sensors; struct input_dev *touchpad; + struct input_dev *jack; /* Update version is used as a feature/capability version. */ - uint16_t update_version; + u16 update_version; /* Calibration data for accelerometer and gyroscope. */ struct ps_calibration_data accel_calib_data[3]; @@ -163,21 +187,26 @@ struct dualsense { /* Timestamp for sensor data */ bool sensor_timestamp_initialized; - uint32_t prev_sensor_timestamp; - uint32_t sensor_timestamp_us; + u32 prev_sensor_timestamp; + u32 sensor_timestamp_us; /* Compatible rumble state */ bool use_vibration_v2; bool update_rumble; - uint8_t motor_left; - uint8_t motor_right; + u8 motor_left; + u8 motor_right; /* RGB lightbar */ struct led_classdev_mc lightbar; bool update_lightbar; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; + + /* Audio Jack plugged state */ + u8 plugged_state; + u8 prev_plugged_state; + bool prev_plugged_state_valid; /* Microphone */ bool update_mic_mute; @@ -186,90 +215,94 @@ struct dualsense { /* Player leds */ bool update_player_leds; - uint8_t player_leds_state; + u8 player_leds_state; struct led_classdev player_leds[5]; struct work_struct output_worker; bool output_worker_initialized; void *output_report_dmabuf; - uint8_t output_seq; /* Sequence number for output report. */ + u8 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; + u8 contact; + u8 x_lo; + u8 x_hi:4, y_lo:4; + u8 y_hi; } __packed; static_assert(sizeof(struct dualsense_touch_point) == 4); /* 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]; + u8 x, y; + u8 rx, ry; + u8 z, rz; + u8 seq_number; + u8 buttons[4]; + u8 reserved[4]; /* Motion sensors */ __le16 gyro[3]; /* x, y, z */ __le16 accel[3]; /* x, y, z */ __le32 sensor_timestamp; - uint8_t reserved2; + u8 reserved2; /* Touchpad */ struct dualsense_touch_point points[2]; - uint8_t reserved3[12]; - uint8_t status; - uint8_t reserved4[10]; + u8 reserved3[12]; + u8 status[3]; + u8 reserved4[8]; } __packed; /* Common input report size shared equals the size of the USB report minus 1 byte for ReportID. */ static_assert(sizeof(struct dualsense_input_report) == DS_INPUT_REPORT_USB_SIZE - 1); /* Common data between DualSense BT/USB main output report. */ struct dualsense_output_report_common { - uint8_t valid_flag0; - uint8_t valid_flag1; + u8 valid_flag0; + u8 valid_flag1; /* For DualShock 4 compatibility mode. */ - uint8_t motor_right; - uint8_t motor_left; + u8 motor_right; + u8 motor_left; /* Audio controls */ - uint8_t reserved[4]; - uint8_t mute_button_led; + u8 headphone_volume; /* 0x0 - 0x7f */ + u8 speaker_volume; /* 0x0 - 0xff */ + u8 mic_volume; /* 0x0 - 0x40 */ + u8 audio_control; + u8 mute_button_led; - uint8_t power_save_control; - uint8_t reserved2[28]; + u8 power_save_control; + u8 reserved2[27]; + u8 audio_control2; /* 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; + u8 valid_flag2; + u8 reserved3[2]; + u8 lightbar_setup; + u8 led_brightness; + u8 player_leds; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; } __packed; static_assert(sizeof(struct dualsense_output_report_common) == 47); struct dualsense_output_report_bt { - uint8_t report_id; /* 0x31 */ - uint8_t seq_tag; - uint8_t tag; + u8 report_id; /* 0x31 */ + u8 seq_tag; + u8 tag; struct dualsense_output_report_common common; - uint8_t reserved[24]; + u8 reserved[24]; __le32 crc32; } __packed; static_assert(sizeof(struct dualsense_output_report_bt) == DS_OUTPUT_REPORT_BT_SIZE); struct dualsense_output_report_usb { - uint8_t report_id; /* 0x02 */ + u8 report_id; /* 0x02 */ struct dualsense_output_report_common common; - uint8_t reserved[15]; + u8 reserved[15]; } __packed; static_assert(sizeof(struct dualsense_output_report_usb) == DS_OUTPUT_REPORT_USB_SIZE); @@ -279,8 +312,8 @@ static_assert(sizeof(struct dualsense_output_report_usb) == DS_OUTPUT_REPORT_USB * 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 */ + u8 *data; /* Start of data */ + u8 len; /* Size of output report */ /* Points to Bluetooth data payload in case for a Bluetooth report else NULL. */ struct dualsense_output_report_bt *bt; @@ -315,7 +348,9 @@ struct dualsense_output_report { * Contact IDs, with highest bit set are 'inactive' * and any associated data is then invalid. */ -#define DS4_TOUCH_POINT_INACTIVE BIT(7) +#define DS4_TOUCH_POINT_INACTIVE BIT(7) +#define DS4_TOUCH_POINT_X(hi, lo) DS_TOUCH_POINT_X(hi, lo) +#define DS4_TOUCH_POINT_Y(hi, lo) DS_TOUCH_POINT_Y(hi, lo) /* Status field of DualShock4 input report. */ #define DS4_STATUS0_BATTERY_CAPACITY GENMASK(3, 0) @@ -323,7 +358,7 @@ struct dualsense_output_report { /* Battery status within batery_status field. */ #define DS4_BATTERY_STATUS_FULL 11 /* Status1 bit2 contains dongle connection state: - * 0 = connectd + * 0 = connected * 1 = disconnected */ #define DS4_STATUS1_DONGLE_STATE BIT(2) @@ -349,9 +384,9 @@ struct dualsense_output_report { /* DualShock4 hardware limits */ #define DS4_ACC_RES_PER_G 8192 -#define DS4_ACC_RANGE (4*DS_ACC_RES_PER_G) +#define DS4_ACC_RANGE (4 * DS_ACC_RES_PER_G) #define DS4_GYRO_RES_PER_DEG_S 1024 -#define DS4_GYRO_RANGE (2048*DS_GYRO_RES_PER_DEG_S) +#define DS4_GYRO_RANGE (2048 * DS_GYRO_RES_PER_DEG_S) #define DS4_LIGHTBAR_MAX_BLINK 255 /* 255 centiseconds */ #define DS4_TOUCHPAD_WIDTH 1920 #define DS4_TOUCHPAD_HEIGHT 942 @@ -380,26 +415,26 @@ struct dualshock4 { /* Timestamp for sensor data */ bool sensor_timestamp_initialized; - uint32_t prev_sensor_timestamp; - uint32_t sensor_timestamp_us; + u32 prev_sensor_timestamp; + u32 sensor_timestamp_us; /* Bluetooth poll interval */ bool update_bt_poll_interval; - uint8_t bt_poll_interval; + u8 bt_poll_interval; bool update_rumble; - uint8_t motor_left; - uint8_t motor_right; + u8 motor_left; + u8 motor_right; /* Lightbar leds */ bool update_lightbar; bool update_lightbar_blink; bool lightbar_enabled; /* For use by global LED control. */ - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; - uint8_t lightbar_blink_on; /* In increments of 10ms. */ - uint8_t lightbar_blink_off; /* In increments of 10ms. */ + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; + u8 lightbar_blink_on; /* In increments of 10ms. */ + u8 lightbar_blink_off; /* In increments of 10ms. */ struct led_classdev lightbar_leds[4]; struct work_struct output_worker; @@ -408,88 +443,88 @@ struct dualshock4 { }; struct dualshock4_touch_point { - uint8_t contact; - uint8_t x_lo; - uint8_t x_hi:4, y_lo:4; - uint8_t y_hi; + u8 contact; + u8 x_lo; + u8 x_hi:4, y_lo:4; + u8 y_hi; } __packed; static_assert(sizeof(struct dualshock4_touch_point) == 4); struct dualshock4_touch_report { - uint8_t timestamp; + u8 timestamp; struct dualshock4_touch_point points[2]; } __packed; static_assert(sizeof(struct dualshock4_touch_report) == 9); /* Main DualShock4 input report excluding any BT/USB specific headers. */ struct dualshock4_input_report_common { - uint8_t x, y; - uint8_t rx, ry; - uint8_t buttons[3]; - uint8_t z, rz; + u8 x, y; + u8 rx, ry; + u8 buttons[3]; + u8 z, rz; /* Motion sensors */ __le16 sensor_timestamp; - uint8_t sensor_temperature; + u8 sensor_temperature; __le16 gyro[3]; /* x, y, z */ __le16 accel[3]; /* x, y, z */ - uint8_t reserved2[5]; + u8 reserved2[5]; - uint8_t status[2]; - uint8_t reserved3; + u8 status[2]; + u8 reserved3; } __packed; static_assert(sizeof(struct dualshock4_input_report_common) == 32); struct dualshock4_input_report_usb { - uint8_t report_id; /* 0x01 */ + u8 report_id; /* 0x01 */ struct dualshock4_input_report_common common; - uint8_t num_touch_reports; + u8 num_touch_reports; struct dualshock4_touch_report touch_reports[3]; - uint8_t reserved[3]; + u8 reserved[3]; } __packed; static_assert(sizeof(struct dualshock4_input_report_usb) == DS4_INPUT_REPORT_USB_SIZE); struct dualshock4_input_report_bt { - uint8_t report_id; /* 0x11 */ - uint8_t reserved[2]; + u8 report_id; /* 0x11 */ + u8 reserved[2]; struct dualshock4_input_report_common common; - uint8_t num_touch_reports; + u8 num_touch_reports; struct dualshock4_touch_report touch_reports[4]; /* BT has 4 compared to 3 for USB */ - uint8_t reserved2[2]; + u8 reserved2[2]; __le32 crc32; } __packed; static_assert(sizeof(struct dualshock4_input_report_bt) == DS4_INPUT_REPORT_BT_SIZE); /* Common data between Bluetooth and USB DualShock4 output reports. */ struct dualshock4_output_report_common { - uint8_t valid_flag0; - uint8_t valid_flag1; + u8 valid_flag0; + u8 valid_flag1; - uint8_t reserved; + u8 reserved; - uint8_t motor_right; - uint8_t motor_left; + u8 motor_right; + u8 motor_left; - uint8_t lightbar_red; - uint8_t lightbar_green; - uint8_t lightbar_blue; - uint8_t lightbar_blink_on; - uint8_t lightbar_blink_off; + u8 lightbar_red; + u8 lightbar_green; + u8 lightbar_blue; + u8 lightbar_blink_on; + u8 lightbar_blink_off; } __packed; struct dualshock4_output_report_usb { - uint8_t report_id; /* 0x5 */ + u8 report_id; /* 0x5 */ struct dualshock4_output_report_common common; - uint8_t reserved[21]; + u8 reserved[21]; } __packed; static_assert(sizeof(struct dualshock4_output_report_usb) == DS4_OUTPUT_REPORT_USB_SIZE); struct dualshock4_output_report_bt { - uint8_t report_id; /* 0x11 */ - uint8_t hw_control; - uint8_t audio_control; + u8 report_id; /* 0x11 */ + u8 hw_control; + u8 audio_control; struct dualshock4_output_report_common common; - uint8_t reserved[61]; + u8 reserved[61]; __le32 crc32; } __packed; static_assert(sizeof(struct dualshock4_output_report_bt) == DS4_OUTPUT_REPORT_BT_SIZE); @@ -500,8 +535,8 @@ static_assert(sizeof(struct dualshock4_output_report_bt) == DS4_OUTPUT_REPORT_BT * This structure hide the differences between the two to simplify sending output reports. */ struct dualshock4_output_report { - uint8_t *data; /* Start of data */ - uint8_t len; /* Size of output report */ + u8 *data; /* Start of data */ + u8 len; /* Size of output report */ /* Points to Bluetooth data payload in case for a Bluetooth report else NULL. */ struct dualshock4_output_report_bt *bt; @@ -540,7 +575,7 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = { static int dualshock4_get_calibration_data(struct dualshock4 *ds4); static inline void dualsense_schedule_work(struct dualsense *ds); static inline void dualshock4_schedule_work(struct dualshock4 *ds4); -static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue); +static void dualsense_set_lightbar(struct dualsense *ds, u8 red, u8 green, u8 blue); static void dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4); /* @@ -552,26 +587,25 @@ static int ps_devices_list_add(struct ps_device *dev) { struct ps_device *entry; - mutex_lock(&ps_devices_lock); + guard(mutex)(&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); + dev->mac_address); 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); + guard(mutex)(&ps_devices_lock); + list_del(&dev->list); - mutex_unlock(&ps_devices_lock); return 0; } @@ -593,7 +627,8 @@ static void ps_device_release_player_id(struct ps_device *dev) dev->player_id = U32_MAX; } -static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const char *name_suffix) +static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, + const char *name_suffix) { struct input_dev *input_dev; @@ -608,8 +643,8 @@ static struct input_dev *ps_allocate_input_dev(struct hid_device *hdev, const ch input_dev->uniq = hdev->uniq; if (name_suffix) { - input_dev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name, - 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 { @@ -629,19 +664,18 @@ static enum power_supply_property ps_power_supply_props[] = { }; static int ps_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) + enum power_supply_property psp, + union power_supply_propval *val) { struct ps_device *dev = power_supply_get_drvdata(psy); - uint8_t battery_capacity; + u8 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); + scoped_guard(spinlock_irqsave, &dev->lock) { + battery_capacity = dev->battery_capacity; + battery_status = dev->battery_status; + } switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -675,7 +709,7 @@ static int ps_device_register_battery(struct ps_device *dev) 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); + "ps-controller-battery-%pMR", dev->mac_address); if (!dev->battery_desc.name) return -ENOMEM; @@ -697,9 +731,9 @@ static int ps_device_register_battery(struct ps_device *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) +static bool ps_check_crc32(u8 seed, u8 *data, size_t len, u32 report_crc) { - uint32_t crc; + u32 crc; crc = crc32_le(0xFFFFFFFF, &seed, 1); crc = ~crc32_le(crc, data, len); @@ -707,8 +741,9 @@ static bool ps_check_crc32(uint8_t seed, uint8_t *data, size_t len, uint32_t rep return crc == report_crc; } -static struct input_dev *ps_gamepad_create(struct hid_device *hdev, - int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) +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; @@ -745,8 +780,8 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev, return gamepad; } -static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *buf, size_t size, - bool check_crc) +static int ps_get_report(struct hid_device *hdev, u8 report_id, u8 *buf, + size_t size, bool check_crc) { int ret; @@ -769,8 +804,8 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu if (hdev->bus == BUS_BLUETOOTH && check_crc) { /* Last 4 bytes contains crc32. */ - uint8_t crc_offset = size - 4; - uint32_t report_crc = get_unaligned_le32(&buf[crc_offset]); + u8 crc_offset = size - 4; + u32 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); @@ -782,17 +817,20 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu } static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led, - const struct ps_led_info *led_info) + const struct ps_led_info *led_info) { int ret; if (led_info->name) { - led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, - "%s:%s:%s", ps_dev->input_dev_name, led_info->color, led_info->name); + led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, "%s:%s:%s", + ps_dev->input_dev_name, led_info->color, + led_info->name); } else { - /* Backwards compatible mode for hid-sony, but not compliant with LED class spec. */ - led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, - "%s:%s", ps_dev->input_dev_name, led_info->color); + /* Backwards compatible mode for hid-sony, but not compliant + * with LED class spec. + */ + led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL, "%s:%s", + ps_dev->input_dev_name, led_info->color); } if (!led->name) @@ -816,7 +854,7 @@ static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led, /* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev, - int (*brightness_set)(struct led_classdev *, enum led_brightness)) + int (*brightness_set)(struct led_classdev *, enum led_brightness)) { struct hid_device *hdev = ps_dev->hdev; struct mc_subled *mc_led_info; @@ -837,7 +875,7 @@ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc led_cdev = &lightbar_mc_dev->led_cdev; led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s:rgb:indicator", - ps_dev->input_dev_name); + ps_dev->input_dev_name); if (!led_cdev->name) return -ENOMEM; led_cdev->brightness = 255; @@ -853,8 +891,8 @@ static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc 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) +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; @@ -890,8 +928,8 @@ static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_ra return sensors; } -static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, int height, - unsigned int num_contacts) +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; @@ -918,9 +956,27 @@ static struct input_dev *ps_touchpad_create(struct hid_device *hdev, int width, return touchpad; } +static struct input_dev *ps_headset_jack_create(struct hid_device *hdev) +{ + struct input_dev *jack; + int ret; + + jack = ps_allocate_input_dev(hdev, "Headset Jack"); + if (IS_ERR(jack)) + return ERR_CAST(jack); + + input_set_capability(jack, EV_SW, SW_HEADPHONE_INSERT); + input_set_capability(jack, EV_SW, SW_MICROPHONE_INSERT); + + ret = input_register_device(jack); + if (ret) + return ERR_PTR(ret); + + return jack; +} + static ssize_t firmware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) + struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct ps_device *ps_dev = hid_get_drvdata(hdev); @@ -931,8 +987,7 @@ static ssize_t firmware_version_show(struct device *dev, static DEVICE_ATTR_RO(firmware_version); static ssize_t hardware_version_show(struct device *dev, - struct device_attribute - *attr, char *buf) + struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); struct ps_device *ps_dev = hid_get_drvdata(hdev); @@ -963,14 +1018,14 @@ static int dualsense_get_calibration_data(struct dualsense *ds) int range_2g; int ret = 0; int i; - uint8_t *buf; + u8 *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, true); + DS_FEATURE_REPORT_CALIBRATION_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense calibration info: %d\n", ret); goto err_free; @@ -1001,19 +1056,19 @@ static int dualsense_get_calibration_data(struct dualsense *ds) speed_2x = (gyro_speed_plus + gyro_speed_minus); ds->gyro_calib_data[0].abs_code = ABS_RX; ds->gyro_calib_data[0].bias = 0; - ds->gyro_calib_data[0].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[0].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) + abs(gyro_pitch_minus - gyro_pitch_bias); ds->gyro_calib_data[1].abs_code = ABS_RY; ds->gyro_calib_data[1].bias = 0; - ds->gyro_calib_data[1].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[1].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) + abs(gyro_yaw_minus - gyro_yaw_bias); ds->gyro_calib_data[2].abs_code = ABS_RZ; ds->gyro_calib_data[2].bias = 0; - ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S; + ds->gyro_calib_data[2].sens_numer = speed_2x * DS_GYRO_RES_PER_DEG_S; ds->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); @@ -1024,8 +1079,9 @@ static int dualsense_get_calibration_data(struct dualsense *ds) */ for (i = 0; i < ARRAY_SIZE(ds->gyro_calib_data); i++) { if (ds->gyro_calib_data[i].sens_denom == 0) { - hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.", - ds->gyro_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid gyro calibration data for axis (%d), disabling calibration.", + ds->gyro_calib_data[i].abs_code); ds->gyro_calib_data[i].bias = 0; ds->gyro_calib_data[i].sens_numer = DS_GYRO_RANGE; ds->gyro_calib_data[i].sens_denom = S16_MAX; @@ -1039,19 +1095,19 @@ static int dualsense_get_calibration_data(struct dualsense *ds) 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_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_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_numer = 2 * DS_ACC_RES_PER_G; ds->accel_calib_data[2].sens_denom = range_2g; /* @@ -1061,8 +1117,9 @@ static int dualsense_get_calibration_data(struct dualsense *ds) */ for (i = 0; i < ARRAY_SIZE(ds->accel_calib_data); i++) { if (ds->accel_calib_data[i].sens_denom == 0) { - hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.", - ds->accel_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds->accel_calib_data[i].abs_code); ds->accel_calib_data[i].bias = 0; ds->accel_calib_data[i].sens_numer = DS_ACC_RANGE; ds->accel_calib_data[i].sens_denom = S16_MAX; @@ -1074,10 +1131,9 @@ err_free: return ret; } - static int dualsense_get_firmware_info(struct dualsense *ds) { - uint8_t *buf; + u8 *buf; int ret; buf = kzalloc(DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); @@ -1085,7 +1141,7 @@ static int dualsense_get_firmware_info(struct dualsense *ds) return -ENOMEM; ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_FIRMWARE_INFO, buf, - DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, true); + DS_FEATURE_REPORT_FIRMWARE_INFO_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense firmware info: %d\n", ret); goto err_free; @@ -1110,7 +1166,7 @@ err_free: static int dualsense_get_mac_address(struct dualsense *ds) { - uint8_t *buf; + u8 *buf; int ret = 0; buf = kzalloc(DS_FEATURE_REPORT_PAIRING_INFO_SIZE, GFP_KERNEL); @@ -1118,7 +1174,7 @@ static int dualsense_get_mac_address(struct dualsense *ds) return -ENOMEM; ret = ps_get_report(ds->base.hdev, DS_FEATURE_REPORT_PAIRING_INFO, buf, - DS_FEATURE_REPORT_PAIRING_INFO_SIZE, true); + DS_FEATURE_REPORT_PAIRING_INFO_SIZE, true); if (ret) { hid_err(ds->base.hdev, "Failed to retrieve DualSense pairing info: %d\n", ret); goto err_free; @@ -1132,11 +1188,11 @@ err_free: } static int dualsense_lightbar_set_brightness(struct led_classdev *cdev, - enum led_brightness brightness) + enum led_brightness brightness) { struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar); - uint8_t red, green, blue; + u8 red, green, blue; led_mc_calc_color_components(mc_cdev, brightness); red = mc_cdev->subled_info[0].brightness; @@ -1159,27 +1215,25 @@ static int dualsense_player_led_set_brightness(struct led_classdev *led, enum le { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualsense *ds = hid_get_drvdata(hdev); - unsigned long flags; unsigned int led_index; - spin_lock_irqsave(&ds->base.lock, flags); - - led_index = led - ds->player_leds; - if (value == LED_OFF) - ds->player_leds_state &= ~BIT(led_index); - else - ds->player_leds_state |= BIT(led_index); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + led_index = led - ds->player_leds; + if (value == LED_OFF) + ds->player_leds_state &= ~BIT(led_index); + else + ds->player_leds_state |= BIT(led_index); - ds->update_player_leds = true; - spin_unlock_irqrestore(&ds->base.lock, flags); + ds->update_player_leds = true; + } dualsense_schedule_work(ds); return 0; } -static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp, - void *buf) +static void dualsense_init_output_report(struct dualsense *ds, + struct dualsense_output_report *rp, void *buf) { struct hid_device *hdev = ds->base.hdev; @@ -1194,7 +1248,8 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_ * 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; + bt->seq_tag = FIELD_PREP(DS_OUTPUT_SEQ_NO, ds->output_seq) | + FIELD_PREP(DS_OUTPUT_SEQ_TAG, 0x0); if (++ds->output_seq == 16) ds->output_seq = 0; @@ -1219,12 +1274,10 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_ static inline void dualsense_schedule_work(struct dualsense *ds) { - unsigned long flags; - - spin_lock_irqsave(&ds->base.lock, flags); - if (ds->output_worker_initialized) - schedule_work(&ds->output_worker); - spin_unlock_irqrestore(&ds->base.lock, flags); + /* Using scoped_guard() instead of guard() to make sparse happy */ + scoped_guard(spinlock_irqsave, &ds->base.lock) + if (ds->output_worker_initialized) + schedule_work(&ds->output_worker); } /* @@ -1232,14 +1285,14 @@ static inline void dualsense_schedule_work(struct dualsense *ds) * for Bluetooth reports. */ static void dualsense_send_output_report(struct dualsense *ds, - struct dualsense_output_report *report) + 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; + u32 crc; + u8 seed = PS_OUTPUT_CRC32_SEED; crc = crc32_le(0xFFFFFFFF, &seed, 1); crc = ~crc32_le(crc, report->data, report->len - 4); @@ -1255,74 +1308,125 @@ 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); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + if (ds->update_rumble) { + /* Select classic rumble style haptics and enable it. */ + common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; + if (ds->use_vibration_v2) + common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2; + else + 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_rumble) { - /* Select classic rumble style haptics and enable it. */ - common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT; - if (ds->use_vibration_v2) - common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2; - else - 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; - 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; + } - 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; - 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; + } - ds->update_player_leds = false; - } + if (ds->plugged_state != ds->prev_plugged_state) { + u8 val = ds->plugged_state & DS_STATUS1_HP_DETECT; + + if (val != (ds->prev_plugged_state & DS_STATUS1_HP_DETECT)) { + common->valid_flag0 = DS_OUTPUT_VALID_FLAG0_AUDIO_CONTROL_ENABLE; + /* + * _--------> Output path setup in audio_flag0 + * / _------> Headphone (HP) Left channel sink + * | / _----> Headphone (HP) Right channel sink + * | | / _--> Internal Speaker (SP) sink + * | | | / + * | | | | L/R - Left/Right channel source + * 0 L-R X X - Unrouted (muted) channel source + * 1 L-L X + * 2 L-L R + * 3 X-X R + */ + if (val) { + /* Mute SP and route L+R channels to HP */ + common->audio_control = 0; + } else { + /* Mute HP and route R channel to SP */ + common->audio_control = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS_OUTPUT_PATH_SEL, + 0x3); + /* + * Set SP hardware volume to 100%. + * Note the accepted range seems to be [0x3d..0x64] + */ + common->valid_flag0 |= + DS_OUTPUT_VALID_FLAG0_SPEAKER_VOLUME_ENABLE; + common->speaker_volume = 0x64; + /* Set SP preamp gain to +6dB */ + common->valid_flag1 = + DS_OUTPUT_VALID_FLAG1_AUDIO_CONTROL2_ENABLE; + common->audio_control2 = + FIELD_PREP(DS_OUTPUT_AUDIO_FLAGS2_SP_PREAMP_GAIN, + 0x2); + } - if (ds->update_mic_mute) { - common->valid_flag1 |= DS_OUTPUT_VALID_FLAG1_MIC_MUTE_LED_CONTROL_ENABLE; - common->mute_button_led = ds->mic_muted; + input_report_switch(ds->jack, SW_HEADPHONE_INSERT, val); + } - 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; + val = ds->plugged_state & DS_STATUS1_MIC_DETECT; + if (val != (ds->prev_plugged_state & DS_STATUS1_MIC_DETECT)) + input_report_switch(ds->jack, SW_MICROPHONE_INSERT, val); + + input_sync(ds->jack); + ds->prev_plugged_state = ds->plugged_state; } - ds->update_mic_mute = 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; + } - spin_unlock_irqrestore(&ds->base.lock, flags); + ds->update_mic_mute = false; + } + } dualsense_send_output_report(ds, &report); } static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + 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; + u8 battery_data, battery_capacity, charging_status, value; int battery_status; - uint32_t sensor_timestamp; + u32 sensor_timestamp; bool btn_mic_state; - unsigned long flags; int i; /* @@ -1331,12 +1435,12 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r * the full report using reportID 49. */ if (hdev->bus == BUS_USB && report->id == DS_INPUT_REPORT_USB && - size == DS_INPUT_REPORT_USB_SIZE) { + 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) { + size == DS_INPUT_REPORT_BT_SIZE) { /* Last 4 bytes of input report contain crc32 */ - uint32_t report_crc = get_unaligned_le32(&data[size - 4]); + u32 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"); @@ -1384,16 +1488,42 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r */ 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); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->update_mic_mute = true; + ds->mic_muted = !ds->mic_muted; /* toggle */ + } /* Schedule updating of microphone state at hardware level. */ dualsense_schedule_work(ds); } ds->last_btn_mic_state = btn_mic_state; + /* + * Parse HP/MIC plugged state data for USB use case, since Bluetooth + * audio is currently not supported. + */ + if (hdev->bus == BUS_USB) { + value = ds_report->status[1] & DS_STATUS1_JACK_DETECT; + + if (!ds->prev_plugged_state_valid) { + /* Initial handling of the plugged state report */ + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->plugged_state = (~value) & DS_STATUS1_JACK_DETECT; + ds->prev_plugged_state_valid = true; + } + } + + if (value != ds->plugged_state) { + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ds->prev_plugged_state = ds->plugged_state; + ds->plugged_state = value; + } + + /* Schedule audio routing towards active endpoint. */ + dualsense_schedule_work(ds); + } + } + /* 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]); @@ -1419,7 +1549,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r ds->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp, 3); ds->sensor_timestamp_initialized = true; } else { - uint32_t delta; + u32 delta; if (ds->prev_sensor_timestamp > sensor_timestamp) delta = (U32_MAX - ds->prev_sensor_timestamp + sensor_timestamp + 1); @@ -1439,19 +1569,18 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r 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_report_abs(ds->touchpad, ABS_MT_POSITION_X, + DS_TOUCH_POINT_X(point->x_hi, point->x_lo)); + input_report_abs(ds->touchpad, ABS_MT_POSITION_Y, + DS_TOUCH_POINT_Y(point->y_hi, point->y_lo)); } } 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; + battery_data = FIELD_GET(DS_STATUS0_BATTERY_CAPACITY, ds_report->status[0]); + charging_status = FIELD_GET(DS_STATUS0_CHARGING, ds_report->status[0]); switch (charging_status) { case 0x0: @@ -1481,10 +1610,10 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r 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); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ps_dev->battery_capacity = battery_capacity; + ps_dev->battery_status = battery_status; + } return 0; } @@ -1493,16 +1622,15 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef { 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); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + ds->update_rumble = true; + ds->motor_left = effect->u.rumble.strong_magnitude / 256; + ds->motor_right = effect->u.rumble.weak_magnitude / 256; + } dualsense_schedule_work(ds); return 0; @@ -1511,11 +1639,9 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef static void dualsense_remove(struct ps_device *ps_dev) { struct dualsense *ds = container_of(ps_dev, struct dualsense, base); - unsigned long flags; - spin_lock_irqsave(&ds->base.lock, flags); - ds->output_worker_initialized = false; - spin_unlock_irqrestore(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) + ds->output_worker_initialized = false; cancel_work_sync(&ds->output_worker); } @@ -1523,9 +1649,9 @@ static void dualsense_remove(struct ps_device *ps_dev) static int dualsense_reset_leds(struct dualsense *ds) { struct dualsense_output_report report; - uint8_t *buf; + struct dualsense_output_report_bt *buf; - buf = kzalloc(sizeof(struct dualsense_output_report_bt), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1545,16 +1671,14 @@ static int dualsense_reset_leds(struct dualsense *ds) return 0; } -static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue) +static void dualsense_set_lightbar(struct dualsense *ds, u8 red, u8 green, u8 blue) { - unsigned long flags; - - spin_lock_irqsave(&ds->base.lock, flags); - ds->update_lightbar = true; - ds->lightbar_red = red; - ds->lightbar_green = green; - ds->lightbar_blue = blue; - spin_unlock_irqrestore(&ds->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds->base.lock) { + ds->update_lightbar = true; + ds->lightbar_red = red; + ds->lightbar_green = green; + ds->lightbar_blue = blue; + } dualsense_schedule_work(ds); } @@ -1575,7 +1699,7 @@ static void dualsense_set_player_leds(struct dualsense *ds) BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0) }; - uint8_t player_id = ds->base.player_id % ARRAY_SIZE(player_ids); + u8 player_id = ds->base.player_id % ARRAY_SIZE(player_ids); ds->update_player_leds = true; ds->player_leds_state = player_ids[player_id]; @@ -1586,7 +1710,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) { struct dualsense *ds; struct ps_device *ps_dev; - uint8_t max_output_report_size; + u8 max_output_report_size; int i, ret; static const struct ps_led_info player_leds_info[] = { @@ -1675,7 +1799,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) ps_dev->input_dev_name = dev_name(&ds->gamepad->dev); ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G, - DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); + DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S); if (IS_ERR(ds->sensors)) { ret = PTR_ERR(ds->sensors); goto err; @@ -1687,6 +1811,15 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) goto err; } + /* Bluetooth audio is currently not supported. */ + if (hdev->bus == BUS_USB) { + ds->jack = ps_headset_jack_create(hdev); + if (IS_ERR(ds->jack)) { + ret = PTR_ERR(ds->jack); + goto err; + } + } + ret = ps_device_register_battery(ps_dev); if (ret) goto err; @@ -1729,7 +1862,7 @@ static struct ps_device *dualsense_create(struct hid_device *hdev) * 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); + ds->base.hw_version, ds->base.fw_version); return &ds->base; @@ -1741,7 +1874,6 @@ err: static void dualshock4_dongle_calibration_work(struct work_struct *work) { struct dualshock4 *ds4 = container_of(work, struct dualshock4, dongle_hotplug_worker); - unsigned long flags; enum dualshock4_dongle_state dongle_state; int ret; @@ -1753,16 +1885,16 @@ static void dualshock4_dongle_calibration_work(struct work_struct *work) * DS4 hotplug is detect from sony_raw_event as any issues * are likely resolved then (the dongle is quite stupid). */ - hid_err(ds4->base.hdev, "DualShock 4 USB dongle: calibration failed, disabling device\n"); + hid_err(ds4->base.hdev, + "DualShock 4 USB dongle: calibration failed, disabling device\n"); dongle_state = DONGLE_DISABLED; } else { hid_info(ds4->base.hdev, "DualShock 4 USB dongle: calibration completed\n"); dongle_state = DONGLE_CONNECTED; } - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->dongle_state = dongle_state; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) + ds4->dongle_state = dongle_state; } static int dualshock4_get_calibration_data(struct dualshock4 *ds4) @@ -1779,7 +1911,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) int range_2g; int ret = 0; int i; - uint8_t *buf; + u8 *buf; if (ds4->base.hdev->bus == BUS_USB) { int retries; @@ -1798,14 +1930,17 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) */ for (retries = 0; retries < 3; retries++) { ret = ps_get_report(hdev, DS4_FEATURE_REPORT_CALIBRATION, buf, - DS4_FEATURE_REPORT_CALIBRATION_SIZE, true); + DS4_FEATURE_REPORT_CALIBRATION_SIZE, true); if (ret) { if (retries < 2) { - hid_warn(hdev, "Retrying DualShock 4 get calibration report (0x02) request\n"); + hid_warn(hdev, + "Retrying DualShock 4 get calibration report (0x02) request\n"); continue; } - hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); + hid_warn(hdev, + "Failed to retrieve DualShock4 calibration info: %d\n", + ret); ret = -EILSEQ; goto transfer_failed; } else { @@ -1820,7 +1955,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) } 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) { hid_warn(hdev, "Failed to retrieve DualShock4 calibration info: %d\n", ret); @@ -1867,19 +2002,19 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) speed_2x = (gyro_speed_plus + gyro_speed_minus); ds4->gyro_calib_data[0].abs_code = ABS_RX; ds4->gyro_calib_data[0].bias = 0; - ds4->gyro_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[0].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[0].sens_denom = abs(gyro_pitch_plus - gyro_pitch_bias) + abs(gyro_pitch_minus - gyro_pitch_bias); ds4->gyro_calib_data[1].abs_code = ABS_RY; ds4->gyro_calib_data[1].bias = 0; - ds4->gyro_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[1].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[1].sens_denom = abs(gyro_yaw_plus - gyro_yaw_bias) + abs(gyro_yaw_minus - gyro_yaw_bias); ds4->gyro_calib_data[2].abs_code = ABS_RZ; ds4->gyro_calib_data[2].bias = 0; - ds4->gyro_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + ds4->gyro_calib_data[2].sens_numer = speed_2x * DS4_GYRO_RES_PER_DEG_S; ds4->gyro_calib_data[2].sens_denom = abs(gyro_roll_plus - gyro_roll_bias) + abs(gyro_roll_minus - gyro_roll_bias); @@ -1890,19 +2025,19 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4) range_2g = acc_x_plus - acc_x_minus; ds4->accel_calib_data[0].abs_code = ABS_X; ds4->accel_calib_data[0].bias = acc_x_plus - range_2g / 2; - ds4->accel_calib_data[0].sens_numer = 2*DS4_ACC_RES_PER_G; + ds4->accel_calib_data[0].sens_numer = 2 * DS4_ACC_RES_PER_G; ds4->accel_calib_data[0].sens_denom = range_2g; range_2g = acc_y_plus - acc_y_minus; ds4->accel_calib_data[1].abs_code = ABS_Y; ds4->accel_calib_data[1].bias = acc_y_plus - range_2g / 2; - ds4->accel_calib_data[1].sens_numer = 2*DS4_ACC_RES_PER_G; + ds4->accel_calib_data[1].sens_numer = 2 * DS4_ACC_RES_PER_G; ds4->accel_calib_data[1].sens_denom = range_2g; range_2g = acc_z_plus - acc_z_minus; ds4->accel_calib_data[2].abs_code = ABS_Z; ds4->accel_calib_data[2].bias = acc_z_plus - range_2g / 2; - 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; transfer_failed: @@ -1914,8 +2049,9 @@ transfer_failed: 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); + 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; @@ -1930,8 +2066,9 @@ transfer_failed: for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) { 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.", - ds4->accel_calib_data[i].abs_code); + hid_warn(hdev, + "Invalid accelerometer calibration data for axis (%d), disabling calibration.", + ds4->accel_calib_data[i].abs_code); ds4->accel_calib_data[i].bias = 0; ds4->accel_calib_data[i].sens_numer = DS4_ACC_RANGE; ds4->accel_calib_data[i].sens_denom = S16_MAX; @@ -1943,7 +2080,7 @@ transfer_failed: static int dualshock4_get_firmware_info(struct dualshock4 *ds4) { - uint8_t *buf; + u8 *buf; int ret; buf = kzalloc(DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, GFP_KERNEL); @@ -1954,7 +2091,7 @@ static int dualshock4_get_firmware_info(struct dualshock4 *ds4) * lacks CRC support, so must be disabled in ps_get_report. */ ret = ps_get_report(ds4->base.hdev, DS4_FEATURE_REPORT_FIRMWARE_INFO, buf, - DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, false); + DS4_FEATURE_REPORT_FIRMWARE_INFO_SIZE, false); if (ret) { hid_err(ds4->base.hdev, "Failed to retrieve DualShock4 firmware info: %d\n", ret); goto err_free; @@ -1971,7 +2108,7 @@ err_free: static int dualshock4_get_mac_address(struct dualshock4 *ds4) { struct hid_device *hdev = ds4->base.hdev; - uint8_t *buf; + u8 *buf; int ret = 0; if (hdev->bus == BUS_USB) { @@ -1980,7 +2117,7 @@ static int dualshock4_get_mac_address(struct dualshock4 *ds4) return -ENOMEM; ret = ps_get_report(hdev, DS4_FEATURE_REPORT_PAIRING_INFO, buf, - DS4_FEATURE_REPORT_PAIRING_INFO_SIZE, false); + DS4_FEATURE_REPORT_PAIRING_INFO_SIZE, false); if (ret) { hid_err(hdev, "Failed to retrieve DualShock4 pairing info: %d\n", ret); goto err_free; @@ -1993,9 +2130,9 @@ static int dualshock4_get_mac_address(struct dualshock4 *ds4) return -EINVAL; ret = sscanf(hdev->uniq, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &ds4->base.mac_address[5], &ds4->base.mac_address[4], - &ds4->base.mac_address[3], &ds4->base.mac_address[2], - &ds4->base.mac_address[1], &ds4->base.mac_address[0]); + &ds4->base.mac_address[5], &ds4->base.mac_address[4], + &ds4->base.mac_address[3], &ds4->base.mac_address[2], + &ds4->base.mac_address[1], &ds4->base.mac_address[0]); if (ret != sizeof(ds4->base.mac_address)) return -EINVAL; @@ -2030,28 +2167,27 @@ static enum led_brightness dualshock4_led_get_brightness(struct led_classdev *le } static int dualshock4_led_set_blink(struct led_classdev *led, unsigned long *delay_on, - unsigned long *delay_off) + unsigned long *delay_off) { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; - spin_lock_irqsave(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + if (!*delay_on && !*delay_off) { + /* Default to 1 Hz (50 centiseconds on, 50 centiseconds off). */ + ds4->lightbar_blink_on = 50; + ds4->lightbar_blink_off = 50; + } else { + /* Blink delays in centiseconds. */ + ds4->lightbar_blink_on = min_t(unsigned long, *delay_on / 10, + DS4_LIGHTBAR_MAX_BLINK); + ds4->lightbar_blink_off = min_t(unsigned long, *delay_off / 10, + DS4_LIGHTBAR_MAX_BLINK); + } - if (!*delay_on && !*delay_off) { - /* Default to 1 Hz (50 centiseconds on, 50 centiseconds off). */ - ds4->lightbar_blink_on = 50; - ds4->lightbar_blink_off = 50; - } else { - /* Blink delays in centiseconds. */ - ds4->lightbar_blink_on = min_t(unsigned long, *delay_on/10, DS4_LIGHTBAR_MAX_BLINK); - ds4->lightbar_blink_off = min_t(unsigned long, *delay_off/10, DS4_LIGHTBAR_MAX_BLINK); + ds4->update_lightbar_blink = true; } - ds4->update_lightbar_blink = true; - - spin_unlock_irqrestore(&ds4->base.lock, flags); - dualshock4_schedule_work(ds4); /* Report scaled values back to LED subsystem */ @@ -2065,36 +2201,33 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig { struct hid_device *hdev = to_hid_device(led->dev->parent); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; unsigned int led_index; - spin_lock_irqsave(&ds4->base.lock, flags); - - led_index = led - ds4->lightbar_leds; - switch (led_index) { - case 0: - ds4->lightbar_red = value; - break; - case 1: - ds4->lightbar_green = value; - break; - case 2: - ds4->lightbar_blue = value; - break; - case 3: - 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; + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + led_index = led - ds4->lightbar_leds; + switch (led_index) { + case 0: + ds4->lightbar_red = value; + break; + case 1: + ds4->lightbar_green = value; + break; + case 2: + ds4->lightbar_blue = value; + break; + case 3: + 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; - - spin_unlock_irqrestore(&ds4->base.lock, flags); + ds4->update_lightbar = true; + } dualshock4_schedule_work(ds4); @@ -2102,7 +2235,7 @@ static int dualshock4_led_set_brightness(struct led_classdev *led, enum led_brig } static void dualshock4_init_output_report(struct dualshock4 *ds4, - struct dualshock4_output_report *rp, void *buf) + struct dualshock4_output_report *rp, void *buf) { struct hid_device *hdev = ds4->base.hdev; @@ -2136,66 +2269,63 @@ static void dualshock4_output_worker(struct work_struct *work) struct dualshock4 *ds4 = container_of(work, struct dualshock4, output_worker); struct dualshock4_output_report report; struct dualshock4_output_report_common *common; - unsigned long flags; dualshock4_init_output_report(ds4, &report, ds4->output_report_dmabuf); common = report.common; - spin_lock_irqsave(&ds4->base.lock, flags); - - /* - * Some 3rd party gamepads expect updates to rumble and lightbar - * together, and setting one may cancel the other. - * - * Let's maximise compatibility by always sending rumble and lightbar - * updates together, even when only one has been scheduled, resulting - * in: - * - * ds4->valid_flag0 >= 0x03 - * - * Hopefully this will maximise compatibility with third-party pads. - * - * Any further update bits, such as 0x04 for lightbar blinking, will - * be or'd on top of this like before. - */ - if (ds4->update_rumble || ds4->update_lightbar) { - ds4->update_rumble = true; /* 0x01 */ - ds4->update_lightbar = true; /* 0x02 */ - } + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + /* + * Some 3rd party gamepads expect updates to rumble and lightbar + * together, and setting one may cancel the other. + * + * Let's maximise compatibility by always sending rumble and lightbar + * updates together, even when only one has been scheduled, resulting + * in: + * + * ds4->valid_flag0 >= 0x03 + * + * Hopefully this will maximise compatibility with third-party pads. + * + * Any further update bits, such as 0x04 for lightbar blinking, will + * be or'd on top of this like before. + */ + if (ds4->update_rumble || ds4->update_lightbar) { + ds4->update_rumble = true; /* 0x01 */ + ds4->update_lightbar = true; /* 0x02 */ + } - if (ds4->update_rumble) { - /* Select classic rumble style haptics and enable it. */ - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR; - common->motor_left = ds4->motor_left; - common->motor_right = ds4->motor_right; - ds4->update_rumble = false; - } + if (ds4->update_rumble) { + /* Select classic rumble style haptics and enable it. */ + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_MOTOR; + common->motor_left = ds4->motor_left; + common->motor_right = ds4->motor_right; + ds4->update_rumble = false; + } - if (ds4->update_lightbar) { - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED; - /* Comptabile behavior with hid-sony, which used a dummy global LED to - * allow enabling/disabling the lightbar. The global LED maps to - * lightbar_enabled. - */ - common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0; - common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0; - common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0; - ds4->update_lightbar = false; - } + if (ds4->update_lightbar) { + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED; + /* Compatible behavior with hid-sony, which used a dummy global LED to + * allow enabling/disabling the lightbar. The global LED maps to + * lightbar_enabled. + */ + common->lightbar_red = ds4->lightbar_enabled ? ds4->lightbar_red : 0; + common->lightbar_green = ds4->lightbar_enabled ? ds4->lightbar_green : 0; + common->lightbar_blue = ds4->lightbar_enabled ? ds4->lightbar_blue : 0; + ds4->update_lightbar = false; + } - if (ds4->update_lightbar_blink) { - common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK; - common->lightbar_blink_on = ds4->lightbar_blink_on; - common->lightbar_blink_off = ds4->lightbar_blink_off; - ds4->update_lightbar_blink = false; + if (ds4->update_lightbar_blink) { + common->valid_flag0 |= DS4_OUTPUT_VALID_FLAG0_LED_BLINK; + common->lightbar_blink_on = ds4->lightbar_blink_on; + common->lightbar_blink_off = ds4->lightbar_blink_off; + ds4->update_lightbar_blink = false; + } } - spin_unlock_irqrestore(&ds4->base.lock, flags); - /* Bluetooth packets need additional flags as well as a CRC in the last 4 bytes. */ if (report.bt) { - uint32_t crc; - uint8_t seed = PS_OUTPUT_CRC32_SEED; + u32 crc; + u8 seed = PS_OUTPUT_CRC32_SEED; /* Hardware control flags need to set to let the device know * there is HID data as well as CRC. @@ -2217,16 +2347,15 @@ static void dualshock4_output_worker(struct work_struct *work) } static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct hid_device *hdev = ps_dev->hdev; struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); struct dualshock4_input_report_common *ds4_report; struct dualshock4_touch_report *touch_reports; - uint8_t battery_capacity, num_touch_reports, value; + u8 battery_capacity, num_touch_reports, value; int battery_status, i, j; - uint16_t sensor_timestamp; - unsigned long flags; + u16 sensor_timestamp; bool is_minimal = false; /* @@ -2235,16 +2364,17 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * * the full report using reportID 17. */ if (hdev->bus == BUS_USB && report->id == DS4_INPUT_REPORT_USB && - size == DS4_INPUT_REPORT_USB_SIZE) { - struct dualshock4_input_report_usb *usb = (struct dualshock4_input_report_usb *)data; + size == DS4_INPUT_REPORT_USB_SIZE) { + struct dualshock4_input_report_usb *usb = + (struct dualshock4_input_report_usb *)data; ds4_report = &usb->common; num_touch_reports = usb->num_touch_reports; touch_reports = usb->touch_reports; } else if (hdev->bus == BUS_BLUETOOTH && report->id == DS4_INPUT_REPORT_BT && - size == DS4_INPUT_REPORT_BT_SIZE) { + size == DS4_INPUT_REPORT_BT_SIZE) { struct dualshock4_input_report_bt *bt = (struct dualshock4_input_report_bt *)data; - uint32_t report_crc = get_unaligned_le32(&bt->crc32); + u32 report_crc = get_unaligned_le32(&bt->crc32); /* Last 4 bytes of input report contains CRC. */ if (!ps_check_crc32(PS_INPUT_CRC32_SEED, data, size - 4, report_crc)) { @@ -2325,16 +2455,16 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * /* Convert timestamp (in 5.33us unit) to timestamp_us */ sensor_timestamp = le16_to_cpu(ds4_report->sensor_timestamp); if (!ds4->sensor_timestamp_initialized) { - ds4->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp*16, 3); + ds4->sensor_timestamp_us = DIV_ROUND_CLOSEST(sensor_timestamp * 16, 3); ds4->sensor_timestamp_initialized = true; } else { - uint16_t delta; + u16 delta; if (ds4->prev_sensor_timestamp > sensor_timestamp) delta = (U16_MAX - ds4->prev_sensor_timestamp + sensor_timestamp + 1); else delta = sensor_timestamp - ds4->prev_sensor_timestamp; - ds4->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta*16, 3); + ds4->sensor_timestamp_us += DIV_ROUND_CLOSEST(delta * 16, 3); } ds4->prev_sensor_timestamp = sensor_timestamp; input_event(ds4->sensors, EV_MSC, MSC_TIMESTAMP, ds4->sensor_timestamp_us); @@ -2351,11 +2481,10 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * input_mt_report_slot_state(ds4->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(ds4->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(ds4->touchpad, ABS_MT_POSITION_Y, y); + input_report_abs(ds4->touchpad, ABS_MT_POSITION_X, + DS4_TOUCH_POINT_X(point->x_hi, point->x_lo)); + input_report_abs(ds4->touchpad, ABS_MT_POSITION_Y, + DS4_TOUCH_POINT_Y(point->y_hi, point->y_lo)); } } input_mt_sync_frame(ds4->touchpad); @@ -2374,7 +2503,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * * - 15: charge error */ if (ds4_report->status[0] & DS4_STATUS0_CABLE_STATE) { - uint8_t battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; + u8 battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; if (battery_data < 10) { /* Take the mid-point for each battery capacity value, @@ -2395,7 +2524,7 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * battery_status = POWER_SUPPLY_STATUS_UNKNOWN; } } else { - uint8_t battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; + u8 battery_data = ds4_report->status[0] & DS4_STATUS0_BATTERY_CAPACITY; if (battery_data < 10) battery_capacity = battery_data * 10 + 5; @@ -2405,16 +2534,16 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report * battery_status = POWER_SUPPLY_STATUS_DISCHARGING; } - 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); + scoped_guard(spinlock_irqsave, &ps_dev->lock) { + ps_dev->battery_capacity = battery_capacity; + ps_dev->battery_status = battery_status; + } return 0; } static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); bool connected = false; @@ -2425,8 +2554,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r * parsing code. */ if (data[0] == DS4_INPUT_REPORT_USB && size == DS4_INPUT_REPORT_USB_SIZE) { - struct dualshock4_input_report_common *ds4_report = (struct dualshock4_input_report_common *)&data[1]; - unsigned long flags; + struct dualshock4_input_report_common *ds4_report = + (struct dualshock4_input_report_common *)&data[1]; connected = ds4_report->status[1] & DS4_STATUS1_DONGLE_STATE ? false : true; @@ -2435,9 +2564,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r dualshock4_set_default_lightbar_colors(ds4); - spin_lock_irqsave(&ps_dev->lock, flags); - ds4->dongle_state = DONGLE_CALIBRATING; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) + ds4->dongle_state = DONGLE_CALIBRATING; schedule_work(&ds4->dongle_hotplug_worker); @@ -2449,9 +2577,8 @@ static int dualshock4_dongle_parse_report(struct ps_device *ps_dev, struct hid_r ds4->dongle_state == DONGLE_DISABLED) && !connected) { hid_info(ps_dev->hdev, "DualShock 4 USB dongle: controller disconnected\n"); - spin_lock_irqsave(&ps_dev->lock, flags); - ds4->dongle_state = DONGLE_DISCONNECTED; - spin_unlock_irqrestore(&ps_dev->lock, flags); + scoped_guard(spinlock_irqsave, &ps_dev->lock) + ds4->dongle_state = DONGLE_DISCONNECTED; /* Return 0, so hidraw can get the report. */ return 0; @@ -2473,16 +2600,15 @@ static int dualshock4_play_effect(struct input_dev *dev, void *data, struct ff_e { struct hid_device *hdev = input_get_drvdata(dev); struct dualshock4 *ds4 = hid_get_drvdata(hdev); - unsigned long flags; if (effect->type != FF_RUMBLE) return 0; - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->update_rumble = true; - ds4->motor_left = effect->u.rumble.strong_magnitude / 256; - ds4->motor_right = effect->u.rumble.weak_magnitude / 256; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) { + ds4->update_rumble = true; + ds4->motor_left = effect->u.rumble.strong_magnitude / 256; + ds4->motor_right = effect->u.rumble.weak_magnitude / 256; + } dualshock4_schedule_work(ds4); return 0; @@ -2491,11 +2617,9 @@ static int dualshock4_play_effect(struct input_dev *dev, void *data, struct ff_e static void dualshock4_remove(struct ps_device *ps_dev) { struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base); - unsigned long flags; - spin_lock_irqsave(&ds4->base.lock, flags); - ds4->output_worker_initialized = false; - spin_unlock_irqrestore(&ds4->base.lock, flags); + scoped_guard(spinlock_irqsave, &ds4->base.lock) + ds4->output_worker_initialized = false; cancel_work_sync(&ds4->output_worker); @@ -2505,15 +2629,13 @@ static void dualshock4_remove(struct ps_device *ps_dev) static inline void dualshock4_schedule_work(struct dualshock4 *ds4) { - unsigned long flags; - - spin_lock_irqsave(&ds4->base.lock, flags); - if (ds4->output_worker_initialized) - schedule_work(&ds4->output_worker); - spin_unlock_irqrestore(&ds4->base.lock, flags); + /* Using scoped_guard() instead of guard() to make sparse happy */ + scoped_guard(spinlock_irqsave, &ds4->base.lock) + if (ds4->output_worker_initialized) + schedule_work(&ds4->output_worker); } -static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval) +static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, u8 interval) { ds4->bt_poll_interval = interval; ds4->update_bt_poll_interval = true; @@ -2533,7 +2655,7 @@ static void dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4) { 0x20, 0x00, 0x20 } /* Pink */ }; - uint8_t player_id = ds4->base.player_id % ARRAY_SIZE(player_colors); + u8 player_id = ds4->base.player_id % ARRAY_SIZE(player_colors); ds4->lightbar_enabled = true; ds4->lightbar_red = player_colors[player_id][0]; @@ -2548,7 +2670,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) { struct dualshock4 *ds4; struct ps_device *ps_dev; - uint8_t max_output_report_size; + u8 max_output_report_size; int i, ret; /* The DualShock4 has an RGB lightbar, which the original hid-sony driver @@ -2561,11 +2683,14 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) * existing applications (e.g. Android). Nothing matches against MAC address. */ static const struct ps_led_info lightbar_leds_info[] = { - { NULL, "red", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "green", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "blue", 255, dualshock4_led_get_brightness, dualshock4_led_set_brightness }, - { NULL, "global", 1, dualshock4_led_get_brightness, dualshock4_led_set_brightness, - dualshock4_led_set_blink }, + { NULL, "red", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "green", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "blue", 255, dualshock4_led_get_brightness, + dualshock4_led_set_brightness }, + { NULL, "global", 1, dualshock4_led_get_brightness, + dualshock4_led_set_brightness, dualshock4_led_set_blink }, }; ds4 = devm_kzalloc(&hdev->dev, sizeof(*ds4), GFP_KERNEL); @@ -2635,7 +2760,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) ps_dev->input_dev_name = dev_name(&ds4->gamepad->dev); ds4->sensors = ps_sensors_create(hdev, DS4_ACC_RANGE, DS4_ACC_RES_PER_G, - DS4_GYRO_RANGE, DS4_GYRO_RES_PER_DEG_S); + DS4_GYRO_RANGE, DS4_GYRO_RES_PER_DEG_S); if (IS_ERR(ds4->sensors)) { ret = PTR_ERR(ds4->sensors); goto err; @@ -2674,7 +2799,7 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev) * can change behavior. */ hid_info(hdev, "Registered DualShock4 controller hw_version=0x%08x fw_version=0x%08x\n", - ds4->base.hw_version, ds4->base.fw_version); + ds4->base.hw_version, ds4->base.fw_version); return &ds4->base; err: @@ -2683,7 +2808,7 @@ err: } static int ps_raw_event(struct hid_device *hdev, struct hid_report *report, - u8 *data, int size) + u8 *data, int size) { struct ps_device *dev = hid_get_drvdata(hdev); |