lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <326123ef-4bcf-4978-a1c6-bb4ebfd4e5ce@gmx.de>
Date: Thu, 2 Jan 2025 17:49:31 +0100
From: Armin Wolf <W_Armin@....de>
To: Kurt Borja <kuurtb@...il.com>, platform-driver-x86@...r.kernel.org
Cc: Dell.Client.Kernel@...l.com, hdegoede@...hat.com,
 ilpo.jarvinen@...ux.intel.com, linux-kernel@...r.kernel.org,
 mario.limonciello@....com
Subject: Re: [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver

Am 29.12.24 um 20:45 schrieb Kurt Borja:

> Split alienware-wmi WMI drivers into different files. This is done
> seamlessly by copying and pasting, however some blocks are reordered.

Reviewed-by: Armin Wolf <W_Armin@....de>

> Reviewed-by: Armin Wolf <W_Armin@....de>
> Signed-off-by: Kurt Borja <kuurtb@...il.com>
> ---
>   drivers/platform/x86/dell/Makefile            |   2 +
>   .../platform/x86/dell/alienware-wmi-base.c    | 849 +-----------------
>   .../platform/x86/dell/alienware-wmi-legacy.c  |  98 ++
>   .../platform/x86/dell/alienware-wmi-wmax.c    | 775 ++++++++++++++++
>   4 files changed, 876 insertions(+), 848 deletions(-)
>   create mode 100644 drivers/platform/x86/dell/alienware-wmi-legacy.c
>   create mode 100644 drivers/platform/x86/dell/alienware-wmi-wmax.c
>
> diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
> index f8aec8502c2f..03ba459f3d31 100644
> --- a/drivers/platform/x86/dell/Makefile
> +++ b/drivers/platform/x86/dell/Makefile
> @@ -6,6 +6,8 @@
>
>   obj-$(CONFIG_ALIENWARE_WMI)		+= alienware-wmi.o
>   alienware-wmi-objs			:= alienware-wmi-base.o
> +alienware-wmi-y				+= alienware-wmi-legacy.o
> +alienware-wmi-y				+= alienware-wmi-wmax.o
>   obj-$(CONFIG_DCDBAS)			+= dcdbas.o
>   obj-$(CONFIG_DELL_LAPTOP)		+= dell-laptop.o
>   obj-$(CONFIG_DELL_RBTN)			+= dell-rbtn.o
> diff --git a/drivers/platform/x86/dell/alienware-wmi-base.c b/drivers/platform/x86/dell/alienware-wmi-base.c
> index a268193ad2a1..fd73c3881dc0 100644
> --- a/drivers/platform/x86/dell/alienware-wmi-base.c
> +++ b/drivers/platform/x86/dell/alienware-wmi-base.c
> @@ -8,96 +8,21 @@
>   #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
>   #include <linux/acpi.h>
> -#include <linux/bitfield.h>
> -#include <linux/bits.h>
>   #include <linux/module.h>
>   #include <linux/platform_device.h>
> -#include <linux/platform_profile.h>
>   #include <linux/dmi.h>
>   #include <linux/leds.h>
> -#include <linux/wmi.h>
>   #include "alienware-wmi.h"
>
> -#define WMAX_METHOD_HDMI_SOURCE		0x1
> -#define WMAX_METHOD_HDMI_STATUS		0x2
> -#define WMAX_METHOD_BRIGHTNESS		0x3
> -#define WMAX_METHOD_ZONE_CONTROL	0x4
> -#define WMAX_METHOD_HDMI_CABLE		0x5
> -#define WMAX_METHOD_AMPLIFIER_CABLE	0x6
> -#define WMAX_METHOD_DEEP_SLEEP_CONTROL	0x0B
> -#define WMAX_METHOD_DEEP_SLEEP_STATUS	0x0C
> -#define WMAX_METHOD_THERMAL_INFORMATION	0x14
> -#define WMAX_METHOD_THERMAL_CONTROL	0x15
> -#define WMAX_METHOD_GAME_SHIFT_STATUS	0x25
> -
> -#define WMAX_THERMAL_MODE_GMODE		0xAB
> -
> -#define WMAX_FAILURE_CODE		0xFFFFFFFF
> -
>   MODULE_AUTHOR("Mario Limonciello <mario.limonciello@...look.com>");
>   MODULE_DESCRIPTION("Alienware special feature control");
>   MODULE_LICENSE("GPL");
>
> -static bool force_platform_profile;
> -module_param_unsafe(force_platform_profile, bool, 0);
> -MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available");
> -
> -static bool force_gmode;
> -module_param_unsafe(force_gmode, bool, 0);
> -MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected");
> -
>   enum INTERFACE_FLAGS {
>   	LEGACY,
>   	WMAX,
>   };
>
> -enum WMAX_THERMAL_INFORMATION_OPERATIONS {
> -	WMAX_OPERATION_SYS_DESCRIPTION		= 0x02,
> -	WMAX_OPERATION_LIST_IDS			= 0x03,
> -	WMAX_OPERATION_CURRENT_PROFILE		= 0x0B,
> -};
> -
> -enum WMAX_THERMAL_CONTROL_OPERATIONS {
> -	WMAX_OPERATION_ACTIVATE_PROFILE		= 0x01,
> -};
> -
> -enum WMAX_GAME_SHIFT_STATUS_OPERATIONS {
> -	WMAX_OPERATION_TOGGLE_GAME_SHIFT	= 0x01,
> -	WMAX_OPERATION_GET_GAME_SHIFT_STATUS	= 0x02,
> -};
> -
> -enum WMAX_THERMAL_TABLES {
> -	WMAX_THERMAL_TABLE_BASIC		= 0x90,
> -	WMAX_THERMAL_TABLE_USTT			= 0xA0,
> -};
> -
> -enum wmax_thermal_mode {
> -	THERMAL_MODE_USTT_BALANCED,
> -	THERMAL_MODE_USTT_BALANCED_PERFORMANCE,
> -	THERMAL_MODE_USTT_COOL,
> -	THERMAL_MODE_USTT_QUIET,
> -	THERMAL_MODE_USTT_PERFORMANCE,
> -	THERMAL_MODE_USTT_LOW_POWER,
> -	THERMAL_MODE_BASIC_QUIET,
> -	THERMAL_MODE_BASIC_BALANCED,
> -	THERMAL_MODE_BASIC_BALANCED_PERFORMANCE,
> -	THERMAL_MODE_BASIC_PERFORMANCE,
> -	THERMAL_MODE_LAST,
> -};
> -
> -static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = {
> -	[THERMAL_MODE_USTT_BALANCED]			= PLATFORM_PROFILE_BALANCED,
> -	[THERMAL_MODE_USTT_BALANCED_PERFORMANCE]	= PLATFORM_PROFILE_BALANCED_PERFORMANCE,
> -	[THERMAL_MODE_USTT_COOL]			= PLATFORM_PROFILE_COOL,
> -	[THERMAL_MODE_USTT_QUIET]			= PLATFORM_PROFILE_QUIET,
> -	[THERMAL_MODE_USTT_PERFORMANCE]			= PLATFORM_PROFILE_PERFORMANCE,
> -	[THERMAL_MODE_USTT_LOW_POWER]			= PLATFORM_PROFILE_LOW_POWER,
> -	[THERMAL_MODE_BASIC_QUIET]			= PLATFORM_PROFILE_QUIET,
> -	[THERMAL_MODE_BASIC_BALANCED]			= PLATFORM_PROFILE_BALANCED,
> -	[THERMAL_MODE_BASIC_BALANCED_PERFORMANCE]	= PLATFORM_PROFILE_BALANCED_PERFORMANCE,
> -	[THERMAL_MODE_BASIC_PERFORMANCE]		= PLATFORM_PROFILE_PERFORMANCE,
> -};
> -
>   static struct alienfx_quirks *quirks;
>
>   static struct alienfx_quirks quirk_inspiron5675 = {
> @@ -222,138 +147,7 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
>   	{}
>   };
>
> -struct wmax_brightness_args {
> -	u32 led_mask;
> -	u32 percentage;
> -};
> -
> -struct wmax_basic_args {
> -	u8 arg;
> -};
> -
> -struct legacy_led_args {
> -	struct color_platform colors;
> -	u8 brightness;
> -	u8 state;
> -} __packed;
> -
> -struct wmax_led_args {
> -	u32 led_mask;
> -	struct color_platform colors;
> -	u8 state;
> -} __packed;
> -
> -struct wmax_u32_args {
> -	u8 operation;
> -	u8 arg1;
> -	u8 arg2;
> -	u8 arg3;
> -};
> -
> -struct awcc_priv {
> -	struct wmi_device *wdev;
> -	struct platform_profile_handler pp_handler;
> -	enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> -};
> -
> -static u8 interface;
> -
> -struct awcc_quirks {
> -	bool gmode;
> -};
> -
> -static struct awcc_quirks g_series_features = {
> -	.gmode = true,
> -};
> -
> -static struct awcc_quirks x_series_features = {
> -	.gmode = false,
> -};
> -
> -static const struct dmi_system_id awcc_dmi_table[] __initconst = {
> -	{
> -		.ident = "Alienware m17 R5",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
> -		},
> -		.driver_data = &x_series_features,
> -	},
> -	{
> -		.ident = "Alienware m18 R2",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
> -		},
> -		.driver_data = &x_series_features,
> -	},
> -	{
> -		.ident = "Alienware x15 R1",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
> -		},
> -		.driver_data = &x_series_features,
> -	},
> -	{
> -		.ident = "Alienware x17 R2",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
> -		},
> -		.driver_data = &x_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G15 5510",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G15 5511",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G15 5515",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G3 3500",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G3 3590",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -	{
> -		.ident = "Dell Inc. G5 5500",
> -		.matches = {
> -			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> -			DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
> -		},
> -		.driver_data = &g_series_features,
> -	},
> -};
> -
> -struct awcc_quirks *awcc;
> +u8 interface;
>
>   int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
>   			  void *in_args, size_t in_size, u32 *out_data)
> @@ -586,458 +380,6 @@ static enum led_brightness global_led_get(struct led_classdev *led_cdev)
>   	return priv->global_brightness;
>   }
>
> -/*
> - *	The HDMI mux sysfs node indicates the status of the HDMI input mux.
> - *	It can toggle between standard system GPU output and HDMI input.
> - */
> -static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
> -			  char *buf)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args in_args = {
> -		.arg = 0,
> -	};
> -	u32 out_data;
> -	int ret;
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_CABLE,
> -				    &in_args, sizeof(in_args), &out_data);
> -
> -	if (!ret) {
> -		if (out_data == 0)
> -			return sysfs_emit(buf, "[unconnected] connected unknown\n");
> -		else if (out_data == 1)
> -			return sysfs_emit(buf, "unconnected [connected] unknown\n");
> -	}
> -
> -	pr_err("alienware-wmi: unknown HDMI cable status: %d\n", ret);
> -	return sysfs_emit(buf, "unconnected connected [unknown]\n");
> -}
> -
> -static ssize_t source_show(struct device *dev, struct device_attribute *attr,
> -			   char *buf)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args in_args = {
> -		.arg = 0,
> -	};
> -	u32 out_data;
> -	int ret;
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_STATUS,
> -				    &in_args, sizeof(in_args), &out_data);
> -
> -	if (!ret) {
> -		if (out_data == 1)
> -			return sysfs_emit(buf, "[input] gpu unknown\n");
> -		else if (out_data == 2)
> -			return sysfs_emit(buf, "input [gpu] unknown\n");
> -	}
> -
> -	pr_err("alienware-wmi: unknown HDMI source status: %u\n", ret);
> -	return sysfs_emit(buf, "input gpu [unknown]\n");
> -}
> -
> -static ssize_t source_store(struct device *dev, struct device_attribute *attr,
> -			    const char *buf, size_t count)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args args;
> -	int ret;
> -
> -	if (strcmp(buf, "gpu\n") == 0)
> -		args.arg = 1;
> -	else if (strcmp(buf, "input\n") == 0)
> -		args.arg = 2;
> -	else
> -		args.arg = 3;
> -	pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_SOURCE, &args,
> -				    sizeof(args), NULL);
> -
> -	if (ret < 0)
> -		pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", ret);
> -
> -	return count;
> -}
> -
> -static DEVICE_ATTR_RO(cable);
> -static DEVICE_ATTR_RW(source);
> -
> -static bool hdmi_group_visible(struct kobject *kobj)
> -{
> -	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> -
> -	return priv->quirks->hdmi_mux;
> -}
> -DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
> -
> -static struct attribute *hdmi_attrs[] = {
> -	&dev_attr_cable.attr,
> -	&dev_attr_source.attr,
> -	NULL,
> -};
> -
> -static const struct attribute_group hdmi_attribute_group = {
> -	.name = "hdmi",
> -	.is_visible = SYSFS_GROUP_VISIBLE(hdmi),
> -	.attrs = hdmi_attrs,
> -};
> -
> -/*
> - * Alienware GFX amplifier support
> - * - Currently supports reading cable status
> - * - Leaving expansion room to possibly support dock/undock events later
> - */
> -static ssize_t status_show(struct device *dev, struct device_attribute *attr,
> -			   char *buf)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args in_args = {
> -		.arg = 0,
> -	};
> -	u32 out_data;
> -	int ret;
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_AMPLIFIER_CABLE,
> -				    &in_args, sizeof(in_args), &out_data);
> -
> -	if (!ret) {
> -		if (out_data == 0)
> -			return sysfs_emit(buf, "[unconnected] connected unknown\n");
> -		else if (out_data == 1)
> -			return sysfs_emit(buf, "unconnected [connected] unknown\n");
> -	}
> -
> -	pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret);
> -	return sysfs_emit(buf, "unconnected connected [unknown]\n");
> -}
> -
> -static DEVICE_ATTR_RO(status);
> -
> -static bool amplifier_group_visible(struct kobject *kobj)
> -{
> -	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> -
> -	return priv->quirks->amplifier;
> -}
> -DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
> -
> -static struct attribute *amplifier_attrs[] = {
> -	&dev_attr_status.attr,
> -	NULL,
> -};
> -
> -static const struct attribute_group amplifier_attribute_group = {
> -	.name = "amplifier",
> -	.is_visible = SYSFS_GROUP_VISIBLE(amplifier),
> -	.attrs = amplifier_attrs,
> -};
> -
> -/*
> - * Deep Sleep Control support
> - * - Modifies BIOS setting for deep sleep control allowing extra wakeup events
> - */
> -static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
> -			      char *buf)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args in_args = {
> -		.arg = 0,
> -	};
> -	u32 out_data;
> -	int ret;
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_STATUS,
> -				    &in_args, sizeof(in_args), &out_data);
> -
> -	if (!ret) {
> -		if (out_data == 0)
> -			return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
> -		else if (out_data == 1)
> -			return sysfs_emit(buf, "disabled [s5] s5_s4\n");
> -		else if (out_data == 2)
> -			return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
> -	}
> -
> -	pr_err("alienware-wmi: unknown deep sleep status: %d\n", ret);
> -	return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
> -}
> -
> -static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
> -			       const char *buf, size_t count)
> -{
> -	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> -	struct wmax_basic_args args;
> -	int ret;
> -
> -	if (strcmp(buf, "disabled\n") == 0)
> -		args.arg = 0;
> -	else if (strcmp(buf, "s5\n") == 0)
> -		args.arg = 1;
> -	else
> -		args.arg = 2;
> -	pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
> -
> -	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_CONTROL,
> -				    &args, sizeof(args), NULL);
> -
> -	if (!ret)
> -		pr_err("alienware-wmi: deep sleep control failed: results: %u\n", ret);
> -
> -	return count;
> -}
> -
> -static DEVICE_ATTR_RW(deepsleep);
> -
> -static bool deepsleep_group_visible(struct kobject *kobj)
> -{
> -	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> -
> -	return priv->quirks->deepslp;
> -}
> -DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
> -
> -static struct attribute *deepsleep_attrs[] = {
> -	&dev_attr_deepsleep.attr,
> -	NULL,
> -};
> -
> -static const struct attribute_group deepsleep_attribute_group = {
> -	.name = "deepsleep",
> -	.is_visible = SYSFS_GROUP_VISIBLE(deepsleep),
> -	.attrs = deepsleep_attrs,
> -};
> -
> -/*
> - * Thermal Profile control
> - *  - Provides thermal profile control through the Platform Profile API
> - */
> -#define WMAX_THERMAL_TABLE_MASK		GENMASK(7, 4)
> -#define WMAX_THERMAL_MODE_MASK		GENMASK(3, 0)
> -#define WMAX_SENSOR_ID_MASK		BIT(8)
> -
> -static bool is_wmax_thermal_code(u32 code)
> -{
> -	if (code & WMAX_SENSOR_ID_MASK)
> -		return false;
> -
> -	if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST)
> -		return false;
> -
> -	if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC &&
> -	    (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET)
> -		return true;
> -
> -	if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT &&
> -	    (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER)
> -		return true;
> -
> -	return false;
> -}
> -
> -static int wmax_thermal_information(struct wmi_device *wdev, u8 operation,
> -				    u8 arg, u32 *out_data)
> -{
> -	struct wmax_u32_args in_args = {
> -		.operation = operation,
> -		.arg1 = arg,
> -		.arg2 = 0,
> -		.arg3 = 0,
> -	};
> -	int ret;
> -
> -	ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_INFORMATION,
> -				    &in_args, sizeof(in_args), out_data);
> -	if (ret < 0)
> -		return ret;
> -
> -	if (*out_data == WMAX_FAILURE_CODE)
> -		return -EBADRQC;
> -
> -	return 0;
> -}
> -
> -static int wmax_thermal_control(struct wmi_device *wdev, u8 profile)
> -{
> -	struct wmax_u32_args in_args = {
> -		.operation = WMAX_OPERATION_ACTIVATE_PROFILE,
> -		.arg1 = profile,
> -		.arg2 = 0,
> -		.arg3 = 0,
> -	};
> -	u32 out_data;
> -	int ret;
> -
> -	ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_CONTROL,
> -				    &in_args, sizeof(in_args), &out_data);
> -	if (ret)
> -		return ret;
> -
> -	if (out_data == WMAX_FAILURE_CODE)
> -		return -EBADRQC;
> -
> -	return 0;
> -}
> -
> -static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation,
> -				  u32 *out_data)
> -{
> -	struct wmax_u32_args in_args = {
> -		.operation = operation,
> -		.arg1 = 0,
> -		.arg2 = 0,
> -		.arg3 = 0,
> -	};
> -	int ret;
> -
> -	ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS,
> -				    &in_args, sizeof(in_args), out_data);
> -
> -	if (ret < 0)
> -		return ret;
> -
> -	if (*out_data == WMAX_FAILURE_CODE)
> -		return -EOPNOTSUPP;
> -
> -	return 0;
> -}
> -
> -static int thermal_profile_get(struct platform_profile_handler *pprof,
> -			       enum platform_profile_option *profile)
> -{
> -	struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
> -	u32 out_data;
> -	int ret;
> -
> -	ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE,
> -				       0, &out_data);
> -
> -	if (ret < 0)
> -		return ret;
> -
> -	if (out_data == WMAX_THERMAL_MODE_GMODE) {
> -		*profile = PLATFORM_PROFILE_PERFORMANCE;
> -		return 0;
> -	}
> -
> -	if (!is_wmax_thermal_code(out_data))
> -		return -ENODATA;
> -
> -	out_data &= WMAX_THERMAL_MODE_MASK;
> -	*profile = wmax_mode_to_platform_profile[out_data];
> -
> -	return 0;
> -}
> -
> -static int thermal_profile_set(struct platform_profile_handler *pprof,
> -			       enum platform_profile_option profile)
> -{
> -	struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
> -
> -	if (awcc->gmode) {
> -		u32 gmode_status;
> -		int ret;
> -
> -		ret = wmax_game_shift_status(priv->wdev,
> -					     WMAX_OPERATION_GET_GAME_SHIFT_STATUS,
> -					     &gmode_status);
> -
> -		if (ret < 0)
> -			return ret;
> -
> -		if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) ||
> -		    (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) {
> -			ret = wmax_game_shift_status(priv->wdev,
> -						     WMAX_OPERATION_TOGGLE_GAME_SHIFT,
> -						     &gmode_status);
> -
> -			if (ret < 0)
> -				return ret;
> -		}
> -	}
> -
> -	return wmax_thermal_control(priv->wdev,
> -				    priv->supported_thermal_profiles[profile]);
> -}
> -
> -static int create_thermal_profile(struct wmi_device *wdev)
> -{
> -	struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
> -	enum platform_profile_option profile;
> -	enum wmax_thermal_mode mode;
> -	u8 sys_desc[4];
> -	u32 first_mode;
> -	u32 out_data;
> -	int ret;
> -
> -	ret = wmax_thermal_information(wdev, WMAX_OPERATION_SYS_DESCRIPTION,
> -				       0, (u32 *) &sys_desc);
> -	if (ret < 0)
> -		return ret;
> -
> -	first_mode = sys_desc[0] + sys_desc[1];
> -
> -	for (u32 i = 0; i < sys_desc[3]; i++) {
> -		ret = wmax_thermal_information(wdev, WMAX_OPERATION_LIST_IDS,
> -					       i + first_mode, &out_data);
> -
> -		if (ret == -EIO)
> -			return ret;
> -
> -		if (ret == -EBADRQC)
> -			break;
> -
> -		if (!is_wmax_thermal_code(out_data))
> -			continue;
> -
> -		mode = out_data & WMAX_THERMAL_MODE_MASK;
> -		profile = wmax_mode_to_platform_profile[mode];
> -		priv->supported_thermal_profiles[profile] = out_data;
> -
> -		set_bit(profile, priv->pp_handler.choices);
> -	}
> -
> -	if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> -		return -ENODEV;
> -
> -	if (awcc->gmode) {
> -		priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> -			WMAX_THERMAL_MODE_GMODE;
> -
> -		set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->pp_handler.choices);
> -	}
> -
> -	priv->pp_handler.profile_get = thermal_profile_get;
> -	priv->pp_handler.profile_set = thermal_profile_set;
> -	priv->pp_handler.name = "alienware-wmi";
> -	priv->pp_handler.dev = &wdev->dev;
> -
> -	return platform_profile_register(&priv->pp_handler);
> -}
> -
> -static int alienware_awcc_setup(struct wmi_device *wdev)
> -{
> -	struct awcc_priv *priv;
> -
> -	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
> -	if (!priv)
> -		return -ENOMEM;
> -
> -	dev_set_drvdata(&wdev->dev, priv);
> -	priv->wdev = wdev;
> -
> -	return create_thermal_profile(wdev);
> -}
> -
> -static void alienware_awcc_exit(struct wmi_device *wdev)
> -{
> -	struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
> -
> -	platform_profile_remove(&priv->pp_handler);
> -}
> -
>   /*
>    * Platform Driver
>    */
> @@ -1073,13 +415,6 @@ static const struct attribute_group *alienfx_groups[] = {
>   	NULL
>   };
>
> -static const struct attribute_group *wmax_alienfx_groups[] = {
> -	&hdmi_attribute_group,
> -	&amplifier_attribute_group,
> -	&deepsleep_attribute_group,
> -	NULL
> -};
> -
>   static struct platform_driver platform_driver = {
>   	.driver = {
>   		.name = "alienware-wmi",
> @@ -1120,188 +455,6 @@ void alienware_alienfx_exit(struct wmi_device *wdev)
>   	platform_driver_unregister(&platform_driver);
>   }
>
> -/*
> - * Legacy WMI driver
> - */
> -static int legacy_wmi_update_led(struct alienfx_priv *priv,
> -				 struct wmi_device *wdev, u8 location)
> -{
> -	struct legacy_led_args legacy_args = {
> -		.colors = priv->colors[location],
> -		.brightness = priv->global_brightness,
> -		.state = 0,
> -	};
> -	struct acpi_buffer input;
> -	acpi_status status;
> -
> -	if (legacy_args.state != LEGACY_RUNNING) {
> -		legacy_args.state = priv->lighting_control_state;
> -
> -		input.length = sizeof(legacy_args);
> -		input.pointer = &legacy_args;
> -
> -		status = wmi_evaluate_method(LEGACY_POWER_CONTROL_GUID, 0,
> -					     location + 1, &input, NULL);
> -		if (ACPI_FAILURE(status))
> -			return -EIO;
> -
> -		return 0;
> -	}
> -
> -	return alienware_wmi_command(wdev, location + 1, &legacy_args,
> -				     sizeof(legacy_args), NULL);
> -}
> -
> -static int legacy_wmi_update_brightness(struct alienfx_priv *priv,
> -					struct wmi_device *wdev, u8 brightness)
> -{
> -	return legacy_wmi_update_led(priv, wdev, 0);
> -}
> -
> -static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
> -{
> -	struct alienfx_platdata pdata = {
> -		.wdev = wdev,
> -		.ops = {
> -			.upd_led = legacy_wmi_update_led,
> -			.upd_brightness = legacy_wmi_update_brightness,
> -		},
> -	};
> -
> -	return alienware_alienfx_setup(&pdata);
> -}
> -
> -static void legacy_wmi_remove(struct wmi_device *wdev)
> -{
> -	alienware_alienfx_exit(wdev);
> -}
> -
> -static struct wmi_device_id alienware_legacy_device_id_table[] = {
> -	{ LEGACY_CONTROL_GUID, NULL },
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(wmi, alienware_legacy_device_id_table);
> -
> -static struct wmi_driver alienware_legacy_wmi_driver = {
> -	.driver = {
> -		.name = "alienware-wmi-alienfx",
> -		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> -	},
> -	.id_table = alienware_legacy_device_id_table,
> -	.probe = legacy_wmi_probe,
> -	.remove = legacy_wmi_remove,
> -};
> -
> -int __init alienware_legacy_wmi_init(void)
> -{
> -	return wmi_driver_register(&alienware_legacy_wmi_driver);
> -}
> -
> -void __exit alienware_legacy_wmi_exit(void)
> -{
> -	wmi_driver_unregister(&alienware_legacy_wmi_driver);
> -}
> -
> -/*
> - * WMAX WMI driver
> - */
> -static int wmax_wmi_update_led(struct alienfx_priv *priv,
> -			       struct wmi_device *wdev, u8 location)
> -{
> -	struct wmax_led_args in_args = {
> -		.led_mask = 1 << location,
> -		.colors = priv->colors[location],
> -		.state = priv->lighting_control_state,
> -	};
> -
> -	return alienware_wmi_command(wdev, WMAX_METHOD_ZONE_CONTROL, &in_args,
> -				     sizeof(in_args), NULL);
> -}
> -
> -static int wmax_wmi_update_brightness(struct alienfx_priv *priv,
> -				      struct wmi_device *wdev, u8 brightness)
> -{
> -	struct wmax_brightness_args in_args = {
> -		.led_mask = 0xFF,
> -		.percentage = brightness,
> -	};
> -
> -	return alienware_wmi_command(wdev, WMAX_METHOD_BRIGHTNESS, &in_args,
> -				     sizeof(in_args), NULL);
> -}
> -
> -static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> -{
> -	struct alienfx_platdata pdata = {
> -		.wdev = wdev,
> -		.ops = {
> -			.upd_led = wmax_wmi_update_led,
> -			.upd_brightness = wmax_wmi_update_brightness,
> -		},
> -	};
> -	struct platform_device *pdev;
> -	int ret;
> -
> -	if (awcc) {
> -		ret = alienware_awcc_setup(wdev);
> -	} else {
> -		ret = alienware_alienfx_setup(&pdata);
> -		if (ret < 0)
> -			return ret;
> -
> -		pdev = dev_get_drvdata(&wdev->dev);
> -		ret = device_add_groups(&pdev->dev, wmax_alienfx_groups);
> -	}
> -
> -	return ret;
> -}
> -
> -static void wmax_wmi_remove(struct wmi_device *wdev)
> -{
> -	if (awcc)
> -		alienware_awcc_exit(wdev);
> -	else
> -		alienware_alienfx_exit(wdev);
> -}
> -
> -static struct wmi_device_id alienware_wmax_device_id_table[] = {
> -	{ WMAX_CONTROL_GUID, NULL },
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(wmi, alienware_wmax_device_id_table);
> -
> -static struct wmi_driver alienware_wmax_wmi_driver = {
> -	.driver = {
> -		.name = "alienware-wmi-wmax",
> -		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> -	},
> -	.id_table = alienware_wmax_device_id_table,
> -	.probe = wmax_wmi_probe,
> -	.remove = wmax_wmi_remove,
> -};
> -
> -int __init alienware_wmax_wmi_init(void)
> -{
> -	const struct dmi_system_id *id;
> -
> -	id = dmi_first_match(awcc_dmi_table);
> -	if (id)
> -		awcc = id->driver_data;
> -
> -	if (force_platform_profile)
> -		awcc = &x_series_features;
> -
> -	if (force_gmode)
> -		awcc = &g_series_features;
> -
> -	return wmi_driver_register(&alienware_wmax_wmi_driver);
> -}
> -
> -void __exit alienware_wmax_wmi_exit(void)
> -{
> -	wmi_driver_unregister(&alienware_wmax_wmi_driver);
> -}
> -
>   static int __init alienware_wmi_init(void)
>   {
>   	int ret;
> diff --git a/drivers/platform/x86/dell/alienware-wmi-legacy.c b/drivers/platform/x86/dell/alienware-wmi-legacy.c
> new file mode 100644
> index 000000000000..b53a931f97b5
> --- /dev/null
> +++ b/drivers/platform/x86/dell/alienware-wmi-legacy.c
> @@ -0,0 +1,98 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Alienware LEGACY WMI device driver
> + *
> + * Copyright (C) 2024 Kurt Borja <kuurtb@...il.com>
> + */
> +
> +#include <linux/wmi.h>
> +#include "alienware-wmi.h"
> +
> +struct legacy_led_args {
> +	struct color_platform colors;
> +	u8 brightness;
> +	u8 state;
> +} __packed;
> +
> +
> +/*
> + * Legacy WMI driver
> + */
> +static int legacy_wmi_update_led(struct alienfx_priv *priv,
> +				 struct wmi_device *wdev, u8 location)
> +{
> +	struct legacy_led_args legacy_args = {
> +		.colors = priv->colors[location],
> +		.brightness = priv->global_brightness,
> +		.state = 0,
> +	};
> +	struct acpi_buffer input;
> +	acpi_status status;
> +
> +	if (legacy_args.state != LEGACY_RUNNING) {
> +		legacy_args.state = priv->lighting_control_state;
> +
> +		input.length = sizeof(legacy_args);
> +		input.pointer = &legacy_args;
> +
> +		status = wmi_evaluate_method(LEGACY_POWER_CONTROL_GUID, 0,
> +					     location + 1, &input, NULL);
> +		if (ACPI_FAILURE(status))
> +			return -EIO;
> +
> +		return 0;
> +	}
> +
> +	return alienware_wmi_command(wdev, location + 1, &legacy_args,
> +				     sizeof(legacy_args), NULL);
> +}
> +
> +static int legacy_wmi_update_brightness(struct alienfx_priv *priv,
> +					struct wmi_device *wdev, u8 brightness)
> +{
> +	return legacy_wmi_update_led(priv, wdev, 0);
> +}
> +
> +static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
> +{
> +	struct alienfx_platdata pdata = {
> +		.wdev = wdev,
> +		.ops = {
> +			.upd_led = legacy_wmi_update_led,
> +			.upd_brightness = legacy_wmi_update_brightness,
> +		},
> +	};
> +
> +	return alienware_alienfx_setup(&pdata);
> +}
> +
> +static void legacy_wmi_remove(struct wmi_device *wdev)
> +{
> +	alienware_alienfx_exit(wdev);
> +}
> +
> +static struct wmi_device_id alienware_legacy_device_id_table[] = {
> +	{ LEGACY_CONTROL_GUID, NULL },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(wmi, alienware_legacy_device_id_table);
> +
> +static struct wmi_driver alienware_legacy_wmi_driver = {
> +	.driver = {
> +		.name = "alienware-wmi-alienfx",
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +	},
> +	.id_table = alienware_legacy_device_id_table,
> +	.probe = legacy_wmi_probe,
> +	.remove = legacy_wmi_remove,
> +};
> +
> +int __init alienware_legacy_wmi_init(void)
> +{
> +	return wmi_driver_register(&alienware_legacy_wmi_driver);
> +}
> +
> +void __exit alienware_legacy_wmi_exit(void)
> +{
> +	wmi_driver_unregister(&alienware_legacy_wmi_driver);
> +}
> diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c
> new file mode 100644
> index 000000000000..597be9e6d19c
> --- /dev/null
> +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c
> @@ -0,0 +1,775 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Alienware WMAX WMI device driver
> + *
> + * Copyright (C) 2024 Kurt Borja <kuurtb@...il.com>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/dmi.h>
> +#include <linux/moduleparam.h>
> +#include <linux/platform_profile.h>
> +#include <linux/wmi.h>
> +#include "alienware-wmi.h"
> +
> +#define WMAX_METHOD_HDMI_SOURCE			0x1
> +#define WMAX_METHOD_HDMI_STATUS			0x2
> +#define WMAX_METHOD_HDMI_CABLE			0x5
> +#define WMAX_METHOD_AMPLIFIER_CABLE		0x6
> +#define WMAX_METHOD_DEEP_SLEEP_CONTROL		0x0B
> +#define WMAX_METHOD_DEEP_SLEEP_STATUS		0x0C
> +#define WMAX_METHOD_BRIGHTNESS			0x3
> +#define WMAX_METHOD_ZONE_CONTROL		0x4
> +#define WMAX_METHOD_THERMAL_INFORMATION		0x14
> +#define WMAX_METHOD_THERMAL_CONTROL		0x15
> +#define WMAX_METHOD_GAME_SHIFT_STATUS		0x25
> +
> +#define WMAX_THERMAL_MODE_GMODE			0xAB
> +
> +#define WMAX_FAILURE_CODE			0xFFFFFFFF
> +#define WMAX_THERMAL_TABLE_MASK			GENMASK(7, 4)
> +#define WMAX_THERMAL_MODE_MASK			GENMASK(3, 0)
> +#define WMAX_SENSOR_ID_MASK			BIT(8)
> +
> +static bool force_platform_profile;
> +module_param_unsafe(force_platform_profile, bool, 0);
> +MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available");
> +
> +static bool force_gmode;
> +module_param_unsafe(force_gmode, bool, 0);
> +MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected");
> +
> +struct awcc_quirks {
> +	bool gmode;
> +};
> +
> +static struct awcc_quirks g_series_features = {
> +	.gmode = true,
> +};
> +
> +static struct awcc_quirks x_series_features = {
> +	.gmode = false,
> +};
> +
> +static const struct dmi_system_id awcc_dmi_table[] __initconst = {
> +	{
> +		.ident = "Alienware m17 R5",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
> +		},
> +		.driver_data = &x_series_features,
> +	},
> +	{
> +		.ident = "Alienware m18 R2",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
> +		},
> +		.driver_data = &x_series_features,
> +	},
> +	{
> +		.ident = "Alienware x15 R1",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
> +		},
> +		.driver_data = &x_series_features,
> +	},
> +	{
> +		.ident = "Alienware x17 R2",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
> +		},
> +		.driver_data = &x_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G15 5510",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G15 5511",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G15 5515",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G3 3500",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G3 3590",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +	{
> +		.ident = "Dell Inc. G5 5500",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
> +		},
> +		.driver_data = &g_series_features,
> +	},
> +};
> +
> +enum WMAX_THERMAL_INFORMATION_OPERATIONS {
> +	WMAX_OPERATION_SYS_DESCRIPTION		= 0x02,
> +	WMAX_OPERATION_LIST_IDS			= 0x03,
> +	WMAX_OPERATION_CURRENT_PROFILE		= 0x0B,
> +};
> +
> +enum WMAX_THERMAL_CONTROL_OPERATIONS {
> +	WMAX_OPERATION_ACTIVATE_PROFILE		= 0x01,
> +};
> +
> +enum WMAX_GAME_SHIFT_STATUS_OPERATIONS {
> +	WMAX_OPERATION_TOGGLE_GAME_SHIFT	= 0x01,
> +	WMAX_OPERATION_GET_GAME_SHIFT_STATUS	= 0x02,
> +};
> +
> +enum WMAX_THERMAL_TABLES {
> +	WMAX_THERMAL_TABLE_BASIC		= 0x90,
> +	WMAX_THERMAL_TABLE_USTT			= 0xA0,
> +};
> +
> +enum wmax_thermal_mode {
> +	THERMAL_MODE_USTT_BALANCED,
> +	THERMAL_MODE_USTT_BALANCED_PERFORMANCE,
> +	THERMAL_MODE_USTT_COOL,
> +	THERMAL_MODE_USTT_QUIET,
> +	THERMAL_MODE_USTT_PERFORMANCE,
> +	THERMAL_MODE_USTT_LOW_POWER,
> +	THERMAL_MODE_BASIC_QUIET,
> +	THERMAL_MODE_BASIC_BALANCED,
> +	THERMAL_MODE_BASIC_BALANCED_PERFORMANCE,
> +	THERMAL_MODE_BASIC_PERFORMANCE,
> +	THERMAL_MODE_LAST,
> +};
> +
> +struct wmax_led_args {
> +	u32 led_mask;
> +	struct color_platform colors;
> +	u8 state;
> +} __packed;
> +
> +struct wmax_brightness_args {
> +	u32 led_mask;
> +	u32 percentage;
> +};
> +
> +struct wmax_basic_args {
> +	u8 arg;
> +};
> +
> +struct wmax_u32_args {
> +	u8 operation;
> +	u8 arg1;
> +	u8 arg2;
> +	u8 arg3;
> +};
> +
> +struct awcc_priv {
> +	struct wmi_device *wdev;
> +	struct platform_profile_handler pp_handler;
> +	enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> +};
> +
> +static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = {
> +	[THERMAL_MODE_USTT_BALANCED]			= PLATFORM_PROFILE_BALANCED,
> +	[THERMAL_MODE_USTT_BALANCED_PERFORMANCE]	= PLATFORM_PROFILE_BALANCED_PERFORMANCE,
> +	[THERMAL_MODE_USTT_COOL]			= PLATFORM_PROFILE_COOL,
> +	[THERMAL_MODE_USTT_QUIET]			= PLATFORM_PROFILE_QUIET,
> +	[THERMAL_MODE_USTT_PERFORMANCE]			= PLATFORM_PROFILE_PERFORMANCE,
> +	[THERMAL_MODE_USTT_LOW_POWER]			= PLATFORM_PROFILE_LOW_POWER,
> +	[THERMAL_MODE_BASIC_QUIET]			= PLATFORM_PROFILE_QUIET,
> +	[THERMAL_MODE_BASIC_BALANCED]			= PLATFORM_PROFILE_BALANCED,
> +	[THERMAL_MODE_BASIC_BALANCED_PERFORMANCE]	= PLATFORM_PROFILE_BALANCED_PERFORMANCE,
> +	[THERMAL_MODE_BASIC_PERFORMANCE]		= PLATFORM_PROFILE_PERFORMANCE,
> +};
> +
> +struct awcc_quirks *awcc;
> +
> +/*
> + *	The HDMI mux sysfs node indicates the status of the HDMI input mux.
> + *	It can toggle between standard system GPU output and HDMI input.
> + */
> +static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
> +			  char *buf)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args in_args = {
> +		.arg = 0,
> +	};
> +	u32 out_data;
> +	int ret;
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_CABLE,
> +				    &in_args, sizeof(in_args), &out_data);
> +
> +	if (!ret) {
> +		if (out_data == 0)
> +			return sysfs_emit(buf, "[unconnected] connected unknown\n");
> +		else if (out_data == 1)
> +			return sysfs_emit(buf, "unconnected [connected] unknown\n");
> +	}
> +
> +	pr_err("alienware-wmi: unknown HDMI cable status: %d\n", ret);
> +	return sysfs_emit(buf, "unconnected connected [unknown]\n");
> +}
> +
> +static ssize_t source_show(struct device *dev, struct device_attribute *attr,
> +			   char *buf)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args in_args = {
> +		.arg = 0,
> +	};
> +	u32 out_data;
> +	int ret;
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_STATUS,
> +				    &in_args, sizeof(in_args), &out_data);
> +
> +	if (!ret) {
> +		if (out_data == 1)
> +			return sysfs_emit(buf, "[input] gpu unknown\n");
> +		else if (out_data == 2)
> +			return sysfs_emit(buf, "input [gpu] unknown\n");
> +	}
> +
> +	pr_err("alienware-wmi: unknown HDMI source status: %u\n", ret);
> +	return sysfs_emit(buf, "input gpu [unknown]\n");
> +}
> +
> +static ssize_t source_store(struct device *dev, struct device_attribute *attr,
> +			    const char *buf, size_t count)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args args;
> +	int ret;
> +
> +	if (strcmp(buf, "gpu\n") == 0)
> +		args.arg = 1;
> +	else if (strcmp(buf, "input\n") == 0)
> +		args.arg = 2;
> +	else
> +		args.arg = 3;
> +	pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_SOURCE, &args,
> +				    sizeof(args), NULL);
> +
> +	if (ret < 0)
> +		pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", ret);
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR_RO(cable);
> +static DEVICE_ATTR_RW(source);
> +
> +static bool hdmi_group_visible(struct kobject *kobj)
> +{
> +	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> +	return priv->quirks->hdmi_mux;
> +}
> +DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
> +
> +static struct attribute *hdmi_attrs[] = {
> +	&dev_attr_cable.attr,
> +	&dev_attr_source.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group hdmi_attribute_group = {
> +	.name = "hdmi",
> +	.is_visible = SYSFS_GROUP_VISIBLE(hdmi),
> +	.attrs = hdmi_attrs,
> +};
> +
> +/*
> + * Alienware GFX amplifier support
> + * - Currently supports reading cable status
> + * - Leaving expansion room to possibly support dock/undock events later
> + */
> +static ssize_t status_show(struct device *dev, struct device_attribute *attr,
> +			   char *buf)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args in_args = {
> +		.arg = 0,
> +	};
> +	u32 out_data;
> +	int ret;
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_AMPLIFIER_CABLE,
> +				    &in_args, sizeof(in_args), &out_data);
> +
> +	if (!ret) {
> +		if (out_data == 0)
> +			return sysfs_emit(buf, "[unconnected] connected unknown\n");
> +		else if (out_data == 1)
> +			return sysfs_emit(buf, "unconnected [connected] unknown\n");
> +	}
> +
> +	pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret);
> +	return sysfs_emit(buf, "unconnected connected [unknown]\n");
> +}
> +
> +static DEVICE_ATTR_RO(status);
> +
> +static bool amplifier_group_visible(struct kobject *kobj)
> +{
> +	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> +	return priv->quirks->amplifier;
> +}
> +DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
> +
> +static struct attribute *amplifier_attrs[] = {
> +	&dev_attr_status.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group amplifier_attribute_group = {
> +	.name = "amplifier",
> +	.is_visible = SYSFS_GROUP_VISIBLE(amplifier),
> +	.attrs = amplifier_attrs,
> +};
> +
> +/*
> + * Deep Sleep Control support
> + * - Modifies BIOS setting for deep sleep control allowing extra wakeup events
> + */
> +static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
> +			      char *buf)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args in_args = {
> +		.arg = 0,
> +	};
> +	u32 out_data;
> +	int ret;
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_STATUS,
> +				    &in_args, sizeof(in_args), &out_data);
> +
> +	if (!ret) {
> +		if (out_data == 0)
> +			return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
> +		else if (out_data == 1)
> +			return sysfs_emit(buf, "disabled [s5] s5_s4\n");
> +		else if (out_data == 2)
> +			return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
> +	}
> +
> +	pr_err("alienware-wmi: unknown deep sleep status: %d\n", ret);
> +	return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
> +}
> +
> +static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
> +			       const char *buf, size_t count)
> +{
> +	struct alienfx_platdata *pdata = dev_get_platdata(dev);
> +	struct wmax_basic_args args;
> +	int ret;
> +
> +	if (strcmp(buf, "disabled\n") == 0)
> +		args.arg = 0;
> +	else if (strcmp(buf, "s5\n") == 0)
> +		args.arg = 1;
> +	else
> +		args.arg = 2;
> +	pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
> +
> +	ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_CONTROL,
> +				    &args, sizeof(args), NULL);
> +
> +	if (!ret)
> +		pr_err("alienware-wmi: deep sleep control failed: results: %u\n", ret);
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR_RW(deepsleep);
> +
> +static bool deepsleep_group_visible(struct kobject *kobj)
> +{
> +	struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> +	return priv->quirks->deepslp;
> +}
> +DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
> +
> +static struct attribute *deepsleep_attrs[] = {
> +	&dev_attr_deepsleep.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group deepsleep_attribute_group = {
> +	.name = "deepsleep",
> +	.is_visible = SYSFS_GROUP_VISIBLE(deepsleep),
> +	.attrs = deepsleep_attrs,
> +};
> +
> +static const struct attribute_group *wmax_alienfx_groups[] = {
> +	&hdmi_attribute_group,
> +	&amplifier_attribute_group,
> +	&deepsleep_attribute_group,
> +	NULL
> +};
> +
> +/*
> + * Thermal Profile control
> + *  - Provides thermal profile control through the Platform Profile API
> + */
> +static bool is_wmax_thermal_code(u32 code)
> +{
> +	if (code & WMAX_SENSOR_ID_MASK)
> +		return false;
> +
> +	if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST)
> +		return false;
> +
> +	if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC &&
> +	    (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET)
> +		return true;
> +
> +	if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT &&
> +	    (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER)
> +		return true;
> +
> +	return false;
> +}
> +
> +static int wmax_thermal_information(struct wmi_device *wdev, u8 operation,
> +				    u8 arg, u32 *out_data)
> +{
> +	struct wmax_u32_args in_args = {
> +		.operation = operation,
> +		.arg1 = arg,
> +		.arg2 = 0,
> +		.arg3 = 0,
> +	};
> +	int ret;
> +
> +	ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_INFORMATION,
> +				    &in_args, sizeof(in_args), out_data);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (*out_data == WMAX_FAILURE_CODE)
> +		return -EBADRQC;
> +
> +	return 0;
> +}
> +
> +static int wmax_thermal_control(struct wmi_device *wdev, u8 profile)
> +{
> +	struct wmax_u32_args in_args = {
> +		.operation = WMAX_OPERATION_ACTIVATE_PROFILE,
> +		.arg1 = profile,
> +		.arg2 = 0,
> +		.arg3 = 0,
> +	};
> +	u32 out_data;
> +	int ret;
> +
> +	ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_CONTROL,
> +				    &in_args, sizeof(in_args), &out_data);
> +	if (ret)
> +		return ret;
> +
> +	if (out_data == WMAX_FAILURE_CODE)
> +		return -EBADRQC;
> +
> +	return 0;
> +}
> +
> +static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation,
> +				  u32 *out_data)
> +{
> +	struct wmax_u32_args in_args = {
> +		.operation = operation,
> +		.arg1 = 0,
> +		.arg2 = 0,
> +		.arg3 = 0,
> +	};
> +	int ret;
> +
> +	ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS,
> +				    &in_args, sizeof(in_args), out_data);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (*out_data == WMAX_FAILURE_CODE)
> +		return -EOPNOTSUPP;
> +
> +	return 0;
> +}
> +
> +static int thermal_profile_get(struct platform_profile_handler *pprof,
> +			       enum platform_profile_option *profile)
> +{
> +	struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
> +	u32 out_data;
> +	int ret;
> +
> +	ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE,
> +				       0, &out_data);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (out_data == WMAX_THERMAL_MODE_GMODE) {
> +		*profile = PLATFORM_PROFILE_PERFORMANCE;
> +		return 0;
> +	}
> +
> +	if (!is_wmax_thermal_code(out_data))
> +		return -ENODATA;
> +
> +	out_data &= WMAX_THERMAL_MODE_MASK;
> +	*profile = wmax_mode_to_platform_profile[out_data];
> +
> +	return 0;
> +}
> +
> +static int thermal_profile_set(struct platform_profile_handler *pprof,
> +			       enum platform_profile_option profile)
> +{
> +	struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
> +
> +	if (awcc->gmode) {
> +		u32 gmode_status;
> +		int ret;
> +
> +		ret = wmax_game_shift_status(priv->wdev,
> +					     WMAX_OPERATION_GET_GAME_SHIFT_STATUS,
> +					     &gmode_status);
> +
> +		if (ret < 0)
> +			return ret;
> +
> +		if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) ||
> +		    (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) {
> +			ret = wmax_game_shift_status(priv->wdev,
> +						     WMAX_OPERATION_TOGGLE_GAME_SHIFT,
> +						     &gmode_status);
> +
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	return wmax_thermal_control(priv->wdev,
> +				    priv->supported_thermal_profiles[profile]);
> +}
> +
> +static int create_thermal_profile(struct wmi_device *wdev)
> +{
> +	struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
> +	enum platform_profile_option profile;
> +	enum wmax_thermal_mode mode;
> +	u8 sys_desc[4];
> +	u32 first_mode;
> +	u32 out_data;
> +	int ret;
> +
> +	ret = wmax_thermal_information(wdev, WMAX_OPERATION_SYS_DESCRIPTION,
> +				       0, (u32 *) &sys_desc);
> +	if (ret < 0)
> +		return ret;
> +
> +	first_mode = sys_desc[0] + sys_desc[1];
> +
> +	for (u32 i = 0; i < sys_desc[3]; i++) {
> +		ret = wmax_thermal_information(wdev, WMAX_OPERATION_LIST_IDS,
> +					       i + first_mode, &out_data);
> +
> +		if (ret == -EIO)
> +			return ret;
> +
> +		if (ret == -EBADRQC)
> +			break;
> +
> +		if (!is_wmax_thermal_code(out_data))
> +			continue;
> +
> +		mode = out_data & WMAX_THERMAL_MODE_MASK;
> +		profile = wmax_mode_to_platform_profile[mode];
> +		priv->supported_thermal_profiles[profile] = out_data;
> +
> +		set_bit(profile, priv->pp_handler.choices);
> +	}
> +
> +	if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> +		return -ENODEV;
> +
> +	if (awcc->gmode) {
> +		priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> +			WMAX_THERMAL_MODE_GMODE;
> +
> +		set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->pp_handler.choices);
> +	}
> +
> +	priv->pp_handler.profile_get = thermal_profile_get;
> +	priv->pp_handler.profile_set = thermal_profile_set;
> +	priv->pp_handler.name = "alienware-wmi";
> +	priv->pp_handler.dev = &wdev->dev;
> +
> +	return platform_profile_register(&priv->pp_handler);
> +}
> +
> +static int alienware_awcc_setup(struct wmi_device *wdev)
> +{
> +	struct awcc_priv *priv;
> +	int ret;
> +
> +	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(&wdev->dev, priv);
> +	priv->wdev = wdev;
> +
> +	ret = create_thermal_profile(wdev);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void alienware_awcc_exit(struct wmi_device *wdev)
> +{
> +	struct awcc_priv *priv;
> +
> +	priv = dev_get_drvdata(&wdev->dev);
> +
> +	platform_profile_remove(&priv->pp_handler);
> +}
> +
> +/*
> + * WMAX WMI driver
> + */
> +static int wmax_wmi_update_led(struct alienfx_priv *priv,
> +			       struct wmi_device *wdev, u8 location)
> +{
> +	struct wmax_led_args in_args = {
> +		.led_mask = 1 << location,
> +		.colors = priv->colors[location],
> +		.state = priv->lighting_control_state,
> +	};
> +
> +	return alienware_wmi_command(wdev, WMAX_METHOD_ZONE_CONTROL, &in_args,
> +				     sizeof(in_args), NULL);
> +}
> +
> +static int wmax_wmi_update_brightness(struct alienfx_priv *priv,
> +				      struct wmi_device *wdev, u8 brightness)
> +{
> +	struct wmax_brightness_args in_args = {
> +		.led_mask = 0xFF,
> +		.percentage = brightness,
> +	};
> +
> +	return alienware_wmi_command(wdev, WMAX_METHOD_BRIGHTNESS, &in_args,
> +				     sizeof(in_args), NULL);
> +}
> +
> +static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> +{
> +	struct alienfx_platdata pdata = {
> +		.wdev = wdev,
> +		.ops = {
> +			.upd_led = wmax_wmi_update_led,
> +			.upd_brightness = wmax_wmi_update_brightness,
> +		},
> +	};
> +	struct platform_device *pdev;
> +	int ret = 0;
> +
> +	if (awcc) {
> +		ret = alienware_awcc_setup(wdev);
> +	} else {
> +		ret = alienware_alienfx_setup(&pdata);
> +		if (ret < 0)
> +			return ret;
> +
> +		pdev = dev_get_drvdata(&wdev->dev);
> +		ret = device_add_groups(&pdev->dev, wmax_alienfx_groups);
> +	}
> +
> +	return ret;
> +}
> +
> +static void wmax_wmi_remove(struct wmi_device *wdev)
> +{
> +	if (awcc)
> +		alienware_awcc_exit(wdev);
> +	else
> +		alienware_alienfx_exit(wdev);
> +}
> +
> +static struct wmi_device_id alienware_wmax_device_id_table[] = {
> +	{ WMAX_CONTROL_GUID, NULL },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(wmi, alienware_wmax_device_id_table);
> +
> +static struct wmi_driver alienware_wmax_wmi_driver = {
> +	.driver = {
> +		.name = "alienware-wmi-wmax",
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +	},
> +	.id_table = alienware_wmax_device_id_table,
> +	.probe = wmax_wmi_probe,
> +	.remove = wmax_wmi_remove,
> +};
> +
> +int __init alienware_wmax_wmi_init(void)
> +{
> +	const struct dmi_system_id *id;
> +
> +	id = dmi_first_match(awcc_dmi_table);
> +	if (id)
> +		awcc = id->driver_data;
> +
> +	if (force_platform_profile)
> +		awcc = &x_series_features;
> +
> +	if (force_gmode)
> +		awcc = &g_series_features;
> +
> +	return wmi_driver_register(&alienware_wmax_wmi_driver);
> +}
> +
> +void __exit alienware_wmax_wmi_exit(void)
> +{
> +	wmi_driver_unregister(&alienware_wmax_wmi_driver);
> +}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