diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-driver-toshiba_acpi | 16 | ||||
| -rw-r--r-- | drivers/leds/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/leds/dell-led.c | 126 | ||||
| -rw-r--r-- | drivers/platform/x86/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
| -rw-r--r-- | drivers/platform/x86/alienware-wmi.c | 286 | ||||
| -rw-r--r-- | drivers/platform/x86/asus-nb-wmi.c | 9 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-laptop.c | 370 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-rbtn.c | 15 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-smbios.c | 193 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-smbios.h | 46 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-wmi.c | 238 | ||||
| -rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 8 | ||||
| -rw-r--r-- | drivers/platform/x86/hp-wmi.c | 46 | ||||
| -rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 14 | ||||
| -rw-r--r-- | drivers/platform/x86/intel-hid.c | 3 | ||||
| -rw-r--r-- | drivers/platform/x86/intel_pmc_ipc.c | 8 | ||||
| -rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 35 | ||||
| -rw-r--r-- | drivers/platform/x86/intel_telemetry_pltdrv.c | 13 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 4 | ||||
| -rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 115 |
21 files changed, 1026 insertions, 536 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi index eed922ef42e5..f34221b52b14 100644 --- a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi +++ b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi @@ -179,3 +179,19 @@ Description: This file controls the USB 3 functionality, valid values are: Note that toggling this value requires a reboot for changes to take effect. Users: KToshiba + +What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/cooling_method +Date: 2016 +KernelVersion: 4.6 +Contact: Azael Avalos <coproscefalo@gmail.com> +Description: This file controls the Cooling Method feature. + Reading this file prints two values, the first is the actual cooling method + and the second is the maximum cooling method supported. + When the maximum cooling method is ONE, valid values are: + * 0 -> Maximum Performance + * 1 -> Battery Optimized + When the maximum cooling method is TWO, valid values are: + * 0 -> Maximum Performance + * 1 -> Performance + * 2 -> Battery Optimized +Users: KToshiba diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 1f6415168998..225147863e02 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -443,6 +443,7 @@ config LEDS_DELL_NETBOOKS tristate "External LED on Dell Business Netbooks" depends on LEDS_CLASS depends on X86 && ACPI_WMI + depends on DELL_SMBIOS help This adds support for the Latitude 2100 and similar notebooks that have an external LED. diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c index c36acaf566a6..b3d6e9c15cf9 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/dmi.h> #include <linux/dell-led.h> +#include "../platform/x86/dell-smbios.h" MODULE_AUTHOR("Louis Davis/Jim Dailey"); MODULE_DESCRIPTION("Dell LED Control Driver"); @@ -42,120 +43,32 @@ MODULE_ALIAS("wmi:" DELL_LED_BIOS_GUID); #define CMD_LED_OFF 17 #define CMD_LED_BLINK 18 -struct app_wmi_args { - u16 class; - u16 selector; - u32 arg1; - u32 arg2; - u32 arg3; - u32 arg4; - u32 res1; - u32 res2; - u32 res3; - u32 res4; - char dummy[92]; -}; - #define GLOBAL_MIC_MUTE_ENABLE 0x364 #define GLOBAL_MIC_MUTE_DISABLE 0x365 -struct dell_bios_data_token { - u16 tokenid; - u16 location; - u16 value; -}; - -struct __attribute__ ((__packed__)) dell_bios_calling_interface { - struct dmi_header header; - u16 cmd_io_addr; - u8 cmd_io_code; - u32 supported_cmds; - struct dell_bios_data_token damap[]; -}; - -static struct dell_bios_data_token dell_mic_tokens[2]; - -static int dell_wmi_perform_query(struct app_wmi_args *args) -{ - struct app_wmi_args *bios_return; - union acpi_object *obj; - struct acpi_buffer input; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_status status; - u32 rc = -EINVAL; - - input.length = 128; - input.pointer = args; - - status = wmi_evaluate_method(DELL_APP_GUID, 0, 1, &input, &output); - if (!ACPI_SUCCESS(status)) - goto err_out0; - - obj = output.pointer; - if (!obj) - goto err_out0; - - if (obj->type != ACPI_TYPE_BUFFER) - goto err_out1; - - bios_return = (struct app_wmi_args *)obj->buffer.pointer; - rc = bios_return->res1; - if (rc) - goto err_out1; - - memcpy(args, bios_return, sizeof(struct app_wmi_args)); - rc = 0; - - err_out1: - kfree(obj); - err_out0: - return rc; -} - -static void __init find_micmute_tokens(const struct dmi_header *dm, void *dummy) -{ - struct dell_bios_calling_interface *calling_interface; - struct dell_bios_data_token *token; - int token_size = sizeof(struct dell_bios_data_token); - int i = 0; - - if (dm->type == 0xda && dm->length > 17) { - calling_interface = container_of(dm, - struct dell_bios_calling_interface, header); - - token = &calling_interface->damap[i]; - while (token->tokenid != 0xffff) { - if (token->tokenid == GLOBAL_MIC_MUTE_DISABLE) - memcpy(&dell_mic_tokens[0], token, token_size); - else if (token->tokenid == GLOBAL_MIC_MUTE_ENABLE) - memcpy(&dell_mic_tokens[1], token, token_size); - - i++; - token = &calling_interface->damap[i]; - } - } -} - static int dell_micmute_led_set(int state) { - struct app_wmi_args args; - struct dell_bios_data_token *token; + struct calling_interface_buffer *buffer; + struct calling_interface_token *token; if (!wmi_has_guid(DELL_APP_GUID)) return -ENODEV; - if (state == 0 || state == 1) - token = &dell_mic_tokens[state]; + if (state == 0) + token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE); + else if (state == 1) + token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE); else return -EINVAL; - memset(&args, 0, sizeof(struct app_wmi_args)); - - args.class = 1; - args.arg1 = token->location; - args.arg2 = token->value; + if (!token) + return -ENODEV; - dell_wmi_perform_query(&args); + buffer = dell_smbios_get_buffer(); + buffer->input[0] = token->location; + buffer->input[1] = token->value; + dell_smbios_send_request(1, 0); + dell_smbios_release_buffer(); return state; } @@ -177,14 +90,6 @@ int dell_app_wmi_led_set(int whichled, int on) } EXPORT_SYMBOL_GPL(dell_app_wmi_led_set); -static int __init dell_micmute_led_init(void) -{ - memset(dell_mic_tokens, 0, sizeof(struct dell_bios_data_token) * 2); - dmi_walk(find_micmute_tokens, NULL); - - return 0; -} - struct bios_args { unsigned char length; unsigned char result_code; @@ -330,9 +235,6 @@ static int __init dell_led_init(void) if (!wmi_has_guid(DELL_LED_BIOS_GUID) && !wmi_has_guid(DELL_APP_GUID)) return -ENODEV; - if (wmi_has_guid(DELL_APP_GUID)) - error = dell_micmute_led_init(); - if (wmi_has_guid(DELL_LED_BIOS_GUID)) { error = led_off(); if (error != 0) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 69f93a576e45..ed2004be13cf 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -91,10 +91,21 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. +config DELL_SMBIOS + tristate "Dell SMBIOS Support" + depends on DCDBAS + default n + ---help--- + This module provides common functions for kernel modules using + Dell SMBIOS. + + If you have a Dell laptop, say Y or M here. + config DELL_LAPTOP tristate "Dell Laptop Extras" depends on X86 - depends on DCDBAS + depends on DELL_SMBIOS + depends on DMI depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n @@ -110,8 +121,10 @@ config DELL_LAPTOP config DELL_WMI tristate "Dell WMI extras" depends on ACPI_WMI + depends on DMI depends on INPUT depends on ACPI_VIDEO || ACPI_VIDEO = n + depends on DELL_SMBIOS select INPUT_SPARSEKMAP ---help--- Say Y here if you want to support WMI-based hotkeys on Dell laptops. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 40574e7390f3..448443c3baba 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o +obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 1e1e59423889..005629447b0c 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -33,6 +33,9 @@ #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"); @@ -60,6 +63,8 @@ enum WMAX_CONTROL_STATES { struct quirk_entry { u8 num_zones; u8 hdmi_mux; + u8 amplifier; + u8 deepslp; }; static struct quirk_entry *quirks; @@ -67,16 +72,43 @@ static struct quirk_entry *quirks; static struct quirk_entry quirk_unknown = { .num_zones = 2, .hdmi_mux = 0, + .amplifier = 0, + .deepslp = 0, }; -static struct quirk_entry quirk_x51_family = { +static struct quirk_entry quirk_x51_r1_r2 = { .num_zones = 3, - .hdmi_mux = 0. + .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) @@ -88,12 +120,12 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) static const struct dmi_system_id alienware_quirks[] __initconst = { { .callback = dmi_matched, - .ident = "Alienware X51 R1", + .ident = "Alienware X51 R3", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), }, - .driver_data = &quirk_x51_family, + .driver_data = &quirk_x51_r3, }, { .callback = dmi_matched, @@ -102,17 +134,44 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), }, - .driver_data = &quirk_x51_family, + .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 ASM100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), - }, - .driver_data = &quirk_asm100, - }, + .callback = dmi_matched, + .ident = "Alienware ASM201", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), + }, + .driver_data = &quirk_asm201, + }, {} }; @@ -133,7 +192,7 @@ struct wmax_brightness_args { u32 percentage; }; -struct hdmi_args { +struct wmax_basic_args { u8 arg; }; @@ -170,7 +229,7 @@ static u8 global_brightness; /* * Helpers used for zone control -*/ + */ static int parse_rgb(const char *buf, struct platform_zone *zone) { long unsigned int rgb; @@ -210,7 +269,7 @@ static struct platform_zone *match_zone(struct device_attribute *attr) /* * Individual RGB zone control -*/ + */ static int alienware_update_led(struct platform_zone *zone) { int method_id; @@ -218,16 +277,16 @@ static int alienware_update_led(struct platform_zone *zone) char *guid; struct acpi_buffer input; struct legacy_led_args legacy_args; - struct wmax_led_args wmax_args; + struct wmax_led_args wmax_basic_args; if (interface == WMAX) { - wmax_args.led_mask = 1 << zone->location; - wmax_args.colors = zone->colors; - wmax_args.state = lighting_control_state; + wmax_basic_args.led_mask = 1 << zone->location; + wmax_basic_args.colors = zone->colors; + wmax_basic_args.state = lighting_control_state; guid = WMAX_CONTROL_GUID; method_id = WMAX_METHOD_ZONE_CONTROL; - input.length = (acpi_size) sizeof(wmax_args); - input.pointer = &wmax_args; + input.length = (acpi_size) sizeof(wmax_basic_args); + input.pointer = &wmax_basic_args; } else { legacy_args.colors = zone->colors; legacy_args.brightness = global_brightness; @@ -283,7 +342,7 @@ static ssize_t zone_set(struct device *dev, struct device_attribute *attr, /* * LED Brightness (Global) -*/ + */ static int wmax_brightness(int brightness) { acpi_status status; @@ -327,7 +386,7 @@ static struct led_classdev global_led = { /* * Lighting control state device attribute (Global) -*/ + */ static ssize_t show_control_state(struct device *dev, struct device_attribute *attr, char *buf) { @@ -435,11 +494,7 @@ static void alienware_zone_exit(struct platform_device *dev) kfree(zone_attrs); } -/* - 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 acpi_status alienware_hdmi_command(struct hdmi_args *in_args, +static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, u32 command, int *out_data) { acpi_status status; @@ -467,16 +522,20 @@ static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, } +/* + * 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) { acpi_status status; u32 out_data; - struct hdmi_args in_args = { + struct wmax_basic_args in_args = { .arg = 0, }; status = - alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, + alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_CABLE, (u32 *) &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 0) @@ -495,11 +554,11 @@ static ssize_t show_hdmi_source(struct device *dev, { acpi_status status; u32 out_data; - struct hdmi_args in_args = { + struct wmax_basic_args in_args = { .arg = 0, }; status = - alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, + alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_STATUS, (u32 *) &out_data); if (ACPI_SUCCESS(status)) { @@ -519,7 +578,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, const char *buf, size_t count) { acpi_status status; - struct hdmi_args args; + struct wmax_basic_args args; if (strcmp(buf, "gpu\n") == 0) args.arg = 1; else if (strcmp(buf, "input\n") == 0) @@ -528,7 +587,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, args.arg = 3; pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); - status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); + status = alienware_wmax_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", @@ -563,11 +622,144 @@ static int create_hdmi(struct platform_device *dev) ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); if (ret) - goto error_create_hdmi; - return 0; + remove_hdmi(dev); + return ret; +} -error_create_hdmi: - remove_hdmi(dev); +/* + * Alienware GFX amplifier support + * - 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) +{ + acpi_status status; + u32 out_data; + struct wmax_basic_args in_args = { + .arg = 0, + }; + status = + alienware_wmax_command(&in_args, WMAX_METHOD_AMPLIFIER_CABLE, + (u32 *) &out_data); + if (ACPI_SUCCESS(status)) { + if (out_data == 0) + return scnprintf(buf, PAGE_SIZE, + "[unconnected] connected unknown\n"); + else if (out_data == 1) + return scnprintf(buf, PAGE_SIZE, + "unconnected [connected] unknown\n"); + } + pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status); + return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); +} + +static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL); + +static struct attribute *amplifier_attrs[] = { + &dev_attr_status.attr, + NULL, +}; + +static struct attribute_group amplifier_attribute_group = { + .name = "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 + */ +static ssize_t show_deepsleep_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + acpi_status status; + u32 out_data; + struct wmax_basic_args in_args = { + .arg = 0, + }; + status = alienware_wmax_command(&in_args, WMAX_METHOD_DEEP_SLEEP_STATUS, + (u32 *) &out_data); + if (ACPI_SUCCESS(status)) { + if (out_data == 0) + return scnprintf(buf, PAGE_SIZE, + "[disabled] s5 s5_s4\n"); + else if (out_data == 1) + return scnprintf(buf, PAGE_SIZE, + "disabled [s5] s5_s4\n"); + else if (out_data == 2) + return scnprintf(buf, PAGE_SIZE, + "disabled s5 [s5_s4]\n"); + } + pr_err("alienware-wmi: unknown deep sleep status: %d\n", status); + return scnprintf(buf, PAGE_SIZE, "disabled s5 s5_s4 [unknown]\n"); +} + +static ssize_t toggle_deepsleep(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + acpi_status status; + struct wmax_basic_args args; + + 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); + + status = alienware_wmax_command(&args, WMAX_METHOD_DEEP_SLEEP_CONTROL, + NULL); + + if (ACPI_FAILURE(status)) + pr_err("alienware-wmi: deep sleep control failed: results: %u\n", + status); + return count; +} + +static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep); + +static struct attribute *deepsleep_attrs[] = { + &dev_attr_deepsleep.attr, + NULL, +}; + +static struct attribute_group deepsleep_attribute_group = { + .name = "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; } @@ -606,6 +798,18 @@ static int __init alienware_wmi_init(void) 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; + } + ret = alienware_zone_init(platform_device); if (ret) goto fail_prep_zones; @@ -614,6 +818,8 @@ static int __init alienware_wmi_init(void) fail_prep_zones: alienware_zone_exit(platform_device); +fail_prep_deepsleep: +fail_prep_amplifier: fail_prep_hdmi: platform_device_del(platform_device); fail_platform_device2: diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 131fee2b093e..091ca7ada8fc 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -272,6 +272,15 @@ static const struct dmi_system_id asus_quirks[] = { }, { .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X75VD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"), + }, + .driver_data = &quirk_asus_wapf4, + }, + { + .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. 1015E", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index aaeeae81e3a9..2c2f02b2e08a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -28,12 +28,11 @@ #include <linux/acpi.h> #include <linux/mm.h> #include <linux/i8042.h> -#include <linux/slab.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <acpi/video.h> -#include "../../firmware/dcdbas.h" #include "dell-rbtn.h" +#include "dell-smbios.h" #define BRIGHTNESS_TOKEN 0x7d #define KBD_LED_OFF_TOKEN 0x01E1 @@ -44,33 +43,6 @@ #define KBD_LED_AUTO_75_TOKEN 0x02EC #define KBD_LED_AUTO_100_TOKEN 0x02F6 -/* This structure will be modified by the firmware when we enter - * system management mode, hence the volatiles */ - -struct calling_interface_buffer { - u16 class; - u16 select; - volatile u32 input[4]; - volatile u32 output[4]; -} __packed; - -struct calling_interface_token { - u16 tokenID; - u16 location; - union { - u16 value; - u16 stringlength; - }; -}; - -struct calling_interface_structure { - struct dmi_header header; - u16 cmdIOAddress; - u8 cmdIOCode; - u32 supportedCmds; - struct calling_interface_token tokens[]; -} __packed; - struct quirk_entry { u8 touchpad_led; @@ -103,11 +75,6 @@ static struct quirk_entry quirk_dell_xps13_9333 = { .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, }; -static int da_command_address; -static int da_command_code; -static int da_num_tokens; -static struct calling_interface_token *da_tokens; - static struct platform_driver platform_driver = { .driver = { .name = "dell-laptop", @@ -306,126 +273,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -static struct calling_interface_buffer *buffer; -static DEFINE_MUTEX(buffer_mutex); - -static void clear_buffer(void) -{ - memset(buffer, 0, sizeof(struct calling_interface_buffer)); -} - -static void get_buffer(void) -{ - mutex_lock(&buffer_mutex); - clear_buffer(); -} - -static void release_buffer(void) -{ - mutex_unlock(&buffer_mutex); -} - -static void __init parse_da_table(const struct dmi_header *dm) -{ - /* Final token is a terminator, so we don't want to copy it */ - int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; - struct calling_interface_token *new_da_tokens; - struct calling_interface_structure *table = - container_of(dm, struct calling_interface_structure, header); - - /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least - 6 bytes of entry */ - - if (dm->length < 17) - return; - - da_command_address = table->cmdIOAddress; - da_command_code = table->cmdIOCode; - - new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * - sizeof(struct calling_interface_token), - GFP_KERNEL); - - if (!new_da_tokens) - return; - da_tokens = new_da_tokens; - - memcpy(da_tokens+da_num_tokens, table->tokens, - sizeof(struct calling_interface_token) * tokens); - - da_num_tokens += tokens; -} - -static void __init find_tokens(const struct dmi_header *dm, void *dummy) -{ - switch (dm->type) { - case 0xd4: /* Indexed IO */ - case 0xd5: /* Protected Area Type 1 */ - case 0xd6: /* Protected Area Type 2 */ - break; - case 0xda: /* Calling interface */ - parse_da_table(dm); - break; - } -} - -static int find_token_id(int tokenid) -{ - int i; - - for (i = 0; i < da_num_tokens; i++) { - if (da_tokens[i].tokenID == tokenid) - return i; - } - - return -1; -} - -static int find_token_location(int tokenid) -{ - int id; - - id = find_token_id(tokenid); - if (id == -1) - return -1; - - return da_tokens[id].location; -} - -static struct calling_interface_buffer * -dell_send_request(struct calling_interface_buffer *buffer, int class, - int select) -{ - struct smi_cmd command; - - command.magic = SMI_CMD_MAGIC; - command.command_address = da_command_address; - command.command_code = da_command_code; - command.ebx = virt_to_phys(buffer); - command.ecx = 0x42534931; - - buffer->class = class; - buffer->select = select; - - dcdbas_smi_request(&command); - - return buffer; -} - -static inline int dell_smi_error(int value) -{ - switch (value) { - case 0: /* Completed successfully */ - return 0; - case -1: /* Completed with error */ - return -EIO; - case -2: /* Function not supported */ - return -ENXIO; - default: /* Unknown error */ - return -EINVAL; - } -} - /* * Derived from information in smbios-wireless-ctl: * @@ -548,6 +395,7 @@ static inline int dell_smi_error(int value) static int dell_rfkill_set(void *data, bool blocked) { + struct calling_interface_buffer *buffer; int disable = blocked ? 1 : 0; unsigned long radio = (unsigned long)data; int hwswitch_bit = (unsigned long)data - 1; @@ -555,19 +403,19 @@ static int dell_rfkill_set(void *data, bool blocked) int status; int ret; - get_buffer(); + buffer = dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; if (ret != 0) goto out; - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; hwswitch = buffer->output[1]; @@ -577,27 +425,28 @@ static int dell_rfkill_set(void *data, bool blocked) (status & BIT(0)) && !(status & BIT(16))) disable = 1; - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio<<8) | (disable << 16)); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; out: - release_buffer(); - return dell_smi_error(ret); + dell_smbios_release_buffer(); + return dell_smbios_error(ret); } /* Must be called with the buffer held */ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, - int status) + int status, + struct calling_interface_buffer *buffer) { if (status & BIT(0)) { /* Has hw-switch, sync sw_state to BIOS */ int block = rfkill_blocked(rfkill); - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio << 8) | (block << 16)); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -613,30 +462,31 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, static void dell_rfkill_query(struct rfkill *rfkill, void *data) { |
