From: Denis Benato <denis.benato@linux.dev>
To: linux-kernel@vger.kernel.org
Cc: linux-input@vger.kernel.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>,
Denis Benato <denis.benato@linux.dev>
Subject: [PATCH 10/12] HID: asus: add support for gamepad mode
Date: Thu, 13 Aug 2026 14:47:34 +0000 [thread overview]
Message-ID: <20260813144736.2477941-11-denis.benato@linux.dev> (raw)
In-Reply-To: <20260813144736.2477941-1-denis.benato@linux.dev>
ROG Ally devices can emulate either a mouse+keyboard (desktop mode)
or an gamepad device (xbox360 controller in ROG ally and a custom
DInput device on newer models): add support for switching the current
controller mode.
Signed-off-by: Luke Jones <luke@ljones.dev>
Signed-off-by: Denis Benato <denis.benato@linux.dev>
---
drivers/hid/hid-asus.c | 153 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 153 insertions(+)
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 301fe33f66b1..8930a246e725 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -397,6 +397,20 @@ enum ally_command_codes {
/* XInput rumble magnitudes use the hardware's 0..100 intensity range. */
#define ALLY_FF_MAX_INTENSITY 100
+enum ally_gamepad_mode_index {
+ ALLY_GAMEPAD_MODE_GAMEPAD = 0x01,
+ ALLY_GAMEPAD_MODE_KEYBOARD = 0x02,
+};
+
+static const char *const ally_gamepad_mode_text[] = {
+ "gamepad", "desktop"
+};
+
+static const u8 ally_gamepad_mode[] = {
+ ALLY_GAMEPAD_MODE_GAMEPAD,
+ ALLY_GAMEPAD_MODE_KEYBOARD
+};
+
static const u8 ALLY_FORCE_FEEDBACK_OFF[] = {
0x0D, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB
};
@@ -793,6 +807,136 @@ static ssize_t xbox_controller_store(struct device *dev,
static DEVICE_ATTR_RW(xbox_controller);
+/**
+ * ally_set_gamepad_mode - Set the gamepad operating mode
+ * @ally: ally handheld structure
+ * @hdev: HID device
+ * @mode: Gamepad mode to set
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int ally_set_gamepad_mode(struct ally_handheld *ally, struct hid_device *hdev, u8 mode)
+{
+ struct ally_config *cfg = ally->config;
+ u8 payload[] = { mode };
+ int ret;
+
+ if (!cfg)
+ return -EINVAL;
+
+ if (mode < ALLY_GAMEPAD_MODE_GAMEPAD ||
+ mode > ALLY_GAMEPAD_MODE_KEYBOARD) {
+ hid_err(hdev, "Invalid gamepad mode: %u\n", mode);
+ return -EINVAL;
+ }
+
+ u8 *buf __free(kfree) = ally_alloc_cmd(CMD_SET_GAMEPAD_MODE, payload, sizeof(payload));
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ally_dev_set_report(hdev, buf, ROG_ALLY_REPORT_SIZE);
+ if (ret < 0) {
+ hid_err(hdev, "Failed to set gamepad mode: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static ssize_t gamepad_mode_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 *ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+ u8 mode_byte;
+ int i;
+
+ if (!ally || !ally->config)
+ return -ENODEV;
+
+ cfg = ally->config;
+ mode_byte = cfg->gamepad_mode;
+
+ for (i = 0; i < ARRAY_SIZE(ally_gamepad_mode); i++) {
+ if (ally_gamepad_mode[i] == mode_byte)
+ return sysfs_emit(buf, "%s\n", ally_gamepad_mode_text[i]);
+ }
+
+ return sysfs_emit(buf, "unsupported\n");
+}
+
+static ssize_t gamepad_mode_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 *ally = drvdata->rog_ally;
+ struct ally_config *cfg;
+ u8 mode_byte;
+ int mode;
+ int ret;
+
+ if (!ally || !ally->config)
+ return -ENODEV;
+
+ cfg = ally->config;
+
+ mode = sysfs_match_string(ally_gamepad_mode_text, buf);
+ if (mode < 0) {
+ hid_err(hdev, "Unknown gamepad mode\n");
+ return mode;
+ }
+
+ /* Convert the index of the text mode array to the byte
+ * that will be accepted by the ally MCU.
+ */
+ mode_byte = ally_gamepad_mode[mode];
+
+ ret = ally_set_gamepad_mode(ally, hdev, mode_byte);
+ if (ret < 0)
+ return ret;
+
+ scoped_guard(mutex, &cfg->config_mutex)
+ cfg->gamepad_mode = mode_byte;
+
+ hid_dbg(hdev, "Set gamepad mode to %s\n", ally_gamepad_mode_text[mode]);
+
+ return count;
+}
+
+static ssize_t gamepad_mode_index_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ ssize_t len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ally_gamepad_mode_text); i++) {
+ if (!ally_gamepad_mode_text[i] || ally_gamepad_mode_text[i][0] == '\0')
+ continue;
+ len += sysfs_emit_at(buf, len, "%s ", ally_gamepad_mode_text[i]);
+ }
+
+ /* Replace the last space with a newline */
+ if (len > 0)
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static DEVICE_ATTR_RW(gamepad_mode);
+static DEVICE_ATTR_RO(gamepad_mode_index);
+
+static int ally_set_default_gamepad_mode(struct hid_device *hdev,
+ struct ally_handheld *ally,
+ struct ally_config *cfg)
+{
+ cfg->gamepad_mode = ALLY_GAMEPAD_MODE_GAMEPAD;
+
+ return ally_set_gamepad_mode(ally, hdev, cfg->gamepad_mode);
+}
+
/**
* ally_set_vibration_intensity() - Set vibration intensity values
* @hdev: HID device
@@ -1950,6 +2094,8 @@ DEFINE_JS_CURVE_ATTRS(4, right);
static struct attribute *ally_config_attrs[] = {
&dev_attr_xbox_controller.attr,
+ &dev_attr_gamepad_mode.attr,
+ &dev_attr_gamepad_mode_index.attr,
NULL
};
@@ -2422,6 +2568,13 @@ static int hid_asus_ally_init(struct hid_device *hdev, struct ally_handheld *all
if (ret < 0)
hid_err(hdev, "Ally failed to init force-feedback off: %d\n", ret);
+ /* Set the default gamepad mode now that the MCU is confirmed ready */
+ if (ally->config) {
+ ret = ally_set_default_gamepad_mode(hdev, ally, ally->config);
+ if (ret < 0)
+ hid_warn(hdev, "Failed to set default gamepad mode: %d\n", ret);
+ }
+
return 0;
}
--
2.47.3
next prev parent reply other threads:[~2026-08-13 14:47 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 14:47 [PATCH 00/12] HID: asus: add support for ROG Ally handhelds Denis Benato
2026-08-13 14:47 ` [PATCH 01/12] HID: asus: reinitialize the device after exiting a sleep state Denis Benato
2026-08-13 14:55 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 02/12] HID: asus: add support for ROG Ally handhelds Denis Benato
2026-08-13 15:00 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 03/12] HID: asus: add gamepad configuration Denis Benato
2026-08-13 14:59 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 04/12] HID: asus: add vibration strength configuration Denis Benato
2026-08-13 14:56 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 05/12] HID: asus: add joysticks inner and outer range configuration Denis Benato
2026-08-13 15:02 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 06/12] HID: asus: add triggers " Denis Benato
2026-08-13 14:58 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 07/12] HID: asus: add joysticks anti-deadzone configuration Denis Benato
2026-08-13 15:02 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 08/12] HID: asus: add support for response curve Denis Benato
2026-08-13 14:59 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 09/12] HID: asus: add support to force feedback Denis Benato
2026-08-13 15:10 ` sashiko-bot
2026-08-13 14:47 ` Denis Benato [this message]
2026-08-13 15:10 ` [PATCH 10/12] HID: asus: add support for gamepad mode sashiko-bot
2026-08-13 14:47 ` [PATCH 11/12] HID: asus: add support for turbo buttons Denis Benato
2026-08-13 15:10 ` sashiko-bot
2026-08-13 14:47 ` [PATCH 12/12] HID: asus: add support for btn remapping Denis Benato
2026-08-13 15:12 ` sashiko-bot
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=20260813144736.2477941-11-denis.benato@linux.dev \
--to=denis.benato@linux.dev \
--cc=benato.denis96@gmail.com \
--cc=bentiss@kernel.org \
--cc=derekjohn.clark@gmail.com \
--cc=jikos@kernel.org \
--cc=jlobue10@gmail.com \
--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 \
/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.