mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v1] platform/x86: asus-wmi: add TUF keyboard RGB readback support
@ 2026-09-25 20:07 Bartu Alev
  2026-09-25 20:25 ` Denis Benato
  2026-09-26  0:56 ` [PATCH v2 0/2] platform/x86: asus-wmi: Fix TUF keyboard shutdown naming and add RGB readback Bartu Alev
  0 siblings, 2 replies; 6+ messages in thread
From: Bartu Alev @ 2026-09-25 20:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: platform-driver-x86, Hans de Goede, Ilpo Järvinen,
	Luke D . Jones, Denis Benato, Bartu Alev

TUF Gaming laptops support setting keyboard RGB lighting modes and
power states via kbd_rgb_mode and kbd_rgb_state, but both attributes
are currently write-only (DEVICE_ATTR_WO). Consequently, userspace
utilities have no way to query the active hardware configuration.

Add readback support by querying the TUF status device ID 0x0010005B
through the WMI DSTS method. On supported platforms, this evaluates the
ACPI DSDT method EC0.KBLS(), which returns a 16-byte status buffer
containing the active lighting mode, RGB color channels, effect speed,
and power-state bitmask.

Introduce kbd_rgb_read_status() to retrieve and validate the KBLS
buffer. Convert kbd_rgb_mode and kbd_rgb_state to DEVICE_ATTR_RW. Map the
hardware speed codes (0xe1, 0xeb, 0xf5) to their sysfs indices (0, 1, 2).
Since the status buffer reports the active state rather than an action
command, emit a synthetic leading '1' to maintain format symmetry with
the input format expected by userspace.

Additionally, relabel the fourth field in kbd_rgb_state_index from
"keyboard" to "shutdown". When the interface was originally introduced,
the purpose of BIT(7) was unknown and noted as having no effect. In
hardware, this bit gates whether the keyboard LED remains powered during
the ACPI S5 sequence. Relabeling it accurately reflects its
actual hardware behavior.

Assisted-by: GLM-5.3
Signed-off-by: Bartu Alev <bartualev@gmail.com>
---
- Tested on ASUS TUF Gaming A15 (FA507NV) running Linux 7.2.6

 drivers/platform/x86/asus-wmi.c            | 87 ++++++++++++++++++++--
 include/linux/platform_data/x86/asus-wmi.h |  3 +
 2 files changed, 84 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index a65090429ca7..36eff5adac52 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -1046,7 +1046,58 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
 static DEVICE_ATTR_RW(gpu_mux_mode);
 #endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
 
+static int kbd_rgb_read_status(u8 data[16])
+{
+	int err;
+
+	err = asus_wmi_evaluate_method_buf(ASUS_WMI_METHODID_DSTS,
+					   ASUS_WMI_DEVID_TUF_RGB_STATUS,
+					   0, data, 16);
+
+	if (err)
+		return err < 0 ? err : -ENODEV;
+
+	/* DUBF[0] is a constant 1 set by the AML: anything else is not KBLS */
+	if (data[0] != 1)
+		return -ENODEV;
+
+	return 0;
+}
+
 /* TUF Laptop Keyboard RGB Modes **********************************************/
