Unverified Commit 898a2302 authored by Kurt Borja's avatar Kurt Borja Committed by Ilpo Järvinen
Browse files

platform/x86: alienware-wmi: Add WMI Drivers



Add WMI drivers for LEGACY and WMAX devices.

This involves moving the platform device registration to a helper
function that is now called from the driver's preferred WMI device
driver probe. In the case of the WMAX this is done only if
`!quirks->thermal` because the newer WMAX interface doesn't support any
of the LED features of this driver. This also eliminates the need to
check for `quirks->num_zones > 0` inside alienfx_probe().

Only one WMI driver is registered on module initialization to prevent
registering a duplicate platform device.

Additionally, create_thermal_profile() now takes wmi_device * instead of
platform_device *.

Reviewed-by: default avatarArmin Wolf <W_Armin@gmx.de>
Signed-off-by: default avatarKurt Borja <kuurtb@gmail.com>
Link: https://lore.kernel.org/r/20250207154610.13675-3-kuurtb@gmail.com


Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent 4c546de9
Loading
Loading
Loading
Loading
+134 −43
Original line number Diff line number Diff line
@@ -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);
@@ -421,7 +420,10 @@ struct alienfx_priv {
	u8 lighting_control_state;
};

static struct platform_device *platform_device;
struct alienfx_platdata {
	struct wmi_device *wdev;
};

static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];

static u8 interface;
@@ -801,7 +803,7 @@ static DEVICE_ATTR_RW(source);

static bool hdmi_group_visible(struct kobject *kobj)
{
	return quirks->hdmi_mux;
	return interface == WMAX && quirks->hdmi_mux;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);

@@ -848,7 +850,7 @@ static DEVICE_ATTR_RO(status);

static bool amplifier_group_visible(struct kobject *kobj)
{
	return quirks->amplifier;
	return interface == WMAX && quirks->amplifier;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);

@@ -917,7 +919,7 @@ static DEVICE_ATTR_RW(deepsleep);

static bool deepsleep_group_visible(struct kobject *kobj)
{
	return quirks->deepslp;
	return interface == WMAX && quirks->deepslp;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);

@@ -1136,11 +1138,11 @@ static const struct platform_profile_ops awcc_platform_profile_ops = {
	.profile_set = thermal_profile_set,
};

static int create_thermal_profile(struct platform_device *platform_device)
static int create_thermal_profile(struct wmi_device *wdev)
{
	struct device *ppdev;

	ppdev = devm_platform_profile_register(&platform_device->dev, "alienware-wmi",
	ppdev = devm_platform_profile_register(&wdev->dev, "alienware-wmi",
					       NULL, &awcc_platform_profile_ops);

	return PTR_ERR_OR_ZERO(ppdev);
@@ -1153,9 +1155,6 @@ static int alienfx_probe(struct platform_device *pdev)
{
	struct alienfx_priv *priv;

	if (!quirks->num_zones)
		return -ENODEV;

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;
@@ -1192,19 +1191,119 @@ static struct platform_driver platform_driver = {
	.probe = alienfx_probe,
};

static int __init alienware_wmi_init(void)
static void alienware_alienfx_remove(void *data)
{
	struct platform_device *pdev = data;

	platform_device_unregister(pdev);
}

static int alienware_alienfx_setup(struct alienfx_platdata *pdata)
{
	struct device *dev = &pdata->wdev->dev;
	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;
	pdev = platform_device_register_data(NULL, "alienware-wmi",
					     PLATFORM_DEVID_NONE, pdata,
					     sizeof(*pdata));
	if (IS_ERR(pdev))
		return PTR_ERR(pdev);

	dev_set_drvdata(dev, pdev);
	ret = devm_add_action_or_reset(dev, alienware_alienfx_remove, pdev);
	if (ret)
		return ret;

	return 0;
}

/*
 * 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 const 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,
	.no_singleton = true,
};

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,
	};
	int ret;

	if (quirks->thermal)
		ret = create_thermal_profile(wdev);
	else
		ret = alienware_alienfx_setup(&pdata);

	return ret;
}

static const 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,
	.no_singleton = true,
};

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;
@@ -1220,32 +1319,20 @@ static int __init alienware_wmi_init(void)
	}

	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;
	}
	ret = platform_device_add(platform_device);
	if (ret)
		goto fail_platform_device2;
	if (ret < 0)
		return ret;

	if (quirks->thermal) {
		ret = create_thermal_profile(platform_device);
		if (ret)
			goto fail_prep_thermal_profile;
	if (wmi_has_guid(WMAX_CONTROL_GUID)) {
		interface = WMAX;
		ret = alienware_wmax_wmi_init();
	} else {
		interface = LEGACY;
		ret = alienware_legacy_wmi_init();
	}

	return 0;

fail_prep_thermal_profile:
	platform_device_del(platform_device);
fail_platform_device2:
	platform_device_put(platform_device);
fail_platform_device1:
	if (ret < 0)
		platform_driver_unregister(&platform_driver);
fail_platform_driver:

	return ret;
}

@@ -1253,7 +1340,11 @@ module_init(alienware_wmi_init);

static void __exit alienware_wmi_exit(void)
{
	platform_device_unregister(platform_device);
	if (interface == WMAX)
		alienware_wmax_wmi_exit();
	else
		alienware_legacy_wmi_exit();

	platform_driver_unregister(&platform_driver);
}