From 661d99773b938feaeeeda8867c8584b5a6fb65eb Mon Sep 17 00:00:00 2001 From: Marco Scardovi Date: Wed, 29 Jul 2026 17:26:49 +0200 Subject: [PATCH 1/4] platform/x86: asus-wmi: add missing WMI device ID defines --- include/linux/platform_data/x86/asus-wmi.h | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 554f41b827e18a..f8f12846a9efeb 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -156,6 +156,30 @@ /* Bootup sound control */ #define ASUS_WMI_DEVID_BOOT_SOUND 0x00130022 +#define ASUS_WMI_DEVID_PRODUCT_TYPE 0x00130021 + +/* Additional inputs & switches */ +#define ASUS_WMI_DEVID_ESS_SWITCH 0x00060091 +#define ASUS_WMI_DEVID_TOUCHSCREEN 0x00050036 +#define ASUS_WMI_DEVID_WINKEY_DISABLE 0x00130024 +#define ASUS_WMI_DEVID_PAD_MODE 0x00060077 + +/* GPU & eGPU extras */ +#define ASUS_WMI_DEVID_EGPU_DOCK_STATE 0x00090017 +#define ASUS_WMI_DEVID_EDP_MODE 0x0009001B +#define ASUS_WMI_DEVID_GPU_SWITCH_CAP 0x0009001C +#define ASUS_WMI_DEVID_EGPU_PCIE_GEN 0x0006005B + +/* TUF lighting & status */ +#define ASUS_WMI_DEVID_TUF_RGB_WDL 0x0010005C + +/* Tuning attributes */ +#define ASUS_WMI_DEVID_PE_CORES 0x001200D2 +#define ASUS_WMI_DEVID_BIOS_PER_CORE 0x0012007B +#define ASUS_WMI_DEVID_OC_RULE 0x0012007D +#define ASUS_WMI_DEVID_PPT_FPPT 0x001200A1 +#define ASUS_WMI_DEVID_FAN_RANGE_CPU 0x00110022 +#define ASUS_WMI_DEVID_FAN_RANGE_GPU 0x00110023 /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 From 1371360fa2da082be47ea27e7c85926d0a247ee1 Mon Sep 17 00:00:00 2001 From: Marco Scardovi Date: Wed, 29 Jul 2026 17:26:49 +0200 Subject: [PATCH 2/4] platform/x86: asus-armoury: add input and GPU toggle attributes --- drivers/platform/x86/asus-armoury.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 5b0987ccc27022..8c9cf9792ab1c9 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -778,6 +778,28 @@ ASUS_ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, "Read the base TGP value"); +/* Input & Switch attributes */ +ASUS_ATTR_GROUP_BOOL_RW(ess_switch, "ess_switch", ASUS_WMI_DEVID_ESS_SWITCH, + "Toggle the ESS DAC"); +ASUS_ATTR_GROUP_BOOL_RW(touchscreen_toggle, "touchscreen_toggle", + ASUS_WMI_DEVID_TOUCHSCREEN, + "Toggle the touchscreen"); +ASUS_ATTR_GROUP_BOOL_RW(winkey_disable, "winkey_disable", + ASUS_WMI_DEVID_WINKEY_DISABLE, + "Toggle the Windows key lock"); + +/* GPU read-only attributes */ +ASUS_ATTR_GROUP_BOOL_RO(egpu_dock_state, "egpu_dock_state", + ASUS_WMI_DEVID_EGPU_DOCK_STATE, + "Show external GPU dock connection"); +ASUS_ATTR_GROUP_BOOL_RO(edp_mode, "edp_mode", ASUS_WMI_DEVID_EDP_MODE, + "Show the eDP panel mode"); + +/* Product type read-only */ +ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(product_type, "product_type", + ASUS_WMI_DEVID_PRODUCT_TYPE, + "Show ASUS firmware product type"); + /* If an attribute does not require any special case handling add it here */ static const struct asus_attr_group armoury_attr_groups[] = { { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED }, @@ -801,6 +823,12 @@ static const struct asus_attr_group armoury_attr_groups[] = { { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD }, { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD }, { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, + { &ess_switch_attr_group, ASUS_WMI_DEVID_ESS_SWITCH }, + { &touchscreen_toggle_attr_group, ASUS_WMI_DEVID_TOUCHSCREEN }, + { &winkey_disable_attr_group, ASUS_WMI_DEVID_WINKEY_DISABLE }, + { &egpu_dock_state_attr_group, ASUS_WMI_DEVID_EGPU_DOCK_STATE }, + { &edp_mode_attr_group, ASUS_WMI_DEVID_EDP_MODE }, + { &product_type_attr_group, ASUS_WMI_DEVID_PRODUCT_TYPE }, }; /** From bbf1d440101647d71e8873e7ca062d607e172663 Mon Sep 17 00:00:00 2001 From: Marco Scardovi Date: Wed, 29 Jul 2026 17:26:49 +0200 Subject: [PATCH 3/4] platform/x86: asus-wmi: expose SMBIOS Type 40 OEM platform identity --- drivers/platform/x86/asus-wmi.c | 179 +++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 80144c412b902f..a5501e84dd9102 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -239,11 +240,21 @@ struct fan_curve_data { u8 percents[FAN_CURVE_POINTS]; }; +struct asus_oem_identity { + u8 product_line; + u8 product_sku; + u16 year; + u32 features_raw; + bool valid; +}; + struct asus_wmi { int dsts_id; int spec; int sfun; + struct asus_oem_identity oem_id; + struct input_dev *inputdev; struct backlight_device *backlight_device; struct backlight_device *screenpad_backlight_device; @@ -4690,6 +4701,161 @@ static ssize_t cpufv_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_WO(cpufv); +/* SMBIOS Type 40 OEM Identity Parsing */ + +static const char *dmi_string_by_index(const struct dmi_header *dm, u8 index) +{ + const char *bp; + + if (index == 0) + return NULL; + + bp = (const char *)dm + dm->length; + + while (index > 1 && *bp) { + bp += strlen(bp) + 1; + index--; + } + + if (!*bp) + return NULL; + + return bp; +} + +static void asus_wmi_parse_type40_struct(const struct dmi_header *dm, void *private_data) +{ + struct asus_oem_identity *oem = private_data; + const u8 *data = (const u8 *)dm; + u8 count, offset, i; + + if (dm->type != 40 || dm->length < 5) + return; + + count = data[4]; + offset = 5; + + for (i = 0; i < count; i++) { + u8 entry_length, name_idx; + const char *name; + const u8 *val; + + if (offset + 5 > dm->length) + break; + + entry_length = data[offset]; + if (entry_length < 5 || offset + entry_length > dm->length) + break; + + name_idx = data[offset + 4]; + name = dmi_string_by_index(dm, name_idx); + val = &data[offset + 5]; + + if (name) { + if (!strcmp(name, "PRODUCT_LINE") && entry_length >= 6) { + oem->product_line = val[0]; + oem->valid = true; + } else if (!strcmp(name, "PRODUCT_SKU") && entry_length >= 6) { + oem->product_sku = val[0]; + oem->valid = true; + } else if (!strcmp(name, "YEAR") && entry_length >= 7) { + oem->year = get_unaligned_le16(val); + oem->valid = true; + } else if (!strcmp(name, "FEATURES") && entry_length >= 9) { + oem->features_raw = get_unaligned_le32(val); + oem->valid = true; + } + } + + offset += entry_length; + } +} + +static void asus_wmi_fetch_oem_identity(struct asus_wmi *asus) +{ + dmi_walk(asus_wmi_parse_type40_struct, &asus->oem_id); +} + +static const char *asus_wmi_get_subbrand(u8 sku) +{ + switch (sku) { + case 0: + case 5: + case 6: + return "ASUS"; + case 1: + case 4: + return "ROG"; + case 2: + case 3: + return "TUF"; + case 7: + return "ProArt"; + default: + return "Unknown"; + } +} + +static ssize_t oem_product_line_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + static const char * const names[] = { + "Motherboard", "Server", "WS", "AIO", "Desktop", "Notebook", "Mini PC" + }; + + if (!asus->oem_id.valid) + return -ENODATA; + + if (asus->oem_id.product_line < ARRAY_SIZE(names)) + return sysfs_emit(buf, "%s\n", names[asus->oem_id.product_line]); + + return sysfs_emit(buf, "Unknown (%u)\n", asus->oem_id.product_line); +} +static DEVICE_ATTR_RO(oem_product_line); + +static ssize_t oem_product_sku_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + static const char * const names[] = { + "PRIME", "ROG", "TUF", "TUF-Gaming", "ROG-Strix", "XU", "Pro", "ProArt" + }; + + if (!asus->oem_id.valid) + return -ENODATA; + + if (asus->oem_id.product_sku < ARRAY_SIZE(names)) + return sysfs_emit(buf, "%s\n", names[asus->oem_id.product_sku]); + + return sysfs_emit(buf, "Unknown (%u)\n", asus->oem_id.product_sku); +} +static DEVICE_ATTR_RO(oem_product_sku); + +static ssize_t oem_subbrand_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + + if (!asus->oem_id.valid) + return -ENODATA; + + return sysfs_emit(buf, "%s\n", asus_wmi_get_subbrand(asus->oem_id.product_sku)); +} +static DEVICE_ATTR_RO(oem_subbrand); + +static ssize_t oem_year_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + + if (!asus->oem_id.valid) + return -ENODATA; + + return sysfs_emit(buf, "%u\n", asus->oem_id.year); +} +static DEVICE_ATTR_RO(oem_year); + static struct attribute *platform_attributes[] = { &dev_attr_cpufv.attr, &dev_attr_camera.attr, @@ -4698,6 +4864,10 @@ static struct attribute *platform_attributes[] = { &dev_attr_lid_resume.attr, &dev_attr_als_enable.attr, &dev_attr_fan_boost_mode.attr, + &dev_attr_oem_product_line.attr, + &dev_attr_oem_product_sku.attr, + &dev_attr_oem_subbrand.attr, + &dev_attr_oem_year.attr, #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) &dev_attr_charge_mode.attr, &dev_attr_egpu_enable.attr, @@ -4729,7 +4899,12 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, bool ok = true; int devid = -1; - if (attr == &dev_attr_camera.attr) + if (attr == &dev_attr_oem_product_line.attr || + attr == &dev_attr_oem_product_sku.attr || + attr == &dev_attr_oem_subbrand.attr || + attr == &dev_attr_oem_year.attr) + ok = asus->oem_id.valid; + else if (attr == &dev_attr_camera.attr) devid = ASUS_WMI_DEVID_CAMERA; else if (attr == &dev_attr_cardr.attr) devid = ASUS_WMI_DEVID_CARDREADER; @@ -5081,6 +5256,8 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_platform_profile_setup; + asus_wmi_fetch_oem_identity(asus); + err = asus_wmi_sysfs_init(asus->platform_device); if (err) goto fail_sysfs; From ea23aac0c6b3199e1faa0a6d24a0762b5ed81a13 Mon Sep 17 00:00:00 2001 From: Marco Scardovi Date: Wed, 29 Jul 2026 17:37:26 +0200 Subject: [PATCH 4/4] platform/x86: asus-armoury: add GPU Dynamic Boost readout attributes --- drivers/platform/x86/asus-armoury.c | 8 ++++++++ include/linux/platform_data/x86/asus-wmi.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 8c9cf9792ab1c9..0faa7ad0a0a8ff 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -794,6 +794,12 @@ ASUS_ATTR_GROUP_BOOL_RO(egpu_dock_state, "egpu_dock_state", "Show external GPU dock connection"); ASUS_ATTR_GROUP_BOOL_RO(edp_mode, "edp_mode", ASUS_WMI_DEVID_EDP_MODE, "Show the eDP panel mode"); +ASUS_ATTR_GROUP_BOOL_RO(gpu_dyn_boost_status, "gpu_dyn_boost_status", + ASUS_WMI_DEVID_GPU_DYN_BOOST_STATUS, + "Show GPU Dynamic Boost support status"); +ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(gpu_dyn_boost_value, "gpu_dyn_boost_value", + ASUS_WMI_DEVID_GPU_DYN_BOOST_VALUE, + "Read GPU Dynamic Boost allocation value"); /* Product type read-only */ ASUS_ATTR_GROUP_INT_VALUE_ONLY_RO(product_type, "product_type", @@ -829,6 +835,8 @@ static const struct asus_attr_group armoury_attr_groups[] = { { &egpu_dock_state_attr_group, ASUS_WMI_DEVID_EGPU_DOCK_STATE }, { &edp_mode_attr_group, ASUS_WMI_DEVID_EDP_MODE }, { &product_type_attr_group, ASUS_WMI_DEVID_PRODUCT_TYPE }, + { &gpu_dyn_boost_status_attr_group, ASUS_WMI_DEVID_GPU_DYN_BOOST_STATUS }, + { &gpu_dyn_boost_value_attr_group, ASUS_WMI_DEVID_GPU_DYN_BOOST_VALUE }, }; /** diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index f8f12846a9efeb..1070903e4df4ed 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -169,6 +169,8 @@ #define ASUS_WMI_DEVID_EDP_MODE 0x0009001B #define ASUS_WMI_DEVID_GPU_SWITCH_CAP 0x0009001C #define ASUS_WMI_DEVID_EGPU_PCIE_GEN 0x0006005B +#define ASUS_WMI_DEVID_GPU_DYN_BOOST_STATUS 0x00090030 +#define ASUS_WMI_DEVID_GPU_DYN_BOOST_VALUE 0x00090031 /* TUF lighting & status */ #define ASUS_WMI_DEVID_TUF_RGB_WDL 0x0010005C