From: Denis Benato <denis.benato@linux.dev>
To: linux-kernel@vger.kernel.org
Cc: platform-driver-x86@vger.kernel.org, linux-input@vger.kernel.org,
kernel@lists.opengamingcollective.org,
"Benjamin Tissoires" <bentiss@kernel.org>,
"Jiri Kosina" <jikos@kernel.org>,
"Luke D . Jones" <luke@ljones.dev>,
"Mateusz Schwartz" <matthew.schwartz@linux.dev>,
"Denis Benato" <benato.denis96@gmail.com>,
"Jonathan LoBue" <jlobue10@gmail.com>,
"Khamunetri Clark" <khamunetriclark@gmail.com>,
"Derek J. Clark" <derekjohn.clark@gmail.com>,
"Joshua Leivenzon" <hacker1024@users.sourceforge.net>,
"Nathan Chancellor" <nathan@kernel.org>,
"Rebecca Mara Müller" <rebecca.mara@posteo.de>,
"Ivan Levchenko" <me@livan.pro>,
"Corentin Chary" <corentin.chary@gmail.com>,
"Hans de Goede" <hansg@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Denis Benato" <denis.benato@linux.dev>
Subject: [PATCH v13 04/18] HID: asus: add vibration strength configuration
Date: Wed, 4 Nov 2026 01:39:21 +0000 [thread overview]
Message-ID: <20261104013935.512713-5-denis.benato@linux.dev> (raw)
In-Reply-To: <20261104013935.512713-1-denis.benato@linux.dev>
ASUS ROG Ally handhelds support the vibration strength to be configured:
add sysfs attributes to allow userspace configure motors vibration
intensity.
Signed-off-by: Denis Benato <denis.benato@linux.dev>
Co-developed-by: Luke Jones <luke@ljones.dev>
Signed-off-by: Luke Jones <luke@ljones.dev>
---
drivers/hid/hid-asus.c | 171 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 171 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 8277d7108bb9..459061391c37 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -97,6 +97,9 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define ASUS_HID_INPUT_KBD_REPORT_ID 0x01
+#define ASUS_ALLY_VIBRATION_INTENSITY_MIN 0
+#define ASUS_ALLY_VIBRATION_INTENSITY_MAX 100
+
/* Spurious HID codes sent by QUIRK_ROG_NKEY_KEYBOARD devices */
#define ASUS_SPURIOUS_CODE_0XEA 0xea
#define ASUS_SPURIOUS_CODE_0XEC 0xec
@@ -804,6 +807,9 @@ static struct ally_prefs {
bool xbox_controller_enabled;
u8 gamepad_mode;
+
+ u8 vibration_intensity_left;
+ u8 vibration_intensity_right;
} ally_prefs = {
.lock = __MUTEX_INITIALIZER(ally_prefs.lock),
};
@@ -976,6 +982,149 @@ static ssize_t xbox_controller_store(struct device *dev,
static DEVICE_ATTR_RW(xbox_controller);
+/**
+ * ally_set_vibration_intensity() - Set the gamepad vibration intensity
+ * @hdev: HID device the command packet is sent on
+ * @left: left motor intensity
+ * @right: right motor intensity
+ *
+ * Context: Caller holds ally_prefs.lock.
+ * Return: 0 on success, negative errno on failure.
+ */
+static int ally_set_vibration_intensity(struct hid_device *hdev, u8 left, u8 right)
+{
+ const u8 data[] = { left, right };
+ size_t buf_len;
+ int ret;
+
+ u8 *buf __free(kfree) = ally_alloc_cmd(hdev, CMD_SET_VIBRATION_INTENSITY,
+ data, sizeof(data), &buf_len);
+
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ally_gamepad_send_packet(hdev, buf, buf_len);
+ if (ret < 0) {
+ hid_err(hdev, "Failed to set vibration intensity: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ally_vibration_defaults(void)
+{
+ guard(mutex)(&ally_prefs.lock);
+
+ if (ally_prefs.initialized)
+ return;
+
+ ally_prefs.vibration_intensity_left = 100;
+ ally_prefs.vibration_intensity_right = 100;
+}
+
+/* Indices into ally_vibration[], in the order ally_set_vibration_intensity() takes them. */
+enum ally_vibration {
+ ALLY_VIBRATION_LEFT,
+ ALLY_VIBRATION_RIGHT,
+};
+
+static u8 *const ally_vibration[] = {
+ [ALLY_VIBRATION_LEFT] = &ally_prefs.vibration_intensity_left,
+ [ALLY_VIBRATION_RIGHT] = &ally_prefs.vibration_intensity_right,
+};
+
+static ssize_t ally_vibration_intensity_show(char *buf, enum ally_vibration which)
+{
+ guard(mutex)(&ally_prefs.lock);
+
+ return sysfs_emit(buf, "%u\n", *ally_vibration[which]);
+}
+
+static ssize_t ally_vibration_intensity_store(struct device *dev, const char *buf,
+ size_t count, enum ally_vibration which,
+ const char *group)
+{
+ u8 value, v[ARRAY_SIZE(ally_vibration)];
+ struct hid_device *hdev = to_hid_device(dev);
+ size_t i;
+ int ret;
+
+ ret = kstrtou8(buf, 10, &value);
+ if (ret || value > ASUS_ALLY_VIBRATION_INTENSITY_MAX)
+ return -EINVAL;
+
+ scoped_guard(mutex, &ally_prefs.lock) {
+ for (i = 0; i < ARRAY_SIZE(v); i++)
+ v[i] = *ally_vibration[i];
+ v[which] = value;
+
+ ret = ally_set_vibration_intensity(hdev,
+ v[ALLY_VIBRATION_LEFT],
+ v[ALLY_VIBRATION_RIGHT]);
+ if (ret < 0)
+ return ret;
+
+ *ally_vibration[which] = value;
+ }
+
+ sysfs_notify(&dev->kobj, group, "intensity");
+
+ return count;
+}
+
+/* Generates <side>_vibration_intensity_{show,store,range_show}. */
+#define ALLY_VIBRATION_FUNCS(side, SIDE) \
+static ssize_t side##_vibration_intensity_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return ally_vibration_intensity_show(buf, ALLY_VIBRATION_##SIDE); \
+} \
+ \
+static ssize_t side##_vibration_intensity_store(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ return ally_vibration_intensity_store(dev, buf, count, ALLY_VIBRATION_##SIDE, \
+ #side "_vibration"); \
+} \
+ \
+static ssize_t side##_vibration_intensity_range_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return sysfs_emit(buf, "%u %u\n", ASUS_ALLY_VIBRATION_INTENSITY_MIN, \
+ ASUS_ALLY_VIBRATION_INTENSITY_MAX); \
+}
+
+ALLY_VIBRATION_FUNCS(left, LEFT)
+ALLY_VIBRATION_FUNCS(right, RIGHT)
+
+static struct device_attribute dev_attr_left_vibration_intensity =
+ __ATTR(intensity, 0644, left_vibration_intensity_show, left_vibration_intensity_store);
+
+static struct device_attribute dev_attr_left_vibration_intensity_range =
+ __ATTR(intensity_range, 0444, left_vibration_intensity_range_show, NULL);
+
+static struct device_attribute dev_attr_right_vibration_intensity =
+ __ATTR(intensity, 0644, right_vibration_intensity_show, right_vibration_intensity_store);
+
+static struct device_attribute dev_attr_right_vibration_intensity_range =
+ __ATTR(intensity_range, 0444, right_vibration_intensity_range_show, NULL);
+
+static struct attribute *ally_left_vibration_attrs[] = {
+ &dev_attr_left_vibration_intensity.attr,
+ &dev_attr_left_vibration_intensity_range.attr,
+ NULL
+};
+
+static struct attribute *ally_right_vibration_attrs[] = {
+ &dev_attr_right_vibration_intensity.attr,
+ &dev_attr_right_vibration_intensity_range.attr,
+ NULL
+};
+
static struct attribute *ally_config_attrs[] = {
&dev_attr_xbox_controller.attr,
NULL
@@ -985,6 +1134,14 @@ static const struct attribute_group ally_attr_groups[] = {
{
.attrs = ally_config_attrs,
},
+ {
+ .name = "left_vibration",
+ .attrs = ally_left_vibration_attrs,
+ },
+ {
+ .name = "right_vibration",
+ .attrs = ally_right_vibration_attrs,
+ },
};
static int ally_prefs_setup(struct hid_device *hdev, struct ally_intf *intf)
@@ -995,6 +1152,8 @@ static int ally_prefs_setup(struct hid_device *hdev, struct ally_intf *intf)
if (ret)
return ret;
+ ally_vibration_defaults();
+
scoped_guard(mutex, &ally_prefs.lock) {
if (!ally_prefs.initialized) {
ally_prefs.gamepad_mode = 0x01;
@@ -1241,6 +1400,18 @@ static int hid_asus_ally_init(struct hid_device *hdev)
hid_warn(hdev, "Failed to apply Xbox controller mode: %d\n", ret);
}
+ /*
+ * The MCU does not keep the vibration intensity across a reset:
+ * send the recorded values again.
+ */
+ if (ally_prefs.initialized) {
+ ret = ally_set_vibration_intensity(hdev,
+ ally_prefs.vibration_intensity_left,
+ ally_prefs.vibration_intensity_right);
+ if (ret < 0)
+ hid_warn(hdev, "Failed to restore vibration intensity: %d\n", ret);
+ }
+
return 0;
}
--
2.47.3
next prev parent reply other threads:[~2026-11-04 1:41 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 1:39 [PATCH v13 00/18] HID: asus: add support for ROG Ally handhelds Denis Benato
2026-11-04 1:39 ` [PATCH v13 01/18] HID: asus: size feature reports from the HID report descriptor Denis Benato
2026-11-04 1:39 ` [PATCH v13 02/18] HID: asus: add support for ROG Ally handhelds Denis Benato
2026-11-04 2:07 ` sashiko-bot
2026-11-04 1:39 ` [PATCH v13 03/18] HID: asus: add gamepad configuration Denis Benato
2026-11-04 1:59 ` sashiko-bot
2026-11-04 1:39 ` Denis Benato [this message]
2026-11-04 1:39 ` [PATCH v13 05/18] HID: asus: add joysticks inner and outer range configuration Denis Benato
2026-11-04 1:53 ` sashiko-bot
2026-11-04 1:39 ` [PATCH v13 06/18] HID: asus: add triggers " Denis Benato
2026-11-04 1:39 ` [PATCH v13 07/18] HID: asus: add joysticks anti-deadzone configuration Denis Benato
2026-11-04 1:39 ` [PATCH v13 08/18] HID: asus: add support for response curve Denis Benato
2026-11-04 1:39 ` [PATCH v13 09/18] HID: asus: add support to force feedback Denis Benato
2026-11-04 1:39 ` [PATCH v13 10/18] HID: asus: add support for gamepad mode Denis Benato
2026-11-04 1:39 ` [PATCH v13 11/18] HID: asus: add support for turbo buttons Denis Benato
2026-11-04 1:52 ` sashiko-bot
2026-11-04 1:39 ` [PATCH v13 12/18] HID: asus: add support for btn remapping Denis Benato
2026-11-04 1:58 ` sashiko-bot
2026-11-04 1:39 ` [PATCH v13 13/18] HID: asus: identify XG Mobile stations and bind the LED to the reported model Denis Benato
2026-11-04 1:39 ` [PATCH v13 14/18] HID: asus: expose XG Mobile identity and firmware information Denis Benato
2026-11-04 1:39 ` [PATCH v13 15/18] HID: asus: document ROG XG Mobile sysfs attributes Denis Benato
2026-11-04 1:39 ` [PATCH v13 16/18] HID: asus: document ROG Ally " Denis Benato
2026-11-04 1:55 ` sashiko-bot
2026-11-04 1:39 ` [PATCH v13 17/18] platform/x86: asus-armoury: pick the eGPU activation from the reported GPU Denis Benato
2026-11-04 1:39 ` [PATCH v13 18/18] MAINTAINERS: add maintainer for the ASUS HID driver Denis Benato
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261104013935.512713-5-denis.benato@linux.dev \
--to=denis.benato@linux.dev \
--cc=benato.denis96@gmail.com \
--cc=bentiss@kernel.org \
--cc=corentin.chary@gmail.com \
--cc=derekjohn.clark@gmail.com \
--cc=hacker1024@users.sourceforge.net \
--cc=hansg@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=jikos@kernel.org \
--cc=jlobue10@gmail.com \
--cc=kernel@lists.opengamingcollective.org \
--cc=khamunetriclark@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luke@ljones.dev \
--cc=matthew.schwartz@linux.dev \
--cc=me@livan.pro \
--cc=nathan@kernel.org \
--cc=platform-driver-x86@vger.kernel.org \
--cc=rebecca.mara@posteo.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.