* [PATCH v2 00/20] alienware-wmi driver rework
@ 2024-12-29 19:44 Kurt Borja
2024-12-29 19:44 ` [PATCH v2 01/20] alienware-wmi: Remove unnecessary check at module exit Kurt Borja
` (20 more replies)
0 siblings, 21 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Hi!
Happy holidays. :)
~ Kurt
---
v1 -> v2:
[2/20]
- Small correction in commit message
[5/20]
- Define the sysfs attributes without macros
[6/20]
- Reworded commit title
- Reorder variables in previous WMAX methods too
- Standarized sysfs method names in hdmi, amplifier and deepsleep
groups
- Dropped Armin's Reviewed-by tag because this patch changed a lot
[7/20]
- Return -ENOMEM in case priv allocation fails in alienfx_probe()
- Assign priv and platdata on variable declaration
- Drop intermediate *leds in alienfx_probe()
- Add quirk_entry to state container
- Use quirks from priv on hdmi_mux, amplifier, deepslp visibility
methods, to eventually be able to move these groups into
alienware-wmi-wmax.c
- Set PROBE_FORCE_SYNCHRONOUS to platform_driver, to avoid racing to
drvdata after using device_create_groups on [8/20]
[8/20]
- Create hdmi, amplifier, deepslp sysfs groups on wmax's probe
[9/20]
- Assign priv on variable declaration
- Directly return create thermal_profile() in alienware_awcc_setup()
[10/20]
- Refactored alienware_wmi_method following Armin's comments
- Fix legacy_wmi_update_led logic
[13/20]
- Split DMI table lower in the file
- Rename quirk_entry -> alienfx_quirks
- Rename awcc_features -> awcc_quirks
- Make hdmi_mux, amplifier and deepslp `bool`
[16/20]:
- Only add common resources on alienware.h
[17/20]
- Reworded commit message: now mentions some blocks were reordered
- Move #include <linux/dmi.h> where it belongs alphabetically
- Included hdmi, amplifier, deepslp groups in alienware-wmi-wmax.c
[18/20]
- static inline init functions in case drivers are not compiled
- Return errno in case drivers are not compiled
v1: https://lore.kernel.org/platform-driver-x86/20241221055917.10555-1-kuurtb@gmail.com/
Kurt Borja (20):
alienware-wmi: Remove unnecessary check at module exit
alienware-wmi: Move Lighting Control State
alienware-wmi: Modify parse_rgb() signature
alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation
alienware-wmi: Improve rgb-zones group creation
alienware_wmi: General cleanup of WMAX methods
alienware-wmi: Add a state container for LED control feature
alienware-wmi: Add WMI Drivers
alienware-wmi: Add a state container for thermal control methods
alienware-wmi: Refactor LED control methods
alienware-wmi: Refactor hdmi, amplifier, deepslp methods
alienware-wmi: Refactor thermal control methods
alienware-wmi: Split DMI table
MAINTAINERS: Update ALIENWARE WMI DRIVER entry
platform/x86: Rename alienware-wmi.c
platform/x86: Add alienware-wmi.h
platform-x86: Split the alienware-wmi driver
platform/x86: dell: Modify Makefile alignment
platform/x86: Update alienware-wmi config entries
alienware-wmi: Update header and module information
MAINTAINERS | 4 +-
drivers/platform/x86/dell/Kconfig | 30 +-
drivers/platform/x86/dell/Makefile | 45 +-
.../platform/x86/dell/alienware-wmi-base.c | 492 +++++++
.../platform/x86/dell/alienware-wmi-legacy.c | 98 ++
.../platform/x86/dell/alienware-wmi-wmax.c | 775 ++++++++++
drivers/platform/x86/dell/alienware-wmi.c | 1269 -----------------
drivers/platform/x86/dell/alienware-wmi.h | 101 ++
8 files changed, 1518 insertions(+), 1296 deletions(-)
create mode 100644 drivers/platform/x86/dell/alienware-wmi-base.c
create mode 100644 drivers/platform/x86/dell/alienware-wmi-legacy.c
create mode 100644 drivers/platform/x86/dell/alienware-wmi-wmax.c
delete mode 100644 drivers/platform/x86/dell/alienware-wmi.c
create mode 100644 drivers/platform/x86/dell/alienware-wmi.h
base-commit: 03f8e0e05510dad6377cd5ef029594d30e6c096d
--
2.47.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH v2 01/20] alienware-wmi: Remove unnecessary check at module exit
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 02/20] alienware-wmi: Move Lighting Control State Kurt Borja
` (19 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Module initialization fails if platform device fails to register so it's
always not NULL at exit.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index e95d22c7b60c..ed66720260ab 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -1257,13 +1257,11 @@ module_init(alienware_wmi_init);
static void __exit alienware_wmi_exit(void)
{
- if (platform_device) {
- alienware_zone_exit(platform_device);
- remove_hdmi(platform_device);
- remove_thermal_profile();
- platform_device_unregister(platform_device);
- platform_driver_unregister(&platform_driver);
- }
+ alienware_zone_exit(platform_device);
+ remove_hdmi(platform_device);
+ remove_thermal_profile();
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&platform_driver);
}
module_exit(alienware_wmi_exit);
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 02/20] alienware-wmi: Move Lighting Control State
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
2024-12-29 19:44 ` [PATCH v2 01/20] alienware-wmi: Remove unnecessary check at module exit Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 03/20] alienware-wmi: Modify parse_rgb() signature Kurt Borja
` (18 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Place Lighting Control State logic next to other attributes of the same
sysfs group.
While at it, rename:
store_control_state() -> lighting_control_state_store()
show_control_state() -> lighting_control_state_show()
Replace DEVICE_ATTR() with DEVICE_ATTR_RW() and do a general style
cleanup.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 74 ++++++++++++-----------
1 file changed, 39 insertions(+), 35 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index ed66720260ab..c5ad0f95c442 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -545,6 +545,45 @@ static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
return ret ? ret : count;
}
+/*
+ * Lighting control state device attribute (Global)
+ */
+static ssize_t lighting_control_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ if (lighting_control_state == LEGACY_BOOTING)
+ return sysfs_emit(buf, "[booting] running suspend\n");
+ else if (lighting_control_state == LEGACY_SUSPEND)
+ return sysfs_emit(buf, "booting running [suspend]\n");
+
+ return sysfs_emit(buf, "booting [running] suspend\n");
+}
+
+static ssize_t lighting_control_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u8 val;
+
+ if (strcmp(buf, "booting\n") == 0)
+ val = LEGACY_BOOTING;
+ else if (strcmp(buf, "suspend\n") == 0)
+ val = LEGACY_SUSPEND;
+ else if (interface == LEGACY)
+ val = LEGACY_RUNNING;
+ else
+ val = WMAX_RUNNING;
+
+ lighting_control_state = val;
+ pr_debug("alienware-wmi: updated control state to %d\n",
+ lighting_control_state);
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(lighting_control_state);
+
/*
* LED Brightness (Global)
*/
@@ -589,41 +628,6 @@ static struct led_classdev global_led = {
.name = "alienware::global_brightness",
};
-/*
- * Lighting control state device attribute (Global)
- */
-static ssize_t show_control_state(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (lighting_control_state == LEGACY_BOOTING)
- return sysfs_emit(buf, "[booting] running suspend\n");
- else if (lighting_control_state == LEGACY_SUSPEND)
- return sysfs_emit(buf, "booting running [suspend]\n");
- return sysfs_emit(buf, "booting [running] suspend\n");
-}
-
-static ssize_t store_control_state(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- long unsigned int val;
- if (strcmp(buf, "booting\n") == 0)
- val = LEGACY_BOOTING;
- else if (strcmp(buf, "suspend\n") == 0)
- val = LEGACY_SUSPEND;
- else if (interface == LEGACY)
- val = LEGACY_RUNNING;
- else
- val = WMAX_RUNNING;
- lighting_control_state = val;
- pr_debug("alienware-wmi: updated control state to %d\n",
- lighting_control_state);
- return count;
-}
-
-static DEVICE_ATTR(lighting_control_state, 0644, show_control_state,
- store_control_state);
-
static int alienware_zone_init(struct platform_device *dev)
{
u8 zone;
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 03/20] alienware-wmi: Modify parse_rgb() signature
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
2024-12-29 19:44 ` [PATCH v2 01/20] alienware-wmi: Remove unnecessary check at module exit Kurt Borja
2024-12-29 19:44 ` [PATCH v2 02/20] alienware-wmi: Move Lighting Control State Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 04/20] alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation Kurt Borja
` (17 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
parse_rgb() now takes struct color_platform instead of struct
platform_zone to support upcoming refactor.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index c5ad0f95c442..273ce9b10765 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -434,7 +434,7 @@ static u8 global_brightness;
/*
* Helpers used for zone control
*/
-static int parse_rgb(const char *buf, struct platform_zone *zone)
+static int parse_rgb(const char *buf, struct color_platform *colors)
{
long unsigned int rgb;
int ret;
@@ -454,7 +454,7 @@ static int parse_rgb(const char *buf, struct platform_zone *zone)
repackager.package = rgb & 0x0f0f0f0f;
pr_debug("alienware-wmi: r: %d g:%d b: %d\n",
repackager.cp.red, repackager.cp.green, repackager.cp.blue);
- zone->colors = repackager.cp;
+ *colors = repackager.cp;
return 0;
}
@@ -538,7 +538,7 @@ static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
pr_err("alienware-wmi: invalid target zone\n");
return 1;
}
- ret = parse_rgb(buf, target_zone);
+ ret = parse_rgb(buf, &target_zone->colors);
if (ret)
return ret;
ret = alienware_update_led(target_zone);
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 04/20] alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (2 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 03/20] alienware-wmi: Modify parse_rgb() signature Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 05/20] alienware-wmi: Improve rgb-zones " Kurt Borja
` (16 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Devices with hdmi_mux, amplifier or deepslp quirks create a sysfs group
for each available feature. To accomplish this, helper create/remove
functions were called on module init, but they had the following
problems:
- Create helpers called remove helpers on failure, which in turn tried
to remove the sysfs group that failed to be created
- If group creation failed mid way, previous successfully created groups
were not cleaned up
- Module exit only removed hdmi_mux group
To improve this, drop all helpers and let the platform driver manage these
sysfs groups, while controlling visibility with their respective quirks.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 114 ++++++++--------------
1 file changed, 38 insertions(+), 76 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 273ce9b10765..e010c94555e8 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -417,12 +417,6 @@ static struct platform_zone *zone_data;
static struct platform_profile_handler pp_handler;
static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
-static struct platform_driver platform_driver = {
- .driver = {
- .name = "alienware-wmi",
- }
-};
-
static struct attribute_group zone_attribute_group = {
.name = "rgb_zones",
};
@@ -804,6 +798,12 @@ static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL);
static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source,
toggle_hdmi_source);
+static bool hdmi_group_visible(struct kobject *kobj)
+{
+ return quirks->hdmi_mux;
+}
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
+
static struct attribute *hdmi_attrs[] = {
&dev_attr_cable.attr,
&dev_attr_source.attr,
@@ -812,25 +812,10 @@ static struct attribute *hdmi_attrs[] = {
static const struct attribute_group hdmi_attribute_group = {
.name = "hdmi",
+ .is_visible = SYSFS_GROUP_VISIBLE(hdmi),
.attrs = hdmi_attrs,
};
-static void remove_hdmi(struct platform_device *dev)
-{
- if (quirks->hdmi_mux > 0)
- sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
-}
-
-static int create_hdmi(struct platform_device *dev)
-{
- int ret;
-
- ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group);
- if (ret)
- remove_hdmi(dev);
- return ret;
-}
-
/*
* Alienware GFX amplifier support
* - Currently supports reading cable status
@@ -859,6 +844,12 @@ static ssize_t show_amplifier_status(struct device *dev,
static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL);
+static bool amplifier_group_visible(struct kobject *kobj)
+{
+ return quirks->amplifier;
+}
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
+
static struct attribute *amplifier_attrs[] = {
&dev_attr_status.attr,
NULL,
@@ -866,25 +857,10 @@ static struct attribute *amplifier_attrs[] = {
static const struct attribute_group amplifier_attribute_group = {
.name = "amplifier",
+ .is_visible = SYSFS_GROUP_VISIBLE(amplifier),
.attrs = amplifier_attrs,
};
-static void remove_amplifier(struct platform_device *dev)
-{
- if (quirks->amplifier > 0)
- sysfs_remove_group(&dev->dev.kobj, &lifier_attribute_group);
-}
-
-static int create_amplifier(struct platform_device *dev)
-{
- int ret;
-
- ret = sysfs_create_group(&dev->dev.kobj, &lifier_attribute_group);
- if (ret)
- remove_amplifier(dev);
- return ret;
-}
-
/*
* Deep Sleep Control support
* - Modifies BIOS setting for deep sleep control allowing extra wakeup events
@@ -937,6 +913,12 @@ static ssize_t toggle_deepsleep(struct device *dev,
static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep);
+static bool deepsleep_group_visible(struct kobject *kobj)
+{
+ return quirks->deepslp;
+}
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
+
static struct attribute *deepsleep_attrs[] = {
&dev_attr_deepsleep.attr,
NULL,
@@ -944,25 +926,10 @@ static struct attribute *deepsleep_attrs[] = {
static const struct attribute_group deepsleep_attribute_group = {
.name = "deepsleep",
+ .is_visible = SYSFS_GROUP_VISIBLE(deepsleep),
.attrs = deepsleep_attrs,
};
-static void remove_deepsleep(struct platform_device *dev)
-{
- if (quirks->deepslp > 0)
- sysfs_remove_group(&dev->dev.kobj, &deepsleep_attribute_group);
-}
-
-static int create_deepsleep(struct platform_device *dev)
-{
- int ret;
-
- ret = sysfs_create_group(&dev->dev.kobj, &deepsleep_attribute_group);
- if (ret)
- remove_deepsleep(dev);
- return ret;
-}
-
/*
* Thermal Profile control
* - Provides thermal profile control through the Platform Profile API
@@ -1172,6 +1139,23 @@ static void remove_thermal_profile(void)
platform_profile_remove(&pp_handler);
}
+/*
+ * Platform Driver
+ */
+static const struct attribute_group *alienfx_groups[] = {
+ &hdmi_attribute_group,
+ &lifier_attribute_group,
+ &deepsleep_attribute_group,
+ NULL
+};
+
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = "alienware-wmi",
+ .dev_groups = alienfx_groups,
+ },
+};
+
static int __init alienware_wmi_init(void)
{
int ret;
@@ -1211,24 +1195,6 @@ static int __init alienware_wmi_init(void)
if (ret)
goto fail_platform_device2;
- if (quirks->hdmi_mux > 0) {
- ret = create_hdmi(platform_device);
- if (ret)
- goto fail_prep_hdmi;
- }
-
- if (quirks->amplifier > 0) {
- ret = create_amplifier(platform_device);
- if (ret)
- goto fail_prep_amplifier;
- }
-
- if (quirks->deepslp > 0) {
- ret = create_deepsleep(platform_device);
- if (ret)
- goto fail_prep_deepsleep;
- }
-
if (quirks->thermal) {
ret = create_thermal_profile(platform_device);
if (ret)
@@ -1245,9 +1211,6 @@ static int __init alienware_wmi_init(void)
alienware_zone_exit(platform_device);
remove_thermal_profile();
fail_prep_thermal_profile:
-fail_prep_deepsleep:
-fail_prep_amplifier:
-fail_prep_hdmi:
platform_device_del(platform_device);
fail_platform_device2:
platform_device_put(platform_device);
@@ -1262,7 +1225,6 @@ module_init(alienware_wmi_init);
static void __exit alienware_wmi_exit(void)
{
alienware_zone_exit(platform_device);
- remove_hdmi(platform_device);
remove_thermal_profile();
platform_device_unregister(platform_device);
platform_driver_unregister(&platform_driver);
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 05/20] alienware-wmi: Improve rgb-zones group creation
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (3 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 04/20] alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 15:44 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods Kurt Borja
` (15 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Define zone_attrs statically and initialize zone_attribute_group with
platform driver's .dev_groups.
Drop match_zone() and instead pass a `location` argument to previous
show/store methods to access the correct `zone` LED state. On top of
that rename zone_set() -> zone_store() to be more consistent with sysfs
conventions.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 209 +++++++++++-----------
1 file changed, 102 insertions(+), 107 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index e010c94555e8..d97e5e15a8f2 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -376,12 +376,6 @@ struct color_platform {
u8 red;
} __packed;
-struct platform_zone {
- u8 location;
- struct device_attribute *attr;
- struct color_platform colors;
-};
-
struct wmax_brightness_args {
u32 led_mask;
u32 percentage;
@@ -411,16 +405,10 @@ struct wmax_u32_args {
};
static struct platform_device *platform_device;
-static struct device_attribute *zone_dev_attrs;
-static struct attribute **zone_attrs;
-static struct platform_zone *zone_data;
+static struct color_platform colors[4];
static struct platform_profile_handler pp_handler;
static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
-static struct attribute_group zone_attribute_group = {
- .name = "rgb_zones",
-};
-
static u8 interface;
static u8 lighting_control_state;
static u8 global_brightness;
@@ -452,24 +440,10 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
return 0;
}
-static struct platform_zone *match_zone(struct device_attribute *attr)
-{
- u8 zone;
-
- for (zone = 0; zone < quirks->num_zones; zone++) {
- if ((struct device_attribute *)zone_data[zone].attr == attr) {
- pr_debug("alienware-wmi: matched zone location: %d\n",
- zone_data[zone].location);
- return &zone_data[zone];
- }
- }
- return NULL;
-}
-
/*
* Individual RGB zone control
*/
-static int alienware_update_led(struct platform_zone *zone)
+static int alienware_update_led(u8 location)
{
int method_id;
acpi_status status;
@@ -478,8 +452,8 @@ static int alienware_update_led(struct platform_zone *zone)
struct legacy_led_args legacy_args;
struct wmax_led_args wmax_basic_args;
if (interface == WMAX) {
- wmax_basic_args.led_mask = 1 << zone->location;
- wmax_basic_args.colors = zone->colors;
+ wmax_basic_args.led_mask = 1 << location;
+ wmax_basic_args.colors = colors[location];
wmax_basic_args.state = lighting_control_state;
guid = WMAX_CONTROL_GUID;
method_id = WMAX_METHOD_ZONE_CONTROL;
@@ -487,7 +461,7 @@ static int alienware_update_led(struct platform_zone *zone)
input.length = sizeof(wmax_basic_args);
input.pointer = &wmax_basic_args;
} else {
- legacy_args.colors = zone->colors;
+ legacy_args.colors = colors[location];
legacy_args.brightness = global_brightness;
legacy_args.state = 0;
if (lighting_control_state == LEGACY_BOOTING ||
@@ -496,7 +470,7 @@ static int alienware_update_led(struct platform_zone *zone)
legacy_args.state = lighting_control_state;
} else
guid = LEGACY_CONTROL_GUID;
- method_id = zone->location + 1;
+ method_id = location + 1;
input.length = sizeof(legacy_args);
input.pointer = &legacy_args;
@@ -510,35 +484,84 @@ static int alienware_update_led(struct platform_zone *zone)
}
static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+ char *buf, u8 location)
{
- struct platform_zone *target_zone;
- target_zone = match_zone(attr);
- if (target_zone == NULL)
- return sprintf(buf, "red: -1, green: -1, blue: -1\n");
return sprintf(buf, "red: %d, green: %d, blue: %d\n",
- target_zone->colors.red,
- target_zone->colors.green, target_zone->colors.blue);
+ colors[location].red, colors[location].green,
+ colors[location].blue);
}
-static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count, u8 location)
{
- struct platform_zone *target_zone;
int ret;
- target_zone = match_zone(attr);
- if (target_zone == NULL) {
- pr_err("alienware-wmi: invalid target zone\n");
- return 1;
- }
- ret = parse_rgb(buf, &target_zone->colors);
+
+ ret = parse_rgb(buf, &colors[location]);
if (ret)
return ret;
- ret = alienware_update_led(target_zone);
+
+ ret = alienware_update_led(location);
+
return ret ? ret : count;
}
+static ssize_t zone00_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return zone_show(dev, attr, buf, 0);
+}
+
+static ssize_t zone00_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return zone_store(dev, attr, buf, count, 0);
+}
+
+DEVICE_ATTR_RW(zone00);
+
+static ssize_t zone01_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return zone_show(dev, attr, buf, 1);
+}
+
+static ssize_t zone01_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return zone_store(dev, attr, buf, count, 1);
+}
+
+DEVICE_ATTR_RW(zone01);
+
+static ssize_t zone02_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return zone_show(dev, attr, buf, 2);
+}
+
+static ssize_t zone02_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return zone_store(dev, attr, buf, count, 2);
+}
+
+DEVICE_ATTR_RW(zone02);
+
+static ssize_t zone03_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return zone_show(dev, attr, buf, 3);
+}
+
+static ssize_t zone03_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return zone_store(dev, attr, buf, count, 3);
+}
+
+DEVICE_ATTR_RW(zone03);
+
/*
* Lighting control state device attribute (Global)
*/
@@ -578,6 +601,33 @@ static ssize_t lighting_control_state_store(struct device *dev,
static DEVICE_ATTR_RW(lighting_control_state);
+static umode_t zone_attr_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ return n < quirks->num_zones + 1 ? 0644 : 0;
+}
+
+static bool zone_group_visible(struct kobject *kobj)
+{
+ return quirks->num_zones > 0;
+}
+DEFINE_SYSFS_GROUP_VISIBLE(zone);
+
+static struct attribute *zone_attrs[] = {
+ &dev_attr_lighting_control_state.attr,
+ &dev_attr_zone00.attr,
+ &dev_attr_zone01.attr,
+ &dev_attr_zone02.attr,
+ &dev_attr_zone03.attr,
+ NULL
+};
+
+static struct attribute_group zone_attribute_group = {
+ .name = "rgb_zones",
+ .is_visible = SYSFS_GROUP_VISIBLE(zone),
+ .attrs = zone_attrs,
+};
+
/*
* LED Brightness (Global)
*/
@@ -606,7 +656,7 @@ static void global_led_set(struct led_classdev *led_cdev,
if (interface == WMAX)
ret = wmax_brightness(brightness);
else
- ret = alienware_update_led(&zone_data[0]);
+ ret = alienware_update_led(0);
if (ret)
pr_err("LED brightness update failed\n");
}
@@ -624,9 +674,6 @@ static struct led_classdev global_led = {
static int alienware_zone_init(struct platform_device *dev)
{
- u8 zone;
- char *name;
-
if (interface == WMAX) {
lighting_control_state = WMAX_RUNNING;
} else if (interface == LEGACY) {
@@ -635,65 +682,12 @@ static int alienware_zone_init(struct platform_device *dev)
global_led.max_brightness = 0x0F;
global_brightness = global_led.max_brightness;
- /*
- * - zone_dev_attrs num_zones + 1 is for individual zones and then
- * null terminated
- * - zone_attrs num_zones + 2 is for all attrs in zone_dev_attrs +
- * the lighting control + null terminated
- * - zone_data num_zones is for the distinct zones
- */
- zone_dev_attrs =
- kcalloc(quirks->num_zones + 1, sizeof(struct device_attribute),
- GFP_KERNEL);
- if (!zone_dev_attrs)
- return -ENOMEM;
-
- zone_attrs =
- kcalloc(quirks->num_zones + 2, sizeof(struct attribute *),
- GFP_KERNEL);
- if (!zone_attrs)
- return -ENOMEM;
-
- zone_data =
- kcalloc(quirks->num_zones, sizeof(struct platform_zone),
- GFP_KERNEL);
- if (!zone_data)
- return -ENOMEM;
-
- for (zone = 0; zone < quirks->num_zones; zone++) {
- name = kasprintf(GFP_KERNEL, "zone%02hhX", zone);
- if (name == NULL)
- return 1;
- sysfs_attr_init(&zone_dev_attrs[zone].attr);
- zone_dev_attrs[zone].attr.name = name;
- zone_dev_attrs[zone].attr.mode = 0644;
- zone_dev_attrs[zone].show = zone_show;
- zone_dev_attrs[zone].store = zone_set;
- zone_data[zone].location = zone;
- zone_attrs[zone] = &zone_dev_attrs[zone].attr;
- zone_data[zone].attr = &zone_dev_attrs[zone];
- }
- zone_attrs[quirks->num_zones] = &dev_attr_lighting_control_state.attr;
- zone_attribute_group.attrs = zone_attrs;
-
- led_classdev_register(&dev->dev, &global_led);
-
- return sysfs_create_group(&dev->dev.kobj, &zone_attribute_group);
+ return led_classdev_register(&dev->dev, &global_led);
}
static void alienware_zone_exit(struct platform_device *dev)
{
- u8 zone;
-
- sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group);
led_classdev_unregister(&global_led);
- if (zone_dev_attrs) {
- for (zone = 0; zone < quirks->num_zones; zone++)
- kfree(zone_dev_attrs[zone].attr.name);
- }
- kfree(zone_dev_attrs);
- kfree(zone_data);
- kfree(zone_attrs);
}
static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
@@ -1143,6 +1137,7 @@ static void remove_thermal_profile(void)
* Platform Driver
*/
static const struct attribute_group *alienfx_groups[] = {
+ &zone_attribute_group,
&hdmi_attribute_group,
&lifier_attribute_group,
&deepsleep_attribute_group,
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (4 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 05/20] alienware-wmi: Improve rgb-zones " Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 15:50 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature Kurt Borja
` (14 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Reorder variable declaration from longest to shortest. Standarize
show/store method names of WMAX's sysfs groups.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 67 +++++++++++------------
1 file changed, 32 insertions(+), 35 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index d97e5e15a8f2..2c17160473a6 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -722,14 +722,14 @@ static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
* 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 show_hdmi_cable(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- acpi_status status;
- u32 out_data;
struct wmax_basic_args in_args = {
.arg = 0,
};
+ acpi_status status;
+ u32 out_data;
status =
alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_HDMI_CABLE, &out_data);
@@ -743,14 +743,14 @@ static ssize_t show_hdmi_cable(struct device *dev,
return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
-static ssize_t show_hdmi_source(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t source_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- acpi_status status;
- u32 out_data;
struct wmax_basic_args in_args = {
.arg = 0,
};
+ acpi_status status;
+ u32 out_data;
status =
alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_HDMI_STATUS, &out_data);
@@ -765,12 +765,11 @@ static ssize_t show_hdmi_source(struct device *dev,
return sysfs_emit(buf, "input gpu [unknown]\n");
}
-static ssize_t toggle_hdmi_source(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t source_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- acpi_status status;
struct wmax_basic_args args;
+ acpi_status status;
if (strcmp(buf, "gpu\n") == 0)
args.arg = 1;
else if (strcmp(buf, "input\n") == 0)
@@ -788,9 +787,8 @@ static ssize_t toggle_hdmi_source(struct device *dev,
return count;
}
-static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL);
-static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source,
- toggle_hdmi_source);
+static DEVICE_ATTR_RO(cable);
+static DEVICE_ATTR_RW(source);
static bool hdmi_group_visible(struct kobject *kobj)
{
@@ -815,14 +813,14 @@ static const struct attribute_group hdmi_attribute_group = {
* - Currently supports reading cable status
* - Leaving expansion room to possibly support dock/undock events later
*/
-static ssize_t show_amplifier_status(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- acpi_status status;
- u32 out_data;
struct wmax_basic_args in_args = {
.arg = 0,
};
+ acpi_status status;
+ u32 out_data;
status =
alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_AMPLIFIER_CABLE, &out_data);
@@ -836,7 +834,7 @@ static ssize_t show_amplifier_status(struct device *dev,
return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
-static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL);
+static DEVICE_ATTR_RO(status);
static bool amplifier_group_visible(struct kobject *kobj)
{
@@ -859,14 +857,14 @@ static const struct attribute_group amplifier_attribute_group = {
* Deep Sleep Control support
* - Modifies BIOS setting for deep sleep control allowing extra wakeup events
*/
-static ssize_t show_deepsleep_status(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- acpi_status status;
- u32 out_data;
struct wmax_basic_args in_args = {
.arg = 0,
};
+ acpi_status status;
+ u32 out_data;
status = alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_DEEP_SLEEP_STATUS, &out_data);
if (ACPI_SUCCESS(status)) {
@@ -881,12 +879,11 @@ static ssize_t show_deepsleep_status(struct device *dev,
return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
}
-static ssize_t toggle_deepsleep(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- acpi_status status;
struct wmax_basic_args args;
+ acpi_status status;
if (strcmp(buf, "disabled\n") == 0)
args.arg = 0;
@@ -905,7 +902,7 @@ static ssize_t toggle_deepsleep(struct device *dev,
return count;
}
-static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep);
+static DEVICE_ATTR_RW(deepsleep);
static bool deepsleep_group_visible(struct kobject *kobj)
{
@@ -953,13 +950,13 @@ static bool is_wmax_thermal_code(u32 code)
static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
{
- acpi_status status;
struct wmax_u32_args in_args = {
.operation = operation,
.arg1 = arg,
.arg2 = 0,
.arg3 = 0,
};
+ acpi_status status;
status = alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_THERMAL_INFORMATION,
@@ -976,13 +973,13 @@ static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
static int wmax_thermal_control(u8 profile)
{
- acpi_status status;
struct wmax_u32_args in_args = {
.operation = WMAX_OPERATION_ACTIVATE_PROFILE,
.arg1 = profile,
.arg2 = 0,
.arg3 = 0,
};
+ acpi_status status;
u32 out_data;
status = alienware_wmax_command(&in_args, sizeof(in_args),
@@ -1000,13 +997,13 @@ static int wmax_thermal_control(u8 profile)
static int wmax_game_shift_status(u8 operation, u32 *out_data)
{
- acpi_status status;
struct wmax_u32_args in_args = {
.operation = operation,
.arg1 = 0,
.arg2 = 0,
.arg3 = 0,
};
+ acpi_status status;
status = alienware_wmax_command(&in_args, sizeof(in_args),
WMAX_METHOD_GAME_SHIFT_STATUS,
@@ -1075,11 +1072,11 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
static int create_thermal_profile(struct platform_device *platform_device)
{
- u32 out_data;
+ enum platform_profile_option profile;
+ enum wmax_thermal_mode mode;
u8 sys_desc[4];
u32 first_mode;
- enum wmax_thermal_mode mode;
- enum platform_profile_option profile;
+ u32 out_data;
int ret;
ret = wmax_thermal_information(WMAX_OPERATION_SYS_DESCRIPTION,
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (5 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 16:07 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 08/20] alienware-wmi: Add WMI Drivers Kurt Borja
` (13 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Add a state container for the "alienware-wmi" platform device and
initialize it on the new alienfx_probe(). Migrate all LED control functions
to use this state container, as well as hdmi, amplifier, deepslp group
visibility methods, to support upcoming file split.
Additionally move the led_classdev registration to the platform driver
probe and make it device managed.
Drop alienware_zone_init() and alienware_zone_exit() because they are no
longer needed.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 135 +++++++++++++---------
1 file changed, 79 insertions(+), 56 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 2c17160473a6..88d4046ed45f 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -404,14 +404,20 @@ struct wmax_u32_args {
u8 arg3;
};
+struct alienfx_priv {
+ struct platform_device *pdev;
+ struct quirk_entry *quirks;
+ struct led_classdev global_led;
+ struct color_platform colors[4];
+ u8 global_brightness;
+ u8 lighting_control_state;
+};
+
static struct platform_device *platform_device;
-static struct color_platform colors[4];
static struct platform_profile_handler pp_handler;
static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
static u8 interface;
-static u8 lighting_control_state;
-static u8 global_brightness;
/*
* Helpers used for zone control
@@ -443,7 +449,7 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
/*
* Individual RGB zone control
*/
-static int alienware_update_led(u8 location)
+static int alienware_update_led(struct alienfx_priv *priv, u8 location)
{
int method_id;
acpi_status status;
@@ -453,21 +459,21 @@ static int alienware_update_led(u8 location)
struct wmax_led_args wmax_basic_args;
if (interface == WMAX) {
wmax_basic_args.led_mask = 1 << location;
- wmax_basic_args.colors = colors[location];
- wmax_basic_args.state = lighting_control_state;
+ wmax_basic_args.colors = priv->colors[location];
+ wmax_basic_args.state = priv->lighting_control_state;
guid = WMAX_CONTROL_GUID;
method_id = WMAX_METHOD_ZONE_CONTROL;
input.length = sizeof(wmax_basic_args);
input.pointer = &wmax_basic_args;
} else {
- legacy_args.colors = colors[location];
- legacy_args.brightness = global_brightness;
+ legacy_args.colors = priv->colors[location];
+ legacy_args.brightness = priv->global_brightness;
legacy_args.state = 0;
- if (lighting_control_state == LEGACY_BOOTING ||
- lighting_control_state == LEGACY_SUSPEND) {
+ if (priv->lighting_control_state == LEGACY_BOOTING ||
+ priv->lighting_control_state == LEGACY_SUSPEND) {
guid = LEGACY_POWER_CONTROL_GUID;
- legacy_args.state = lighting_control_state;
+ legacy_args.state = priv->lighting_control_state;
} else
guid = LEGACY_CONTROL_GUID;
method_id = location + 1;
@@ -486,22 +492,26 @@ static int alienware_update_led(u8 location)
static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
char *buf, u8 location)
{
+ struct alienfx_priv *priv = dev_get_drvdata(dev);
+ struct color_platform *colors = &priv->colors[location];
+
return sprintf(buf, "red: %d, green: %d, blue: %d\n",
- colors[location].red, colors[location].green,
- colors[location].blue);
+ colors->red, colors->green, colors->blue);
}
static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count, u8 location)
{
+ struct alienfx_priv *priv = dev_get_drvdata(dev);
+ struct color_platform *colors = &priv->colors[location];
int ret;
- ret = parse_rgb(buf, &colors[location]);
+ ret = parse_rgb(buf, colors);
if (ret)
return ret;
- ret = alienware_update_led(location);
+ ret = alienware_update_led(priv, location);
return ret ? ret : count;
}
@@ -569,9 +579,11 @@ static ssize_t lighting_control_state_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- if (lighting_control_state == LEGACY_BOOTING)
+ struct alienfx_priv *priv = dev_get_drvdata(dev);
+
+ if (priv->lighting_control_state == LEGACY_BOOTING)
return sysfs_emit(buf, "[booting] running suspend\n");
- else if (lighting_control_state == LEGACY_SUSPEND)
+ else if (priv->lighting_control_state == LEGACY_SUSPEND)
return sysfs_emit(buf, "booting running [suspend]\n");
return sysfs_emit(buf, "booting [running] suspend\n");
@@ -581,6 +593,7 @@ static ssize_t lighting_control_state_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct alienfx_priv *priv = dev_get_drvdata(dev);
u8 val;
if (strcmp(buf, "booting\n") == 0)
@@ -592,9 +605,9 @@ static ssize_t lighting_control_state_store(struct device *dev,
else
val = WMAX_RUNNING;
- lighting_control_state = val;
+ priv->lighting_control_state = val;
pr_debug("alienware-wmi: updated control state to %d\n",
- lighting_control_state);
+ priv->lighting_control_state);
return count;
}
@@ -651,43 +664,26 @@ static int wmax_brightness(int brightness)
static void global_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
+ struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
+ global_led);
int ret;
- global_brightness = brightness;
+
+ priv->global_brightness = brightness;
+
if (interface == WMAX)
ret = wmax_brightness(brightness);
else
- ret = alienware_update_led(0);
+ ret = alienware_update_led(priv, 0);
if (ret)
pr_err("LED brightness update failed\n");
}
static enum led_brightness global_led_get(struct led_classdev *led_cdev)
{
- return global_brightness;
-}
-
-static struct led_classdev global_led = {
- .brightness_set = global_led_set,
- .brightness_get = global_led_get,
- .name = "alienware::global_brightness",
-};
+ struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
+ global_led);
-static int alienware_zone_init(struct platform_device *dev)
-{
- if (interface == WMAX) {
- lighting_control_state = WMAX_RUNNING;
- } else if (interface == LEGACY) {
- lighting_control_state = LEGACY_RUNNING;
- }
- global_led.max_brightness = 0x0F;
- global_brightness = global_led.max_brightness;
-
- return led_classdev_register(&dev->dev, &global_led);
-}
-
-static void alienware_zone_exit(struct platform_device *dev)
-{
- led_classdev_unregister(&global_led);
+ return priv->global_brightness;
}
static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
@@ -792,7 +788,9 @@ static DEVICE_ATTR_RW(source);
static bool hdmi_group_visible(struct kobject *kobj)
{
- return quirks->hdmi_mux;
+ struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
+
+ return priv->quirks->hdmi_mux;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
@@ -838,7 +836,9 @@ static DEVICE_ATTR_RO(status);
static bool amplifier_group_visible(struct kobject *kobj)
{
- return quirks->amplifier;
+ struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
+
+ return priv->quirks->amplifier;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
@@ -906,7 +906,9 @@ static DEVICE_ATTR_RW(deepsleep);
static bool deepsleep_group_visible(struct kobject *kobj)
{
- return quirks->deepslp;
+ struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
+
+ return priv->quirks->deepslp;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
@@ -1133,6 +1135,33 @@ static void remove_thermal_profile(void)
/*
* Platform Driver
*/
+static int alienfx_probe(struct platform_device *pdev)
+{
+ struct alienfx_priv *priv;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+ priv->pdev = pdev;
+ priv->quirks = quirks;
+
+ if (interface == WMAX)
+ priv->lighting_control_state = WMAX_RUNNING;
+ else if (interface == LEGACY)
+ priv->lighting_control_state = LEGACY_RUNNING;
+
+ priv->global_led.name = "alienware::global_brightness";
+ priv->global_led.brightness_set = global_led_set;
+ priv->global_led.brightness_get = global_led_get;
+ priv->global_led.max_brightness = 0x0F;
+
+ priv->global_brightness = priv->global_led.max_brightness;
+
+ return devm_led_classdev_register(&pdev->dev, &priv->global_led);
+}
+
static const struct attribute_group *alienfx_groups[] = {
&zone_attribute_group,
&hdmi_attribute_group,
@@ -1145,7 +1174,9 @@ static struct platform_driver platform_driver = {
.driver = {
.name = "alienware-wmi",
.dev_groups = alienfx_groups,
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
+ .probe = alienfx_probe,
};
static int __init alienware_wmi_init(void)
@@ -1193,15 +1224,8 @@ static int __init alienware_wmi_init(void)
goto fail_prep_thermal_profile;
}
- ret = alienware_zone_init(platform_device);
- if (ret)
- goto fail_prep_zones;
-
return 0;
-fail_prep_zones:
- alienware_zone_exit(platform_device);
- remove_thermal_profile();
fail_prep_thermal_profile:
platform_device_del(platform_device);
fail_platform_device2:
@@ -1216,7 +1240,6 @@ module_init(alienware_wmi_init);
static void __exit alienware_wmi_exit(void)
{
- alienware_zone_exit(platform_device);
remove_thermal_profile();
platform_device_unregister(platform_device);
platform_driver_unregister(&platform_driver);
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 08/20] alienware-wmi: Add WMI Drivers
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (6 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 16:16 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods Kurt Borja
` (12 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Add WMI drivers for LEGACY and WMAX devices.
This involves moving platform driver and device registration to a helper
function, which is now called from the driver's preferred WMI device
driver probe. However this is only done if !quirks->thermal because
newer WMAX interface doesn't support any of the features exposed by this
device.
Only one driver is registered on module initialization to prevent
registering duplicate platform driver and device.
Additionally, create_thermal_profile() now takes wmi_device * instead of
platform_device *.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 195 +++++++++++++++++-----
1 file changed, 155 insertions(+), 40 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 88d4046ed45f..87a7997579c9 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -15,6 +15,7 @@
#include <linux/platform_profile.h>
#include <linux/dmi.h>
#include <linux/leds.h>
+#include <linux/wmi.h>
#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
@@ -39,8 +40,6 @@
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
-MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID);
static bool force_platform_profile;
module_param_unsafe(force_platform_profile, bool, 0);
@@ -413,7 +412,10 @@ struct alienfx_priv {
u8 lighting_control_state;
};
-static struct platform_device *platform_device;
+struct alienfx_platdata {
+ struct wmi_device *wdev;
+};
+
static struct platform_profile_handler pp_handler;
static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
@@ -1072,7 +1074,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
return wmax_thermal_control(supported_thermal_profiles[profile]);
}
-static int create_thermal_profile(struct platform_device *platform_device)
+static int create_thermal_profile(struct wmi_device *wdev)
{
enum platform_profile_option profile;
enum wmax_thermal_mode mode;
@@ -1121,7 +1123,7 @@ static int create_thermal_profile(struct platform_device *platform_device)
pp_handler.profile_get = thermal_profile_get;
pp_handler.profile_set = thermal_profile_set;
pp_handler.name = "alienware-wmi";
- pp_handler.dev = &platform_device->dev;
+ pp_handler.dev = &wdev->dev;
return platform_profile_register(&pp_handler);
}
@@ -1164,6 +1166,10 @@ static int alienfx_probe(struct platform_device *pdev)
static const struct attribute_group *alienfx_groups[] = {
&zone_attribute_group,
+ NULL
+};
+
+static const struct attribute_group *wmax_alienfx_groups[] = {
&hdmi_attribute_group,
&lifier_attribute_group,
&deepsleep_attribute_group,
@@ -1179,19 +1185,143 @@ static struct platform_driver platform_driver = {
.probe = alienfx_probe,
};
-static int __init alienware_wmi_init(void)
+static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
{
+ struct platform_device *pdev;
int ret;
- if (wmi_has_guid(LEGACY_CONTROL_GUID))
- interface = LEGACY;
- else if (wmi_has_guid(WMAX_CONTROL_GUID))
- interface = WMAX;
- else {
- pr_warn("alienware-wmi: No known WMI GUID found\n");
- return -ENODEV;
+ ret = platform_driver_register(&platform_driver);
+ if (ret < 0)
+ return ret;
+
+ pdev = platform_device_register_data(NULL, "alienware-wmi",
+ PLATFORM_DEVID_NONE, pdata,
+ sizeof(*pdata));
+
+ if (IS_ERR(pdev)) {
+ platform_driver_unregister(&platform_driver);
+ return PTR_ERR(pdev);
+ }
+
+ dev_set_drvdata(&pdata->wdev->dev, pdev);
+
+ return 0;
+}
+
+static void alienware_alienfx_exit(struct wmi_device *wdev)
+{
+ struct platform_device *pdev = dev_get_drvdata(&wdev->dev);
+
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&platform_driver);
+}
+
+/*
+ * Legacy WMI driver
+ */
+static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct alienfx_platdata pdata = {
+ .wdev = wdev,
+ };
+
+ 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,
+};
+
+static int __init alienware_legacy_wmi_init(void)
+{
+ return wmi_driver_register(&alienware_legacy_wmi_driver);
+}
+
+static void __exit alienware_legacy_wmi_exit(void)
+{
+ wmi_driver_unregister(&alienware_legacy_wmi_driver);
+}
+
+/*
+ * WMAX WMI driver
+ */
+static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+ struct alienfx_platdata pdata = {
+ .wdev = wdev,
+ };
+ struct platform_device *pdev;
+ int ret;
+
+ if (quirks->thermal) {
+ ret = create_thermal_profile(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 (quirks->thermal)
+ remove_thermal_profile();
+ 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,
+};
+
+static int __init alienware_wmax_wmi_init(void)
+{
+ return wmi_driver_register(&alienware_wmax_wmi_driver);
+}
+
+static void __exit alienware_wmax_wmi_exit(void)
+{
+ wmi_driver_unregister(&alienware_wmax_wmi_driver);
+}
+
+static int __init alienware_wmi_init(void)
+{
+ int ret;
+
dmi_check_system(alienware_quirks);
if (quirks == NULL)
quirks = &quirk_unknown;
@@ -1206,43 +1336,28 @@ static int __init alienware_wmi_init(void)
pr_warn("force_gmode requires platform profile support\n");
}
- ret = platform_driver_register(&platform_driver);
- if (ret)
- goto fail_platform_driver;
- platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE);
- if (!platform_device) {
- ret = -ENOMEM;
- goto fail_platform_device1;
+ if (wmi_has_guid(WMAX_CONTROL_GUID)) {
+ interface = WMAX;
+ ret = alienware_wmax_wmi_init();
+ } else {
+ interface = LEGACY;
+ ret = alienware_legacy_wmi_init();
}
- ret = platform_device_add(platform_device);
- if (ret)
- goto fail_platform_device2;
- if (quirks->thermal) {
- ret = create_thermal_profile(platform_device);
- if (ret)
- goto fail_prep_thermal_profile;
- }
+ if (ret < 0)
+ return ret;
return 0;
-
-fail_prep_thermal_profile:
- platform_device_del(platform_device);
-fail_platform_device2:
- platform_device_put(platform_device);
-fail_platform_device1:
- platform_driver_unregister(&platform_driver);
-fail_platform_driver:
- return ret;
}
module_init(alienware_wmi_init);
static void __exit alienware_wmi_exit(void)
{
- remove_thermal_profile();
- platform_device_unregister(platform_device);
- platform_driver_unregister(&platform_driver);
+ if (interface == WMAX)
+ alienware_wmax_wmi_exit();
+ else
+ alienware_legacy_wmi_exit();
}
module_exit(alienware_wmi_exit);
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (7 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 08/20] alienware-wmi: Add WMI Drivers Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 16:19 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 10/20] alienware-wmi: Refactor LED " Kurt Borja
` (11 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Refactor all thermal control methods to use the newly defined awcc_priv
state container instead of global variables.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 66 ++++++++++++++++-------
1 file changed, 47 insertions(+), 19 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 87a7997579c9..512384635c4c 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -403,6 +403,12 @@ struct wmax_u32_args {
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];
+};
+
struct alienfx_priv {
struct platform_device *pdev;
struct quirk_entry *quirks;
@@ -416,9 +422,6 @@ struct alienfx_platdata {
struct wmi_device *wdev;
};
-static struct platform_profile_handler pp_handler;
-static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
-
static u8 interface;
/*
@@ -1051,6 +1054,8 @@ static int thermal_profile_get(struct platform_profile_handler *pprof,
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 (quirks->gmode) {
u32 gmode_status;
int ret;
@@ -1071,11 +1076,12 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
}
}
- return wmax_thermal_control(supported_thermal_profiles[profile]);
+ return wmax_thermal_control(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];
@@ -1105,33 +1111,55 @@ static int create_thermal_profile(struct wmi_device *wdev)
mode = out_data & WMAX_THERMAL_MODE_MASK;
profile = wmax_mode_to_platform_profile[mode];
- supported_thermal_profiles[profile] = out_data;
+ priv->supported_thermal_profiles[profile] = out_data;
- set_bit(profile, pp_handler.choices);
+ set_bit(profile, priv->pp_handler.choices);
}
- if (bitmap_empty(pp_handler.choices, PLATFORM_PROFILE_LAST))
+ if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
return -ENODEV;
if (quirks->gmode) {
- supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
+ priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
WMAX_THERMAL_MODE_GMODE;
- set_bit(PLATFORM_PROFILE_PERFORMANCE, pp_handler.choices);
+ set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->pp_handler.choices);
}
- pp_handler.profile_get = thermal_profile_get;
- pp_handler.profile_set = thermal_profile_set;
- pp_handler.name = "alienware-wmi";
- pp_handler.dev = &wdev->dev;
+ 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(&pp_handler);
+ return platform_profile_register(&priv->pp_handler);
}
-static void remove_thermal_profile(void)
+static int alienware_awcc_setup(struct wmi_device *wdev)
{
- if (quirks->thermal)
- platform_profile_remove(&pp_handler);
+ 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);
}
/*
@@ -1271,7 +1299,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
int ret;
if (quirks->thermal) {
- ret = create_thermal_profile(wdev);
+ ret = alienware_awcc_setup(wdev);
} else {
ret = alienware_alienfx_setup(&pdata);
if (ret < 0)
@@ -1287,7 +1315,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
static void wmax_wmi_remove(struct wmi_device *wdev)
{
if (quirks->thermal)
- remove_thermal_profile();
+ alienware_awcc_exit(wdev);
else
alienware_alienfx_exit(wdev);
}
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 10/20] alienware-wmi: Refactor LED control methods
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (8 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2025-01-02 16:29 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 11/20] alienware-wmi: Refactor hdmi, amplifier, deepslp methods Kurt Borja
` (10 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Both WMI devices handled by this module specify a distinct interface for
LED control. Previously this module handled this by dynamically adapting
arguments passed to wmi_evaluate_method() based on the `interface`
global variable.
To avoid the use of global variables, and enable the migration to
non-deprecated WMI methods, let the WMI drivers define upd_led and
upd_brightness operations, which completely replace
alienware_update_led() and wmax_brightness().
Also define alienware_wmi_command(), which serves as a wrapper for
wmidev_evaluate_method(). This new method is very similar to
alienware_wmax_command() but is WMI device agnostic.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 164 ++++++++++++++--------
1 file changed, 102 insertions(+), 62 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 512384635c4c..494a3772065c 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -418,12 +418,42 @@ struct alienfx_priv {
u8 lighting_control_state;
};
+struct alienfx_ops {
+ int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
+ u8 location);
+ int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
+ u8 brightness);
+};
+
struct alienfx_platdata {
struct wmi_device *wdev;
+ struct alienfx_ops ops;
};
static u8 interface;
+static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
+ void *in_args, size_t in_size, u32 *out_data)
+{
+ struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_buffer in = {in_size, in_args};
+ union acpi_object *obj;
+ acpi_status ret;
+
+ ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL);
+ if (ACPI_FAILURE(ret))
+ return -EIO;
+
+ obj = out.pointer;
+
+ if (obj && obj->type == ACPI_TYPE_INTEGER) {
+ *out_data = (u32)obj->integer.value;
+ kfree(out.pointer);
+ }
+
+ return 0;
+}
+
/*
* Helpers used for zone control
*/
@@ -454,46 +484,6 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
/*
* Individual RGB zone control
*/
-static int alienware_update_led(struct alienfx_priv *priv, u8 location)
-{
- int method_id;
- acpi_status status;
- char *guid;
- struct acpi_buffer input;
- struct legacy_led_args legacy_args;
- struct wmax_led_args wmax_basic_args;
- if (interface == WMAX) {
- wmax_basic_args.led_mask = 1 << location;
- wmax_basic_args.colors = priv->colors[location];
- wmax_basic_args.state = priv->lighting_control_state;
- guid = WMAX_CONTROL_GUID;
- method_id = WMAX_METHOD_ZONE_CONTROL;
-
- input.length = sizeof(wmax_basic_args);
- input.pointer = &wmax_basic_args;
- } else {
- legacy_args.colors = priv->colors[location];
- legacy_args.brightness = priv->global_brightness;
- legacy_args.state = 0;
- if (priv->lighting_control_state == LEGACY_BOOTING ||
- priv->lighting_control_state == LEGACY_SUSPEND) {
- guid = LEGACY_POWER_CONTROL_GUID;
- legacy_args.state = priv->lighting_control_state;
- } else
- guid = LEGACY_CONTROL_GUID;
- method_id = location + 1;
-
- input.length = sizeof(legacy_args);
- input.pointer = &legacy_args;
- }
- pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id);
-
- status = wmi_evaluate_method(guid, 0, method_id, &input, NULL);
- if (ACPI_FAILURE(status))
- pr_err("alienware-wmi: zone set failure: %u\n", status);
- return ACPI_FAILURE(status);
-}
-
static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
char *buf, u8 location)
{
@@ -510,13 +500,14 @@ static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
{
struct alienfx_priv *priv = dev_get_drvdata(dev);
struct color_platform *colors = &priv->colors[location];
+ struct alienfx_platdata *pdata = dev_get_platdata(dev);
int ret;
ret = parse_rgb(buf, colors);
if (ret)
return ret;
- ret = alienware_update_led(priv, location);
+ ret = pdata->ops.upd_led(priv, pdata->wdev, location);
return ret ? ret : count;
}
@@ -649,36 +640,17 @@ static struct attribute_group zone_attribute_group = {
/*
* LED Brightness (Global)
*/
-static int wmax_brightness(int brightness)
-{
- acpi_status status;
- struct acpi_buffer input;
- struct wmax_brightness_args args = {
- .led_mask = 0xFF,
- .percentage = brightness,
- };
- input.length = sizeof(args);
- input.pointer = &args;
- status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
- WMAX_METHOD_BRIGHTNESS, &input, NULL);
- if (ACPI_FAILURE(status))
- pr_err("alienware-wmi: brightness set failure: %u\n", status);
- return ACPI_FAILURE(status);
-}
-
static void global_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
global_led);
+ struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev);
int ret;
priv->global_brightness = brightness;
- if (interface == WMAX)
- ret = wmax_brightness(brightness);
- else
- ret = alienware_update_led(priv, 0);
+ ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness);
if (ret)
pr_err("LED brightness update failed\n");
}
@@ -1247,10 +1219,49 @@ static void alienware_alienfx_exit(struct wmi_device *wdev)
/*
* 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);
@@ -1290,10 +1301,39 @@ static void __exit alienware_legacy_wmi_exit(void)
/*
* 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;
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 11/20] alienware-wmi: Refactor hdmi, amplifier, deepslp methods
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (9 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 10/20] alienware-wmi: Refactor LED " Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 12/20] alienware-wmi: Refactor thermal control methods Kurt Borja
` (9 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Refactor show/store methods for hdmi, amplifier, deepslp sysfs groups to
use alienware_wmi_command() instead of alienware_wmax_command() which
uses deprecated WMI methods.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 85 +++++++++++++----------
1 file changed, 50 insertions(+), 35 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index 494a3772065c..ea276d32cf14 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -698,51 +698,58 @@ static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
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,
};
- acpi_status status;
u32 out_data;
- status =
- alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_HDMI_CABLE, &out_data);
- if (ACPI_SUCCESS(status)) {
+ 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", status);
+
+ 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,
};
- acpi_status status;
u32 out_data;
- status =
- alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_HDMI_STATUS, &out_data);
+ int ret;
- if (ACPI_SUCCESS(status)) {
+ 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", status);
+
+ 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;
- acpi_status status;
+ int ret;
+
if (strcmp(buf, "gpu\n") == 0)
args.arg = 1;
else if (strcmp(buf, "input\n") == 0)
@@ -751,12 +758,12 @@ static ssize_t source_store(struct device *dev, struct device_attribute *attr,
args.arg = 3;
pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
- status = alienware_wmax_command(&args, sizeof(args),
- WMAX_METHOD_HDMI_SOURCE, NULL);
+ 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);
- if (ACPI_FAILURE(status))
- pr_err("alienware-wmi: HDMI toggle failed: results: %u\n",
- status);
return count;
}
@@ -791,21 +798,24 @@ static const struct attribute_group hdmi_attribute_group = {
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,
};
- acpi_status status;
u32 out_data;
- status =
- alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_AMPLIFIER_CABLE, &out_data);
- if (ACPI_SUCCESS(status)) {
+ 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", status);
+
+ pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret);
return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
@@ -837,14 +847,17 @@ static const struct attribute_group amplifier_attribute_group = {
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,
};
- acpi_status status;
u32 out_data;
- status = alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_DEEP_SLEEP_STATUS, &out_data);
- if (ACPI_SUCCESS(status)) {
+ 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)
@@ -852,15 +865,17 @@ static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
else if (out_data == 2)
return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
}
- pr_err("alienware-wmi: unknown deep sleep status: %d\n", status);
+
+ 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;
- acpi_status status;
+ int ret;
if (strcmp(buf, "disabled\n") == 0)
args.arg = 0;
@@ -870,12 +885,12 @@ static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr
args.arg = 2;
pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
- status = alienware_wmax_command(&args, sizeof(args),
- WMAX_METHOD_DEEP_SLEEP_CONTROL, NULL);
+ 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);
- if (ACPI_FAILURE(status))
- pr_err("alienware-wmi: deep sleep control failed: results: %u\n",
- status);
return count;
}
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 12/20] alienware-wmi: Refactor thermal control methods
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (10 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 11/20] alienware-wmi: Refactor hdmi, amplifier, deepslp methods Kurt Borja
@ 2024-12-29 19:44 ` Kurt Borja
2024-12-29 19:45 ` [PATCH v2 13/20] alienware-wmi: Split DMI table Kurt Borja
` (8 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:44 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Refactor thermal control methods to use alienware_wmi_command() instead
of alienware_wmax_command().
Drop alienware_wmax_command() as there is no more users left.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 98 ++++++++---------------
1 file changed, 32 insertions(+), 66 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index ea276d32cf14..f80e7d488b9d 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -663,34 +663,6 @@ static enum led_brightness global_led_get(struct led_classdev *led_cdev)
return priv->global_brightness;
}
-static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
- u32 command, u32 *out_data)
-{
- acpi_status status;
- union acpi_object *obj;
- struct acpi_buffer input;
- struct acpi_buffer output;
-
- input.length = in_size;
- input.pointer = in_args;
- if (out_data) {
- output.length = ACPI_ALLOCATE_BUFFER;
- output.pointer = NULL;
- status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
- command, &input, &output);
- if (ACPI_SUCCESS(status)) {
- obj = (union acpi_object *)output.pointer;
- if (obj && obj->type == ACPI_TYPE_INTEGER)
- *out_data = (u32)obj->integer.value;
- }
- kfree(output.pointer);
- } else {
- status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
- command, &input, NULL);
- }
- return status;
-}
-
/*
* The HDMI mux sysfs node indicates the status of the HDMI input mux.
* It can toggle between standard system GPU output and HDMI input.
@@ -942,7 +914,8 @@ static bool is_wmax_thermal_code(u32 code)
return false;
}
-static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
+static int wmax_thermal_information(struct wmi_device *wdev, u8 operation,
+ u8 arg, u32 *out_data)
{
struct wmax_u32_args in_args = {
.operation = operation,
@@ -950,14 +923,12 @@ static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
.arg2 = 0,
.arg3 = 0,
};
- acpi_status status;
-
- status = alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_THERMAL_INFORMATION,
- out_data);
+ int ret;
- if (ACPI_FAILURE(status))
- return -EIO;
+ 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;
@@ -965,7 +936,7 @@ static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
return 0;
}
-static int wmax_thermal_control(u8 profile)
+static int wmax_thermal_control(struct wmi_device *wdev, u8 profile)
{
struct wmax_u32_args in_args = {
.operation = WMAX_OPERATION_ACTIVATE_PROFILE,
@@ -973,15 +944,13 @@ static int wmax_thermal_control(u8 profile)
.arg2 = 0,
.arg3 = 0,
};
- acpi_status status;
u32 out_data;
+ int ret;
- status = alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_THERMAL_CONTROL,
- &out_data);
-
- if (ACPI_FAILURE(status))
- return -EIO;
+ 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;
@@ -989,7 +958,8 @@ static int wmax_thermal_control(u8 profile)
return 0;
}
-static int wmax_game_shift_status(u8 operation, u32 *out_data)
+static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation,
+ u32 *out_data)
{
struct wmax_u32_args in_args = {
.operation = operation,
@@ -997,14 +967,13 @@ static int wmax_game_shift_status(u8 operation, u32 *out_data)
.arg2 = 0,
.arg3 = 0,
};
- acpi_status status;
+ int ret;
- status = alienware_wmax_command(&in_args, sizeof(in_args),
- WMAX_METHOD_GAME_SHIFT_STATUS,
- out_data);
+ ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS,
+ &in_args, sizeof(in_args), out_data);
- if (ACPI_FAILURE(status))
- return -EIO;
+ if (ret < 0)
+ return ret;
if (*out_data == WMAX_FAILURE_CODE)
return -EOPNOTSUPP;
@@ -1015,10 +984,11 @@ static int wmax_game_shift_status(u8 operation, u32 *out_data)
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(WMAX_OPERATION_CURRENT_PROFILE,
+ ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE,
0, &out_data);
if (ret < 0)
@@ -1047,7 +1017,8 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
u32 gmode_status;
int ret;
- ret = wmax_game_shift_status(WMAX_OPERATION_GET_GAME_SHIFT_STATUS,
+ ret = wmax_game_shift_status(priv->wdev,
+ WMAX_OPERATION_GET_GAME_SHIFT_STATUS,
&gmode_status);
if (ret < 0)
@@ -1055,7 +1026,8 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) ||
(profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) {
- ret = wmax_game_shift_status(WMAX_OPERATION_TOGGLE_GAME_SHIFT,
+ ret = wmax_game_shift_status(priv->wdev,
+ WMAX_OPERATION_TOGGLE_GAME_SHIFT,
&gmode_status);
if (ret < 0)
@@ -1063,7 +1035,8 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
}
}
- return wmax_thermal_control(priv->supported_thermal_profiles[profile]);
+ return wmax_thermal_control(priv->wdev,
+ priv->supported_thermal_profiles[profile]);
}
static int create_thermal_profile(struct wmi_device *wdev)
@@ -1076,7 +1049,7 @@ static int create_thermal_profile(struct wmi_device *wdev)
u32 out_data;
int ret;
- ret = wmax_thermal_information(WMAX_OPERATION_SYS_DESCRIPTION,
+ ret = wmax_thermal_information(wdev, WMAX_OPERATION_SYS_DESCRIPTION,
0, (u32 *) &sys_desc);
if (ret < 0)
return ret;
@@ -1084,7 +1057,7 @@ static int create_thermal_profile(struct wmi_device *wdev)
first_mode = sys_desc[0] + sys_desc[1];
for (u32 i = 0; i < sys_desc[3]; i++) {
- ret = wmax_thermal_information(WMAX_OPERATION_LIST_IDS,
+ ret = wmax_thermal_information(wdev, WMAX_OPERATION_LIST_IDS,
i + first_mode, &out_data);
if (ret == -EIO)
@@ -1124,7 +1097,6 @@ static int create_thermal_profile(struct wmi_device *wdev)
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)
@@ -1133,18 +1105,12 @@ static int alienware_awcc_setup(struct wmi_device *wdev)
dev_set_drvdata(&wdev->dev, priv);
priv->wdev = wdev;
- ret = create_thermal_profile(wdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return create_thermal_profile(wdev);
}
static void alienware_awcc_exit(struct wmi_device *wdev)
{
- struct awcc_priv *priv;
-
- priv = dev_get_drvdata(&wdev->dev);
+ struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
platform_profile_remove(&priv->pp_handler);
}
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 13/20] alienware-wmi: Split DMI table
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (11 preceding siblings ...)
2024-12-29 19:44 ` [PATCH v2 12/20] alienware-wmi: Refactor thermal control methods Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2025-01-02 16:36 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 14/20] MAINTAINERS: Update ALIENWARE WMI DRIVER entry Kurt Borja
` (7 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Split thermal features into a new DMI table to support upcoming file
split. While at it rename quirk_entry -> alienfx_features and change
hdmi_mux, amplifier and deepslp types to bool, because they are already
being implicitly used as bools.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi.c | 319 ++++++++++------------
1 file changed, 147 insertions(+), 172 deletions(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
index f80e7d488b9d..b9daf22efdbe 100644
--- a/drivers/platform/x86/dell/alienware-wmi.c
+++ b/drivers/platform/x86/dell/alienware-wmi.c
@@ -113,97 +113,63 @@ static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_
[THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
};
-struct quirk_entry {
+struct alienfx_quirks {
u8 num_zones;
- u8 hdmi_mux;
- u8 amplifier;
- u8 deepslp;
- bool thermal;
- bool gmode;
+ bool hdmi_mux;
+ bool amplifier;
+ bool deepslp;
};
-static struct quirk_entry *quirks;
+static struct alienfx_quirks *quirks;
-static struct quirk_entry quirk_inspiron5675 = {
+static struct alienfx_quirks quirk_inspiron5675 = {
.num_zones = 2,
- .hdmi_mux = 0,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = false,
- .gmode = false,
+ .hdmi_mux = false,
+ .amplifier = false,
+ .deepslp = false,
};
-static struct quirk_entry quirk_unknown = {
+static struct alienfx_quirks quirk_unknown = {
.num_zones = 2,
- .hdmi_mux = 0,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = false,
- .gmode = false,
+ .hdmi_mux = false,
+ .amplifier = false,
+ .deepslp = false,
};
-static struct quirk_entry quirk_x51_r1_r2 = {
+static struct alienfx_quirks quirk_x51_r1_r2 = {
.num_zones = 3,
- .hdmi_mux = 0,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = false,
- .gmode = false,
+ .hdmi_mux = false,
+ .amplifier = false,
+ .deepslp = false,
};
-static struct quirk_entry quirk_x51_r3 = {
+static struct alienfx_quirks quirk_x51_r3 = {
.num_zones = 4,
- .hdmi_mux = 0,
- .amplifier = 1,
- .deepslp = 0,
- .thermal = false,
- .gmode = false,
-};
-
-static struct quirk_entry quirk_asm100 = {
- .num_zones = 2,
- .hdmi_mux = 1,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = false,
- .gmode = false,
-};
-
-static struct quirk_entry quirk_asm200 = {
- .num_zones = 2,
- .hdmi_mux = 1,
- .amplifier = 0,
- .deepslp = 1,
- .thermal = false,
- .gmode = false,
+ .hdmi_mux = false,
+ .amplifier = true,
+ .deepslp = false,
};
-static struct quirk_entry quirk_asm201 = {
+static struct alienfx_quirks quirk_asm100 = {
.num_zones = 2,
- .hdmi_mux = 1,
- .amplifier = 1,
- .deepslp = 1,
- .thermal = false,
- .gmode = false,
+ .hdmi_mux = true,
+ .amplifier = false,
+ .deepslp = false,
};
-static struct quirk_entry quirk_g_series = {
+static struct alienfx_quirks quirk_asm200 = {
.num_zones = 2,
- .hdmi_mux = 0,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = true,
- .gmode = true,
+ .hdmi_mux = true,
+ .amplifier = false,
+ .deepslp = true,
};
-static struct quirk_entry quirk_x_series = {
+static struct alienfx_quirks quirk_asm201 = {
.num_zones = 2,
- .hdmi_mux = 0,
- .amplifier = 0,
- .deepslp = 0,
- .thermal = true,
- .gmode = false,
+ .hdmi_mux = true,
+ .amplifier = true,
+ .deepslp = true,
};
static int __init dmi_matched(const struct dmi_system_id *dmi)
@@ -240,42 +206,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
},
.driver_data = &quirk_asm201,
},
- {
- .callback = dmi_matched,
- .ident = "Alienware m17 R5",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
- },
- .driver_data = &quirk_x_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Alienware m18 R2",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
- },
- .driver_data = &quirk_x_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Alienware x15 R1",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
- },
- .driver_data = &quirk_x_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Alienware x17 R2",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
- },
- .driver_data = &quirk_x_series,
- },
{
.callback = dmi_matched,
.ident = "Alienware X51 R1",
@@ -303,60 +233,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
},
.driver_data = &quirk_x51_r3,
},
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G15 5510",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
- },
- .driver_data = &quirk_g_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G15 5511",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
- },
- .driver_data = &quirk_g_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G15 5515",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
- },
- .driver_data = &quirk_g_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G3 3500",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
- },
- .driver_data = &quirk_g_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G3 3590",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
- },
- .driver_data = &quirk_g_series,
- },
- {
- .callback = dmi_matched,
- .ident = "Dell Inc. G5 5500",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
- },
- .driver_data = &quirk_g_series,
- },
{
.callback = dmi_matched,
.ident = "Dell Inc. Inspiron 5675",
@@ -411,7 +287,7 @@ struct awcc_priv {
struct alienfx_priv {
struct platform_device *pdev;
- struct quirk_entry *quirks;
+ struct alienfx_quirks *quirks;
struct led_classdev global_led;
struct color_platform colors[4];
u8 global_brightness;
@@ -432,6 +308,103 @@ struct alienfx_platdata {
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;
+
static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
void *in_args, size_t in_size, u32 *out_data)
{
@@ -1013,7 +986,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
{
struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
- if (quirks->gmode) {
+ if (awcc->gmode) {
u32 gmode_status;
int ret;
@@ -1079,7 +1052,7 @@ static int create_thermal_profile(struct wmi_device *wdev)
if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
return -ENODEV;
- if (quirks->gmode) {
+ if (awcc->gmode) {
priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
WMAX_THERMAL_MODE_GMODE;
@@ -1319,7 +1292,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
struct platform_device *pdev;
int ret;
- if (quirks->thermal) {
+ if (awcc) {
ret = alienware_awcc_setup(wdev);
} else {
ret = alienware_alienfx_setup(&pdata);
@@ -1335,7 +1308,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
static void wmax_wmi_remove(struct wmi_device *wdev)
{
- if (quirks->thermal)
+ if (awcc)
alienware_awcc_exit(wdev);
else
alienware_alienfx_exit(wdev);
@@ -1359,6 +1332,18 @@ static struct wmi_driver alienware_wmax_wmi_driver = {
static 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);
}
@@ -1375,16 +1360,6 @@ static int __init alienware_wmi_init(void)
if (quirks == NULL)
quirks = &quirk_unknown;
- if (force_platform_profile)
- quirks->thermal = true;
-
- if (force_gmode) {
- if (quirks->thermal)
- quirks->gmode = true;
- else
- pr_warn("force_gmode requires platform profile support\n");
- }
-
if (wmi_has_guid(WMAX_CONTROL_GUID)) {
interface = WMAX;
ret = alienware_wmax_wmi_init();
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 14/20] MAINTAINERS: Update ALIENWARE WMI DRIVER entry
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (12 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 13/20] alienware-wmi: Split DMI table Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2024-12-29 19:45 ` [PATCH v2 15/20] platform/x86: Rename alienware-wmi.c Kurt Borja
` (6 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Dell has been inactive in its maintainership role of this driver since
around 2021. Due to this, add myself as a maintainer and update path
to support upcoming changes.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
MAINTAINERS | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3809931b9240..596c6a46478c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -784,10 +784,12 @@ F: Documentation/admin-guide/perf/alibaba_pmu.rst
F: drivers/perf/alibaba_uncore_drw_pmu.c
ALIENWARE WMI DRIVER
+M: Kurt Borja <kuurtb@gmail.com>
+L: platform-driver-x86@vger.kernel.org
L: Dell.Client.Kernel@dell.com
S: Maintained
F: Documentation/wmi/devices/alienware-wmi.rst
-F: drivers/platform/x86/dell/alienware-wmi.c
+F: drivers/platform/x86/dell/alienware-wmi*
ALLEGRO DVT VIDEO IP CORE DRIVER
M: Michael Tretter <m.tretter@pengutronix.de>
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 15/20] platform/x86: Rename alienware-wmi.c
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (13 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 14/20] MAINTAINERS: Update ALIENWARE WMI DRIVER entry Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2024-12-29 19:45 ` [PATCH v2 16/20] platform/x86: Add alienware-wmi.h Kurt Borja
` (5 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Rename alienware-wmi to support upcoming split.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/Makefile | 1 +
.../platform/x86/dell/{alienware-wmi.c => alienware-wmi-base.c} | 0
2 files changed, 1 insertion(+)
rename drivers/platform/x86/dell/{alienware-wmi.c => alienware-wmi-base.c} (100%)
diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
index bb3cbd470a46..f8aec8502c2f 100644
--- a/drivers/platform/x86/dell/Makefile
+++ b/drivers/platform/x86/dell/Makefile
@@ -5,6 +5,7 @@
#
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
+alienware-wmi-objs := alienware-wmi-base.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.c b/drivers/platform/x86/dell/alienware-wmi-base.c
similarity index 100%
rename from drivers/platform/x86/dell/alienware-wmi.c
rename to drivers/platform/x86/dell/alienware-wmi-base.c
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 16/20] platform/x86: Add alienware-wmi.h
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (14 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 15/20] platform/x86: Rename alienware-wmi.c Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2025-01-02 16:43 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver Kurt Borja
` (4 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Add a header file for alienware-wmi with shared resources to support the
upcoming file split.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
.../platform/x86/dell/alienware-wmi-base.c | 68 +++-------------
drivers/platform/x86/dell/alienware-wmi.h | 78 +++++++++++++++++++
2 files changed, 87 insertions(+), 59 deletions(-)
create mode 100644 drivers/platform/x86/dell/alienware-wmi.h
diff --git a/drivers/platform/x86/dell/alienware-wmi-base.c b/drivers/platform/x86/dell/alienware-wmi-base.c
index b9daf22efdbe..a268193ad2a1 100644
--- a/drivers/platform/x86/dell/alienware-wmi-base.c
+++ b/drivers/platform/x86/dell/alienware-wmi-base.c
@@ -16,10 +16,7 @@
#include <linux/dmi.h>
#include <linux/leds.h>
#include <linux/wmi.h>
-
-#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
-#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
-#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
+#include "alienware-wmi.h"
#define WMAX_METHOD_HDMI_SOURCE 0x1
#define WMAX_METHOD_HDMI_STATUS 0x2
@@ -54,18 +51,6 @@ enum INTERFACE_FLAGS {
WMAX,
};
-enum LEGACY_CONTROL_STATES {
- LEGACY_RUNNING = 1,
- LEGACY_BOOTING = 0,
- LEGACY_SUSPEND = 3,
-};
-
-enum WMAX_CONTROL_STATES {
- WMAX_RUNNING = 0xFF,
- WMAX_BOOTING = 0,
- WMAX_SUSPEND = 3,
-};
-
enum WMAX_THERMAL_INFORMATION_OPERATIONS {
WMAX_OPERATION_SYS_DESCRIPTION = 0x02,
WMAX_OPERATION_LIST_IDS = 0x03,
@@ -113,16 +98,8 @@ static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_
[THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
};
-struct alienfx_quirks {
- u8 num_zones;
- bool hdmi_mux;
- bool amplifier;
- bool deepslp;
-};
-
static struct alienfx_quirks *quirks;
-
static struct alienfx_quirks quirk_inspiron5675 = {
.num_zones = 2,
.hdmi_mux = false,
@@ -245,12 +222,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
{}
};
-struct color_platform {
- u8 blue;
- u8 green;
- u8 red;
-} __packed;
-
struct wmax_brightness_args {
u32 led_mask;
u32 percentage;
@@ -285,27 +256,6 @@ struct awcc_priv {
enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
};
-struct alienfx_priv {
- struct platform_device *pdev;
- struct alienfx_quirks *quirks;
- struct led_classdev global_led;
- struct color_platform colors[4];
- u8 global_brightness;
- u8 lighting_control_state;
-};
-
-struct alienfx_ops {
- int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
- u8 location);
- int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
- u8 brightness);
-};
-
-struct alienfx_platdata {
- struct wmi_device *wdev;
- struct alienfx_ops ops;
-};
-
static u8 interface;
struct awcc_quirks {
@@ -405,8 +355,8 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
struct awcc_quirks *awcc;
-static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
- void *in_args, size_t in_size, u32 *out_data)
+int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
+ void *in_args, size_t in_size, u32 *out_data)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer in = {in_size, in_args};
@@ -1139,7 +1089,7 @@ static struct platform_driver platform_driver = {
.probe = alienfx_probe,
};
-static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
+int alienware_alienfx_setup(struct alienfx_platdata *pdata)
{
struct platform_device *pdev;
int ret;
@@ -1162,7 +1112,7 @@ static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
return 0;
}
-static void alienware_alienfx_exit(struct wmi_device *wdev)
+void alienware_alienfx_exit(struct wmi_device *wdev)
{
struct platform_device *pdev = dev_get_drvdata(&wdev->dev);
@@ -1242,12 +1192,12 @@ static struct wmi_driver alienware_legacy_wmi_driver = {
.remove = legacy_wmi_remove,
};
-static int __init alienware_legacy_wmi_init(void)
+int __init alienware_legacy_wmi_init(void)
{
return wmi_driver_register(&alienware_legacy_wmi_driver);
}
-static void __exit alienware_legacy_wmi_exit(void)
+void __exit alienware_legacy_wmi_exit(void)
{
wmi_driver_unregister(&alienware_legacy_wmi_driver);
}
@@ -1330,7 +1280,7 @@ static struct wmi_driver alienware_wmax_wmi_driver = {
.remove = wmax_wmi_remove,
};
-static int __init alienware_wmax_wmi_init(void)
+int __init alienware_wmax_wmi_init(void)
{
const struct dmi_system_id *id;
@@ -1347,7 +1297,7 @@ static int __init alienware_wmax_wmi_init(void)
return wmi_driver_register(&alienware_wmax_wmi_driver);
}
-static void __exit alienware_wmax_wmi_exit(void)
+void __exit alienware_wmax_wmi_exit(void)
{
wmi_driver_unregister(&alienware_wmax_wmi_driver);
}
diff --git a/drivers/platform/x86/dell/alienware-wmi.h b/drivers/platform/x86/dell/alienware-wmi.h
new file mode 100644
index 000000000000..dccbf4f95da0
--- /dev/null
+++ b/drivers/platform/x86/dell/alienware-wmi.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Alienware WMI special features driver
+ *
+ * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
+ * Copyright (C) 2024 Kurt Borja <kuurtb@gmail.com>
+ */
+
+#ifndef _ALIENWARE_WMI_H_
+#define _ALIENWARE_WMI_H_
+
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/wmi.h>
+
+#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
+#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
+#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
+
+enum LEGACY_CONTROL_STATES {
+ LEGACY_RUNNING = 1,
+ LEGACY_BOOTING = 0,
+ LEGACY_SUSPEND = 3,
+};
+
+enum WMAX_CONTROL_STATES {
+ WMAX_RUNNING = 0xFF,
+ WMAX_BOOTING = 0,
+ WMAX_SUSPEND = 3,
+};
+
+struct alienfx_quirks {
+ u8 num_zones;
+ bool hdmi_mux;
+ bool amplifier;
+ bool deepslp;
+};
+
+struct color_platform {
+ u8 blue;
+ u8 green;
+ u8 red;
+} __packed;
+
+struct alienfx_priv {
+ struct platform_device *pdev;
+ struct alienfx_quirks *quirks;
+ struct led_classdev global_led;
+ struct color_platform colors[4];
+ u8 global_brightness;
+ u8 lighting_control_state;
+};
+
+struct alienfx_ops {
+ int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
+ u8 location);
+ int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
+ u8 brightness);
+};
+
+struct alienfx_platdata {
+ struct wmi_device *wdev;
+ struct alienfx_ops ops;
+};
+
+int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
+ void *in_args, size_t in_size, u32 *out_data);
+
+int alienware_alienfx_setup(struct alienfx_platdata *pdata);
+void alienware_alienfx_exit(struct wmi_device *wdev);
+
+int __init alienware_legacy_wmi_init(void);
+void __exit alienware_legacy_wmi_exit(void);
+
+int __init alienware_wmax_wmi_init(void);
+void __exit alienware_wmax_wmi_exit(void);
+
+#endif
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (15 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 16/20] platform/x86: Add alienware-wmi.h Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2025-01-02 16:49 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 18/20] platform/x86: dell: Modify Makefile alignment Kurt Borja
` (3 subsequent siblings)
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
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@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.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@outlook.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,
- &lifier_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@gmail.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@gmail.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,
+ &lifier_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);
+}
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 18/20] platform/x86: dell: Modify Makefile alignment
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (16 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2024-12-29 19:45 ` [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries Kurt Borja
` (2 subsequent siblings)
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Add one more TAB to each line to support upcoming changes.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/Makefile | 48 +++++++++++++++---------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
index 03ba459f3d31..d5718ef34c48 100644
--- a/drivers/platform/x86/dell/Makefile
+++ b/drivers/platform/x86/dell/Makefile
@@ -4,27 +4,27 @@
# Dell x86 Platform-Specific Drivers
#
-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
-obj-$(CONFIG_DELL_RBU) += dell_rbu.o
-obj-$(CONFIG_DELL_PC) += dell-pc.o
-obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
-dell-smbios-objs := dell-smbios-base.o
-dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
-dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
-obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
-obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o
-obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o
-obj-$(CONFIG_DELL_WMI) += dell-wmi.o
-dell-wmi-objs := dell-wmi-base.o
-dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
-obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
-obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
-obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
-obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
-obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
+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
+obj-$(CONFIG_DELL_RBU) += dell_rbu.o
+obj-$(CONFIG_DELL_PC) += dell-pc.o
+obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
+dell-smbios-objs := dell-smbios-base.o
+dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
+dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
+obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
+obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o
+obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o
+obj-$(CONFIG_DELL_WMI) += dell-wmi.o
+dell-wmi-objs := dell-wmi-base.o
+dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
+obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
+obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
+obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
+obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
+obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (17 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 18/20] platform/x86: dell: Modify Makefile alignment Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2025-01-02 16:57 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 20/20] alienware-wmi: Update header and module information Kurt Borja
2025-01-02 15:50 ` [PATCH v2 00/20] alienware-wmi driver rework Armin Wolf
20 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja
Add config entries for each WMI driver managed by the alienware-wmi
module to be able to conditionally compile them.
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/Kconfig | 30 +++++++++++++++++++----
drivers/platform/x86/dell/Makefile | 4 +--
drivers/platform/x86/dell/alienware-wmi.h | 23 +++++++++++++++++
3 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
index d09060aedd3f..f8a0dffcaab7 100644
--- a/drivers/platform/x86/dell/Kconfig
+++ b/drivers/platform/x86/dell/Kconfig
@@ -18,15 +18,35 @@ config ALIENWARE_WMI
tristate "Alienware Special feature control"
default m
depends on ACPI
+ depends on ACPI_WMI
+ depends on DMI
depends on LEDS_CLASS
depends on NEW_LEDS
- depends on ACPI_WMI
+ help
+ This is a driver for controlling Alienware WMI driven features.
+
+ On legacy devices, it exposes an interface for controlling the AlienFX
+ zones on Alienware machines that don't contain a dedicated
+ AlienFX USB MCU such as the X51 and X51-R2.
+
+ On newer devices, it exposes the AWCC thermal control interface through
+ known Kernel APIs.
+
+config ALIENWARE_WMI_LEGACY
+ bool "Alienware Legacy WMI device driver"
+ default y
+ depends on ALIENWARE_WMI
+ help
+ Legacy Alienware WMI driver with AlienFX LED control capabilities.
+
+config ALIENWARE_WMI_WMAX
+ bool "Alienware WMAX WMI device driver"
+ default y
+ depends on ALIENWARE_WMI
select ACPI_PLATFORM_PROFILE
help
- This is a driver for controlling Alienware BIOS driven
- features. It exposes an interface for controlling the AlienFX
- zones on Alienware machines that don't contain a dedicated AlienFX
- USB MCU such as the X51 and X51-R2.
+ Alienware WMI driver with AlienFX LED, HDMI, amplifier, deep sleep and
+ AWCC thermal control capabilities.
config DCDBAS
tristate "Dell Systems Management Base Driver"
diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
index d5718ef34c48..8ac9a933c770 100644
--- a/drivers/platform/x86/dell/Makefile
+++ b/drivers/platform/x86/dell/Makefile
@@ -6,8 +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
+alienware-wmi-$(CONFIG_ALIENWARE_WMI_LEGACY) += alienware-wmi-legacy.o
+alienware-wmi-$(CONFIG_ALIENWARE_WMI_WMAX) += 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.h b/drivers/platform/x86/dell/alienware-wmi.h
index dccbf4f95da0..ae3731f2fef2 100644
--- a/drivers/platform/x86/dell/alienware-wmi.h
+++ b/drivers/platform/x86/dell/alienware-wmi.h
@@ -69,10 +69,33 @@ int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
int alienware_alienfx_setup(struct alienfx_platdata *pdata);
void alienware_alienfx_exit(struct wmi_device *wdev);
+#if IS_ENABLED(CONFIG_ALIENWARE_WMI_LEGACY)
int __init alienware_legacy_wmi_init(void);
void __exit alienware_legacy_wmi_exit(void);
+#else
+static inline int alienware_legacy_wmi_init(void)
+{
+ return -ENODEV;
+}
+static inline void alienware_legacy_wmi_exit(void)
+{
+}
+#endif
+
+#if IS_ENABLED(CONFIG_ALIENWARE_WMI_WMAX)
int __init alienware_wmax_wmi_init(void);
void __exit alienware_wmax_wmi_exit(void);
+#else
+static inline int alienware_wmax_wmi_init(void)
+{
+ return -ENODEV;
+}
+
+
+static inline void alienware_wmax_wmi_exit(void)
+{
+}
+#endif
#endif
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [PATCH v2 20/20] alienware-wmi: Update header and module information
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (18 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries Kurt Borja
@ 2024-12-29 19:45 ` Kurt Borja
2025-01-02 15:50 ` [PATCH v2 00/20] alienware-wmi driver rework Armin Wolf
20 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2024-12-29 19:45 UTC (permalink / raw)
To: platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello, w_armin, Kurt Borja, Armin Wolf
Update module header and description. Additionally add myself as a module
author.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
drivers/platform/x86/dell/alienware-wmi-base.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/dell/alienware-wmi-base.c b/drivers/platform/x86/dell/alienware-wmi-base.c
index fd73c3881dc0..bf0f37363998 100644
--- a/drivers/platform/x86/dell/alienware-wmi-base.c
+++ b/drivers/platform/x86/dell/alienware-wmi-base.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Alienware AlienFX control
+ * Alienware special feature control
*
* Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
+ * Copyright (C) 2024 Kurt Borja <kuurtb@gmail.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -15,6 +16,7 @@
#include "alienware-wmi.h"
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
+MODULE_AUTHOR("Kurt Borja <kuurtb@gmail.com>");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");
--
2.47.1
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [PATCH v2 05/20] alienware-wmi: Improve rgb-zones group creation
2024-12-29 19:44 ` [PATCH v2 05/20] alienware-wmi: Improve rgb-zones " Kurt Borja
@ 2025-01-02 15:44 ` Armin Wolf
2025-01-02 18:33 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 15:44 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Define zone_attrs statically and initialize zone_attribute_group with
> platform driver's .dev_groups.
>
> Drop match_zone() and instead pass a `location` argument to previous
> show/store methods to access the correct `zone` LED state. On top of
> that rename zone_set() -> zone_store() to be more consistent with sysfs
> conventions.
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 209 +++++++++++-----------
> 1 file changed, 102 insertions(+), 107 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index e010c94555e8..d97e5e15a8f2 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -376,12 +376,6 @@ struct color_platform {
> u8 red;
> } __packed;
>
> -struct platform_zone {
> - u8 location;
> - struct device_attribute *attr;
> - struct color_platform colors;
> -};
> -
> struct wmax_brightness_args {
> u32 led_mask;
> u32 percentage;
> @@ -411,16 +405,10 @@ struct wmax_u32_args {
> };
>
> static struct platform_device *platform_device;
> -static struct device_attribute *zone_dev_attrs;
> -static struct attribute **zone_attrs;
> -static struct platform_zone *zone_data;
> +static struct color_platform colors[4];
> static struct platform_profile_handler pp_handler;
> static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
>
> -static struct attribute_group zone_attribute_group = {
> - .name = "rgb_zones",
> -};
> -
> static u8 interface;
> static u8 lighting_control_state;
> static u8 global_brightness;
> @@ -452,24 +440,10 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> return 0;
> }
>
> -static struct platform_zone *match_zone(struct device_attribute *attr)
> -{
> - u8 zone;
> -
> - for (zone = 0; zone < quirks->num_zones; zone++) {
> - if ((struct device_attribute *)zone_data[zone].attr == attr) {
> - pr_debug("alienware-wmi: matched zone location: %d\n",
> - zone_data[zone].location);
> - return &zone_data[zone];
> - }
> - }
> - return NULL;
> -}
> -
> /*
> * Individual RGB zone control
> */
> -static int alienware_update_led(struct platform_zone *zone)
> +static int alienware_update_led(u8 location)
> {
> int method_id;
> acpi_status status;
> @@ -478,8 +452,8 @@ static int alienware_update_led(struct platform_zone *zone)
> struct legacy_led_args legacy_args;
> struct wmax_led_args wmax_basic_args;
> if (interface == WMAX) {
> - wmax_basic_args.led_mask = 1 << zone->location;
> - wmax_basic_args.colors = zone->colors;
> + wmax_basic_args.led_mask = 1 << location;
> + wmax_basic_args.colors = colors[location];
> wmax_basic_args.state = lighting_control_state;
> guid = WMAX_CONTROL_GUID;
> method_id = WMAX_METHOD_ZONE_CONTROL;
> @@ -487,7 +461,7 @@ static int alienware_update_led(struct platform_zone *zone)
> input.length = sizeof(wmax_basic_args);
> input.pointer = &wmax_basic_args;
> } else {
> - legacy_args.colors = zone->colors;
> + legacy_args.colors = colors[location];
> legacy_args.brightness = global_brightness;
> legacy_args.state = 0;
> if (lighting_control_state == LEGACY_BOOTING ||
> @@ -496,7 +470,7 @@ static int alienware_update_led(struct platform_zone *zone)
> legacy_args.state = lighting_control_state;
> } else
> guid = LEGACY_CONTROL_GUID;
> - method_id = zone->location + 1;
> + method_id = location + 1;
>
> input.length = sizeof(legacy_args);
> input.pointer = &legacy_args;
> @@ -510,35 +484,84 @@ static int alienware_update_led(struct platform_zone *zone)
> }
>
> static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> - char *buf)
> + char *buf, u8 location)
> {
> - struct platform_zone *target_zone;
> - target_zone = match_zone(attr);
> - if (target_zone == NULL)
> - return sprintf(buf, "red: -1, green: -1, blue: -1\n");
> return sprintf(buf, "red: %d, green: %d, blue: %d\n",
> - target_zone->colors.red,
> - target_zone->colors.green, target_zone->colors.blue);
> + colors[location].red, colors[location].green,
> + colors[location].blue);
>
> }
>
> -static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
> - const char *buf, size_t count)
> +static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count, u8 location)
> {
> - struct platform_zone *target_zone;
> int ret;
> - target_zone = match_zone(attr);
> - if (target_zone == NULL) {
> - pr_err("alienware-wmi: invalid target zone\n");
> - return 1;
> - }
> - ret = parse_rgb(buf, &target_zone->colors);
> +
> + ret = parse_rgb(buf, &colors[location]);
> if (ret)
> return ret;
> - ret = alienware_update_led(target_zone);
> +
> + ret = alienware_update_led(location);
> +
> return ret ? ret : count;
> }
>
> +static ssize_t zone00_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + return zone_show(dev, attr, buf, 0);
> +}
> +
> +static ssize_t zone00_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + return zone_store(dev, attr, buf, count, 0);
> +}
> +
> +DEVICE_ATTR_RW(zone00);
> +
> +static ssize_t zone01_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + return zone_show(dev, attr, buf, 1);
> +}
> +
> +static ssize_t zone01_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + return zone_store(dev, attr, buf, count, 1);
> +}
> +
> +DEVICE_ATTR_RW(zone01);
> +
> +static ssize_t zone02_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + return zone_show(dev, attr, buf, 2);
> +}
> +
> +static ssize_t zone02_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + return zone_store(dev, attr, buf, count, 2);
> +}
> +
> +DEVICE_ATTR_RW(zone02);
> +
> +static ssize_t zone03_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + return zone_show(dev, attr, buf, 3);
> +}
> +
> +static ssize_t zone03_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + return zone_store(dev, attr, buf, count, 3);
> +}
> +
> +DEVICE_ATTR_RW(zone03);
> +
> /*
> * Lighting control state device attribute (Global)
> */
> @@ -578,6 +601,33 @@ static ssize_t lighting_control_state_store(struct device *dev,
>
> static DEVICE_ATTR_RW(lighting_control_state);
>
> +static umode_t zone_attr_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return n < quirks->num_zones + 1 ? 0644 : 0;
Please return attr->mode here instead of 0644. I would also prefer if you use a traditional if statement here.
With this small issue being addressed:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> +}
> +
> +static bool zone_group_visible(struct kobject *kobj)
> +{
> + return quirks->num_zones > 0;
> +}
> +DEFINE_SYSFS_GROUP_VISIBLE(zone);
> +
> +static struct attribute *zone_attrs[] = {
> + &dev_attr_lighting_control_state.attr,
> + &dev_attr_zone00.attr,
> + &dev_attr_zone01.attr,
> + &dev_attr_zone02.attr,
> + &dev_attr_zone03.attr,
> + NULL
> +};
> +
> +static struct attribute_group zone_attribute_group = {
> + .name = "rgb_zones",
> + .is_visible = SYSFS_GROUP_VISIBLE(zone),
> + .attrs = zone_attrs,
> +};
> +
> /*
> * LED Brightness (Global)
> */
> @@ -606,7 +656,7 @@ static void global_led_set(struct led_classdev *led_cdev,
> if (interface == WMAX)
> ret = wmax_brightness(brightness);
> else
> - ret = alienware_update_led(&zone_data[0]);
> + ret = alienware_update_led(0);
> if (ret)
> pr_err("LED brightness update failed\n");
> }
> @@ -624,9 +674,6 @@ static struct led_classdev global_led = {
>
> static int alienware_zone_init(struct platform_device *dev)
> {
> - u8 zone;
> - char *name;
> -
> if (interface == WMAX) {
> lighting_control_state = WMAX_RUNNING;
> } else if (interface == LEGACY) {
> @@ -635,65 +682,12 @@ static int alienware_zone_init(struct platform_device *dev)
> global_led.max_brightness = 0x0F;
> global_brightness = global_led.max_brightness;
>
> - /*
> - * - zone_dev_attrs num_zones + 1 is for individual zones and then
> - * null terminated
> - * - zone_attrs num_zones + 2 is for all attrs in zone_dev_attrs +
> - * the lighting control + null terminated
> - * - zone_data num_zones is for the distinct zones
> - */
> - zone_dev_attrs =
> - kcalloc(quirks->num_zones + 1, sizeof(struct device_attribute),
> - GFP_KERNEL);
> - if (!zone_dev_attrs)
> - return -ENOMEM;
> -
> - zone_attrs =
> - kcalloc(quirks->num_zones + 2, sizeof(struct attribute *),
> - GFP_KERNEL);
> - if (!zone_attrs)
> - return -ENOMEM;
> -
> - zone_data =
> - kcalloc(quirks->num_zones, sizeof(struct platform_zone),
> - GFP_KERNEL);
> - if (!zone_data)
> - return -ENOMEM;
> -
> - for (zone = 0; zone < quirks->num_zones; zone++) {
> - name = kasprintf(GFP_KERNEL, "zone%02hhX", zone);
> - if (name == NULL)
> - return 1;
> - sysfs_attr_init(&zone_dev_attrs[zone].attr);
> - zone_dev_attrs[zone].attr.name = name;
> - zone_dev_attrs[zone].attr.mode = 0644;
> - zone_dev_attrs[zone].show = zone_show;
> - zone_dev_attrs[zone].store = zone_set;
> - zone_data[zone].location = zone;
> - zone_attrs[zone] = &zone_dev_attrs[zone].attr;
> - zone_data[zone].attr = &zone_dev_attrs[zone];
> - }
> - zone_attrs[quirks->num_zones] = &dev_attr_lighting_control_state.attr;
> - zone_attribute_group.attrs = zone_attrs;
> -
> - led_classdev_register(&dev->dev, &global_led);
> -
> - return sysfs_create_group(&dev->dev.kobj, &zone_attribute_group);
> + return led_classdev_register(&dev->dev, &global_led);
> }
>
> static void alienware_zone_exit(struct platform_device *dev)
> {
> - u8 zone;
> -
> - sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group);
> led_classdev_unregister(&global_led);
> - if (zone_dev_attrs) {
> - for (zone = 0; zone < quirks->num_zones; zone++)
> - kfree(zone_dev_attrs[zone].attr.name);
> - }
> - kfree(zone_dev_attrs);
> - kfree(zone_data);
> - kfree(zone_attrs);
> }
>
> static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> @@ -1143,6 +1137,7 @@ static void remove_thermal_profile(void)
> * Platform Driver
> */
> static const struct attribute_group *alienfx_groups[] = {
> + &zone_attribute_group,
> &hdmi_attribute_group,
> &lifier_attribute_group,
> &deepsleep_attribute_group,
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 00/20] alienware-wmi driver rework
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
` (19 preceding siblings ...)
2024-12-29 19:45 ` [PATCH v2 20/20] alienware-wmi: Update header and module information Kurt Borja
@ 2025-01-02 15:50 ` Armin Wolf
2025-01-02 19:41 ` Kurt Borja
20 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 15:50 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Hi!
>
> Happy holidays. :)
Hi,
i just noticed that your patch are missing the "platform/x86:" prefix. Please add this prefix
for the next patch revision.
Thanks,
Armin Wolf
>
> ~ Kurt
> ---
> v1 -> v2:
>
> [2/20]
> - Small correction in commit message
>
> [5/20]
> - Define the sysfs attributes without macros
>
> [6/20]
> - Reworded commit title
> - Reorder variables in previous WMAX methods too
> - Standarized sysfs method names in hdmi, amplifier and deepsleep
> groups
> - Dropped Armin's Reviewed-by tag because this patch changed a lot
>
> [7/20]
> - Return -ENOMEM in case priv allocation fails in alienfx_probe()
> - Assign priv and platdata on variable declaration
> - Drop intermediate *leds in alienfx_probe()
> - Add quirk_entry to state container
> - Use quirks from priv on hdmi_mux, amplifier, deepslp visibility
> methods, to eventually be able to move these groups into
> alienware-wmi-wmax.c
> - Set PROBE_FORCE_SYNCHRONOUS to platform_driver, to avoid racing to
> drvdata after using device_create_groups on [8/20]
>
> [8/20]
> - Create hdmi, amplifier, deepslp sysfs groups on wmax's probe
>
> [9/20]
> - Assign priv on variable declaration
> - Directly return create thermal_profile() in alienware_awcc_setup()
>
> [10/20]
> - Refactored alienware_wmi_method following Armin's comments
> - Fix legacy_wmi_update_led logic
>
> [13/20]
> - Split DMI table lower in the file
> - Rename quirk_entry -> alienfx_quirks
> - Rename awcc_features -> awcc_quirks
> - Make hdmi_mux, amplifier and deepslp `bool`
>
> [16/20]:
> - Only add common resources on alienware.h
>
> [17/20]
> - Reworded commit message: now mentions some blocks were reordered
> - Move #include <linux/dmi.h> where it belongs alphabetically
> - Included hdmi, amplifier, deepslp groups in alienware-wmi-wmax.c
>
> [18/20]
> - static inline init functions in case drivers are not compiled
> - Return errno in case drivers are not compiled
>
> v1: https://lore.kernel.org/platform-driver-x86/20241221055917.10555-1-kuurtb@gmail.com/
>
> Kurt Borja (20):
> alienware-wmi: Remove unnecessary check at module exit
> alienware-wmi: Move Lighting Control State
> alienware-wmi: Modify parse_rgb() signature
> alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation
> alienware-wmi: Improve rgb-zones group creation
> alienware_wmi: General cleanup of WMAX methods
> alienware-wmi: Add a state container for LED control feature
> alienware-wmi: Add WMI Drivers
> alienware-wmi: Add a state container for thermal control methods
> alienware-wmi: Refactor LED control methods
> alienware-wmi: Refactor hdmi, amplifier, deepslp methods
> alienware-wmi: Refactor thermal control methods
> alienware-wmi: Split DMI table
> MAINTAINERS: Update ALIENWARE WMI DRIVER entry
> platform/x86: Rename alienware-wmi.c
> platform/x86: Add alienware-wmi.h
> platform-x86: Split the alienware-wmi driver
> platform/x86: dell: Modify Makefile alignment
> platform/x86: Update alienware-wmi config entries
> alienware-wmi: Update header and module information
>
> MAINTAINERS | 4 +-
> drivers/platform/x86/dell/Kconfig | 30 +-
> drivers/platform/x86/dell/Makefile | 45 +-
> .../platform/x86/dell/alienware-wmi-base.c | 492 +++++++
> .../platform/x86/dell/alienware-wmi-legacy.c | 98 ++
> .../platform/x86/dell/alienware-wmi-wmax.c | 775 ++++++++++
> drivers/platform/x86/dell/alienware-wmi.c | 1269 -----------------
> drivers/platform/x86/dell/alienware-wmi.h | 101 ++
> 8 files changed, 1518 insertions(+), 1296 deletions(-)
> create mode 100644 drivers/platform/x86/dell/alienware-wmi-base.c
> create mode 100644 drivers/platform/x86/dell/alienware-wmi-legacy.c
> create mode 100644 drivers/platform/x86/dell/alienware-wmi-wmax.c
> delete mode 100644 drivers/platform/x86/dell/alienware-wmi.c
> create mode 100644 drivers/platform/x86/dell/alienware-wmi.h
>
>
> base-commit: 03f8e0e05510dad6377cd5ef029594d30e6c096d
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods
2024-12-29 19:44 ` [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods Kurt Borja
@ 2025-01-02 15:50 ` Armin Wolf
0 siblings, 0 replies; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 15:50 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Reorder variable declaration from longest to shortest. Standarize
> show/store method names of WMAX's sysfs groups.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 67 +++++++++++------------
> 1 file changed, 32 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index d97e5e15a8f2..2c17160473a6 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -722,14 +722,14 @@ static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> * 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 show_hdmi_cable(struct device *dev,
> - struct device_attribute *attr, char *buf)
> +static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> {
> - acpi_status status;
> - u32 out_data;
> struct wmax_basic_args in_args = {
> .arg = 0,
> };
> + acpi_status status;
> + u32 out_data;
> status =
> alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_HDMI_CABLE, &out_data);
> @@ -743,14 +743,14 @@ static ssize_t show_hdmi_cable(struct device *dev,
> return sysfs_emit(buf, "unconnected connected [unknown]\n");
> }
>
> -static ssize_t show_hdmi_source(struct device *dev,
> - struct device_attribute *attr, char *buf)
> +static ssize_t source_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> {
> - acpi_status status;
> - u32 out_data;
> struct wmax_basic_args in_args = {
> .arg = 0,
> };
> + acpi_status status;
> + u32 out_data;
> status =
> alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_HDMI_STATUS, &out_data);
> @@ -765,12 +765,11 @@ static ssize_t show_hdmi_source(struct device *dev,
> return sysfs_emit(buf, "input gpu [unknown]\n");
> }
>
> -static ssize_t toggle_hdmi_source(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> +static ssize_t source_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> {
> - acpi_status status;
> struct wmax_basic_args args;
> + acpi_status status;
> if (strcmp(buf, "gpu\n") == 0)
> args.arg = 1;
> else if (strcmp(buf, "input\n") == 0)
> @@ -788,9 +787,8 @@ static ssize_t toggle_hdmi_source(struct device *dev,
> return count;
> }
>
> -static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL);
> -static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source,
> - toggle_hdmi_source);
> +static DEVICE_ATTR_RO(cable);
> +static DEVICE_ATTR_RW(source);
>
> static bool hdmi_group_visible(struct kobject *kobj)
> {
> @@ -815,14 +813,14 @@ static const struct attribute_group hdmi_attribute_group = {
> * - Currently supports reading cable status
> * - Leaving expansion room to possibly support dock/undock events later
> */
> -static ssize_t show_amplifier_status(struct device *dev,
> - struct device_attribute *attr, char *buf)
> +static ssize_t status_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> {
> - acpi_status status;
> - u32 out_data;
> struct wmax_basic_args in_args = {
> .arg = 0,
> };
> + acpi_status status;
> + u32 out_data;
> status =
> alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_AMPLIFIER_CABLE, &out_data);
> @@ -836,7 +834,7 @@ static ssize_t show_amplifier_status(struct device *dev,
> return sysfs_emit(buf, "unconnected connected [unknown]\n");
> }
>
> -static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL);
> +static DEVICE_ATTR_RO(status);
>
> static bool amplifier_group_visible(struct kobject *kobj)
> {
> @@ -859,14 +857,14 @@ static const struct attribute_group amplifier_attribute_group = {
> * Deep Sleep Control support
> * - Modifies BIOS setting for deep sleep control allowing extra wakeup events
> */
> -static ssize_t show_deepsleep_status(struct device *dev,
> - struct device_attribute *attr, char *buf)
> +static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> {
> - acpi_status status;
> - u32 out_data;
> struct wmax_basic_args in_args = {
> .arg = 0,
> };
> + acpi_status status;
> + u32 out_data;
> status = alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_DEEP_SLEEP_STATUS, &out_data);
> if (ACPI_SUCCESS(status)) {
> @@ -881,12 +879,11 @@ static ssize_t show_deepsleep_status(struct device *dev,
> return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
> }
>
> -static ssize_t toggle_deepsleep(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> +static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> {
> - acpi_status status;
> struct wmax_basic_args args;
> + acpi_status status;
>
> if (strcmp(buf, "disabled\n") == 0)
> args.arg = 0;
> @@ -905,7 +902,7 @@ static ssize_t toggle_deepsleep(struct device *dev,
> return count;
> }
>
> -static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep);
> +static DEVICE_ATTR_RW(deepsleep);
>
> static bool deepsleep_group_visible(struct kobject *kobj)
> {
> @@ -953,13 +950,13 @@ static bool is_wmax_thermal_code(u32 code)
>
> static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
> {
> - acpi_status status;
> struct wmax_u32_args in_args = {
> .operation = operation,
> .arg1 = arg,
> .arg2 = 0,
> .arg3 = 0,
> };
> + acpi_status status;
>
> status = alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_THERMAL_INFORMATION,
> @@ -976,13 +973,13 @@ static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data)
>
> static int wmax_thermal_control(u8 profile)
> {
> - acpi_status status;
> struct wmax_u32_args in_args = {
> .operation = WMAX_OPERATION_ACTIVATE_PROFILE,
> .arg1 = profile,
> .arg2 = 0,
> .arg3 = 0,
> };
> + acpi_status status;
> u32 out_data;
>
> status = alienware_wmax_command(&in_args, sizeof(in_args),
> @@ -1000,13 +997,13 @@ static int wmax_thermal_control(u8 profile)
>
> static int wmax_game_shift_status(u8 operation, u32 *out_data)
> {
> - acpi_status status;
> struct wmax_u32_args in_args = {
> .operation = operation,
> .arg1 = 0,
> .arg2 = 0,
> .arg3 = 0,
> };
> + acpi_status status;
>
> status = alienware_wmax_command(&in_args, sizeof(in_args),
> WMAX_METHOD_GAME_SHIFT_STATUS,
> @@ -1075,11 +1072,11 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
>
> static int create_thermal_profile(struct platform_device *platform_device)
> {
> - u32 out_data;
> + enum platform_profile_option profile;
> + enum wmax_thermal_mode mode;
> u8 sys_desc[4];
> u32 first_mode;
> - enum wmax_thermal_mode mode;
> - enum platform_profile_option profile;
> + u32 out_data;
> int ret;
>
> ret = wmax_thermal_information(WMAX_OPERATION_SYS_DESCRIPTION,
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature
2024-12-29 19:44 ` [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature Kurt Borja
@ 2025-01-02 16:07 ` Armin Wolf
2025-01-02 18:45 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:07 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Add a state container for the "alienware-wmi" platform device and
> initialize it on the new alienfx_probe(). Migrate all LED control functions
> to use this state container, as well as hdmi, amplifier, deepslp group
> visibility methods, to support upcoming file split.
>
> Additionally move the led_classdev registration to the platform driver
> probe and make it device managed.
>
> Drop alienware_zone_init() and alienware_zone_exit() because they are no
> longer needed.
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 135 +++++++++++++---------
> 1 file changed, 79 insertions(+), 56 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index 2c17160473a6..88d4046ed45f 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -404,14 +404,20 @@ struct wmax_u32_args {
> u8 arg3;
> };
>
> +struct alienfx_priv {
> + struct platform_device *pdev;
> + struct quirk_entry *quirks;
> + struct led_classdev global_led;
> + struct color_platform colors[4];
> + u8 global_brightness;
> + u8 lighting_control_state;
> +};
> +
> static struct platform_device *platform_device;
> -static struct color_platform colors[4];
> static struct platform_profile_handler pp_handler;
> static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
>
> static u8 interface;
> -static u8 lighting_control_state;
> -static u8 global_brightness;
>
> /*
> * Helpers used for zone control
> @@ -443,7 +449,7 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> /*
> * Individual RGB zone control
> */
> -static int alienware_update_led(u8 location)
> +static int alienware_update_led(struct alienfx_priv *priv, u8 location)
> {
> int method_id;
> acpi_status status;
> @@ -453,21 +459,21 @@ static int alienware_update_led(u8 location)
> struct wmax_led_args wmax_basic_args;
> if (interface == WMAX) {
> wmax_basic_args.led_mask = 1 << location;
> - wmax_basic_args.colors = colors[location];
> - wmax_basic_args.state = lighting_control_state;
> + wmax_basic_args.colors = priv->colors[location];
> + wmax_basic_args.state = priv->lighting_control_state;
> guid = WMAX_CONTROL_GUID;
> method_id = WMAX_METHOD_ZONE_CONTROL;
>
> input.length = sizeof(wmax_basic_args);
> input.pointer = &wmax_basic_args;
> } else {
> - legacy_args.colors = colors[location];
> - legacy_args.brightness = global_brightness;
> + legacy_args.colors = priv->colors[location];
> + legacy_args.brightness = priv->global_brightness;
> legacy_args.state = 0;
> - if (lighting_control_state == LEGACY_BOOTING ||
> - lighting_control_state == LEGACY_SUSPEND) {
> + if (priv->lighting_control_state == LEGACY_BOOTING ||
> + priv->lighting_control_state == LEGACY_SUSPEND) {
> guid = LEGACY_POWER_CONTROL_GUID;
> - legacy_args.state = lighting_control_state;
> + legacy_args.state = priv->lighting_control_state;
> } else
> guid = LEGACY_CONTROL_GUID;
> method_id = location + 1;
> @@ -486,22 +492,26 @@ static int alienware_update_led(u8 location)
> static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> char *buf, u8 location)
> {
> + struct alienfx_priv *priv = dev_get_drvdata(dev);
> + struct color_platform *colors = &priv->colors[location];
> +
> return sprintf(buf, "red: %d, green: %d, blue: %d\n",
> - colors[location].red, colors[location].green,
> - colors[location].blue);
> + colors->red, colors->green, colors->blue);
>
> }
>
> static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> const char *buf, size_t count, u8 location)
> {
> + struct alienfx_priv *priv = dev_get_drvdata(dev);
> + struct color_platform *colors = &priv->colors[location];
> int ret;
>
> - ret = parse_rgb(buf, &colors[location]);
> + ret = parse_rgb(buf, colors);
> if (ret)
> return ret;
>
> - ret = alienware_update_led(location);
> + ret = alienware_update_led(priv, location);
>
> return ret ? ret : count;
> }
> @@ -569,9 +579,11 @@ static ssize_t lighting_control_state_show(struct device *dev,
> struct device_attribute *attr,
> char *buf)
> {
> - if (lighting_control_state == LEGACY_BOOTING)
> + struct alienfx_priv *priv = dev_get_drvdata(dev);
> +
> + if (priv->lighting_control_state == LEGACY_BOOTING)
> return sysfs_emit(buf, "[booting] running suspend\n");
> - else if (lighting_control_state == LEGACY_SUSPEND)
> + else if (priv->lighting_control_state == LEGACY_SUSPEND)
> return sysfs_emit(buf, "booting running [suspend]\n");
>
> return sysfs_emit(buf, "booting [running] suspend\n");
> @@ -581,6 +593,7 @@ static ssize_t lighting_control_state_store(struct device *dev,
> struct device_attribute *attr,
> const char *buf, size_t count)
> {
> + struct alienfx_priv *priv = dev_get_drvdata(dev);
> u8 val;
>
> if (strcmp(buf, "booting\n") == 0)
> @@ -592,9 +605,9 @@ static ssize_t lighting_control_state_store(struct device *dev,
> else
> val = WMAX_RUNNING;
>
> - lighting_control_state = val;
> + priv->lighting_control_state = val;
> pr_debug("alienware-wmi: updated control state to %d\n",
> - lighting_control_state);
> + priv->lighting_control_state);
>
> return count;
> }
> @@ -651,43 +664,26 @@ static int wmax_brightness(int brightness)
> static void global_led_set(struct led_classdev *led_cdev,
> enum led_brightness brightness)
> {
> + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> + global_led);
> int ret;
> - global_brightness = brightness;
> +
> + priv->global_brightness = brightness;
> +
> if (interface == WMAX)
> ret = wmax_brightness(brightness);
> else
> - ret = alienware_update_led(0);
> + ret = alienware_update_led(priv, 0);
> if (ret)
> pr_err("LED brightness update failed\n");
> }
>
> static enum led_brightness global_led_get(struct led_classdev *led_cdev)
> {
> - return global_brightness;
> -}
> -
> -static struct led_classdev global_led = {
> - .brightness_set = global_led_set,
> - .brightness_get = global_led_get,
> - .name = "alienware::global_brightness",
> -};
> + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> + global_led);
>
> -static int alienware_zone_init(struct platform_device *dev)
> -{
> - if (interface == WMAX) {
> - lighting_control_state = WMAX_RUNNING;
> - } else if (interface == LEGACY) {
> - lighting_control_state = LEGACY_RUNNING;
> - }
> - global_led.max_brightness = 0x0F;
> - global_brightness = global_led.max_brightness;
> -
> - return led_classdev_register(&dev->dev, &global_led);
> -}
> -
> -static void alienware_zone_exit(struct platform_device *dev)
> -{
> - led_classdev_unregister(&global_led);
> + return priv->global_brightness;
> }
>
> static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> @@ -792,7 +788,9 @@ static DEVICE_ATTR_RW(source);
>
> static bool hdmi_group_visible(struct kobject *kobj)
> {
> - return quirks->hdmi_mux;
> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> + return priv->quirks->hdmi_mux;
> }
> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
>
> @@ -838,7 +836,9 @@ static DEVICE_ATTR_RO(status);
>
> static bool amplifier_group_visible(struct kobject *kobj)
> {
> - return quirks->amplifier;
> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> + return priv->quirks->amplifier;
> }
> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
>
> @@ -906,7 +906,9 @@ static DEVICE_ATTR_RW(deepsleep);
>
> static bool deepsleep_group_visible(struct kobject *kobj)
> {
> - return quirks->deepslp;
> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> +
> + return priv->quirks->deepslp;
> }
> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
>
> @@ -1133,6 +1135,33 @@ static void remove_thermal_profile(void)
> /*
> * Platform Driver
> */
> +static int alienfx_probe(struct platform_device *pdev)
> +{
> + struct alienfx_priv *priv;
> +
> + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, priv);
> + priv->pdev = pdev;
> + priv->quirks = quirks;
> +
> + if (interface == WMAX)
> + priv->lighting_control_state = WMAX_RUNNING;
> + else if (interface == LEGACY)
> + priv->lighting_control_state = LEGACY_RUNNING;
> +
> + priv->global_led.name = "alienware::global_brightness";
> + priv->global_led.brightness_set = global_led_set;
> + priv->global_led.brightness_get = global_led_get;
> + priv->global_led.max_brightness = 0x0F;
> +
> + priv->global_brightness = priv->global_led.max_brightness;
> +
> + return devm_led_classdev_register(&pdev->dev, &priv->global_led);
> +}
> +
> static const struct attribute_group *alienfx_groups[] = {
> &zone_attribute_group,
> &hdmi_attribute_group,
> @@ -1145,7 +1174,9 @@ static struct platform_driver platform_driver = {
> .driver = {
> .name = "alienware-wmi",
> .dev_groups = alienfx_groups,
> + .probe_type = PROBE_FORCE_SYNCHRONOUS,
Can you please explain to me why this is exactly necessary?
Thanks,
Armin Wolf
> },
> + .probe = alienfx_probe,
> };
>
> static int __init alienware_wmi_init(void)
> @@ -1193,15 +1224,8 @@ static int __init alienware_wmi_init(void)
> goto fail_prep_thermal_profile;
> }
>
> - ret = alienware_zone_init(platform_device);
> - if (ret)
> - goto fail_prep_zones;
> -
> return 0;
>
> -fail_prep_zones:
> - alienware_zone_exit(platform_device);
> - remove_thermal_profile();
> fail_prep_thermal_profile:
> platform_device_del(platform_device);
> fail_platform_device2:
> @@ -1216,7 +1240,6 @@ module_init(alienware_wmi_init);
>
> static void __exit alienware_wmi_exit(void)
> {
> - alienware_zone_exit(platform_device);
> remove_thermal_profile();
> platform_device_unregister(platform_device);
> platform_driver_unregister(&platform_driver);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 08/20] alienware-wmi: Add WMI Drivers
2024-12-29 19:44 ` [PATCH v2 08/20] alienware-wmi: Add WMI Drivers Kurt Borja
@ 2025-01-02 16:16 ` Armin Wolf
2025-01-02 18:49 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:16 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Add WMI drivers for LEGACY and WMAX devices.
>
> This involves moving platform driver and device registration to a helper
> function, which is now called from the driver's preferred WMI device
> driver probe. However this is only done if !quirks->thermal because
> newer WMAX interface doesn't support any of the features exposed by this
> device.
>
> Only one driver is registered on module initialization to prevent
> registering duplicate platform driver and device.
>
> Additionally, create_thermal_profile() now takes wmi_device * instead of
> platform_device *.
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 195 +++++++++++++++++-----
> 1 file changed, 155 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index 88d4046ed45f..87a7997579c9 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -15,6 +15,7 @@
> #include <linux/platform_profile.h>
> #include <linux/dmi.h>
> #include <linux/leds.h>
> +#include <linux/wmi.h>
>
> #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
> #define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
> @@ -39,8 +40,6 @@
> MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
> MODULE_DESCRIPTION("Alienware special feature control");
> MODULE_LICENSE("GPL");
> -MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
> -MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID);
>
> static bool force_platform_profile;
> module_param_unsafe(force_platform_profile, bool, 0);
> @@ -413,7 +412,10 @@ struct alienfx_priv {
> u8 lighting_control_state;
> };
>
> -static struct platform_device *platform_device;
> +struct alienfx_platdata {
> + struct wmi_device *wdev;
> +};
> +
> static struct platform_profile_handler pp_handler;
> static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
>
> @@ -1072,7 +1074,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> return wmax_thermal_control(supported_thermal_profiles[profile]);
> }
>
> -static int create_thermal_profile(struct platform_device *platform_device)
> +static int create_thermal_profile(struct wmi_device *wdev)
> {
> enum platform_profile_option profile;
> enum wmax_thermal_mode mode;
> @@ -1121,7 +1123,7 @@ static int create_thermal_profile(struct platform_device *platform_device)
> pp_handler.profile_get = thermal_profile_get;
> pp_handler.profile_set = thermal_profile_set;
> pp_handler.name = "alienware-wmi";
> - pp_handler.dev = &platform_device->dev;
> + pp_handler.dev = &wdev->dev;
>
> return platform_profile_register(&pp_handler);
> }
> @@ -1164,6 +1166,10 @@ static int alienfx_probe(struct platform_device *pdev)
>
> static const struct attribute_group *alienfx_groups[] = {
> &zone_attribute_group,
> + NULL
> +};
> +
> +static const struct attribute_group *wmax_alienfx_groups[] = {
> &hdmi_attribute_group,
> &lifier_attribute_group,
> &deepsleep_attribute_group,
> @@ -1179,19 +1185,143 @@ static struct platform_driver platform_driver = {
> .probe = alienfx_probe,
> };
>
> -static int __init alienware_wmi_init(void)
> +static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
> {
> + struct platform_device *pdev;
> int ret;
>
> - if (wmi_has_guid(LEGACY_CONTROL_GUID))
> - interface = LEGACY;
> - else if (wmi_has_guid(WMAX_CONTROL_GUID))
> - interface = WMAX;
> - else {
> - pr_warn("alienware-wmi: No known WMI GUID found\n");
> - return -ENODEV;
> + ret = platform_driver_register(&platform_driver);
> + if (ret < 0)
> + return ret;
> +
> + pdev = platform_device_register_data(NULL, "alienware-wmi",
> + PLATFORM_DEVID_NONE, pdata,
> + sizeof(*pdata));
> +
> + if (IS_ERR(pdev)) {
> + platform_driver_unregister(&platform_driver);
> + return PTR_ERR(pdev);
> + }
> +
> + dev_set_drvdata(&pdata->wdev->dev, pdev);
> +
> + return 0;
> +}
> +
> +static void alienware_alienfx_exit(struct wmi_device *wdev)
> +{
> + struct platform_device *pdev = dev_get_drvdata(&wdev->dev);
> +
> + platform_device_unregister(pdev);
> + platform_driver_unregister(&platform_driver);
> +}
> +
> +/*
> + * Legacy WMI driver
> + */
> +static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
> +{
> + struct alienfx_platdata pdata = {
> + .wdev = wdev,
> + };
> +
> + 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,
> +};
> +
> +static int __init alienware_legacy_wmi_init(void)
> +{
> + return wmi_driver_register(&alienware_legacy_wmi_driver);
> +}
> +
> +static void __exit alienware_legacy_wmi_exit(void)
> +{
> + wmi_driver_unregister(&alienware_legacy_wmi_driver);
> +}
> +
> +/*
> + * WMAX WMI driver
> + */
> +static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> +{
> + struct alienfx_platdata pdata = {
> + .wdev = wdev,
> + };
> + struct platform_device *pdev;
> + int ret;
> +
> + if (quirks->thermal) {
> + ret = create_thermal_profile(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);
If device_add_groups() fails you need to call alienware_alienfx_exit().
> }
>
> + return ret;
> +}
> +
> +static void wmax_wmi_remove(struct wmi_device *wdev)
> +{
> + if (quirks->thermal)
> + remove_thermal_profile();
> + else
> + alienware_alienfx_exit(wdev);
Missing call to device_remove_groups().
> +}
> +
> +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,
> +};
> +
> +static int __init alienware_wmax_wmi_init(void)
> +{
> + return wmi_driver_register(&alienware_wmax_wmi_driver);
> +}
> +
> +static void __exit alienware_wmax_wmi_exit(void)
> +{
> + wmi_driver_unregister(&alienware_wmax_wmi_driver);
> +}
> +
> +static int __init alienware_wmi_init(void)
> +{
> + int ret;
> +
> dmi_check_system(alienware_quirks);
> if (quirks == NULL)
> quirks = &quirk_unknown;
> @@ -1206,43 +1336,28 @@ static int __init alienware_wmi_init(void)
> pr_warn("force_gmode requires platform profile support\n");
> }
>
> - ret = platform_driver_register(&platform_driver);
> - if (ret)
> - goto fail_platform_driver;
> - platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE);
> - if (!platform_device) {
> - ret = -ENOMEM;
> - goto fail_platform_device1;
> + if (wmi_has_guid(WMAX_CONTROL_GUID)) {
> + interface = WMAX;
> + ret = alienware_wmax_wmi_init();
> + } else {
> + interface = LEGACY;
> + ret = alienware_legacy_wmi_init();
> }
> - ret = platform_device_add(platform_device);
> - if (ret)
> - goto fail_platform_device2;
>
> - if (quirks->thermal) {
> - ret = create_thermal_profile(platform_device);
> - if (ret)
> - goto fail_prep_thermal_profile;
> - }
> + if (ret < 0)
> + return ret;
>
> return 0;
Please just return ret here.
Thanks,
Armin Wolf
> -
> -fail_prep_thermal_profile:
> - platform_device_del(platform_device);
> -fail_platform_device2:
> - platform_device_put(platform_device);
> -fail_platform_device1:
> - platform_driver_unregister(&platform_driver);
> -fail_platform_driver:
> - return ret;
> }
>
> module_init(alienware_wmi_init);
>
> static void __exit alienware_wmi_exit(void)
> {
> - remove_thermal_profile();
> - platform_device_unregister(platform_device);
> - platform_driver_unregister(&platform_driver);
> + if (interface == WMAX)
> + alienware_wmax_wmi_exit();
> + else
> + alienware_legacy_wmi_exit();
> }
>
> module_exit(alienware_wmi_exit);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods
2024-12-29 19:44 ` [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods Kurt Borja
@ 2025-01-02 16:19 ` Armin Wolf
2025-01-02 18:52 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:19 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Refactor all thermal control methods to use the newly defined awcc_priv
> state container instead of global variables.
>
> Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 66 ++++++++++++++++-------
> 1 file changed, 47 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index 87a7997579c9..512384635c4c 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -403,6 +403,12 @@ struct wmax_u32_args {
> 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];
> +};
> +
> struct alienfx_priv {
> struct platform_device *pdev;
> struct quirk_entry *quirks;
> @@ -416,9 +422,6 @@ struct alienfx_platdata {
> struct wmi_device *wdev;
> };
>
> -static struct platform_profile_handler pp_handler;
> -static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> -
> static u8 interface;
>
> /*
> @@ -1051,6 +1054,8 @@ static int thermal_profile_get(struct platform_profile_handler *pprof,
> 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 (quirks->gmode) {
> u32 gmode_status;
> int ret;
> @@ -1071,11 +1076,12 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> }
> }
>
> - return wmax_thermal_control(supported_thermal_profiles[profile]);
> + return wmax_thermal_control(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];
> @@ -1105,33 +1111,55 @@ static int create_thermal_profile(struct wmi_device *wdev)
>
> mode = out_data & WMAX_THERMAL_MODE_MASK;
> profile = wmax_mode_to_platform_profile[mode];
> - supported_thermal_profiles[profile] = out_data;
> + priv->supported_thermal_profiles[profile] = out_data;
>
> - set_bit(profile, pp_handler.choices);
> + set_bit(profile, priv->pp_handler.choices);
> }
>
> - if (bitmap_empty(pp_handler.choices, PLATFORM_PROFILE_LAST))
> + if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> return -ENODEV;
>
> if (quirks->gmode) {
> - supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> + priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> WMAX_THERMAL_MODE_GMODE;
>
> - set_bit(PLATFORM_PROFILE_PERFORMANCE, pp_handler.choices);
> + set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->pp_handler.choices);
> }
>
> - pp_handler.profile_get = thermal_profile_get;
> - pp_handler.profile_set = thermal_profile_set;
> - pp_handler.name = "alienware-wmi";
> - pp_handler.dev = &wdev->dev;
> + 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(&pp_handler);
> + return platform_profile_register(&priv->pp_handler);
> }
>
> -static void remove_thermal_profile(void)
> +static int alienware_awcc_setup(struct wmi_device *wdev)
> {
> - if (quirks->thermal)
> - platform_profile_remove(&pp_handler);
> + 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;
Please directly return the result of create_thermal_profile() here.
> +}
> +
> +static void alienware_awcc_exit(struct wmi_device *wdev)
> +{
> + struct awcc_priv *priv;
> +
> + priv = dev_get_drvdata(&wdev->dev);
Please assign priv directly.
With those minor issues being fixed:
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> +
> + platform_profile_remove(&priv->pp_handler);
> }
>
> /*
> @@ -1271,7 +1299,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> int ret;
>
> if (quirks->thermal) {
> - ret = create_thermal_profile(wdev);
> + ret = alienware_awcc_setup(wdev);
> } else {
> ret = alienware_alienfx_setup(&pdata);
> if (ret < 0)
> @@ -1287,7 +1315,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> static void wmax_wmi_remove(struct wmi_device *wdev)
> {
> if (quirks->thermal)
> - remove_thermal_profile();
> + alienware_awcc_exit(wdev);
> else
> alienware_alienfx_exit(wdev);
> }
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 10/20] alienware-wmi: Refactor LED control methods
2024-12-29 19:44 ` [PATCH v2 10/20] alienware-wmi: Refactor LED " Kurt Borja
@ 2025-01-02 16:29 ` Armin Wolf
2025-01-02 19:36 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:29 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:44 schrieb Kurt Borja:
> Both WMI devices handled by this module specify a distinct interface for
> LED control. Previously this module handled this by dynamically adapting
> arguments passed to wmi_evaluate_method() based on the `interface`
> global variable.
>
> To avoid the use of global variables, and enable the migration to
> non-deprecated WMI methods, let the WMI drivers define upd_led and
> upd_brightness operations, which completely replace
> alienware_update_led() and wmax_brightness().
>
> Also define alienware_wmi_command(), which serves as a wrapper for
> wmidev_evaluate_method(). This new method is very similar to
> alienware_wmax_command() but is WMI device agnostic.
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 164 ++++++++++++++--------
> 1 file changed, 102 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index 512384635c4c..494a3772065c 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -418,12 +418,42 @@ struct alienfx_priv {
> u8 lighting_control_state;
> };
>
> +struct alienfx_ops {
> + int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
> + u8 location);
> + int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
> + u8 brightness);
> +};
> +
> struct alienfx_platdata {
> struct wmi_device *wdev;
> + struct alienfx_ops ops;
> };
>
> static u8 interface;
>
> +static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> + void *in_args, size_t in_size, u32 *out_data)
> +{
> + struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
> + struct acpi_buffer in = {in_size, in_args};
> + union acpi_object *obj;
> + acpi_status ret;
> +
> + ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL);
> + if (ACPI_FAILURE(ret))
> + return -EIO;
> +
> + obj = out.pointer;
> +
> + if (obj && obj->type == ACPI_TYPE_INTEGER) {
> + *out_data = (u32)obj->integer.value;
> + kfree(out.pointer);
If obj->type is not ACPI_TYPE_INTEGER then we have a memory leak here, so please always free obj.
Also you will dereference a NULL pointer if out_data is NULL, please check this.
Thanks,
Armin Wolf
> + }
> +
> + return 0;
> +}
> +
> /*
> * Helpers used for zone control
> */
> @@ -454,46 +484,6 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> /*
> * Individual RGB zone control
> */
> -static int alienware_update_led(struct alienfx_priv *priv, u8 location)
> -{
> - int method_id;
> - acpi_status status;
> - char *guid;
> - struct acpi_buffer input;
> - struct legacy_led_args legacy_args;
> - struct wmax_led_args wmax_basic_args;
> - if (interface == WMAX) {
> - wmax_basic_args.led_mask = 1 << location;
> - wmax_basic_args.colors = priv->colors[location];
> - wmax_basic_args.state = priv->lighting_control_state;
> - guid = WMAX_CONTROL_GUID;
> - method_id = WMAX_METHOD_ZONE_CONTROL;
> -
> - input.length = sizeof(wmax_basic_args);
> - input.pointer = &wmax_basic_args;
> - } else {
> - legacy_args.colors = priv->colors[location];
> - legacy_args.brightness = priv->global_brightness;
> - legacy_args.state = 0;
> - if (priv->lighting_control_state == LEGACY_BOOTING ||
> - priv->lighting_control_state == LEGACY_SUSPEND) {
> - guid = LEGACY_POWER_CONTROL_GUID;
> - legacy_args.state = priv->lighting_control_state;
> - } else
> - guid = LEGACY_CONTROL_GUID;
> - method_id = location + 1;
> -
> - input.length = sizeof(legacy_args);
> - input.pointer = &legacy_args;
> - }
> - pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id);
> -
> - status = wmi_evaluate_method(guid, 0, method_id, &input, NULL);
> - if (ACPI_FAILURE(status))
> - pr_err("alienware-wmi: zone set failure: %u\n", status);
> - return ACPI_FAILURE(status);
> -}
> -
> static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> char *buf, u8 location)
> {
> @@ -510,13 +500,14 @@ static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> {
> struct alienfx_priv *priv = dev_get_drvdata(dev);
> struct color_platform *colors = &priv->colors[location];
> + struct alienfx_platdata *pdata = dev_get_platdata(dev);
> int ret;
>
> ret = parse_rgb(buf, colors);
> if (ret)
> return ret;
>
> - ret = alienware_update_led(priv, location);
> + ret = pdata->ops.upd_led(priv, pdata->wdev, location);
>
> return ret ? ret : count;
> }
> @@ -649,36 +640,17 @@ static struct attribute_group zone_attribute_group = {
> /*
> * LED Brightness (Global)
> */
> -static int wmax_brightness(int brightness)
> -{
> - acpi_status status;
> - struct acpi_buffer input;
> - struct wmax_brightness_args args = {
> - .led_mask = 0xFF,
> - .percentage = brightness,
> - };
> - input.length = sizeof(args);
> - input.pointer = &args;
> - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
> - WMAX_METHOD_BRIGHTNESS, &input, NULL);
> - if (ACPI_FAILURE(status))
> - pr_err("alienware-wmi: brightness set failure: %u\n", status);
> - return ACPI_FAILURE(status);
> -}
> -
> static void global_led_set(struct led_classdev *led_cdev,
> enum led_brightness brightness)
> {
> struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> global_led);
> + struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev);
> int ret;
>
> priv->global_brightness = brightness;
>
> - if (interface == WMAX)
> - ret = wmax_brightness(brightness);
> - else
> - ret = alienware_update_led(priv, 0);
> + ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness);
> if (ret)
> pr_err("LED brightness update failed\n");
> }
> @@ -1247,10 +1219,49 @@ static void alienware_alienfx_exit(struct wmi_device *wdev)
> /*
> * 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);
> @@ -1290,10 +1301,39 @@ static void __exit alienware_legacy_wmi_exit(void)
> /*
> * 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;
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 13/20] alienware-wmi: Split DMI table
2024-12-29 19:45 ` [PATCH v2 13/20] alienware-wmi: Split DMI table Kurt Borja
@ 2025-01-02 16:36 ` Armin Wolf
2025-01-02 19:37 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:36 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:45 schrieb Kurt Borja:
> Split thermal features into a new DMI table to support upcoming file
> split. While at it rename quirk_entry -> alienfx_features and change
> hdmi_mux, amplifier and deepslp types to bool, because they are already
> being implicitly used as bools.
>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/alienware-wmi.c | 319 ++++++++++------------
> 1 file changed, 147 insertions(+), 172 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> index f80e7d488b9d..b9daf22efdbe 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.c
> +++ b/drivers/platform/x86/dell/alienware-wmi.c
> @@ -113,97 +113,63 @@ static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_
> [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
> };
>
> -struct quirk_entry {
> +struct alienfx_quirks {
> u8 num_zones;
> - u8 hdmi_mux;
> - u8 amplifier;
> - u8 deepslp;
> - bool thermal;
> - bool gmode;
> + bool hdmi_mux;
> + bool amplifier;
> + bool deepslp;
> };
>
> -static struct quirk_entry *quirks;
> +static struct alienfx_quirks *quirks;
>
>
> -static struct quirk_entry quirk_inspiron5675 = {
> +static struct alienfx_quirks quirk_inspiron5675 = {
> .num_zones = 2,
> - .hdmi_mux = 0,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = false,
> - .gmode = false,
> + .hdmi_mux = false,
> + .amplifier = false,
> + .deepslp = false,
> };
>
> -static struct quirk_entry quirk_unknown = {
> +static struct alienfx_quirks quirk_unknown = {
> .num_zones = 2,
> - .hdmi_mux = 0,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = false,
> - .gmode = false,
> + .hdmi_mux = false,
> + .amplifier = false,
> + .deepslp = false,
> };
>
> -static struct quirk_entry quirk_x51_r1_r2 = {
> +static struct alienfx_quirks quirk_x51_r1_r2 = {
> .num_zones = 3,
> - .hdmi_mux = 0,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = false,
> - .gmode = false,
> + .hdmi_mux = false,
> + .amplifier = false,
> + .deepslp = false,
> };
>
> -static struct quirk_entry quirk_x51_r3 = {
> +static struct alienfx_quirks quirk_x51_r3 = {
> .num_zones = 4,
> - .hdmi_mux = 0,
> - .amplifier = 1,
> - .deepslp = 0,
> - .thermal = false,
> - .gmode = false,
> -};
> -
> -static struct quirk_entry quirk_asm100 = {
> - .num_zones = 2,
> - .hdmi_mux = 1,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = false,
> - .gmode = false,
> -};
> -
> -static struct quirk_entry quirk_asm200 = {
> - .num_zones = 2,
> - .hdmi_mux = 1,
> - .amplifier = 0,
> - .deepslp = 1,
> - .thermal = false,
> - .gmode = false,
> + .hdmi_mux = false,
> + .amplifier = true,
> + .deepslp = false,
> };
>
> -static struct quirk_entry quirk_asm201 = {
> +static struct alienfx_quirks quirk_asm100 = {
> .num_zones = 2,
> - .hdmi_mux = 1,
> - .amplifier = 1,
> - .deepslp = 1,
> - .thermal = false,
> - .gmode = false,
> + .hdmi_mux = true,
> + .amplifier = false,
> + .deepslp = false,
> };
>
> -static struct quirk_entry quirk_g_series = {
> +static struct alienfx_quirks quirk_asm200 = {
> .num_zones = 2,
> - .hdmi_mux = 0,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = true,
> - .gmode = true,
> + .hdmi_mux = true,
> + .amplifier = false,
> + .deepslp = true,
> };
>
> -static struct quirk_entry quirk_x_series = {
> +static struct alienfx_quirks quirk_asm201 = {
> .num_zones = 2,
> - .hdmi_mux = 0,
> - .amplifier = 0,
> - .deepslp = 0,
> - .thermal = true,
> - .gmode = false,
> + .hdmi_mux = true,
> + .amplifier = true,
> + .deepslp = true,
> };
>
> static int __init dmi_matched(const struct dmi_system_id *dmi)
> @@ -240,42 +206,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
> },
> .driver_data = &quirk_asm201,
> },
> - {
> - .callback = dmi_matched,
> - .ident = "Alienware m17 R5",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
> - },
> - .driver_data = &quirk_x_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Alienware m18 R2",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
> - },
> - .driver_data = &quirk_x_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Alienware x15 R1",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
> - },
> - .driver_data = &quirk_x_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Alienware x17 R2",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
> - },
> - .driver_data = &quirk_x_series,
> - },
> {
> .callback = dmi_matched,
> .ident = "Alienware X51 R1",
> @@ -303,60 +233,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
> },
> .driver_data = &quirk_x51_r3,
> },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G15 5510",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G15 5511",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G15 5515",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G3 3500",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G3 3590",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> - {
> - .callback = dmi_matched,
> - .ident = "Dell Inc. G5 5500",
> - .matches = {
> - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> - DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
> - },
> - .driver_data = &quirk_g_series,
> - },
> {
> .callback = dmi_matched,
> .ident = "Dell Inc. Inspiron 5675",
> @@ -411,7 +287,7 @@ struct awcc_priv {
>
> struct alienfx_priv {
> struct platform_device *pdev;
> - struct quirk_entry *quirks;
> + struct alienfx_quirks *quirks;
> struct led_classdev global_led;
> struct color_platform colors[4];
> u8 global_brightness;
> @@ -432,6 +308,103 @@ struct alienfx_platdata {
>
> 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;
> +
> static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> void *in_args, size_t in_size, u32 *out_data)
> {
> @@ -1013,7 +986,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> {
> struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
>
> - if (quirks->gmode) {
> + if (awcc->gmode) {
> u32 gmode_status;
> int ret;
>
> @@ -1079,7 +1052,7 @@ static int create_thermal_profile(struct wmi_device *wdev)
> if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> return -ENODEV;
>
> - if (quirks->gmode) {
> + if (awcc->gmode) {
> priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> WMAX_THERMAL_MODE_GMODE;
>
> @@ -1319,7 +1292,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> struct platform_device *pdev;
> int ret;
>
> - if (quirks->thermal) {
> + if (awcc) {
> ret = alienware_awcc_setup(wdev);
> } else {
> ret = alienware_alienfx_setup(&pdata);
> @@ -1335,7 +1308,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
>
> static void wmax_wmi_remove(struct wmi_device *wdev)
> {
> - if (quirks->thermal)
> + if (awcc)
> alienware_awcc_exit(wdev);
> else
> alienware_alienfx_exit(wdev);
> @@ -1359,6 +1332,18 @@ static struct wmi_driver alienware_wmax_wmi_driver = {
>
> static 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;
Please add a check here if awcc is not NULL and keep "pr_warn("force_gmode requires platform profile support\n")"
if awcc is NULL.
Thanks,
Armin Wolf
> +
> return wmi_driver_register(&alienware_wmax_wmi_driver);
> }
>
> @@ -1375,16 +1360,6 @@ static int __init alienware_wmi_init(void)
> if (quirks == NULL)
> quirks = &quirk_unknown;
>
> - if (force_platform_profile)
> - quirks->thermal = true;
> -
> - if (force_gmode) {
> - if (quirks->thermal)
> - quirks->gmode = true;
> - else
> - pr_warn("force_gmode requires platform profile support\n");
> - }
> -
> if (wmi_has_guid(WMAX_CONTROL_GUID)) {
> interface = WMAX;
> ret = alienware_wmax_wmi_init();
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 16/20] platform/x86: Add alienware-wmi.h
2024-12-29 19:45 ` [PATCH v2 16/20] platform/x86: Add alienware-wmi.h Kurt Borja
@ 2025-01-02 16:43 ` Armin Wolf
0 siblings, 0 replies; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:43 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:45 schrieb Kurt Borja:
> Add a header file for alienware-wmi with shared resources to support the
> upcoming file split.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> .../platform/x86/dell/alienware-wmi-base.c | 68 +++-------------
> drivers/platform/x86/dell/alienware-wmi.h | 78 +++++++++++++++++++
> 2 files changed, 87 insertions(+), 59 deletions(-)
> create mode 100644 drivers/platform/x86/dell/alienware-wmi.h
>
> diff --git a/drivers/platform/x86/dell/alienware-wmi-base.c b/drivers/platform/x86/dell/alienware-wmi-base.c
> index b9daf22efdbe..a268193ad2a1 100644
> --- a/drivers/platform/x86/dell/alienware-wmi-base.c
> +++ b/drivers/platform/x86/dell/alienware-wmi-base.c
> @@ -16,10 +16,7 @@
> #include <linux/dmi.h>
> #include <linux/leds.h>
> #include <linux/wmi.h>
> -
> -#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
> -#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
> -#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
> +#include "alienware-wmi.h"
>
> #define WMAX_METHOD_HDMI_SOURCE 0x1
> #define WMAX_METHOD_HDMI_STATUS 0x2
> @@ -54,18 +51,6 @@ enum INTERFACE_FLAGS {
> WMAX,
> };
>
> -enum LEGACY_CONTROL_STATES {
> - LEGACY_RUNNING = 1,
> - LEGACY_BOOTING = 0,
> - LEGACY_SUSPEND = 3,
> -};
> -
> -enum WMAX_CONTROL_STATES {
> - WMAX_RUNNING = 0xFF,
> - WMAX_BOOTING = 0,
> - WMAX_SUSPEND = 3,
> -};
> -
> enum WMAX_THERMAL_INFORMATION_OPERATIONS {
> WMAX_OPERATION_SYS_DESCRIPTION = 0x02,
> WMAX_OPERATION_LIST_IDS = 0x03,
> @@ -113,16 +98,8 @@ static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_
> [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
> };
>
> -struct alienfx_quirks {
> - u8 num_zones;
> - bool hdmi_mux;
> - bool amplifier;
> - bool deepslp;
> -};
> -
> static struct alienfx_quirks *quirks;
>
> -
> static struct alienfx_quirks quirk_inspiron5675 = {
> .num_zones = 2,
> .hdmi_mux = false,
> @@ -245,12 +222,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
> {}
> };
>
> -struct color_platform {
> - u8 blue;
> - u8 green;
> - u8 red;
> -} __packed;
> -
> struct wmax_brightness_args {
> u32 led_mask;
> u32 percentage;
> @@ -285,27 +256,6 @@ struct awcc_priv {
> enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> };
>
> -struct alienfx_priv {
> - struct platform_device *pdev;
> - struct alienfx_quirks *quirks;
> - struct led_classdev global_led;
> - struct color_platform colors[4];
> - u8 global_brightness;
> - u8 lighting_control_state;
> -};
> -
> -struct alienfx_ops {
> - int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
> - u8 location);
> - int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
> - u8 brightness);
> -};
> -
> -struct alienfx_platdata {
> - struct wmi_device *wdev;
> - struct alienfx_ops ops;
> -};
> -
> static u8 interface;
>
> struct awcc_quirks {
> @@ -405,8 +355,8 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
>
> struct awcc_quirks *awcc;
>
> -static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> - void *in_args, size_t in_size, u32 *out_data)
> +int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> + void *in_args, size_t in_size, u32 *out_data)
> {
> struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
> struct acpi_buffer in = {in_size, in_args};
> @@ -1139,7 +1089,7 @@ static struct platform_driver platform_driver = {
> .probe = alienfx_probe,
> };
>
> -static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
> +int alienware_alienfx_setup(struct alienfx_platdata *pdata)
> {
> struct platform_device *pdev;
> int ret;
> @@ -1162,7 +1112,7 @@ static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
> return 0;
> }
>
> -static void alienware_alienfx_exit(struct wmi_device *wdev)
> +void alienware_alienfx_exit(struct wmi_device *wdev)
> {
> struct platform_device *pdev = dev_get_drvdata(&wdev->dev);
>
> @@ -1242,12 +1192,12 @@ static struct wmi_driver alienware_legacy_wmi_driver = {
> .remove = legacy_wmi_remove,
> };
>
> -static int __init alienware_legacy_wmi_init(void)
> +int __init alienware_legacy_wmi_init(void)
> {
> return wmi_driver_register(&alienware_legacy_wmi_driver);
> }
>
> -static void __exit alienware_legacy_wmi_exit(void)
> +void __exit alienware_legacy_wmi_exit(void)
> {
> wmi_driver_unregister(&alienware_legacy_wmi_driver);
> }
> @@ -1330,7 +1280,7 @@ static struct wmi_driver alienware_wmax_wmi_driver = {
> .remove = wmax_wmi_remove,
> };
>
> -static int __init alienware_wmax_wmi_init(void)
> +int __init alienware_wmax_wmi_init(void)
> {
> const struct dmi_system_id *id;
>
> @@ -1347,7 +1297,7 @@ static int __init alienware_wmax_wmi_init(void)
> return wmi_driver_register(&alienware_wmax_wmi_driver);
> }
>
> -static void __exit alienware_wmax_wmi_exit(void)
> +void __exit alienware_wmax_wmi_exit(void)
> {
> wmi_driver_unregister(&alienware_wmax_wmi_driver);
> }
> diff --git a/drivers/platform/x86/dell/alienware-wmi.h b/drivers/platform/x86/dell/alienware-wmi.h
> new file mode 100644
> index 000000000000..dccbf4f95da0
> --- /dev/null
> +++ b/drivers/platform/x86/dell/alienware-wmi.h
> @@ -0,0 +1,78 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Alienware WMI special features driver
> + *
> + * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
> + * Copyright (C) 2024 Kurt Borja <kuurtb@gmail.com>
> + */
> +
> +#ifndef _ALIENWARE_WMI_H_
> +#define _ALIENWARE_WMI_H_
> +
> +#include <linux/leds.h>
> +#include <linux/platform_device.h>
> +#include <linux/wmi.h>
> +
> +#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
> +#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
> +#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
> +
> +enum LEGACY_CONTROL_STATES {
> + LEGACY_RUNNING = 1,
> + LEGACY_BOOTING = 0,
> + LEGACY_SUSPEND = 3,
> +};
> +
> +enum WMAX_CONTROL_STATES {
> + WMAX_RUNNING = 0xFF,
> + WMAX_BOOTING = 0,
> + WMAX_SUSPEND = 3,
> +};
> +
> +struct alienfx_quirks {
> + u8 num_zones;
> + bool hdmi_mux;
> + bool amplifier;
> + bool deepslp;
> +};
> +
> +struct color_platform {
> + u8 blue;
> + u8 green;
> + u8 red;
> +} __packed;
> +
> +struct alienfx_priv {
> + struct platform_device *pdev;
> + struct alienfx_quirks *quirks;
> + struct led_classdev global_led;
> + struct color_platform colors[4];
> + u8 global_brightness;
> + u8 lighting_control_state;
> +};
> +
> +struct alienfx_ops {
> + int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
> + u8 location);
> + int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
> + u8 brightness);
> +};
> +
> +struct alienfx_platdata {
> + struct wmi_device *wdev;
> + struct alienfx_ops ops;
> +};
> +
> +int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> + void *in_args, size_t in_size, u32 *out_data);
> +
> +int alienware_alienfx_setup(struct alienfx_platdata *pdata);
> +void alienware_alienfx_exit(struct wmi_device *wdev);
> +
> +int __init alienware_legacy_wmi_init(void);
> +void __exit alienware_legacy_wmi_exit(void);
> +
> +int __init alienware_wmax_wmi_init(void);
> +void __exit alienware_wmax_wmi_exit(void);
> +
> +#endif
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver
2024-12-29 19:45 ` [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver Kurt Borja
@ 2025-01-02 16:49 ` Armin Wolf
0 siblings, 0 replies; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:49 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
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@gmx.de>
> Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> Signed-off-by: Kurt Borja <kuurtb@gmail.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@outlook.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,
> - &lifier_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@gmail.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@gmail.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,
> + &lifier_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);
> +}
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries
2024-12-29 19:45 ` [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries Kurt Borja
@ 2025-01-02 16:57 ` Armin Wolf
0 siblings, 0 replies; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 16:57 UTC (permalink / raw)
To: Kurt Borja, platform-driver-x86
Cc: Dell.Client.Kernel, hdegoede, ilpo.jarvinen, linux-kernel,
mario.limonciello
Am 29.12.24 um 20:45 schrieb Kurt Borja:
> Add config entries for each WMI driver managed by the alienware-wmi
> module to be able to conditionally compile them.
Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> ---
> drivers/platform/x86/dell/Kconfig | 30 +++++++++++++++++++----
> drivers/platform/x86/dell/Makefile | 4 +--
> drivers/platform/x86/dell/alienware-wmi.h | 23 +++++++++++++++++
> 3 files changed, 50 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
> index d09060aedd3f..f8a0dffcaab7 100644
> --- a/drivers/platform/x86/dell/Kconfig
> +++ b/drivers/platform/x86/dell/Kconfig
> @@ -18,15 +18,35 @@ config ALIENWARE_WMI
> tristate "Alienware Special feature control"
> default m
> depends on ACPI
> + depends on ACPI_WMI
> + depends on DMI
> depends on LEDS_CLASS
> depends on NEW_LEDS
> - depends on ACPI_WMI
> + help
> + This is a driver for controlling Alienware WMI driven features.
> +
> + On legacy devices, it exposes an interface for controlling the AlienFX
> + zones on Alienware machines that don't contain a dedicated
> + AlienFX USB MCU such as the X51 and X51-R2.
> +
> + On newer devices, it exposes the AWCC thermal control interface through
> + known Kernel APIs.
> +
> +config ALIENWARE_WMI_LEGACY
> + bool "Alienware Legacy WMI device driver"
> + default y
> + depends on ALIENWARE_WMI
> + help
> + Legacy Alienware WMI driver with AlienFX LED control capabilities.
> +
> +config ALIENWARE_WMI_WMAX
> + bool "Alienware WMAX WMI device driver"
> + default y
> + depends on ALIENWARE_WMI
> select ACPI_PLATFORM_PROFILE
> help
> - This is a driver for controlling Alienware BIOS driven
> - features. It exposes an interface for controlling the AlienFX
> - zones on Alienware machines that don't contain a dedicated AlienFX
> - USB MCU such as the X51 and X51-R2.
> + Alienware WMI driver with AlienFX LED, HDMI, amplifier, deep sleep and
> + AWCC thermal control capabilities.
>
> config DCDBAS
> tristate "Dell Systems Management Base Driver"
> diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile
> index d5718ef34c48..8ac9a933c770 100644
> --- a/drivers/platform/x86/dell/Makefile
> +++ b/drivers/platform/x86/dell/Makefile
> @@ -6,8 +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
> +alienware-wmi-$(CONFIG_ALIENWARE_WMI_LEGACY) += alienware-wmi-legacy.o
> +alienware-wmi-$(CONFIG_ALIENWARE_WMI_WMAX) += 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.h b/drivers/platform/x86/dell/alienware-wmi.h
> index dccbf4f95da0..ae3731f2fef2 100644
> --- a/drivers/platform/x86/dell/alienware-wmi.h
> +++ b/drivers/platform/x86/dell/alienware-wmi.h
> @@ -69,10 +69,33 @@ int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> int alienware_alienfx_setup(struct alienfx_platdata *pdata);
> void alienware_alienfx_exit(struct wmi_device *wdev);
>
> +#if IS_ENABLED(CONFIG_ALIENWARE_WMI_LEGACY)
> int __init alienware_legacy_wmi_init(void);
> void __exit alienware_legacy_wmi_exit(void);
> +#else
> +static inline int alienware_legacy_wmi_init(void)
> +{
> + return -ENODEV;
> +}
>
> +static inline void alienware_legacy_wmi_exit(void)
> +{
> +}
> +#endif
> +
> +#if IS_ENABLED(CONFIG_ALIENWARE_WMI_WMAX)
> int __init alienware_wmax_wmi_init(void);
> void __exit alienware_wmax_wmi_exit(void);
> +#else
> +static inline int alienware_wmax_wmi_init(void)
> +{
> + return -ENODEV;
> +}
> +
> +
> +static inline void alienware_wmax_wmi_exit(void)
> +{
> +}
> +#endif
>
> #endif
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 05/20] alienware-wmi: Improve rgb-zones group creation
2025-01-02 15:44 ` Armin Wolf
@ 2025-01-02 18:33 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 18:33 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 04:44:16PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Define zone_attrs statically and initialize zone_attribute_group with
> > platform driver's .dev_groups.
> >
> > Drop match_zone() and instead pass a `location` argument to previous
> > show/store methods to access the correct `zone` LED state. On top of
> > that rename zone_set() -> zone_store() to be more consistent with sysfs
> > conventions.
> >
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 209 +++++++++++-----------
> > 1 file changed, 102 insertions(+), 107 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index e010c94555e8..d97e5e15a8f2 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -376,12 +376,6 @@ struct color_platform {
> > u8 red;
> > } __packed;
> >
> > -struct platform_zone {
> > - u8 location;
> > - struct device_attribute *attr;
> > - struct color_platform colors;
> > -};
> > -
> > struct wmax_brightness_args {
> > u32 led_mask;
> > u32 percentage;
> > @@ -411,16 +405,10 @@ struct wmax_u32_args {
> > };
> >
> > static struct platform_device *platform_device;
> > -static struct device_attribute *zone_dev_attrs;
> > -static struct attribute **zone_attrs;
> > -static struct platform_zone *zone_data;
> > +static struct color_platform colors[4];
> > static struct platform_profile_handler pp_handler;
> > static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> >
> > -static struct attribute_group zone_attribute_group = {
> > - .name = "rgb_zones",
> > -};
> > -
> > static u8 interface;
> > static u8 lighting_control_state;
> > static u8 global_brightness;
> > @@ -452,24 +440,10 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> > return 0;
> > }
> >
> > -static struct platform_zone *match_zone(struct device_attribute *attr)
> > -{
> > - u8 zone;
> > -
> > - for (zone = 0; zone < quirks->num_zones; zone++) {
> > - if ((struct device_attribute *)zone_data[zone].attr == attr) {
> > - pr_debug("alienware-wmi: matched zone location: %d\n",
> > - zone_data[zone].location);
> > - return &zone_data[zone];
> > - }
> > - }
> > - return NULL;
> > -}
> > -
> > /*
> > * Individual RGB zone control
> > */
> > -static int alienware_update_led(struct platform_zone *zone)
> > +static int alienware_update_led(u8 location)
> > {
> > int method_id;
> > acpi_status status;
> > @@ -478,8 +452,8 @@ static int alienware_update_led(struct platform_zone *zone)
> > struct legacy_led_args legacy_args;
> > struct wmax_led_args wmax_basic_args;
> > if (interface == WMAX) {
> > - wmax_basic_args.led_mask = 1 << zone->location;
> > - wmax_basic_args.colors = zone->colors;
> > + wmax_basic_args.led_mask = 1 << location;
> > + wmax_basic_args.colors = colors[location];
> > wmax_basic_args.state = lighting_control_state;
> > guid = WMAX_CONTROL_GUID;
> > method_id = WMAX_METHOD_ZONE_CONTROL;
> > @@ -487,7 +461,7 @@ static int alienware_update_led(struct platform_zone *zone)
> > input.length = sizeof(wmax_basic_args);
> > input.pointer = &wmax_basic_args;
> > } else {
> > - legacy_args.colors = zone->colors;
> > + legacy_args.colors = colors[location];
> > legacy_args.brightness = global_brightness;
> > legacy_args.state = 0;
> > if (lighting_control_state == LEGACY_BOOTING ||
> > @@ -496,7 +470,7 @@ static int alienware_update_led(struct platform_zone *zone)
> > legacy_args.state = lighting_control_state;
> > } else
> > guid = LEGACY_CONTROL_GUID;
> > - method_id = zone->location + 1;
> > + method_id = location + 1;
> >
> > input.length = sizeof(legacy_args);
> > input.pointer = &legacy_args;
> > @@ -510,35 +484,84 @@ static int alienware_update_led(struct platform_zone *zone)
> > }
> >
> > static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> > - char *buf)
> > + char *buf, u8 location)
> > {
> > - struct platform_zone *target_zone;
> > - target_zone = match_zone(attr);
> > - if (target_zone == NULL)
> > - return sprintf(buf, "red: -1, green: -1, blue: -1\n");
> > return sprintf(buf, "red: %d, green: %d, blue: %d\n",
> > - target_zone->colors.red,
> > - target_zone->colors.green, target_zone->colors.blue);
> > + colors[location].red, colors[location].green,
> > + colors[location].blue);
> >
> > }
> >
> > -static ssize_t zone_set(struct device *dev, struct device_attribute *attr,
> > - const char *buf, size_t count)
> > +static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> > + const char *buf, size_t count, u8 location)
> > {
> > - struct platform_zone *target_zone;
> > int ret;
> > - target_zone = match_zone(attr);
> > - if (target_zone == NULL) {
> > - pr_err("alienware-wmi: invalid target zone\n");
> > - return 1;
> > - }
> > - ret = parse_rgb(buf, &target_zone->colors);
> > +
> > + ret = parse_rgb(buf, &colors[location]);
> > if (ret)
> > return ret;
> > - ret = alienware_update_led(target_zone);
> > +
> > + ret = alienware_update_led(location);
> > +
> > return ret ? ret : count;
> > }
> >
> > +static ssize_t zone00_show(struct device *dev, struct device_attribute *attr,
> > + char *buf)
> > +{
> > + return zone_show(dev, attr, buf, 0);
> > +}
> > +
> > +static ssize_t zone00_store(struct device *dev, struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + return zone_store(dev, attr, buf, count, 0);
> > +}
> > +
> > +DEVICE_ATTR_RW(zone00);
> > +
> > +static ssize_t zone01_show(struct device *dev, struct device_attribute *attr,
> > + char *buf)
> > +{
> > + return zone_show(dev, attr, buf, 1);
> > +}
> > +
> > +static ssize_t zone01_store(struct device *dev, struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + return zone_store(dev, attr, buf, count, 1);
> > +}
> > +
> > +DEVICE_ATTR_RW(zone01);
> > +
> > +static ssize_t zone02_show(struct device *dev, struct device_attribute *attr,
> > + char *buf)
> > +{
> > + return zone_show(dev, attr, buf, 2);
> > +}
> > +
> > +static ssize_t zone02_store(struct device *dev, struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + return zone_store(dev, attr, buf, count, 2);
> > +}
> > +
> > +DEVICE_ATTR_RW(zone02);
> > +
> > +static ssize_t zone03_show(struct device *dev, struct device_attribute *attr,
> > + char *buf)
> > +{
> > + return zone_show(dev, attr, buf, 3);
> > +}
> > +
> > +static ssize_t zone03_store(struct device *dev, struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + return zone_store(dev, attr, buf, count, 3);
> > +}
> > +
> > +DEVICE_ATTR_RW(zone03);
> > +
> > /*
> > * Lighting control state device attribute (Global)
> > */
> > @@ -578,6 +601,33 @@ static ssize_t lighting_control_state_store(struct device *dev,
> >
> > static DEVICE_ATTR_RW(lighting_control_state);
> >
> > +static umode_t zone_attr_visible(struct kobject *kobj,
> > + struct attribute *attr, int n)
> > +{
> > + return n < quirks->num_zones + 1 ? 0644 : 0;
>
> Please return attr->mode here instead of 0644. I would also prefer if you use a traditional if statement here.
Sure!
>
> With this small issue being addressed:
>
> Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
> > +}
> > +
> > +static bool zone_group_visible(struct kobject *kobj)
> > +{
> > + return quirks->num_zones > 0;
> > +}
> > +DEFINE_SYSFS_GROUP_VISIBLE(zone);
> > +
> > +static struct attribute *zone_attrs[] = {
> > + &dev_attr_lighting_control_state.attr,
> > + &dev_attr_zone00.attr,
> > + &dev_attr_zone01.attr,
> > + &dev_attr_zone02.attr,
> > + &dev_attr_zone03.attr,
> > + NULL
> > +};
> > +
> > +static struct attribute_group zone_attribute_group = {
> > + .name = "rgb_zones",
> > + .is_visible = SYSFS_GROUP_VISIBLE(zone),
> > + .attrs = zone_attrs,
> > +};
> > +
> > /*
> > * LED Brightness (Global)
> > */
> > @@ -606,7 +656,7 @@ static void global_led_set(struct led_classdev *led_cdev,
> > if (interface == WMAX)
> > ret = wmax_brightness(brightness);
> > else
> > - ret = alienware_update_led(&zone_data[0]);
> > + ret = alienware_update_led(0);
> > if (ret)
> > pr_err("LED brightness update failed\n");
> > }
> > @@ -624,9 +674,6 @@ static struct led_classdev global_led = {
> >
> > static int alienware_zone_init(struct platform_device *dev)
> > {
> > - u8 zone;
> > - char *name;
> > -
> > if (interface == WMAX) {
> > lighting_control_state = WMAX_RUNNING;
> > } else if (interface == LEGACY) {
> > @@ -635,65 +682,12 @@ static int alienware_zone_init(struct platform_device *dev)
> > global_led.max_brightness = 0x0F;
> > global_brightness = global_led.max_brightness;
> >
> > - /*
> > - * - zone_dev_attrs num_zones + 1 is for individual zones and then
> > - * null terminated
> > - * - zone_attrs num_zones + 2 is for all attrs in zone_dev_attrs +
> > - * the lighting control + null terminated
> > - * - zone_data num_zones is for the distinct zones
> > - */
> > - zone_dev_attrs =
> > - kcalloc(quirks->num_zones + 1, sizeof(struct device_attribute),
> > - GFP_KERNEL);
> > - if (!zone_dev_attrs)
> > - return -ENOMEM;
> > -
> > - zone_attrs =
> > - kcalloc(quirks->num_zones + 2, sizeof(struct attribute *),
> > - GFP_KERNEL);
> > - if (!zone_attrs)
> > - return -ENOMEM;
> > -
> > - zone_data =
> > - kcalloc(quirks->num_zones, sizeof(struct platform_zone),
> > - GFP_KERNEL);
> > - if (!zone_data)
> > - return -ENOMEM;
> > -
> > - for (zone = 0; zone < quirks->num_zones; zone++) {
> > - name = kasprintf(GFP_KERNEL, "zone%02hhX", zone);
> > - if (name == NULL)
> > - return 1;
> > - sysfs_attr_init(&zone_dev_attrs[zone].attr);
> > - zone_dev_attrs[zone].attr.name = name;
> > - zone_dev_attrs[zone].attr.mode = 0644;
> > - zone_dev_attrs[zone].show = zone_show;
> > - zone_dev_attrs[zone].store = zone_set;
> > - zone_data[zone].location = zone;
> > - zone_attrs[zone] = &zone_dev_attrs[zone].attr;
> > - zone_data[zone].attr = &zone_dev_attrs[zone];
> > - }
> > - zone_attrs[quirks->num_zones] = &dev_attr_lighting_control_state.attr;
> > - zone_attribute_group.attrs = zone_attrs;
> > -
> > - led_classdev_register(&dev->dev, &global_led);
> > -
> > - return sysfs_create_group(&dev->dev.kobj, &zone_attribute_group);
> > + return led_classdev_register(&dev->dev, &global_led);
> > }
> >
> > static void alienware_zone_exit(struct platform_device *dev)
> > {
> > - u8 zone;
> > -
> > - sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group);
> > led_classdev_unregister(&global_led);
> > - if (zone_dev_attrs) {
> > - for (zone = 0; zone < quirks->num_zones; zone++)
> > - kfree(zone_dev_attrs[zone].attr.name);
> > - }
> > - kfree(zone_dev_attrs);
> > - kfree(zone_data);
> > - kfree(zone_attrs);
> > }
> >
> > static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> > @@ -1143,6 +1137,7 @@ static void remove_thermal_profile(void)
> > * Platform Driver
> > */
> > static const struct attribute_group *alienfx_groups[] = {
> > + &zone_attribute_group,
> > &hdmi_attribute_group,
> > &lifier_attribute_group,
> > &deepsleep_attribute_group,
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature
2025-01-02 16:07 ` Armin Wolf
@ 2025-01-02 18:45 ` Kurt Borja
2025-01-02 19:20 ` Armin Wolf
0 siblings, 1 reply; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 18:45 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 05:07:16PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Add a state container for the "alienware-wmi" platform device and
> > initialize it on the new alienfx_probe(). Migrate all LED control functions
> > to use this state container, as well as hdmi, amplifier, deepslp group
> > visibility methods, to support upcoming file split.
> >
> > Additionally move the led_classdev registration to the platform driver
> > probe and make it device managed.
> >
> > Drop alienware_zone_init() and alienware_zone_exit() because they are no
> > longer needed.
> >
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 135 +++++++++++++---------
> > 1 file changed, 79 insertions(+), 56 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index 2c17160473a6..88d4046ed45f 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -404,14 +404,20 @@ struct wmax_u32_args {
> > u8 arg3;
> > };
> >
> > +struct alienfx_priv {
> > + struct platform_device *pdev;
> > + struct quirk_entry *quirks;
> > + struct led_classdev global_led;
> > + struct color_platform colors[4];
> > + u8 global_brightness;
> > + u8 lighting_control_state;
> > +};
> > +
> > static struct platform_device *platform_device;
> > -static struct color_platform colors[4];
> > static struct platform_profile_handler pp_handler;
> > static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> >
> > static u8 interface;
> > -static u8 lighting_control_state;
> > -static u8 global_brightness;
> >
> > /*
> > * Helpers used for zone control
> > @@ -443,7 +449,7 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> > /*
> > * Individual RGB zone control
> > */
> > -static int alienware_update_led(u8 location)
> > +static int alienware_update_led(struct alienfx_priv *priv, u8 location)
> > {
> > int method_id;
> > acpi_status status;
> > @@ -453,21 +459,21 @@ static int alienware_update_led(u8 location)
> > struct wmax_led_args wmax_basic_args;
> > if (interface == WMAX) {
> > wmax_basic_args.led_mask = 1 << location;
> > - wmax_basic_args.colors = colors[location];
> > - wmax_basic_args.state = lighting_control_state;
> > + wmax_basic_args.colors = priv->colors[location];
> > + wmax_basic_args.state = priv->lighting_control_state;
> > guid = WMAX_CONTROL_GUID;
> > method_id = WMAX_METHOD_ZONE_CONTROL;
> >
> > input.length = sizeof(wmax_basic_args);
> > input.pointer = &wmax_basic_args;
> > } else {
> > - legacy_args.colors = colors[location];
> > - legacy_args.brightness = global_brightness;
> > + legacy_args.colors = priv->colors[location];
> > + legacy_args.brightness = priv->global_brightness;
> > legacy_args.state = 0;
> > - if (lighting_control_state == LEGACY_BOOTING ||
> > - lighting_control_state == LEGACY_SUSPEND) {
> > + if (priv->lighting_control_state == LEGACY_BOOTING ||
> > + priv->lighting_control_state == LEGACY_SUSPEND) {
> > guid = LEGACY_POWER_CONTROL_GUID;
> > - legacy_args.state = lighting_control_state;
> > + legacy_args.state = priv->lighting_control_state;
> > } else
> > guid = LEGACY_CONTROL_GUID;
> > method_id = location + 1;
> > @@ -486,22 +492,26 @@ static int alienware_update_led(u8 location)
> > static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> > char *buf, u8 location)
> > {
> > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > + struct color_platform *colors = &priv->colors[location];
> > +
> > return sprintf(buf, "red: %d, green: %d, blue: %d\n",
> > - colors[location].red, colors[location].green,
> > - colors[location].blue);
> > + colors->red, colors->green, colors->blue);
> >
> > }
> >
> > static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> > const char *buf, size_t count, u8 location)
> > {
> > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > + struct color_platform *colors = &priv->colors[location];
> > int ret;
> >
> > - ret = parse_rgb(buf, &colors[location]);
> > + ret = parse_rgb(buf, colors);
> > if (ret)
> > return ret;
> >
> > - ret = alienware_update_led(location);
> > + ret = alienware_update_led(priv, location);
> >
> > return ret ? ret : count;
> > }
> > @@ -569,9 +579,11 @@ static ssize_t lighting_control_state_show(struct device *dev,
> > struct device_attribute *attr,
> > char *buf)
> > {
> > - if (lighting_control_state == LEGACY_BOOTING)
> > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > +
> > + if (priv->lighting_control_state == LEGACY_BOOTING)
> > return sysfs_emit(buf, "[booting] running suspend\n");
> > - else if (lighting_control_state == LEGACY_SUSPEND)
> > + else if (priv->lighting_control_state == LEGACY_SUSPEND)
> > return sysfs_emit(buf, "booting running [suspend]\n");
> >
> > return sysfs_emit(buf, "booting [running] suspend\n");
> > @@ -581,6 +593,7 @@ static ssize_t lighting_control_state_store(struct device *dev,
> > struct device_attribute *attr,
> > const char *buf, size_t count)
> > {
> > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > u8 val;
> >
> > if (strcmp(buf, "booting\n") == 0)
> > @@ -592,9 +605,9 @@ static ssize_t lighting_control_state_store(struct device *dev,
> > else
> > val = WMAX_RUNNING;
> >
> > - lighting_control_state = val;
> > + priv->lighting_control_state = val;
> > pr_debug("alienware-wmi: updated control state to %d\n",
> > - lighting_control_state);
> > + priv->lighting_control_state);
> >
> > return count;
> > }
> > @@ -651,43 +664,26 @@ static int wmax_brightness(int brightness)
> > static void global_led_set(struct led_classdev *led_cdev,
> > enum led_brightness brightness)
> > {
> > + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> > + global_led);
> > int ret;
> > - global_brightness = brightness;
> > +
> > + priv->global_brightness = brightness;
> > +
> > if (interface == WMAX)
> > ret = wmax_brightness(brightness);
> > else
> > - ret = alienware_update_led(0);
> > + ret = alienware_update_led(priv, 0);
> > if (ret)
> > pr_err("LED brightness update failed\n");
> > }
> >
> > static enum led_brightness global_led_get(struct led_classdev *led_cdev)
> > {
> > - return global_brightness;
> > -}
> > -
> > -static struct led_classdev global_led = {
> > - .brightness_set = global_led_set,
> > - .brightness_get = global_led_get,
> > - .name = "alienware::global_brightness",
> > -};
> > + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> > + global_led);
> >
> > -static int alienware_zone_init(struct platform_device *dev)
> > -{
> > - if (interface == WMAX) {
> > - lighting_control_state = WMAX_RUNNING;
> > - } else if (interface == LEGACY) {
> > - lighting_control_state = LEGACY_RUNNING;
> > - }
> > - global_led.max_brightness = 0x0F;
> > - global_brightness = global_led.max_brightness;
> > -
> > - return led_classdev_register(&dev->dev, &global_led);
> > -}
> > -
> > -static void alienware_zone_exit(struct platform_device *dev)
> > -{
> > - led_classdev_unregister(&global_led);
> > + return priv->global_brightness;
> > }
> >
> > static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> > @@ -792,7 +788,9 @@ static DEVICE_ATTR_RW(source);
> >
> > static bool hdmi_group_visible(struct kobject *kobj)
> > {
> > - return quirks->hdmi_mux;
> > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > +
> > + return priv->quirks->hdmi_mux;
> > }
> > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
> >
> > @@ -838,7 +836,9 @@ static DEVICE_ATTR_RO(status);
> >
> > static bool amplifier_group_visible(struct kobject *kobj)
> > {
> > - return quirks->amplifier;
> > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > +
> > + return priv->quirks->amplifier;
> > }
> > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
> >
> > @@ -906,7 +906,9 @@ static DEVICE_ATTR_RW(deepsleep);
> >
> > static bool deepsleep_group_visible(struct kobject *kobj)
> > {
> > - return quirks->deepslp;
> > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > +
> > + return priv->quirks->deepslp;
> > }
> > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
> >
> > @@ -1133,6 +1135,33 @@ static void remove_thermal_profile(void)
> > /*
> > * Platform Driver
> > */
> > +static int alienfx_probe(struct platform_device *pdev)
> > +{
> > + struct alienfx_priv *priv;
> > +
> > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> > + if (!priv)
> > + return -ENOMEM;
> > +
> > + platform_set_drvdata(pdev, priv);
> > + priv->pdev = pdev;
> > + priv->quirks = quirks;
> > +
> > + if (interface == WMAX)
> > + priv->lighting_control_state = WMAX_RUNNING;
> > + else if (interface == LEGACY)
> > + priv->lighting_control_state = LEGACY_RUNNING;
> > +
> > + priv->global_led.name = "alienware::global_brightness";
> > + priv->global_led.brightness_set = global_led_set;
> > + priv->global_led.brightness_get = global_led_get;
> > + priv->global_led.max_brightness = 0x0F;
> > +
> > + priv->global_brightness = priv->global_led.max_brightness;
> > +
> > + return devm_led_classdev_register(&pdev->dev, &priv->global_led);
> > +}
> > +
> > static const struct attribute_group *alienfx_groups[] = {
> > &zone_attribute_group,
> > &hdmi_attribute_group,
> > @@ -1145,7 +1174,9 @@ static struct platform_driver platform_driver = {
> > .driver = {
> > .name = "alienware-wmi",
> > .dev_groups = alienfx_groups,
> > + .probe_type = PROBE_FORCE_SYNCHRONOUS,
>
> Can you please explain to me why this is exactly necessary?
Because I want to add wmax_alienfx_groups after the platform_device has
finished probing. I think it's not exactly "necessary" because those
methods only access `platdata` which is set before probing, but to me it
doesn't feel right to race with alienfx_probe().
I wanted to somehow mimic platform_create_bundle(), which I can't use
because that function needs to be called from an __init section.
If this is unnecessary I will drop it, otherwise I think it makes more
sense to move this to [8/20].
>
> Thanks,
> Armin Wolf
>
> > },
> > + .probe = alienfx_probe,
> > };
> >
> > static int __init alienware_wmi_init(void)
> > @@ -1193,15 +1224,8 @@ static int __init alienware_wmi_init(void)
> > goto fail_prep_thermal_profile;
> > }
> >
> > - ret = alienware_zone_init(platform_device);
> > - if (ret)
> > - goto fail_prep_zones;
> > -
> > return 0;
> >
> > -fail_prep_zones:
> > - alienware_zone_exit(platform_device);
> > - remove_thermal_profile();
> > fail_prep_thermal_profile:
> > platform_device_del(platform_device);
> > fail_platform_device2:
> > @@ -1216,7 +1240,6 @@ module_init(alienware_wmi_init);
> >
> > static void __exit alienware_wmi_exit(void)
> > {
> > - alienware_zone_exit(platform_device);
> > remove_thermal_profile();
> > platform_device_unregister(platform_device);
> > platform_driver_unregister(&platform_driver);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 08/20] alienware-wmi: Add WMI Drivers
2025-01-02 16:16 ` Armin Wolf
@ 2025-01-02 18:49 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 18:49 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 05:16:21PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Add WMI drivers for LEGACY and WMAX devices.
> >
> > This involves moving platform driver and device registration to a helper
> > function, which is now called from the driver's preferred WMI device
> > driver probe. However this is only done if !quirks->thermal because
> > newer WMAX interface doesn't support any of the features exposed by this
> > device.
> >
> > Only one driver is registered on module initialization to prevent
> > registering duplicate platform driver and device.
> >
> > Additionally, create_thermal_profile() now takes wmi_device * instead of
> > platform_device *.
> >
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 195 +++++++++++++++++-----
> > 1 file changed, 155 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index 88d4046ed45f..87a7997579c9 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -15,6 +15,7 @@
> > #include <linux/platform_profile.h>
> > #include <linux/dmi.h>
> > #include <linux/leds.h>
> > +#include <linux/wmi.h>
> >
> > #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
> > #define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
> > @@ -39,8 +40,6 @@
> > MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
> > MODULE_DESCRIPTION("Alienware special feature control");
> > MODULE_LICENSE("GPL");
> > -MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
> > -MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID);
> >
> > static bool force_platform_profile;
> > module_param_unsafe(force_platform_profile, bool, 0);
> > @@ -413,7 +412,10 @@ struct alienfx_priv {
> > u8 lighting_control_state;
> > };
> >
> > -static struct platform_device *platform_device;
> > +struct alienfx_platdata {
> > + struct wmi_device *wdev;
> > +};
> > +
> > static struct platform_profile_handler pp_handler;
> > static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> >
> > @@ -1072,7 +1074,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> > return wmax_thermal_control(supported_thermal_profiles[profile]);
> > }
> >
> > -static int create_thermal_profile(struct platform_device *platform_device)
> > +static int create_thermal_profile(struct wmi_device *wdev)
> > {
> > enum platform_profile_option profile;
> > enum wmax_thermal_mode mode;
> > @@ -1121,7 +1123,7 @@ static int create_thermal_profile(struct platform_device *platform_device)
> > pp_handler.profile_get = thermal_profile_get;
> > pp_handler.profile_set = thermal_profile_set;
> > pp_handler.name = "alienware-wmi";
> > - pp_handler.dev = &platform_device->dev;
> > + pp_handler.dev = &wdev->dev;
> >
> > return platform_profile_register(&pp_handler);
> > }
> > @@ -1164,6 +1166,10 @@ static int alienfx_probe(struct platform_device *pdev)
> >
> > static const struct attribute_group *alienfx_groups[] = {
> > &zone_attribute_group,
> > + NULL
> > +};
> > +
> > +static const struct attribute_group *wmax_alienfx_groups[] = {
> > &hdmi_attribute_group,
> > &lifier_attribute_group,
> > &deepsleep_attribute_group,
> > @@ -1179,19 +1185,143 @@ static struct platform_driver platform_driver = {
> > .probe = alienfx_probe,
> > };
> >
> > -static int __init alienware_wmi_init(void)
> > +static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
> > {
> > + struct platform_device *pdev;
> > int ret;
> >
> > - if (wmi_has_guid(LEGACY_CONTROL_GUID))
> > - interface = LEGACY;
> > - else if (wmi_has_guid(WMAX_CONTROL_GUID))
> > - interface = WMAX;
> > - else {
> > - pr_warn("alienware-wmi: No known WMI GUID found\n");
> > - return -ENODEV;
> > + ret = platform_driver_register(&platform_driver);
> > + if (ret < 0)
> > + return ret;
> > +
> > + pdev = platform_device_register_data(NULL, "alienware-wmi",
> > + PLATFORM_DEVID_NONE, pdata,
> > + sizeof(*pdata));
> > +
> > + if (IS_ERR(pdev)) {
> > + platform_driver_unregister(&platform_driver);
> > + return PTR_ERR(pdev);
> > + }
> > +
> > + dev_set_drvdata(&pdata->wdev->dev, pdev);
> > +
> > + return 0;
> > +}
> > +
> > +static void alienware_alienfx_exit(struct wmi_device *wdev)
> > +{
> > + struct platform_device *pdev = dev_get_drvdata(&wdev->dev);
> > +
> > + platform_device_unregister(pdev);
> > + platform_driver_unregister(&platform_driver);
> > +}
> > +
> > +/*
> > + * Legacy WMI driver
> > + */
> > +static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
> > +{
> > + struct alienfx_platdata pdata = {
> > + .wdev = wdev,
> > + };
> > +
> > + 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,
> > +};
> > +
> > +static int __init alienware_legacy_wmi_init(void)
> > +{
> > + return wmi_driver_register(&alienware_legacy_wmi_driver);
> > +}
> > +
> > +static void __exit alienware_legacy_wmi_exit(void)
> > +{
> > + wmi_driver_unregister(&alienware_legacy_wmi_driver);
> > +}
> > +
> > +/*
> > + * WMAX WMI driver
> > + */
> > +static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> > +{
> > + struct alienfx_platdata pdata = {
> > + .wdev = wdev,
> > + };
> > + struct platform_device *pdev;
> > + int ret;
> > +
> > + if (quirks->thermal) {
> > + ret = create_thermal_profile(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);
>
> If device_add_groups() fails you need to call alienware_alienfx_exit().
>
> > }
> >
> > + return ret;
> > +}
> > +
> > +static void wmax_wmi_remove(struct wmi_device *wdev)
> > +{
> > + if (quirks->thermal)
> > + remove_thermal_profile();
> > + else
> > + alienware_alienfx_exit(wdev);
>
> Missing call to device_remove_groups().
Thanks, I missed both of these comments!
>
> > +}
> > +
> > +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,
> > +};
> > +
> > +static int __init alienware_wmax_wmi_init(void)
> > +{
> > + return wmi_driver_register(&alienware_wmax_wmi_driver);
> > +}
> > +
> > +static void __exit alienware_wmax_wmi_exit(void)
> > +{
> > + wmi_driver_unregister(&alienware_wmax_wmi_driver);
> > +}
> > +
> > +static int __init alienware_wmi_init(void)
> > +{
> > + int ret;
> > +
> > dmi_check_system(alienware_quirks);
> > if (quirks == NULL)
> > quirks = &quirk_unknown;
> > @@ -1206,43 +1336,28 @@ static int __init alienware_wmi_init(void)
> > pr_warn("force_gmode requires platform profile support\n");
> > }
> >
> > - ret = platform_driver_register(&platform_driver);
> > - if (ret)
> > - goto fail_platform_driver;
> > - platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE);
> > - if (!platform_device) {
> > - ret = -ENOMEM;
> > - goto fail_platform_device1;
> > + if (wmi_has_guid(WMAX_CONTROL_GUID)) {
> > + interface = WMAX;
> > + ret = alienware_wmax_wmi_init();
> > + } else {
> > + interface = LEGACY;
> > + ret = alienware_legacy_wmi_init();
> > }
> > - ret = platform_device_add(platform_device);
> > - if (ret)
> > - goto fail_platform_device2;
> >
> > - if (quirks->thermal) {
> > - ret = create_thermal_profile(platform_device);
> > - if (ret)
> > - goto fail_prep_thermal_profile;
> > - }
> > + if (ret < 0)
> > + return ret;
> >
> > return 0;
>
> Please just return ret here.
>
> Thanks,
> Armin Wolf
>
> > -
> > -fail_prep_thermal_profile:
> > - platform_device_del(platform_device);
> > -fail_platform_device2:
> > - platform_device_put(platform_device);
> > -fail_platform_device1:
> > - platform_driver_unregister(&platform_driver);
> > -fail_platform_driver:
> > - return ret;
> > }
> >
> > module_init(alienware_wmi_init);
> >
> > static void __exit alienware_wmi_exit(void)
> > {
> > - remove_thermal_profile();
> > - platform_device_unregister(platform_device);
> > - platform_driver_unregister(&platform_driver);
> > + if (interface == WMAX)
> > + alienware_wmax_wmi_exit();
> > + else
> > + alienware_legacy_wmi_exit();
> > }
> >
> > module_exit(alienware_wmi_exit);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods
2025-01-02 16:19 ` Armin Wolf
@ 2025-01-02 18:52 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 18:52 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 05:19:45PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Refactor all thermal control methods to use the newly defined awcc_priv
> > state container instead of global variables.
> >
> > Reviewed-by: Armin Wolf <W_Armin@gmx.de>
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 66 ++++++++++++++++-------
> > 1 file changed, 47 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index 87a7997579c9..512384635c4c 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -403,6 +403,12 @@ struct wmax_u32_args {
> > 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];
> > +};
> > +
> > struct alienfx_priv {
> > struct platform_device *pdev;
> > struct quirk_entry *quirks;
> > @@ -416,9 +422,6 @@ struct alienfx_platdata {
> > struct wmi_device *wdev;
> > };
> >
> > -static struct platform_profile_handler pp_handler;
> > -static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> > -
> > static u8 interface;
> >
> > /*
> > @@ -1051,6 +1054,8 @@ static int thermal_profile_get(struct platform_profile_handler *pprof,
> > 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 (quirks->gmode) {
> > u32 gmode_status;
> > int ret;
> > @@ -1071,11 +1076,12 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> > }
> > }
> >
> > - return wmax_thermal_control(supported_thermal_profiles[profile]);
> > + return wmax_thermal_control(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];
> > @@ -1105,33 +1111,55 @@ static int create_thermal_profile(struct wmi_device *wdev)
> >
> > mode = out_data & WMAX_THERMAL_MODE_MASK;
> > profile = wmax_mode_to_platform_profile[mode];
> > - supported_thermal_profiles[profile] = out_data;
> > + priv->supported_thermal_profiles[profile] = out_data;
> >
> > - set_bit(profile, pp_handler.choices);
> > + set_bit(profile, priv->pp_handler.choices);
> > }
> >
> > - if (bitmap_empty(pp_handler.choices, PLATFORM_PROFILE_LAST))
> > + if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> > return -ENODEV;
> >
> > if (quirks->gmode) {
> > - supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> > + priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> > WMAX_THERMAL_MODE_GMODE;
> >
> > - set_bit(PLATFORM_PROFILE_PERFORMANCE, pp_handler.choices);
> > + set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->pp_handler.choices);
> > }
> >
> > - pp_handler.profile_get = thermal_profile_get;
> > - pp_handler.profile_set = thermal_profile_set;
> > - pp_handler.name = "alienware-wmi";
> > - pp_handler.dev = &wdev->dev;
> > + 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(&pp_handler);
> > + return platform_profile_register(&priv->pp_handler);
> > }
> >
> > -static void remove_thermal_profile(void)
> > +static int alienware_awcc_setup(struct wmi_device *wdev)
> > {
> > - if (quirks->thermal)
> > - platform_profile_remove(&pp_handler);
> > + 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;
>
> Please directly return the result of create_thermal_profile() here.
Sure!
>
> > +}
> > +
> > +static void alienware_awcc_exit(struct wmi_device *wdev)
> > +{
> > + struct awcc_priv *priv;
> > +
> > + priv = dev_get_drvdata(&wdev->dev);
>
> Please assign priv directly.
I will.
>
> With those minor issues being fixed:
>
> Reviewed-by: Armin Wolf <W_Armin@gmx.de>
>
> > +
> > + platform_profile_remove(&priv->pp_handler);
> > }
> >
> > /*
> > @@ -1271,7 +1299,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> > int ret;
> >
> > if (quirks->thermal) {
> > - ret = create_thermal_profile(wdev);
> > + ret = alienware_awcc_setup(wdev);
> > } else {
> > ret = alienware_alienfx_setup(&pdata);
> > if (ret < 0)
> > @@ -1287,7 +1315,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> > static void wmax_wmi_remove(struct wmi_device *wdev)
> > {
> > if (quirks->thermal)
> > - remove_thermal_profile();
> > + alienware_awcc_exit(wdev);
> > else
> > alienware_alienfx_exit(wdev);
> > }
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature
2025-01-02 18:45 ` Kurt Borja
@ 2025-01-02 19:20 ` Armin Wolf
2025-01-02 19:40 ` Kurt Borja
0 siblings, 1 reply; 41+ messages in thread
From: Armin Wolf @ 2025-01-02 19:20 UTC (permalink / raw)
To: Kurt Borja
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
Am 02.01.25 um 19:45 schrieb Kurt Borja:
> On Thu, Jan 02, 2025 at 05:07:16PM +0100, Armin Wolf wrote:
>> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>>
>>> Add a state container for the "alienware-wmi" platform device and
>>> initialize it on the new alienfx_probe(). Migrate all LED control functions
>>> to use this state container, as well as hdmi, amplifier, deepslp group
>>> visibility methods, to support upcoming file split.
>>>
>>> Additionally move the led_classdev registration to the platform driver
>>> probe and make it device managed.
>>>
>>> Drop alienware_zone_init() and alienware_zone_exit() because they are no
>>> longer needed.
>>>
>>> Signed-off-by: Kurt Borja <kuurtb@gmail.com>
>>> ---
>>> drivers/platform/x86/dell/alienware-wmi.c | 135 +++++++++++++---------
>>> 1 file changed, 79 insertions(+), 56 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
>>> index 2c17160473a6..88d4046ed45f 100644
>>> --- a/drivers/platform/x86/dell/alienware-wmi.c
>>> +++ b/drivers/platform/x86/dell/alienware-wmi.c
>>> @@ -404,14 +404,20 @@ struct wmax_u32_args {
>>> u8 arg3;
>>> };
>>>
>>> +struct alienfx_priv {
>>> + struct platform_device *pdev;
>>> + struct quirk_entry *quirks;
>>> + struct led_classdev global_led;
>>> + struct color_platform colors[4];
>>> + u8 global_brightness;
>>> + u8 lighting_control_state;
>>> +};
>>> +
>>> static struct platform_device *platform_device;
>>> -static struct color_platform colors[4];
>>> static struct platform_profile_handler pp_handler;
>>> static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
>>>
>>> static u8 interface;
>>> -static u8 lighting_control_state;
>>> -static u8 global_brightness;
>>>
>>> /*
>>> * Helpers used for zone control
>>> @@ -443,7 +449,7 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
>>> /*
>>> * Individual RGB zone control
>>> */
>>> -static int alienware_update_led(u8 location)
>>> +static int alienware_update_led(struct alienfx_priv *priv, u8 location)
>>> {
>>> int method_id;
>>> acpi_status status;
>>> @@ -453,21 +459,21 @@ static int alienware_update_led(u8 location)
>>> struct wmax_led_args wmax_basic_args;
>>> if (interface == WMAX) {
>>> wmax_basic_args.led_mask = 1 << location;
>>> - wmax_basic_args.colors = colors[location];
>>> - wmax_basic_args.state = lighting_control_state;
>>> + wmax_basic_args.colors = priv->colors[location];
>>> + wmax_basic_args.state = priv->lighting_control_state;
>>> guid = WMAX_CONTROL_GUID;
>>> method_id = WMAX_METHOD_ZONE_CONTROL;
>>>
>>> input.length = sizeof(wmax_basic_args);
>>> input.pointer = &wmax_basic_args;
>>> } else {
>>> - legacy_args.colors = colors[location];
>>> - legacy_args.brightness = global_brightness;
>>> + legacy_args.colors = priv->colors[location];
>>> + legacy_args.brightness = priv->global_brightness;
>>> legacy_args.state = 0;
>>> - if (lighting_control_state == LEGACY_BOOTING ||
>>> - lighting_control_state == LEGACY_SUSPEND) {
>>> + if (priv->lighting_control_state == LEGACY_BOOTING ||
>>> + priv->lighting_control_state == LEGACY_SUSPEND) {
>>> guid = LEGACY_POWER_CONTROL_GUID;
>>> - legacy_args.state = lighting_control_state;
>>> + legacy_args.state = priv->lighting_control_state;
>>> } else
>>> guid = LEGACY_CONTROL_GUID;
>>> method_id = location + 1;
>>> @@ -486,22 +492,26 @@ static int alienware_update_led(u8 location)
>>> static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
>>> char *buf, u8 location)
>>> {
>>> + struct alienfx_priv *priv = dev_get_drvdata(dev);
>>> + struct color_platform *colors = &priv->colors[location];
>>> +
>>> return sprintf(buf, "red: %d, green: %d, blue: %d\n",
>>> - colors[location].red, colors[location].green,
>>> - colors[location].blue);
>>> + colors->red, colors->green, colors->blue);
>>>
>>> }
>>>
>>> static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
>>> const char *buf, size_t count, u8 location)
>>> {
>>> + struct alienfx_priv *priv = dev_get_drvdata(dev);
>>> + struct color_platform *colors = &priv->colors[location];
>>> int ret;
>>>
>>> - ret = parse_rgb(buf, &colors[location]);
>>> + ret = parse_rgb(buf, colors);
>>> if (ret)
>>> return ret;
>>>
>>> - ret = alienware_update_led(location);
>>> + ret = alienware_update_led(priv, location);
>>>
>>> return ret ? ret : count;
>>> }
>>> @@ -569,9 +579,11 @@ static ssize_t lighting_control_state_show(struct device *dev,
>>> struct device_attribute *attr,
>>> char *buf)
>>> {
>>> - if (lighting_control_state == LEGACY_BOOTING)
>>> + struct alienfx_priv *priv = dev_get_drvdata(dev);
>>> +
>>> + if (priv->lighting_control_state == LEGACY_BOOTING)
>>> return sysfs_emit(buf, "[booting] running suspend\n");
>>> - else if (lighting_control_state == LEGACY_SUSPEND)
>>> + else if (priv->lighting_control_state == LEGACY_SUSPEND)
>>> return sysfs_emit(buf, "booting running [suspend]\n");
>>>
>>> return sysfs_emit(buf, "booting [running] suspend\n");
>>> @@ -581,6 +593,7 @@ static ssize_t lighting_control_state_store(struct device *dev,
>>> struct device_attribute *attr,
>>> const char *buf, size_t count)
>>> {
>>> + struct alienfx_priv *priv = dev_get_drvdata(dev);
>>> u8 val;
>>>
>>> if (strcmp(buf, "booting\n") == 0)
>>> @@ -592,9 +605,9 @@ static ssize_t lighting_control_state_store(struct device *dev,
>>> else
>>> val = WMAX_RUNNING;
>>>
>>> - lighting_control_state = val;
>>> + priv->lighting_control_state = val;
>>> pr_debug("alienware-wmi: updated control state to %d\n",
>>> - lighting_control_state);
>>> + priv->lighting_control_state);
>>>
>>> return count;
>>> }
>>> @@ -651,43 +664,26 @@ static int wmax_brightness(int brightness)
>>> static void global_led_set(struct led_classdev *led_cdev,
>>> enum led_brightness brightness)
>>> {
>>> + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
>>> + global_led);
>>> int ret;
>>> - global_brightness = brightness;
>>> +
>>> + priv->global_brightness = brightness;
>>> +
>>> if (interface == WMAX)
>>> ret = wmax_brightness(brightness);
>>> else
>>> - ret = alienware_update_led(0);
>>> + ret = alienware_update_led(priv, 0);
>>> if (ret)
>>> pr_err("LED brightness update failed\n");
>>> }
>>>
>>> static enum led_brightness global_led_get(struct led_classdev *led_cdev)
>>> {
>>> - return global_brightness;
>>> -}
>>> -
>>> -static struct led_classdev global_led = {
>>> - .brightness_set = global_led_set,
>>> - .brightness_get = global_led_get,
>>> - .name = "alienware::global_brightness",
>>> -};
>>> + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
>>> + global_led);
>>>
>>> -static int alienware_zone_init(struct platform_device *dev)
>>> -{
>>> - if (interface == WMAX) {
>>> - lighting_control_state = WMAX_RUNNING;
>>> - } else if (interface == LEGACY) {
>>> - lighting_control_state = LEGACY_RUNNING;
>>> - }
>>> - global_led.max_brightness = 0x0F;
>>> - global_brightness = global_led.max_brightness;
>>> -
>>> - return led_classdev_register(&dev->dev, &global_led);
>>> -}
>>> -
>>> -static void alienware_zone_exit(struct platform_device *dev)
>>> -{
>>> - led_classdev_unregister(&global_led);
>>> + return priv->global_brightness;
>>> }
>>>
>>> static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
>>> @@ -792,7 +788,9 @@ static DEVICE_ATTR_RW(source);
>>>
>>> static bool hdmi_group_visible(struct kobject *kobj)
>>> {
>>> - return quirks->hdmi_mux;
>>> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
>>> +
>>> + return priv->quirks->hdmi_mux;
>>> }
>>> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
>>>
>>> @@ -838,7 +836,9 @@ static DEVICE_ATTR_RO(status);
>>>
>>> static bool amplifier_group_visible(struct kobject *kobj)
>>> {
>>> - return quirks->amplifier;
>>> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
>>> +
>>> + return priv->quirks->amplifier;
>>> }
>>> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
>>>
>>> @@ -906,7 +906,9 @@ static DEVICE_ATTR_RW(deepsleep);
>>>
>>> static bool deepsleep_group_visible(struct kobject *kobj)
>>> {
>>> - return quirks->deepslp;
>>> + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
>>> +
>>> + return priv->quirks->deepslp;
>>> }
>>> DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
>>>
>>> @@ -1133,6 +1135,33 @@ static void remove_thermal_profile(void)
>>> /*
>>> * Platform Driver
>>> */
>>> +static int alienfx_probe(struct platform_device *pdev)
>>> +{
>>> + struct alienfx_priv *priv;
>>> +
>>> + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
>>> + if (!priv)
>>> + return -ENOMEM;
>>> +
>>> + platform_set_drvdata(pdev, priv);
>>> + priv->pdev = pdev;
>>> + priv->quirks = quirks;
>>> +
>>> + if (interface == WMAX)
>>> + priv->lighting_control_state = WMAX_RUNNING;
>>> + else if (interface == LEGACY)
>>> + priv->lighting_control_state = LEGACY_RUNNING;
>>> +
>>> + priv->global_led.name = "alienware::global_brightness";
>>> + priv->global_led.brightness_set = global_led_set;
>>> + priv->global_led.brightness_get = global_led_get;
>>> + priv->global_led.max_brightness = 0x0F;
>>> +
>>> + priv->global_brightness = priv->global_led.max_brightness;
>>> +
>>> + return devm_led_classdev_register(&pdev->dev, &priv->global_led);
>>> +}
>>> +
>>> static const struct attribute_group *alienfx_groups[] = {
>>> &zone_attribute_group,
>>> &hdmi_attribute_group,
>>> @@ -1145,7 +1174,9 @@ static struct platform_driver platform_driver = {
>>> .driver = {
>>> .name = "alienware-wmi",
>>> .dev_groups = alienfx_groups,
>>> + .probe_type = PROBE_FORCE_SYNCHRONOUS,
>> Can you please explain to me why this is exactly necessary?
> Because I want to add wmax_alienfx_groups after the platform_device has
> finished probing. I think it's not exactly "necessary" because those
> methods only access `platdata` which is set before probing, but to me it
> doesn't feel right to race with alienfx_probe().
>
> I wanted to somehow mimic platform_create_bundle(), which I can't use
> because that function needs to be called from an __init section.
>
> If this is unnecessary I will drop it, otherwise I think it makes more
> sense to move this to [8/20].
>
I just saw that the *_is_visible() callbacks use alienfx_priv which is only available
after the driver has finished probing.
I would prefer if you make the quirk values available outside of alienware-wmi-base so
that those callbacks can access them without having to use alienfx_priv. This would allow
us to omit PROBE_FORCE_SYNCHRONOUS.
Thanks,
Armin Wolf
>> Thanks,
>> Armin Wolf
>>
>>> },
>>> + .probe = alienfx_probe,
>>> };
>>>
>>> static int __init alienware_wmi_init(void)
>>> @@ -1193,15 +1224,8 @@ static int __init alienware_wmi_init(void)
>>> goto fail_prep_thermal_profile;
>>> }
>>>
>>> - ret = alienware_zone_init(platform_device);
>>> - if (ret)
>>> - goto fail_prep_zones;
>>> -
>>> return 0;
>>>
>>> -fail_prep_zones:
>>> - alienware_zone_exit(platform_device);
>>> - remove_thermal_profile();
>>> fail_prep_thermal_profile:
>>> platform_device_del(platform_device);
>>> fail_platform_device2:
>>> @@ -1216,7 +1240,6 @@ module_init(alienware_wmi_init);
>>>
>>> static void __exit alienware_wmi_exit(void)
>>> {
>>> - alienware_zone_exit(platform_device);
>>> remove_thermal_profile();
>>> platform_device_unregister(platform_device);
>>> platform_driver_unregister(&platform_driver);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 10/20] alienware-wmi: Refactor LED control methods
2025-01-02 16:29 ` Armin Wolf
@ 2025-01-02 19:36 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 19:36 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 05:29:42PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Both WMI devices handled by this module specify a distinct interface for
> > LED control. Previously this module handled this by dynamically adapting
> > arguments passed to wmi_evaluate_method() based on the `interface`
> > global variable.
> >
> > To avoid the use of global variables, and enable the migration to
> > non-deprecated WMI methods, let the WMI drivers define upd_led and
> > upd_brightness operations, which completely replace
> > alienware_update_led() and wmax_brightness().
> >
> > Also define alienware_wmi_command(), which serves as a wrapper for
> > wmidev_evaluate_method(). This new method is very similar to
> > alienware_wmax_command() but is WMI device agnostic.
> >
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 164 ++++++++++++++--------
> > 1 file changed, 102 insertions(+), 62 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index 512384635c4c..494a3772065c 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -418,12 +418,42 @@ struct alienfx_priv {
> > u8 lighting_control_state;
> > };
> >
> > +struct alienfx_ops {
> > + int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
> > + u8 location);
> > + int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
> > + u8 brightness);
> > +};
> > +
> > struct alienfx_platdata {
> > struct wmi_device *wdev;
> > + struct alienfx_ops ops;
> > };
> >
> > static u8 interface;
> >
> > +static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> > + void *in_args, size_t in_size, u32 *out_data)
> > +{
> > + struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
> > + struct acpi_buffer in = {in_size, in_args};
> > + union acpi_object *obj;
> > + acpi_status ret;
> > +
> > + ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL);
> > + if (ACPI_FAILURE(ret))
> > + return -EIO;
> > +
> > + obj = out.pointer;
> > +
> > + if (obj && obj->type == ACPI_TYPE_INTEGER) {
> > + *out_data = (u32)obj->integer.value;
> > + kfree(out.pointer);
>
> If obj->type is not ACPI_TYPE_INTEGER then we have a memory leak here, so please always free obj.
> Also you will dereference a NULL pointer if out_data is NULL, please check this.
I was a bit careless when refactoring this method, I'll fix it.
>
> Thanks,
> Armin Wolf
>
> > + }
> > +
> > + return 0;
> > +}
> > +
> > /*
> > * Helpers used for zone control
> > */
> > @@ -454,46 +484,6 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> > /*
> > * Individual RGB zone control
> > */
> > -static int alienware_update_led(struct alienfx_priv *priv, u8 location)
> > -{
> > - int method_id;
> > - acpi_status status;
> > - char *guid;
> > - struct acpi_buffer input;
> > - struct legacy_led_args legacy_args;
> > - struct wmax_led_args wmax_basic_args;
> > - if (interface == WMAX) {
> > - wmax_basic_args.led_mask = 1 << location;
> > - wmax_basic_args.colors = priv->colors[location];
> > - wmax_basic_args.state = priv->lighting_control_state;
> > - guid = WMAX_CONTROL_GUID;
> > - method_id = WMAX_METHOD_ZONE_CONTROL;
> > -
> > - input.length = sizeof(wmax_basic_args);
> > - input.pointer = &wmax_basic_args;
> > - } else {
> > - legacy_args.colors = priv->colors[location];
> > - legacy_args.brightness = priv->global_brightness;
> > - legacy_args.state = 0;
> > - if (priv->lighting_control_state == LEGACY_BOOTING ||
> > - priv->lighting_control_state == LEGACY_SUSPEND) {
> > - guid = LEGACY_POWER_CONTROL_GUID;
> > - legacy_args.state = priv->lighting_control_state;
> > - } else
> > - guid = LEGACY_CONTROL_GUID;
> > - method_id = location + 1;
> > -
> > - input.length = sizeof(legacy_args);
> > - input.pointer = &legacy_args;
> > - }
> > - pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id);
> > -
> > - status = wmi_evaluate_method(guid, 0, method_id, &input, NULL);
> > - if (ACPI_FAILURE(status))
> > - pr_err("alienware-wmi: zone set failure: %u\n", status);
> > - return ACPI_FAILURE(status);
> > -}
> > -
> > static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> > char *buf, u8 location)
> > {
> > @@ -510,13 +500,14 @@ static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> > {
> > struct alienfx_priv *priv = dev_get_drvdata(dev);
> > struct color_platform *colors = &priv->colors[location];
> > + struct alienfx_platdata *pdata = dev_get_platdata(dev);
> > int ret;
> >
> > ret = parse_rgb(buf, colors);
> > if (ret)
> > return ret;
> >
> > - ret = alienware_update_led(priv, location);
> > + ret = pdata->ops.upd_led(priv, pdata->wdev, location);
> >
> > return ret ? ret : count;
> > }
> > @@ -649,36 +640,17 @@ static struct attribute_group zone_attribute_group = {
> > /*
> > * LED Brightness (Global)
> > */
> > -static int wmax_brightness(int brightness)
> > -{
> > - acpi_status status;
> > - struct acpi_buffer input;
> > - struct wmax_brightness_args args = {
> > - .led_mask = 0xFF,
> > - .percentage = brightness,
> > - };
> > - input.length = sizeof(args);
> > - input.pointer = &args;
> > - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0,
> > - WMAX_METHOD_BRIGHTNESS, &input, NULL);
> > - if (ACPI_FAILURE(status))
> > - pr_err("alienware-wmi: brightness set failure: %u\n", status);
> > - return ACPI_FAILURE(status);
> > -}
> > -
> > static void global_led_set(struct led_classdev *led_cdev,
> > enum led_brightness brightness)
> > {
> > struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> > global_led);
> > + struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev);
> > int ret;
> >
> > priv->global_brightness = brightness;
> >
> > - if (interface == WMAX)
> > - ret = wmax_brightness(brightness);
> > - else
> > - ret = alienware_update_led(priv, 0);
> > + ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness);
> > if (ret)
> > pr_err("LED brightness update failed\n");
> > }
> > @@ -1247,10 +1219,49 @@ static void alienware_alienfx_exit(struct wmi_device *wdev)
> > /*
> > * 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);
> > @@ -1290,10 +1301,39 @@ static void __exit alienware_legacy_wmi_exit(void)
> > /*
> > * 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;
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 13/20] alienware-wmi: Split DMI table
2025-01-02 16:36 ` Armin Wolf
@ 2025-01-02 19:37 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 19:37 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 05:36:32PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:45 schrieb Kurt Borja:
>
> > Split thermal features into a new DMI table to support upcoming file
> > split. While at it rename quirk_entry -> alienfx_features and change
> > hdmi_mux, amplifier and deepslp types to bool, because they are already
> > being implicitly used as bools.
> >
> > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > ---
> > drivers/platform/x86/dell/alienware-wmi.c | 319 ++++++++++------------
> > 1 file changed, 147 insertions(+), 172 deletions(-)
> >
> > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > index f80e7d488b9d..b9daf22efdbe 100644
> > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > @@ -113,97 +113,63 @@ static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_
> > [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
> > };
> >
> > -struct quirk_entry {
> > +struct alienfx_quirks {
> > u8 num_zones;
> > - u8 hdmi_mux;
> > - u8 amplifier;
> > - u8 deepslp;
> > - bool thermal;
> > - bool gmode;
> > + bool hdmi_mux;
> > + bool amplifier;
> > + bool deepslp;
> > };
> >
> > -static struct quirk_entry *quirks;
> > +static struct alienfx_quirks *quirks;
> >
> >
> > -static struct quirk_entry quirk_inspiron5675 = {
> > +static struct alienfx_quirks quirk_inspiron5675 = {
> > .num_zones = 2,
> > - .hdmi_mux = 0,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = false,
> > - .gmode = false,
> > + .hdmi_mux = false,
> > + .amplifier = false,
> > + .deepslp = false,
> > };
> >
> > -static struct quirk_entry quirk_unknown = {
> > +static struct alienfx_quirks quirk_unknown = {
> > .num_zones = 2,
> > - .hdmi_mux = 0,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = false,
> > - .gmode = false,
> > + .hdmi_mux = false,
> > + .amplifier = false,
> > + .deepslp = false,
> > };
> >
> > -static struct quirk_entry quirk_x51_r1_r2 = {
> > +static struct alienfx_quirks quirk_x51_r1_r2 = {
> > .num_zones = 3,
> > - .hdmi_mux = 0,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = false,
> > - .gmode = false,
> > + .hdmi_mux = false,
> > + .amplifier = false,
> > + .deepslp = false,
> > };
> >
> > -static struct quirk_entry quirk_x51_r3 = {
> > +static struct alienfx_quirks quirk_x51_r3 = {
> > .num_zones = 4,
> > - .hdmi_mux = 0,
> > - .amplifier = 1,
> > - .deepslp = 0,
> > - .thermal = false,
> > - .gmode = false,
> > -};
> > -
> > -static struct quirk_entry quirk_asm100 = {
> > - .num_zones = 2,
> > - .hdmi_mux = 1,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = false,
> > - .gmode = false,
> > -};
> > -
> > -static struct quirk_entry quirk_asm200 = {
> > - .num_zones = 2,
> > - .hdmi_mux = 1,
> > - .amplifier = 0,
> > - .deepslp = 1,
> > - .thermal = false,
> > - .gmode = false,
> > + .hdmi_mux = false,
> > + .amplifier = true,
> > + .deepslp = false,
> > };
> >
> > -static struct quirk_entry quirk_asm201 = {
> > +static struct alienfx_quirks quirk_asm100 = {
> > .num_zones = 2,
> > - .hdmi_mux = 1,
> > - .amplifier = 1,
> > - .deepslp = 1,
> > - .thermal = false,
> > - .gmode = false,
> > + .hdmi_mux = true,
> > + .amplifier = false,
> > + .deepslp = false,
> > };
> >
> > -static struct quirk_entry quirk_g_series = {
> > +static struct alienfx_quirks quirk_asm200 = {
> > .num_zones = 2,
> > - .hdmi_mux = 0,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = true,
> > - .gmode = true,
> > + .hdmi_mux = true,
> > + .amplifier = false,
> > + .deepslp = true,
> > };
> >
> > -static struct quirk_entry quirk_x_series = {
> > +static struct alienfx_quirks quirk_asm201 = {
> > .num_zones = 2,
> > - .hdmi_mux = 0,
> > - .amplifier = 0,
> > - .deepslp = 0,
> > - .thermal = true,
> > - .gmode = false,
> > + .hdmi_mux = true,
> > + .amplifier = true,
> > + .deepslp = true,
> > };
> >
> > static int __init dmi_matched(const struct dmi_system_id *dmi)
> > @@ -240,42 +206,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
> > },
> > .driver_data = &quirk_asm201,
> > },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Alienware m17 R5",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
> > - },
> > - .driver_data = &quirk_x_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Alienware m18 R2",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
> > - },
> > - .driver_data = &quirk_x_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Alienware x15 R1",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
> > - },
> > - .driver_data = &quirk_x_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Alienware x17 R2",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
> > - },
> > - .driver_data = &quirk_x_series,
> > - },
> > {
> > .callback = dmi_matched,
> > .ident = "Alienware X51 R1",
> > @@ -303,60 +233,6 @@ static const struct dmi_system_id alienware_quirks[] __initconst = {
> > },
> > .driver_data = &quirk_x51_r3,
> > },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G15 5510",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G15 5511",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G15 5515",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G3 3500",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G3 3590",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > - {
> > - .callback = dmi_matched,
> > - .ident = "Dell Inc. G5 5500",
> > - .matches = {
> > - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
> > - DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
> > - },
> > - .driver_data = &quirk_g_series,
> > - },
> > {
> > .callback = dmi_matched,
> > .ident = "Dell Inc. Inspiron 5675",
> > @@ -411,7 +287,7 @@ struct awcc_priv {
> >
> > struct alienfx_priv {
> > struct platform_device *pdev;
> > - struct quirk_entry *quirks;
> > + struct alienfx_quirks *quirks;
> > struct led_classdev global_led;
> > struct color_platform colors[4];
> > u8 global_brightness;
> > @@ -432,6 +308,103 @@ struct alienfx_platdata {
> >
> > 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;
> > +
> > static int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
> > void *in_args, size_t in_size, u32 *out_data)
> > {
> > @@ -1013,7 +986,7 @@ static int thermal_profile_set(struct platform_profile_handler *pprof,
> > {
> > struct awcc_priv *priv = container_of(pprof, struct awcc_priv, pp_handler);
> >
> > - if (quirks->gmode) {
> > + if (awcc->gmode) {
> > u32 gmode_status;
> > int ret;
> >
> > @@ -1079,7 +1052,7 @@ static int create_thermal_profile(struct wmi_device *wdev)
> > if (bitmap_empty(priv->pp_handler.choices, PLATFORM_PROFILE_LAST))
> > return -ENODEV;
> >
> > - if (quirks->gmode) {
> > + if (awcc->gmode) {
> > priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
> > WMAX_THERMAL_MODE_GMODE;
> >
> > @@ -1319,7 +1292,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> > struct platform_device *pdev;
> > int ret;
> >
> > - if (quirks->thermal) {
> > + if (awcc) {
> > ret = alienware_awcc_setup(wdev);
> > } else {
> > ret = alienware_alienfx_setup(&pdata);
> > @@ -1335,7 +1308,7 @@ static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
> >
> > static void wmax_wmi_remove(struct wmi_device *wdev)
> > {
> > - if (quirks->thermal)
> > + if (awcc)
> > alienware_awcc_exit(wdev);
> > else
> > alienware_alienfx_exit(wdev);
> > @@ -1359,6 +1332,18 @@ static struct wmi_driver alienware_wmax_wmi_driver = {
> >
> > static 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;
>
> Please add a check here if awcc is not NULL and keep "pr_warn("force_gmode requires platform profile support\n")"
> if awcc is NULL.
Sure!
>
>
> Thanks,
> Armin Wolf
>
> > +
> > return wmi_driver_register(&alienware_wmax_wmi_driver);
> > }
> >
> > @@ -1375,16 +1360,6 @@ static int __init alienware_wmi_init(void)
> > if (quirks == NULL)
> > quirks = &quirk_unknown;
> >
> > - if (force_platform_profile)
> > - quirks->thermal = true;
> > -
> > - if (force_gmode) {
> > - if (quirks->thermal)
> > - quirks->gmode = true;
> > - else
> > - pr_warn("force_gmode requires platform profile support\n");
> > - }
> > -
> > if (wmi_has_guid(WMAX_CONTROL_GUID)) {
> > interface = WMAX;
> > ret = alienware_wmax_wmi_init();
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature
2025-01-02 19:20 ` Armin Wolf
@ 2025-01-02 19:40 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 19:40 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 08:20:48PM +0100, Armin Wolf wrote:
> Am 02.01.25 um 19:45 schrieb Kurt Borja:
>
> > On Thu, Jan 02, 2025 at 05:07:16PM +0100, Armin Wolf wrote:
> > > Am 29.12.24 um 20:44 schrieb Kurt Borja:
> > >
> > > > Add a state container for the "alienware-wmi" platform device and
> > > > initialize it on the new alienfx_probe(). Migrate all LED control functions
> > > > to use this state container, as well as hdmi, amplifier, deepslp group
> > > > visibility methods, to support upcoming file split.
> > > >
> > > > Additionally move the led_classdev registration to the platform driver
> > > > probe and make it device managed.
> > > >
> > > > Drop alienware_zone_init() and alienware_zone_exit() because they are no
> > > > longer needed.
> > > >
> > > > Signed-off-by: Kurt Borja <kuurtb@gmail.com>
> > > > ---
> > > > drivers/platform/x86/dell/alienware-wmi.c | 135 +++++++++++++---------
> > > > 1 file changed, 79 insertions(+), 56 deletions(-)
> > > >
> > > > diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c
> > > > index 2c17160473a6..88d4046ed45f 100644
> > > > --- a/drivers/platform/x86/dell/alienware-wmi.c
> > > > +++ b/drivers/platform/x86/dell/alienware-wmi.c
> > > > @@ -404,14 +404,20 @@ struct wmax_u32_args {
> > > > u8 arg3;
> > > > };
> > > >
> > > > +struct alienfx_priv {
> > > > + struct platform_device *pdev;
> > > > + struct quirk_entry *quirks;
> > > > + struct led_classdev global_led;
> > > > + struct color_platform colors[4];
> > > > + u8 global_brightness;
> > > > + u8 lighting_control_state;
> > > > +};
> > > > +
> > > > static struct platform_device *platform_device;
> > > > -static struct color_platform colors[4];
> > > > static struct platform_profile_handler pp_handler;
> > > > static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
> > > >
> > > > static u8 interface;
> > > > -static u8 lighting_control_state;
> > > > -static u8 global_brightness;
> > > >
> > > > /*
> > > > * Helpers used for zone control
> > > > @@ -443,7 +449,7 @@ static int parse_rgb(const char *buf, struct color_platform *colors)
> > > > /*
> > > > * Individual RGB zone control
> > > > */
> > > > -static int alienware_update_led(u8 location)
> > > > +static int alienware_update_led(struct alienfx_priv *priv, u8 location)
> > > > {
> > > > int method_id;
> > > > acpi_status status;
> > > > @@ -453,21 +459,21 @@ static int alienware_update_led(u8 location)
> > > > struct wmax_led_args wmax_basic_args;
> > > > if (interface == WMAX) {
> > > > wmax_basic_args.led_mask = 1 << location;
> > > > - wmax_basic_args.colors = colors[location];
> > > > - wmax_basic_args.state = lighting_control_state;
> > > > + wmax_basic_args.colors = priv->colors[location];
> > > > + wmax_basic_args.state = priv->lighting_control_state;
> > > > guid = WMAX_CONTROL_GUID;
> > > > method_id = WMAX_METHOD_ZONE_CONTROL;
> > > >
> > > > input.length = sizeof(wmax_basic_args);
> > > > input.pointer = &wmax_basic_args;
> > > > } else {
> > > > - legacy_args.colors = colors[location];
> > > > - legacy_args.brightness = global_brightness;
> > > > + legacy_args.colors = priv->colors[location];
> > > > + legacy_args.brightness = priv->global_brightness;
> > > > legacy_args.state = 0;
> > > > - if (lighting_control_state == LEGACY_BOOTING ||
> > > > - lighting_control_state == LEGACY_SUSPEND) {
> > > > + if (priv->lighting_control_state == LEGACY_BOOTING ||
> > > > + priv->lighting_control_state == LEGACY_SUSPEND) {
> > > > guid = LEGACY_POWER_CONTROL_GUID;
> > > > - legacy_args.state = lighting_control_state;
> > > > + legacy_args.state = priv->lighting_control_state;
> > > > } else
> > > > guid = LEGACY_CONTROL_GUID;
> > > > method_id = location + 1;
> > > > @@ -486,22 +492,26 @@ static int alienware_update_led(u8 location)
> > > > static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
> > > > char *buf, u8 location)
> > > > {
> > > > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > > > + struct color_platform *colors = &priv->colors[location];
> > > > +
> > > > return sprintf(buf, "red: %d, green: %d, blue: %d\n",
> > > > - colors[location].red, colors[location].green,
> > > > - colors[location].blue);
> > > > + colors->red, colors->green, colors->blue);
> > > >
> > > > }
> > > >
> > > > static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
> > > > const char *buf, size_t count, u8 location)
> > > > {
> > > > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > > > + struct color_platform *colors = &priv->colors[location];
> > > > int ret;
> > > >
> > > > - ret = parse_rgb(buf, &colors[location]);
> > > > + ret = parse_rgb(buf, colors);
> > > > if (ret)
> > > > return ret;
> > > >
> > > > - ret = alienware_update_led(location);
> > > > + ret = alienware_update_led(priv, location);
> > > >
> > > > return ret ? ret : count;
> > > > }
> > > > @@ -569,9 +579,11 @@ static ssize_t lighting_control_state_show(struct device *dev,
> > > > struct device_attribute *attr,
> > > > char *buf)
> > > > {
> > > > - if (lighting_control_state == LEGACY_BOOTING)
> > > > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > > > +
> > > > + if (priv->lighting_control_state == LEGACY_BOOTING)
> > > > return sysfs_emit(buf, "[booting] running suspend\n");
> > > > - else if (lighting_control_state == LEGACY_SUSPEND)
> > > > + else if (priv->lighting_control_state == LEGACY_SUSPEND)
> > > > return sysfs_emit(buf, "booting running [suspend]\n");
> > > >
> > > > return sysfs_emit(buf, "booting [running] suspend\n");
> > > > @@ -581,6 +593,7 @@ static ssize_t lighting_control_state_store(struct device *dev,
> > > > struct device_attribute *attr,
> > > > const char *buf, size_t count)
> > > > {
> > > > + struct alienfx_priv *priv = dev_get_drvdata(dev);
> > > > u8 val;
> > > >
> > > > if (strcmp(buf, "booting\n") == 0)
> > > > @@ -592,9 +605,9 @@ static ssize_t lighting_control_state_store(struct device *dev,
> > > > else
> > > > val = WMAX_RUNNING;
> > > >
> > > > - lighting_control_state = val;
> > > > + priv->lighting_control_state = val;
> > > > pr_debug("alienware-wmi: updated control state to %d\n",
> > > > - lighting_control_state);
> > > > + priv->lighting_control_state);
> > > >
> > > > return count;
> > > > }
> > > > @@ -651,43 +664,26 @@ static int wmax_brightness(int brightness)
> > > > static void global_led_set(struct led_classdev *led_cdev,
> > > > enum led_brightness brightness)
> > > > {
> > > > + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> > > > + global_led);
> > > > int ret;
> > > > - global_brightness = brightness;
> > > > +
> > > > + priv->global_brightness = brightness;
> > > > +
> > > > if (interface == WMAX)
> > > > ret = wmax_brightness(brightness);
> > > > else
> > > > - ret = alienware_update_led(0);
> > > > + ret = alienware_update_led(priv, 0);
> > > > if (ret)
> > > > pr_err("LED brightness update failed\n");
> > > > }
> > > >
> > > > static enum led_brightness global_led_get(struct led_classdev *led_cdev)
> > > > {
> > > > - return global_brightness;
> > > > -}
> > > > -
> > > > -static struct led_classdev global_led = {
> > > > - .brightness_set = global_led_set,
> > > > - .brightness_get = global_led_get,
> > > > - .name = "alienware::global_brightness",
> > > > -};
> > > > + struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
> > > > + global_led);
> > > >
> > > > -static int alienware_zone_init(struct platform_device *dev)
> > > > -{
> > > > - if (interface == WMAX) {
> > > > - lighting_control_state = WMAX_RUNNING;
> > > > - } else if (interface == LEGACY) {
> > > > - lighting_control_state = LEGACY_RUNNING;
> > > > - }
> > > > - global_led.max_brightness = 0x0F;
> > > > - global_brightness = global_led.max_brightness;
> > > > -
> > > > - return led_classdev_register(&dev->dev, &global_led);
> > > > -}
> > > > -
> > > > -static void alienware_zone_exit(struct platform_device *dev)
> > > > -{
> > > > - led_classdev_unregister(&global_led);
> > > > + return priv->global_brightness;
> > > > }
> > > >
> > > > static acpi_status alienware_wmax_command(void *in_args, size_t in_size,
> > > > @@ -792,7 +788,9 @@ static DEVICE_ATTR_RW(source);
> > > >
> > > > static bool hdmi_group_visible(struct kobject *kobj)
> > > > {
> > > > - return quirks->hdmi_mux;
> > > > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > > > +
> > > > + return priv->quirks->hdmi_mux;
> > > > }
> > > > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
> > > >
> > > > @@ -838,7 +836,9 @@ static DEVICE_ATTR_RO(status);
> > > >
> > > > static bool amplifier_group_visible(struct kobject *kobj)
> > > > {
> > > > - return quirks->amplifier;
> > > > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > > > +
> > > > + return priv->quirks->amplifier;
> > > > }
> > > > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
> > > >
> > > > @@ -906,7 +906,9 @@ static DEVICE_ATTR_RW(deepsleep);
> > > >
> > > > static bool deepsleep_group_visible(struct kobject *kobj)
> > > > {
> > > > - return quirks->deepslp;
> > > > + struct alienfx_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
> > > > +
> > > > + return priv->quirks->deepslp;
> > > > }
> > > > DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
> > > >
> > > > @@ -1133,6 +1135,33 @@ static void remove_thermal_profile(void)
> > > > /*
> > > > * Platform Driver
> > > > */
> > > > +static int alienfx_probe(struct platform_device *pdev)
> > > > +{
> > > > + struct alienfx_priv *priv;
> > > > +
> > > > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> > > > + if (!priv)
> > > > + return -ENOMEM;
> > > > +
> > > > + platform_set_drvdata(pdev, priv);
> > > > + priv->pdev = pdev;
> > > > + priv->quirks = quirks;
> > > > +
> > > > + if (interface == WMAX)
> > > > + priv->lighting_control_state = WMAX_RUNNING;
> > > > + else if (interface == LEGACY)
> > > > + priv->lighting_control_state = LEGACY_RUNNING;
> > > > +
> > > > + priv->global_led.name = "alienware::global_brightness";
> > > > + priv->global_led.brightness_set = global_led_set;
> > > > + priv->global_led.brightness_get = global_led_get;
> > > > + priv->global_led.max_brightness = 0x0F;
> > > > +
> > > > + priv->global_brightness = priv->global_led.max_brightness;
> > > > +
> > > > + return devm_led_classdev_register(&pdev->dev, &priv->global_led);
> > > > +}
> > > > +
> > > > static const struct attribute_group *alienfx_groups[] = {
> > > > &zone_attribute_group,
> > > > &hdmi_attribute_group,
> > > > @@ -1145,7 +1174,9 @@ static struct platform_driver platform_driver = {
> > > > .driver = {
> > > > .name = "alienware-wmi",
> > > > .dev_groups = alienfx_groups,
> > > > + .probe_type = PROBE_FORCE_SYNCHRONOUS,
> > > Can you please explain to me why this is exactly necessary?
> > Because I want to add wmax_alienfx_groups after the platform_device has
> > finished probing. I think it's not exactly "necessary" because those
> > methods only access `platdata` which is set before probing, but to me it
> > doesn't feel right to race with alienfx_probe().
> >
> > I wanted to somehow mimic platform_create_bundle(), which I can't use
> > because that function needs to be called from an __init section.
> >
> > If this is unnecessary I will drop it, otherwise I think it makes more
> > sense to move this to [8/20].
> >
> I just saw that the *_is_visible() callbacks use alienfx_priv which is only available
> after the driver has finished probing.
>
> I would prefer if you make the quirk values available outside of alienware-wmi-base so
> that those callbacks can access them without having to use alienfx_priv. This would allow
> us to omit PROBE_FORCE_SYNCHRONOUS.
Right! I forgot about that. Then I will make it available in alienware-wmi.h and drop
PROBE_FORCE_SYNCHRONOUS.
>
> Thanks,
> Armin Wolf
>
> > > Thanks,
> > > Armin Wolf
> > >
> > > > },
> > > > + .probe = alienfx_probe,
> > > > };
> > > >
> > > > static int __init alienware_wmi_init(void)
> > > > @@ -1193,15 +1224,8 @@ static int __init alienware_wmi_init(void)
> > > > goto fail_prep_thermal_profile;
> > > > }
> > > >
> > > > - ret = alienware_zone_init(platform_device);
> > > > - if (ret)
> > > > - goto fail_prep_zones;
> > > > -
> > > > return 0;
> > > >
> > > > -fail_prep_zones:
> > > > - alienware_zone_exit(platform_device);
> > > > - remove_thermal_profile();
> > > > fail_prep_thermal_profile:
> > > > platform_device_del(platform_device);
> > > > fail_platform_device2:
> > > > @@ -1216,7 +1240,6 @@ module_init(alienware_wmi_init);
> > > >
> > > > static void __exit alienware_wmi_exit(void)
> > > > {
> > > > - alienware_zone_exit(platform_device);
> > > > remove_thermal_profile();
> > > > platform_device_unregister(platform_device);
> > > > platform_driver_unregister(&platform_driver);
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH v2 00/20] alienware-wmi driver rework
2025-01-02 15:50 ` [PATCH v2 00/20] alienware-wmi driver rework Armin Wolf
@ 2025-01-02 19:41 ` Kurt Borja
0 siblings, 0 replies; 41+ messages in thread
From: Kurt Borja @ 2025-01-02 19:41 UTC (permalink / raw)
To: Armin Wolf
Cc: platform-driver-x86, Dell.Client.Kernel, hdegoede, ilpo.jarvinen,
linux-kernel, mario.limonciello
On Thu, Jan 02, 2025 at 04:50:05PM +0100, Armin Wolf wrote:
> Am 29.12.24 um 20:44 schrieb Kurt Borja:
>
> > Hi!
> >
> > Happy holidays. :)
>
> Hi,
>
> i just noticed that your patch are missing the "platform/x86:" prefix. Please add this prefix
> for the next patch revision.
I will.
Thanks again for your review Armin!
~ Kurt
>
> Thanks,
> Armin Wolf
>
> >
> > ~ Kurt
> > ---
> > v1 -> v2:
> >
> > [2/20]
> > - Small correction in commit message
> >
> > [5/20]
> > - Define the sysfs attributes without macros
> >
> > [6/20]
> > - Reworded commit title
> > - Reorder variables in previous WMAX methods too
> > - Standarized sysfs method names in hdmi, amplifier and deepsleep
> > groups
> > - Dropped Armin's Reviewed-by tag because this patch changed a lot
> >
> > [7/20]
> > - Return -ENOMEM in case priv allocation fails in alienfx_probe()
> > - Assign priv and platdata on variable declaration
> > - Drop intermediate *leds in alienfx_probe()
> > - Add quirk_entry to state container
> > - Use quirks from priv on hdmi_mux, amplifier, deepslp visibility
> > methods, to eventually be able to move these groups into
> > alienware-wmi-wmax.c
> > - Set PROBE_FORCE_SYNCHRONOUS to platform_driver, to avoid racing to
> > drvdata after using device_create_groups on [8/20]
> >
> > [8/20]
> > - Create hdmi, amplifier, deepslp sysfs groups on wmax's probe
> >
> > [9/20]
> > - Assign priv on variable declaration
> > - Directly return create thermal_profile() in alienware_awcc_setup()
> >
> > [10/20]
> > - Refactored alienware_wmi_method following Armin's comments
> > - Fix legacy_wmi_update_led logic
> >
> > [13/20]
> > - Split DMI table lower in the file
> > - Rename quirk_entry -> alienfx_quirks
> > - Rename awcc_features -> awcc_quirks
> > - Make hdmi_mux, amplifier and deepslp `bool`
> >
> > [16/20]:
> > - Only add common resources on alienware.h
> >
> > [17/20]
> > - Reworded commit message: now mentions some blocks were reordered
> > - Move #include <linux/dmi.h> where it belongs alphabetically
> > - Included hdmi, amplifier, deepslp groups in alienware-wmi-wmax.c
> >
> > [18/20]
> > - static inline init functions in case drivers are not compiled
> > - Return errno in case drivers are not compiled
> >
> > v1: https://lore.kernel.org/platform-driver-x86/20241221055917.10555-1-kuurtb@gmail.com/
> >
> > Kurt Borja (20):
> > alienware-wmi: Remove unnecessary check at module exit
> > alienware-wmi: Move Lighting Control State
> > alienware-wmi: Modify parse_rgb() signature
> > alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation
> > alienware-wmi: Improve rgb-zones group creation
> > alienware_wmi: General cleanup of WMAX methods
> > alienware-wmi: Add a state container for LED control feature
> > alienware-wmi: Add WMI Drivers
> > alienware-wmi: Add a state container for thermal control methods
> > alienware-wmi: Refactor LED control methods
> > alienware-wmi: Refactor hdmi, amplifier, deepslp methods
> > alienware-wmi: Refactor thermal control methods
> > alienware-wmi: Split DMI table
> > MAINTAINERS: Update ALIENWARE WMI DRIVER entry
> > platform/x86: Rename alienware-wmi.c
> > platform/x86: Add alienware-wmi.h
> > platform-x86: Split the alienware-wmi driver
> > platform/x86: dell: Modify Makefile alignment
> > platform/x86: Update alienware-wmi config entries
> > alienware-wmi: Update header and module information
> >
> > MAINTAINERS | 4 +-
> > drivers/platform/x86/dell/Kconfig | 30 +-
> > drivers/platform/x86/dell/Makefile | 45 +-
> > .../platform/x86/dell/alienware-wmi-base.c | 492 +++++++
> > .../platform/x86/dell/alienware-wmi-legacy.c | 98 ++
> > .../platform/x86/dell/alienware-wmi-wmax.c | 775 ++++++++++
> > drivers/platform/x86/dell/alienware-wmi.c | 1269 -----------------
> > drivers/platform/x86/dell/alienware-wmi.h | 101 ++
> > 8 files changed, 1518 insertions(+), 1296 deletions(-)
> > create mode 100644 drivers/platform/x86/dell/alienware-wmi-base.c
> > create mode 100644 drivers/platform/x86/dell/alienware-wmi-legacy.c
> > create mode 100644 drivers/platform/x86/dell/alienware-wmi-wmax.c
> > delete mode 100644 drivers/platform/x86/dell/alienware-wmi.c
> > create mode 100644 drivers/platform/x86/dell/alienware-wmi.h
> >
> >
> > base-commit: 03f8e0e05510dad6377cd5ef029594d30e6c096d
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2025-01-02 19:41 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-29 19:44 [PATCH v2 00/20] alienware-wmi driver rework Kurt Borja
2024-12-29 19:44 ` [PATCH v2 01/20] alienware-wmi: Remove unnecessary check at module exit Kurt Borja
2024-12-29 19:44 ` [PATCH v2 02/20] alienware-wmi: Move Lighting Control State Kurt Borja
2024-12-29 19:44 ` [PATCH v2 03/20] alienware-wmi: Modify parse_rgb() signature Kurt Borja
2024-12-29 19:44 ` [PATCH v2 04/20] alienware-wmi: Improve hdmi_mux, amplifier and deepslp group creation Kurt Borja
2024-12-29 19:44 ` [PATCH v2 05/20] alienware-wmi: Improve rgb-zones " Kurt Borja
2025-01-02 15:44 ` Armin Wolf
2025-01-02 18:33 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 06/20] alienware_wmi: General cleanup of WMAX methods Kurt Borja
2025-01-02 15:50 ` Armin Wolf
2024-12-29 19:44 ` [PATCH v2 07/20] alienware-wmi: Add a state container for LED control feature Kurt Borja
2025-01-02 16:07 ` Armin Wolf
2025-01-02 18:45 ` Kurt Borja
2025-01-02 19:20 ` Armin Wolf
2025-01-02 19:40 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 08/20] alienware-wmi: Add WMI Drivers Kurt Borja
2025-01-02 16:16 ` Armin Wolf
2025-01-02 18:49 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 09/20] alienware-wmi: Add a state container for thermal control methods Kurt Borja
2025-01-02 16:19 ` Armin Wolf
2025-01-02 18:52 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 10/20] alienware-wmi: Refactor LED " Kurt Borja
2025-01-02 16:29 ` Armin Wolf
2025-01-02 19:36 ` Kurt Borja
2024-12-29 19:44 ` [PATCH v2 11/20] alienware-wmi: Refactor hdmi, amplifier, deepslp methods Kurt Borja
2024-12-29 19:44 ` [PATCH v2 12/20] alienware-wmi: Refactor thermal control methods Kurt Borja
2024-12-29 19:45 ` [PATCH v2 13/20] alienware-wmi: Split DMI table Kurt Borja
2025-01-02 16:36 ` Armin Wolf
2025-01-02 19:37 ` Kurt Borja
2024-12-29 19:45 ` [PATCH v2 14/20] MAINTAINERS: Update ALIENWARE WMI DRIVER entry Kurt Borja
2024-12-29 19:45 ` [PATCH v2 15/20] platform/x86: Rename alienware-wmi.c Kurt Borja
2024-12-29 19:45 ` [PATCH v2 16/20] platform/x86: Add alienware-wmi.h Kurt Borja
2025-01-02 16:43 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 17/20] platform-x86: Split the alienware-wmi driver Kurt Borja
2025-01-02 16:49 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 18/20] platform/x86: dell: Modify Makefile alignment Kurt Borja
2024-12-29 19:45 ` [PATCH v2 19/20] platform/x86: Update alienware-wmi config entries Kurt Borja
2025-01-02 16:57 ` Armin Wolf
2024-12-29 19:45 ` [PATCH v2 20/20] alienware-wmi: Update header and module information Kurt Borja
2025-01-02 15:50 ` [PATCH v2 00/20] alienware-wmi driver rework Armin Wolf
2025-01-02 19:41 ` Kurt Borja
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox