Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions drivers/platform/x86/asus-armoury.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,34 @@ 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");
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",
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 },
Expand All @@ -801,6 +829,14 @@ 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 },
{ &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 },
};

/**
Expand Down
179 changes: 178 additions & 1 deletion drivers/platform/x86/asus-wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/unaligned.h>

#include <acpi/battery.h>
#include <acpi/video.h>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions include/linux/platform_data/x86/asus-wmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,32 @@

/* 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
#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

/* 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
Expand Down