[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250508214305.836406-1-titanv3585@gmail.com>
Date: Thu, 8 May 2025 23:41:32 +0200
From: Vadym Tytan <titanv3585@...il.com>
To: Roderick Colenbrander <roderick.colenbrander@...y.com>,
Jiri Kosina <jikos@...nel.org>,
Benjamin Tissoires <bentiss@...nel.org>,
linux-kernel@...r.kernel.org,
linux-input@...r.kernel.org
Cc: Vadym Tytan <titanv3585@...il.com>
Subject: [PATCH] HID: playstation: DS4: Add BT poll interval adjustment
Between v6.1 and v6.2 versions of Linux kernel,
DualShock4 related code was moved from `hid-sony.c`
to `hid-playstation.c` (near DualSense code) and
Bluetooth poll interval adjustment functionality was lost
Signed-off-by: Vadym Tytan <titanv3585@...il.com>
---
CREDITS | 4 +++
drivers/hid/hid-playstation.c | 64 +++++++++++++++++++++++++++++++++--
2 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/CREDITS b/CREDITS
index f74d230992d6..137c3636e318 100644
--- a/CREDITS
+++ b/CREDITS
@@ -4001,6 +4001,10 @@ S: 44 Campbell Park Crescent
S: Edinburgh EH13 0HT
S: United Kingdom
+N: Vadym Tytan
+E: titanv3585@...il.com
+D: Minor game controllers features
+
N: Thomas Uhl
E: uhl@...1.rz.fh-heilbronn.de
D: Application programmer
diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index 1468fb11e39d..fd51f00b0516 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -337,7 +337,7 @@ struct dualsense_output_report {
* 0x3F - disabled
*/
#define DS4_OUTPUT_HWCTL_BT_POLL_MASK 0x3F
-/* Default to 4ms poll interval, which is same as USB (not adjustable). */
+/* Default to 4ms poll interval, which is same as USB (adjustable). */
#define DS4_BT_DEFAULT_POLL_INTERVAL_MS 4
#define DS4_OUTPUT_HWCTL_CRC32 0x40
#define DS4_OUTPUT_HWCTL_HID 0x80
@@ -542,6 +542,7 @@ 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 dualshock4_set_default_lightbar_colors(struct dualshock4 *ds4);
+static int dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval);
/*
* Add a new ps_device to ps_devices if it doesn't exist.
@@ -1738,6 +1739,43 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
return ERR_PTR(ret);
}
+static ssize_t dualshock4_show_poll_interval(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);
+ struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base);
+
+ return sysfs_emit(buf, "%i\n", ds4->bt_poll_interval);
+}
+
+static ssize_t dualshock4_store_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct ps_device *ps_dev = hid_get_drvdata(hdev);
+ struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base);
+ int ret;
+ u8 interval;
+
+ if (kstrtou8(buf, 0, &interval))
+ return -EINVAL;
+
+ ret = dualshock4_set_bt_poll_interval(ds4, interval);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+struct device_attribute dev_attr_dualshock4_bt_poll_interval = {
+ .attr = { .name = "bt_poll_interval", .mode = 0644 },
+ .show = dualshock4_show_poll_interval,
+ .store = dualshock4_store_poll_interval,
+};
+
static void dualshock4_dongle_calibration_work(struct work_struct *work)
{
struct dualshock4 *ds4 = container_of(work, struct dualshock4, dongle_hotplug_worker);
@@ -2493,6 +2531,9 @@ static void dualshock4_remove(struct ps_device *ps_dev)
struct dualshock4 *ds4 = container_of(ps_dev, struct dualshock4, base);
unsigned long flags;
+ if (ps_dev->hdev->bus == BUS_BLUETOOTH)
+ device_remove_file(&ps_dev->hdev->dev, &dev_attr_dualshock4_bt_poll_interval);
+
spin_lock_irqsave(&ds4->base.lock, flags);
ds4->output_worker_initialized = false;
spin_unlock_irqrestore(&ds4->base.lock, flags);
@@ -2513,11 +2554,16 @@ static inline void dualshock4_schedule_work(struct dualshock4 *ds4)
spin_unlock_irqrestore(&ds4->base.lock, flags);
}
-static void dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval)
+static int dualshock4_set_bt_poll_interval(struct dualshock4 *ds4, uint8_t interval)
{
+ if (interval >= DS4_OUTPUT_HWCTL_BT_POLL_MASK)
+ return -EINVAL;
+
ds4->bt_poll_interval = interval;
ds4->update_bt_poll_interval = true;
dualshock4_schedule_work(ds4);
+
+ return 0;
}
/* Set default lightbar color based on player. */
@@ -2659,7 +2705,17 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
goto err;
}
- dualshock4_set_bt_poll_interval(ds4, DS4_BT_DEFAULT_POLL_INTERVAL_MS);
+ if (hdev->bus == BUS_BLUETOOTH) {
+ ret = dualshock4_set_bt_poll_interval(ds4, DS4_BT_DEFAULT_POLL_INTERVAL_MS);
+ if (ret) {
+ hid_err(hdev, "Failed to set poll interval for DualShock4: %d\n", ret);
+ goto err;
+ }
+
+ ret = device_create_file(&hdev->dev, &dev_attr_dualshock4_bt_poll_interval);
+ if (ret)
+ hid_warn(hdev, "can't create sysfs bt_poll_interval attribute err: %d\n", ret);
+ }
ret = ps_device_set_player_id(ps_dev);
if (ret) {
@@ -2678,6 +2734,8 @@ static struct ps_device *dualshock4_create(struct hid_device *hdev)
return &ds4->base;
err:
+ if (hdev->bus == BUS_BLUETOOTH)
+ device_remove_file(&hdev->dev, &dev_attr_dualshock4_bt_poll_interval);
ps_devices_list_remove(ps_dev);
return ERR_PTR(ret);
}
--
2.49.0
Powered by blists - more mailing lists