+static ssize_t kbd_rgb_mode_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	u8 data[16] = {};
+	u32 speed;
+	int err;
+
+	err = kbd_rgb_read_status(data);
+	if (err)
+		return err;
+
+	/* Map hardware speed codes back to sysfs index:
+	 * 0xe1 -> 0 (slow), 0xeb -> 1 (normal), 0xf5 -> 2 (fast)
+	 */
+	switch (data[5]) {
+	case 0xe1:
+		speed = 0;
+		break;
+	case 0xeb:
+		speed = 1;
+		break;
+	case 0xf5:
+		speed = 2;
+		break;
+	default:
+		speed = 1;
+		break;
+	}
+
+	return sysfs_emit(buf, "1 %d %d %d %d %d\n",
+			  data[1], data[2], data[3], data[4], speed);
+}
 static ssize_t kbd_rgb_mode_store(struct device *dev,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
@@ -1099,7 +1150,7 @@ static ssize_t kbd_rgb_mode_store(struct device *dev,
 
 	return count;
 }
-static DEVICE_ATTR_WO(kbd_rgb_mode);
+static DEVICE_ATTR_RW(kbd_rgb_mode);
 
 static DEVICE_STRING_ATTR_RO(kbd_rgb_mode_index, 0444,
 			     "cmd mode red green blue speed");
@@ -1115,14 +1166,38 @@ static const struct attribute_group kbd_rgb_mode_group = {
 };
 
 /* TUF Laptop Keyboard RGB State **********************************************/
+static ssize_t kbd_rgb_state_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	u8 data[16] = {};
+	u8 flags;
+	int err;
+
+	err = kbd_rgb_read_status(data);
+	if (err)
+		return err;
+
+	/*
+	 * data[6] power-state bitmask:
+	 * BIT(1) boot, BIT(3) awake, BIT(5) sleep, BIT(7) shutdown
+	 */
+	flags = data[6];
+
+	return sysfs_emit(buf, "1 %d %d %d %d\n",
+			  !!(flags & BIT(1)),
+			  !!(flags & BIT(3)),
+			  !!(flags & BIT(5)),
+			  !!(flags & BIT(7)));
+}
 static ssize_t kbd_rgb_state_store(struct device *dev,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	u32 flags, cmd, boot, awake, sleep, keyboard;
+	u32 flags, cmd, boot, awake, sleep, shutdown;
 	int err;
 
-	if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5)
+	if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &shutdown) != 5)
 		return -EINVAL;
 
 	if (cmd)
@@ -1135,7 +1210,7 @@ static ssize_t kbd_rgb_state_store(struct device *dev,
 		flags |= BIT(3);
 	if (sleep)
 		flags |= BIT(5);
-	if (keyboard)
+	if (shutdown)
 		flags |= BIT(7);
 
 	/* 0xbd is the required default arg0 for the method. Nothing happens otherwise */
@@ -1146,10 +1221,10 @@ static ssize_t kbd_rgb_state_store(struct device *dev,
 
 	return count;
 }
-static DEVICE_ATTR_WO(kbd_rgb_state);
+static DEVICE_ATTR_RW(kbd_rgb_state);
 
 static DEVICE_STRING_ATTR_RO(kbd_rgb_state_index, 0444,
-			     "cmd boot awake sleep keyboard");
+			     "cmd boot awake sleep shutdown");
 
 static struct attribute *kbd_rgb_state_attrs[] = {
 	&dev_attr_kbd_rgb_state.attr,
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index b5ed8c83ace1..a6eb8f8cf159 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -161,6 +161,9 @@
 /* TUF laptop RGB power/state */
 #define ASUS_WMI_DEVID_TUF_RGB_STATE	0x00100057
 
+/* TUF laptop RGB keyboard status */
+#define ASUS_WMI_DEVID_TUF_RGB_STATUS	0x0010005B
+
 /* Bootup sound control */
 #define ASUS_WMI_DEVID_BOOT_SOUND	0x00130022
 
-- 
2.55.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-26  1:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-25 20:07 [PATCH v1] platform/x86: asus-wmi: add TUF keyboard RGB readback support Bartu Alev
2026-09-25 20:25 ` Denis Benato
2026-09-26  0:56 ` [PATCH v2 0/2] platform/x86: asus-wmi: Fix TUF keyboard shutdown naming and add RGB readback Bartu Alev
2026-09-26  0:56   ` [PATCH v2 1/2] platform/x86: asus-wmi: fix TUF keyboard power state shutdown naming Bartu Alev
2026-09-26  0:56   ` [PATCH v2 2/2] platform/x86: asus-wmi: add TUF keyboard RGB readback support Bartu Alev
2026-09-26  1:41     ` Denis Benato

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®