diff mbox series

HID: playstation: DS4: Add BT poll interval adjustment

Message ID 20250508214305.836406-1-titanv3585@gmail.com
State New
Headers show
Series HID: playstation: DS4: Add BT poll interval adjustment | expand

Commit Message

Vadym Tytan May 8, 2025, 9:41 p.m. UTC
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@gmail.com>
---
 CREDITS                       |  4 +++
 drivers/hid/hid-playstation.c | 64 +++++++++++++++++++++++++++++++++--
 2 files changed, 65 insertions(+), 3 deletions(-)

Comments

kernel test robot May 9, 2025, 10:06 p.m. UTC | #1
Hi Vadym,

kernel test robot noticed the following build warnings:

[auto build test WARNING on hid/for-next]
[also build test WARNING on linus/master v6.15-rc5 next-20250509]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Vadym-Tytan/HID-playstation-DS4-Add-BT-poll-interval-adjustment/20250509-054413
base:   https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link:    https://lore.kernel.org/r/20250508214305.836406-1-titanv3585%40gmail.com
patch subject: [PATCH] HID: playstation: DS4: Add BT poll interval adjustment
config: x86_64-randconfig-122-20250509 (https://download.01.org/0day-ci/archive/20250510/202505100535.vKH3zHW6-lkp@intel.com/config)
compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250510/202505100535.vKH3zHW6-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505100535.vKH3zHW6-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/hid/hid-playstation.c:1773:25: sparse: sparse: symbol 'dev_attr_dualshock4_bt_poll_interval' was not declared. Should it be static?

vim +/dev_attr_dualshock4_bt_poll_interval +1773 drivers/hid/hid-playstation.c

  1772	
> 1773	struct device_attribute dev_attr_dualshock4_bt_poll_interval = {
  1774		.attr	= { .name = "bt_poll_interval", .mode = 0644 },
  1775		.show	= dualshock4_show_poll_interval,
  1776		.store	= dualshock4_store_poll_interval,
  1777	};
  1778
diff mbox series

Patch

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@gmail.com
+D: Minor game controllers features
+
 N: Thomas Uhl
 E: uhl@sun1.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);
 }