// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Alienware AlienFX control
*
* Copyright (C) 2014 Dell Inc <mario_limonciello@dell.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmi.h>
#include <linux/leds.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"
#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
MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");
MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID);
MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID);
enum INTERFACE_FLAGS {
LEGACY,
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,
};
struct quirk_entry {
u8 num_zones;
u8 hdmi_mux;
u8 amplifier;
u8 deepslp;
};
static struct quirk_entry *quirks;
static struct quirk_entry quirk_inspiron5675 = {
.num_zones = 2,
.hdmi_mux = 0,
.amplifier = 0,
.deepslp = 0,
};
static struct quirk_entry quirk_unknown = {
.num_zones = 2,
.hdmi_mux = 0,
.amplifier = 0,
.deepslp = 0,
};
static struct quirk_entry quirk_x51_r1_r2 = {
.num_zones = 3,
.hdmi_mux = 0,
.amplifier = 0,
.deepslp = 0,
};
static struct quirk_entry quirk_x51_r3 = {
.num_zones = 4,
.hdmi_mux = 0,
.amplifier = 1,
.deepslp = 0,
};
static struct quirk_entry quirk_asm100 = {
.num_zones = 2,
.hdmi_mux = 1,
.amplifier = 0,
.deepslp = 0,
};
static struct quirk_entry quirk_asm200 = {
.num_zones = 2,
.hdmi_mux = 1,
.amplifier = 0,
.deepslp = 1,
};
static struct quirk_entry quirk_asm201 = {
.num_zones = 2,
.hdmi_mux = 1,
.amplifier = 1,
.deepslp = 1,
};
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
quirks = dmi->driver_data;
return 1;
}
static const struct dmi_system_id alienware_quirks[] __initconst = {
{
.callback = dmi_matched,
.ident = "Alienware X51 R3",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"),
},
.driver_data = &quirk_x51_r3,
},
{
.callback = dmi_matched,
.ident = "Alienware X51 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"),
},
.driver_data = &quirk_x51_r1_r2,
},
{
.callback = dmi_matched,
.ident = "Alienware X51 R1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"),
},
.driver_data = &quirk_x51_r1_r2,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
},
.driver_data = &quirk_asm100,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM200",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"),
},
.driver_data = &quirk_asm200,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM201",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"),
},
.driver_data = &quirk_asm201,
},
{
.callback = dmi_matched,
.ident = "Dell Inc. Inspiron 5675",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
},
.driver_data = &quirk_inspiron5675,
},
{}
};
struct color_platform {
u8 blue;
u8 green;
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;
};
struct wmax_basic_args {
u8 arg;
};
struct legacy_led_args {
struct color_platform colors;
u8 brightness;
u8 state;
} __packed;
struct