[PATCH v5 08/13] HID: asus: add joysticks anti-deadzone configuration
From: Denis Benato
Date: Fri Sep 04 2026 - 11:46:27 EST
ROG Ally devices allow configuring the anti-deadzone parameter for
the resistive joysticks devices as over time those develops drift,
therefore allow userspace to configure the anti-deadzone by exposing
relevant sysfs attributes.
Assisted-by: opencode:glm-5.2
Signed-off-by: Denis Benato <denis.benato@xxxxxxxxx>
Signed-off-by: Luke Jones <luke@xxxxxxxxxx>
---
drivers/hid/hid-asus.c | 211 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 207 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index eef91b3fe77e..cddb72973bae 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1336,6 +1336,193 @@ static struct device_attribute dev_attr_right_joystick_outer_threshold =
static struct device_attribute dev_attr_right_joystick_outer_threshold_range =
__ATTR(outer_threshold_range, 0444, right_joystick_outer_threshold_range_show, NULL);
+/**
+ * ally_set_anti_deadzone() - Set anti-deadzone values for joysticks
+ * @ally: ally handheld structure
+ * @hdev: HID device
+ * @cfg: ally config
+ * @left_adz: left joystick anti-deadzone value (0-100)
+ * @right_adz: right joystick anti-deadzone value (0-100)
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int ally_set_anti_deadzone(struct ally_handheld *ally,
+ struct hid_device *hdev, struct ally_config *cfg,
+ u8 left_adz, u8 right_adz)
+{
+ const u8 payload[] = { left_adz, right_adz };
+ int ret;
+
+ if (!cfg->anti_deadzone_support) {
+ hid_dbg(hdev, "Anti-deadzone not supported on this device\n");
+ return -EOPNOTSUPP;
+ }
+
+ u8 *buf __free(kfree) = ally_alloc_cmd(CMD_SET_ANTI_DEADZONE, payload, sizeof(payload));
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ally_gamepad_send_packet(ally, hdev, buf, ROG_ALLY_REPORT_SIZE);
+ if (ret < 0) {
+ hid_err(hdev, "Failed to set anti-deadzone values: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static ssize_t left_joystick_anti_deadzone_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct ally_handheld *const ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+
+ if (!ally)
+ return -ENODEV;
+
+ cfg = ally_get_config(ally);
+ if (!cfg)
+ return -ENODEV;
+
+ guard(mutex)(&cfg->config_mutex);
+
+ if (!cfg->anti_deadzone_support) {
+ hid_dbg(hdev, "Anti-deadzone not supported on this device\n");
+ return -EOPNOTSUPP;
+ }
+
+ return sysfs_emit(buf, "%u\n", cfg->left_anti_deadzone);
+}
+
+static ssize_t left_joystick_anti_deadzone_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct ally_handheld *const ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+ u8 value;
+ int ret;
+
+ if (!ally)
+ return -ENODEV;
+
+ cfg = ally_get_config(ally);
+ if (!cfg)
+ return -ENODEV;
+
+ ret = kstrtou8(buf, 10, &value);
+ if (ret || value > 100)
+ return -EINVAL;
+
+ guard(mutex)(&cfg->config_mutex);
+
+ if (!cfg->anti_deadzone_support) {
+ hid_dbg(hdev, "Anti-deadzone not supported on this device\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = ally_set_anti_deadzone(ally, hdev, cfg, value, cfg->right_anti_deadzone);
+ if (ret)
+ return ret;
+
+ cfg->left_anti_deadzone = value;
+
+ return count;
+}
+
+static ssize_t left_joystick_anti_deadzone_range_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "0 100\n");
+}
+
+static ssize_t right_joystick_anti_deadzone_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct ally_handheld *const ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+
+ if (!ally)
+ return -ENODEV;
+
+ cfg = ally_get_config(ally);
+ if (!cfg)
+ return -ENODEV;
+
+ guard(mutex)(&cfg->config_mutex);
+
+ if (!cfg->anti_deadzone_support) {
+ hid_dbg(hdev, "Anti-deadzone not supported on this device\n");
+ return -EOPNOTSUPP;
+ }
+
+ return sysfs_emit(buf, "%u\n", cfg->right_anti_deadzone);
+}
+
+static ssize_t right_joystick_anti_deadzone_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
+ struct ally_handheld *const ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+ u8 value;
+ int ret;
+
+ if (!ally)
+ return -ENODEV;
+
+ cfg = ally_get_config(ally);
+ if (!cfg)
+ return -ENODEV;
+
+ ret = kstrtou8(buf, 10, &value);
+ if (ret || value > 100)
+ return -EINVAL;
+
+ guard(mutex)(&cfg->config_mutex);
+
+ if (!cfg->anti_deadzone_support) {
+ hid_dbg(hdev, "Anti-deadzone not supported on this device\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = ally_set_anti_deadzone(ally, hdev, cfg, cfg->left_anti_deadzone, value);
+ if (ret)
+ return ret;
+
+ cfg->right_anti_deadzone = value;
+
+ return count;
+}
+
+static ssize_t right_joystick_anti_deadzone_range_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "0 100\n");
+}
+
+static struct device_attribute dev_attr_left_joystick_anti_deadzone =
+ __ATTR(anti_deadzone, 0644, left_joystick_anti_deadzone_show,
+ left_joystick_anti_deadzone_store);
+
+static struct device_attribute dev_attr_left_joystick_anti_deadzone_range =
+ __ATTR(anti_deadzone_range, 0444, left_joystick_anti_deadzone_range_show, NULL);
+
+static struct device_attribute dev_attr_right_joystick_anti_deadzone =
+ __ATTR(anti_deadzone, 0644, right_joystick_anti_deadzone_show,
+ right_joystick_anti_deadzone_store);
+
+static struct device_attribute dev_attr_right_joystick_anti_deadzone_range =
+ __ATTR(anti_deadzone_range, 0444, right_joystick_anti_deadzone_range_show, NULL);
+
/**
* ally_set_trigger_ranges() - Generic function to set triggers ranges
* @ally: ally handheld structure
@@ -1702,6 +1889,8 @@ static struct attribute *left_joystick_axis_attrs[] = {
&dev_attr_left_joystick_outer_threshold.attr,
&dev_attr_left_joystick_inner_threshold_range.attr,
&dev_attr_left_joystick_outer_threshold_range.attr,
+ &dev_attr_left_joystick_anti_deadzone.attr,
+ &dev_attr_left_joystick_anti_deadzone_range.attr,
NULL
};
@@ -1710,6 +1899,8 @@ static struct attribute *right_joystick_axis_attrs[] = {
&dev_attr_right_joystick_outer_threshold.attr,
&dev_attr_right_joystick_inner_threshold_range.attr,
&dev_attr_right_joystick_outer_threshold_range.attr,
+ &dev_attr_right_joystick_anti_deadzone.attr,
+ &dev_attr_right_joystick_anti_deadzone_range.attr,
NULL
};
@@ -1835,8 +2026,11 @@ static struct ally_config *ally_config_create(struct hid_device *hdev, struct al
}
}
- /* Skip the calibration groups when the capability is missing. */
- if (cfg->user_cal_support) {
+ /*
+ * Skip the calibration and anti-deadzone groups when none of the
+ * features they expose is supported.
+ */
+ if (cfg->user_cal_support || cfg->anti_deadzone_support) {
int cal_i;
for (cal_i = 0; cal_i < ARRAY_SIZE(ally_cal_attr_groups);
@@ -1894,8 +2088,7 @@ static void ally_config_remove(struct hid_device *hdev, struct ally_config *cfg)
* create them, so a device without those capabilities does not
* trigger a "not found" warning.
*/
- if (cfg->user_cal_support || cfg->anti_deadzone_support ||
- cfg->resp_curve_support) {
+ if (cfg->user_cal_support || cfg->anti_deadzone_support) {
for (i = 0; i < ARRAY_SIZE(ally_cal_attr_groups); i++)
sysfs_remove_group(&hdev->dev.kobj,
ally_cal_attr_groups[i]);
@@ -2222,6 +2415,16 @@ static int hid_asus_ally_init(struct hid_device *hdev, struct ally_handheld *all
ret);
}
+ if (cfg->anti_deadzone_support) {
+ ret = ally_set_anti_deadzone(ally, hdev, cfg,
+ cfg->left_anti_deadzone,
+ cfg->right_anti_deadzone);
+ if (ret < 0)
+ hid_warn(hdev,
+ "Failed to restore anti-deadzone: %d\n",
+ ret);
+ }
+
return 0;
}
--
2.47.3