Commit 334fe5d3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-2022102101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Benjamin Tissoires:

 - a 12 year old bug fix for the Apple Magic Trackpad v1 (José Expósito)

 - a fix for a potential crash on removal of the Playstation controllers
   (Roderick Colenbrander)

 - a few new device IDs and device-specific quirks, most notably support
   of the new Playstation DualSense Edge controller

* tag 'for-linus-2022102101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: lenovo: Make array tp10ubkbd_led static const
  HID: saitek: add madcatz variant of MMO7 mouse device ID
  HID: playstation: support updated DualSense rumble mode.
  HID: playstation: add initial DualSense Edge controller support
  HID: playstation: stop DualSense output work on remove.
  HID: magicmouse: Do not set BTN_MOUSE on double report
parents bd8e9634 e66928af
......@@ -867,6 +867,7 @@
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
#define USB_DEVICE_ID_MADCATZ_RAT5 0x1705
#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709
#define USB_DEVICE_ID_MADCATZ_MMO7 0x1713
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
......@@ -1142,6 +1143,7 @@
#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_PS5_CONTROLLER_2 0x0df2
#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
......
......@@ -985,7 +985,7 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
struct device *dev = led_cdev->dev->parent;
struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
static const u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
int led_nr = 0;
int ret = 0;
......
......@@ -480,7 +480,7 @@ static int magicmouse_raw_event(struct hid_device *hdev,
magicmouse_raw_event(hdev, report, data + 2, data[1]);
magicmouse_raw_event(hdev, report, data + 2 + data[1],
size - 2 - data[1]);
break;
return 0;
default:
return 0;
}
......
......@@ -46,6 +46,7 @@ struct ps_device {
uint32_t fw_version;
int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size);
void (*remove)(struct ps_device *dev);
};
/* Calibration data for playstation motion sensors. */
......@@ -107,6 +108,9 @@ struct ps_led_info {
#define DS_STATUS_CHARGING GENMASK(7, 4)
#define DS_STATUS_CHARGING_SHIFT 4
/* Feature version from DualSense Firmware Info report. */
#define DS_FEATURE_VERSION(major, minor) ((major & 0xff) << 8 | (minor & 0xff))
/*
* Status of a DualSense touch point contact.
* Contact IDs, with highest bit set are 'inactive'
......@@ -125,6 +129,7 @@ struct ps_led_info {
#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)
......@@ -142,6 +147,9 @@ struct dualsense {
struct input_dev *sensors;
struct input_dev *touchpad;
/* Update version is used as a feature/capability version. */
uint16_t update_version;
/* Calibration data for accelerometer and gyroscope. */
struct ps_calibration_data accel_calib_data[3];
struct ps_calibration_data gyro_calib_data[3];
......@@ -152,6 +160,7 @@ struct dualsense {
uint32_t sensor_timestamp_us;
/* Compatible rumble state */
bool use_vibration_v2;
bool update_rumble;
uint8_t motor_left;
uint8_t motor_right;
......@@ -174,6 +183,7 @@ struct dualsense {
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. */
};
......@@ -299,6 +309,7 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = {
{0, 0},
};
static inline void dualsense_schedule_work(struct dualsense *ds);
static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue);
/*
......@@ -789,6 +800,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
return ret;
}
static int dualsense_get_firmware_info(struct dualsense *ds)
{
uint8_t *buf;
......@@ -808,6 +820,15 @@ static int dualsense_get_firmware_info(struct dualsense *ds)
ds->base.hw_version = get_unaligned_le32(&buf[24]);
ds->base.fw_version = get_unaligned_le32(&buf[28]);
/* Update version is some kind of feature version. It is distinct from
* the firmware version as there can be many different variations of a
* controller over time with the same physical shell, but with different
* PCBs and other internal changes. The update version (internal name) is
* used as a means to detect what features are available and change behavior.
* Note: the version is different between DualSense and DualSense Edge.
*/
ds->update_version = get_unaligned_le16(&buf[44]);
err_free:
kfree(buf);
return ret;
......@@ -878,7 +899,7 @@ static int dualsense_player_led_set_brightness(struct led_classdev *led, enum le
ds->update_player_leds = true;
spin_unlock_irqrestore(&ds->base.lock, flags);
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
return 0;
}
......@@ -922,6 +943,16 @@ 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);
}
/*
* Helper function to send DualSense output reports. Applies a CRC at the end of a report
* for Bluetooth reports.
......@@ -960,7 +991,10 @@ static void dualsense_output_worker(struct work_struct *work)
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;
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;
......@@ -1082,7 +1116,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
spin_unlock_irqrestore(&ps_dev->lock, flags);
/* Schedule updating of microphone state at hardware level. */
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
ds->last_btn_mic_state = btn_mic_state;
......@@ -1197,10 +1231,22 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
ds->motor_right = effect->u.rumble.weak_magnitude / 256;
spin_unlock_irqrestore(&ds->base.lock, flags);
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
return 0;
}
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);
cancel_work_sync(&ds->output_worker);
}
static int dualsense_reset_leds(struct dualsense *ds)
{
struct dualsense_output_report report;
......@@ -1237,7 +1283,7 @@ static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t gr
ds->lightbar_blue = blue;
spin_unlock_irqrestore(&ds->base.lock, flags);
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
static void dualsense_set_player_leds(struct dualsense *ds)
......@@ -1260,7 +1306,7 @@ static void dualsense_set_player_leds(struct dualsense *ds)
ds->update_player_leds = true;
ds->player_leds_state = player_ids[player_id];
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
static struct ps_device *dualsense_create(struct hid_device *hdev)
......@@ -1299,7 +1345,9 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
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;
ps_dev->remove = dualsense_remove;
INIT_WORK(&ds->output_worker, dualsense_output_worker);
ds->output_worker_initialized = true;
hid_set_drvdata(hdev, ds);
max_output_report_size = sizeof(struct dualsense_output_report_bt);
......@@ -1320,6 +1368,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
return ERR_PTR(ret);
}
/* Original DualSense firmware simulated classic controller rumble through
* its new haptics hardware. It felt different from classic rumble users
* were used to. Since then new firmwares were introduced to change behavior
* and make this new 'v2' behavior default on PlayStation and other platforms.
* The original DualSense requires a new enough firmware as bundled with PS5
* software released in 2021. DualSense edge supports it out of the box.
* Both devices also support the old mode, but it is not really used.
*/
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
/* Feature version 2.21 introduced new vibration method. */
ds->use_vibration_v2 = ds->update_version >= DS_FEATURE_VERSION(2, 21);
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
ds->use_vibration_v2 = true;
}
ret = ps_devices_list_add(ps_dev);
if (ret)
return ERR_PTR(ret);
......@@ -1436,7 +1499,8 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
}
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER ||
hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
dev = dualsense_create(hdev);
if (IS_ERR(dev)) {
hid_err(hdev, "Failed to create dualsense.\n");
......@@ -1461,6 +1525,9 @@ static void ps_remove(struct hid_device *hdev)
ps_devices_list_remove(dev);
ps_device_release_player_id(dev);
if (dev->remove)
dev->remove(dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
......@@ -1468,6 +1535,8 @@ static void ps_remove(struct hid_device *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) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
{ }
};
MODULE_DEVICE_TABLE(hid, ps_devices);
......
......@@ -620,6 +620,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_MMO7) },
#endif
#if IS_ENABLED(CONFIG_HID_SAMSUNG)
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
......
......@@ -187,6 +187,8 @@ static const struct hid_device_id saitek_devices[] = {
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
.driver_data = SAITEK_RELEASE_MODE_MMO7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_MMO7),
.driver_data = SAITEK_RELEASE_MODE_MMO7 },
{ }
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment