From 66ad0dd30285e14529566a2f816a0d463f63cf81 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:52 -0600 Subject: [PATCH 01/47] alienware-wmi: Clean up whitespace for ASM100 platform This brings them more in line with the usage of whitespace in other platforms. Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 1e1e59423889..a8750ed720b8 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -105,14 +105,14 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { .driver_data = &quirk_x51_family, }, { - .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 ASM100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), + }, + .driver_data = &quirk_asm100, + }, {} }; From 9e503a9d0c18b277f902570a3dfd74a7c86ec9a7 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:53 -0600 Subject: [PATCH 02/47] alienware-wmi: Add support for new platform: X51-R3 The X51-R3 is in the X51 family. It includes 3 internal lighting zones as well as is the first AW desktop that includes support for a graphics amplifier. Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index a8750ed720b8..8e8ea4f2d59f 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -69,11 +69,16 @@ static struct quirk_entry quirk_unknown = { .hdmi_mux = 0, }; -static struct quirk_entry quirk_x51_family = { +static struct quirk_entry quirk_x51_r1_r2 = { .num_zones = 3, .hdmi_mux = 0. }; +static struct quirk_entry quirk_x51_r3 = { + .num_zones = 4, + .hdmi_mux = 0, +}; + static struct quirk_entry quirk_asm100 = { .num_zones = 2, .hdmi_mux = 1, @@ -88,12 +93,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,7 +107,16 @@ 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, From cbbb50d6038bc093154fb6e209729bbf8bebd614 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:54 -0600 Subject: [PATCH 03/47] alienware-wmi: Add initial support for alienware graphics amplifier. The alienware graphics amplifier is a device that provides external access to a full PCIe slot, USB hub, and additional control zone. This patch enables support for reading status whether the cable is plugged in as well as for setting the colors in the new zone on the amplifier. Signed-off-by: Mario Limonciello [dvhart: minor comment formatting fixes] Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 107 ++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 8e8ea4f2d59f..fa86b7d5d6b5 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -33,6 +33,7 @@ #define WMAX_METHOD_BRIGHTNESS 0x3 #define WMAX_METHOD_ZONE_CONTROL 0x4 #define WMAX_METHOD_HDMI_CABLE 0x5 +#define WMAX_METHOD_AMPLIFIER_CABLE 0x6 MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Alienware special feature control"); @@ -60,6 +61,7 @@ enum WMAX_CONTROL_STATES { struct quirk_entry { u8 num_zones; u8 hdmi_mux; + u8 amplifier; }; static struct quirk_entry *quirks; @@ -67,21 +69,25 @@ static struct quirk_entry *quirks; static struct quirk_entry quirk_unknown = { .num_zones = 2, .hdmi_mux = 0, + .amplifier = 0, }; static struct quirk_entry quirk_x51_r1_r2 = { .num_zones = 3, - .hdmi_mux = 0. + .hdmi_mux = 0, + .amplifier = 0, }; static struct quirk_entry quirk_x51_r3 = { .num_zones = 4, .hdmi_mux = 0, + .amplifier = 1, }; static struct quirk_entry quirk_asm100 = { .num_zones = 2, .hdmi_mux = 1, + .amplifier = 0, }; static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -147,7 +153,7 @@ struct wmax_brightness_args { u32 percentage; }; -struct hdmi_args { +struct wmax_basic_args { u8 arg; }; @@ -232,16 +238,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; @@ -449,11 +455,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; @@ -481,16 +483,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) @@ -509,11 +515,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)) { @@ -533,7 +539,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) @@ -542,7 +548,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", @@ -585,6 +591,62 @@ static int create_hdmi(struct platform_device *dev) return ret; } +/* + * 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; +} + static int __init alienware_wmi_init(void) { int ret; @@ -620,6 +682,12 @@ 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; + } + ret = alienware_zone_init(platform_device); if (ret) goto fail_prep_zones; @@ -628,6 +696,7 @@ static int __init alienware_wmi_init(void) fail_prep_zones: alienware_zone_exit(platform_device); +fail_prep_amplifier: fail_prep_hdmi: platform_device_del(platform_device); fail_platform_device2: From 8ea81ec67b82fd35e389c3eef395206bac8e2259 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:55 -0600 Subject: [PATCH 04/47] alienware-wmi: Add support for deep sleep control. Allow for user configuration of BIOS settings that allow the system to be turned on via HID devices. The feature requires hardware architectural modifications and can not be supported on existing systems. Signed-off-by: Mario Limonciello [dvhart: comment formatting and line length fixes] Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 95 ++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index fa86b7d5d6b5..a9f8d3044cd3 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -34,6 +34,8 @@ #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 "); MODULE_DESCRIPTION("Alienware special feature control"); @@ -62,6 +64,7 @@ struct quirk_entry { u8 num_zones; u8 hdmi_mux; u8 amplifier; + u8 deepslp; }; static struct quirk_entry *quirks; @@ -70,24 +73,28 @@ 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 int __init dmi_matched(const struct dmi_system_id *dmi) @@ -647,6 +654,87 @@ static int create_amplifier(struct platform_device *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; +} + static int __init alienware_wmi_init(void) { int ret; @@ -688,6 +776,12 @@ static int __init alienware_wmi_init(void) 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; @@ -696,6 +790,7 @@ 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); From b332f82e3868bc191914adfb1caadcc77c076df2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:56 -0600 Subject: [PATCH 05/47] alienware-wmi: Add support for two new systems: ASM200 and ASM201. Both of these systems support: * 2 lighting control zones * HDMI mux control * deep sleep control (to enable wakup from controller) The ASM201 also supports the external graphics amplifier. Signed-off-by: Mario Limonciello Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index a9f8d3044cd3..275a56d47e56 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -97,6 +97,20 @@ static struct quirk_entry quirk_asm100 = { .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; @@ -140,6 +154,24 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { }, .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, + }, {} }; From ec5eeadc44bf05a8619627d6882fdf5775c19396 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Tue, 2 Feb 2016 15:38:57 -0600 Subject: [PATCH 06/47] alienware-wmi: whitespace improvements These were some items that were pointed out in previous patches that weren't caught be previous reviewers, but should be applied to other parts of the driver as well. Signed-off-by: Mario Limonciello [dvhart: reverted a couple incorrect line wrapping changes] Signed-off-by: Darren Hart --- drivers/platform/x86/alienware-wmi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 275a56d47e56..005629447b0c 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -229,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; @@ -269,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; @@ -342,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; @@ -386,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) { @@ -622,11 +622,7 @@ 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; - -error_create_hdmi: - remove_hdmi(dev); + remove_hdmi(dev); return ret; } From 15c75626f0999cce8357c8bf8578247134032acb Mon Sep 17 00:00:00 2001 From: Eric Curtin Date: Sat, 30 Jan 2016 16:55:59 +0000 Subject: [PATCH 07/47] thinkpad_acpi: Remove ambiguous logging for "Unsupported brightness interface" "Unsupported brightness interface" message gets logged on machines that are well supported. Signed-off-by: Eric Curtin Acked-by: Henrique de Moraes Holschuh Signed-off-by: Darren Hart --- drivers/platform/x86/thinkpad_acpi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a268a7abf8ab..e305ab541a22 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6653,18 +6653,16 @@ static void __init tpacpi_detect_brightness_capabilities(void) switch (b) { case 16: bright_maxlvl = 15; - pr_info("detected a 16-level brightness capable ThinkPad\n"); break; case 8: case 0: bright_maxlvl = 7; - pr_info("detected a 8-level brightness capable ThinkPad\n"); break; default: - pr_info("Unsupported brightness interface\n"); tp_features.bright_unkfw = 1; bright_maxlvl = b - 1; } + pr_debug("detected %u brightness levels\n", bright_maxlvl + 1); } static int __init brightness_init(struct ibm_init_struct *iibm) From 763ff32f19442b952406d4ac1ec1fb19733d23be Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 25 Jan 2016 11:29:10 -0700 Subject: [PATCH 08/47] toshiba_acpi: Add support for cooling method feature This patch adds support to query and set the "Cooling Method" feature, which basically changes how the system fan behaves, depending on the supported cooling methods. Depending on the laptop model, these are the (so far...) available cooling methods: - Maximum Performance - Performance - Battery Optimized Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 73833079bac8..c6f92ec636e7 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -117,6 +117,7 @@ MODULE_LICENSE("GPL"); #define HCI_LCD_BRIGHTNESS 0x002a #define HCI_WIRELESS 0x0056 #define HCI_ACCELEROMETER 0x006d +#define HCI_COOLING_METHOD 0x007f #define HCI_KBD_ILLUMINATION 0x0095 #define HCI_ECO_MODE 0x0097 #define HCI_ACCELEROMETER2 0x00a6 @@ -186,6 +187,7 @@ struct toshiba_acpi_dev { int usbsc_bat_level; int usbsc_mode_base; int hotkey_event_type; + int max_cooling_method; unsigned int illumination_supported:1; unsigned int video_supported:1; @@ -205,6 +207,7 @@ struct toshiba_acpi_dev { unsigned int panel_power_on_supported:1; unsigned int usb_three_supported:1; unsigned int wwan_supported:1; + unsigned int cooling_method_supported:1; unsigned int sysfs_created:1; unsigned int special_functions; @@ -1194,6 +1197,53 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) return out[0] == TOS_SUCCESS ? 0 : -EIO; } +/* Cooling Method */ +static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) +{ + u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; + u32 out[TCI_WORDS]; + acpi_status status; + + dev->cooling_method_supported = 0; + dev->max_cooling_method = 0; + + status = tci_raw(dev, in, out); + if (ACPI_FAILURE(status)) + pr_err("ACPI call to get Cooling Method failed\n"); + + if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) + return; + + dev->cooling_method_supported = 1; + dev->max_cooling_method = out[3]; +} + +static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) +{ + u32 result = hci_read(dev, HCI_COOLING_METHOD, state); + + if (result == TOS_FAILURE) + pr_err("ACPI call to get Cooling Method failed\n"); + + if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; +} + +static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) +{ + u32 result = hci_write(dev, HCI_COOLING_METHOD, state); + + if (result == TOS_FAILURE) + pr_err("ACPI call to get Cooling Method failed\n"); + + if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; +} + /* Transflective Backlight */ static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) { @@ -2779,6 +2829,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev) pr_cont(" usb3"); if (dev->wwan_supported) pr_cont(" wwan"); + if (dev->cooling_method_supported) + pr_cont(" cooling-method"); pr_cont("\n"); } @@ -2963,6 +3015,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) if (dev->wwan_supported) toshiba_acpi_setup_wwan_rfkill(dev); + toshiba_cooling_method_available(dev); + print_supported_features(dev); ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, From b1009b919b4061293f4a5e68210ccbc6d3f33a99 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 25 Jan 2016 11:29:11 -0700 Subject: [PATCH 09/47] toshiba_acpi: Add sysfs entries for the Cooling Method feature This patch adds the sysfs entry Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c6f92ec636e7..5ace1e0fd0bd 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2289,6 +2289,54 @@ static ssize_t usb_three_store(struct device *dev, } static DEVICE_ATTR_RW(usb_three); +static ssize_t cooling_method_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); + int state; + int ret; + + ret = toshiba_cooling_method_get(toshiba, &state); + if (ret < 0) + return ret; + + return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); +} + +static ssize_t cooling_method_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); + int state; + int ret; + + ret = kstrtoint(buf, 0, &state); + if (ret) + return ret; + + /* + * Check for supported values + * Depending on the laptop model, some only support these two: + * 0 - Maximum Performance + * 1 - Battery Optimized + * + * While some others support all three methods: + * 0 - Maximum Performance + * 1 - Performance + * 2 - Battery Optimized + */ + if (state < 0 || state > toshiba->max_cooling_method) + return -EINVAL; + + ret = toshiba_cooling_method_set(toshiba, state); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_RW(cooling_method); + static struct attribute *toshiba_attributes[] = { &dev_attr_version.attr, &dev_attr_fan.attr, @@ -2305,6 +2353,7 @@ static struct attribute *toshiba_attributes[] = { &dev_attr_kbd_function_keys.attr, &dev_attr_panel_power_on.attr, &dev_attr_usb_three.attr, + &dev_attr_cooling_method.attr, NULL, }; @@ -2339,6 +2388,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, exists = (drv->panel_power_on_supported) ? true : false; else if (attr == &dev_attr_usb_three.attr) exists = (drv->usb_three_supported) ? true : false; + else if (attr == &dev_attr_cooling_method.attr) + exists = (drv->cooling_method_supported) ? true : false; return exists ? attr->mode : 0; } From 33f857a441f05b68a55e1f6b3ecf1ea82d6633a4 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 25 Jan 2016 11:29:53 -0700 Subject: [PATCH 10/47] Documentation/ABI: Update sysfs-driver-toshiba_acpi file This patch updates the documentation file adding the Cooling Method entry. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- .../ABI/testing/sysfs-driver-toshiba_acpi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 +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 From 7faa6a37fa106cb0cad6203e8fc2aea646cb253a Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 25 Jan 2016 12:52:18 -0700 Subject: [PATCH 11/47] toshiba_acpi: Add a module parameter to disable hotkeys registration Some laptop models have working hotkeys without the need of the driver to activate them. This patch adds a module parameter to tell the driver not to register the hotkeys. The new parameter is useful in DE less installations or where the DE does not handle the hotkeys (see bug 99501). Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 5ace1e0fd0bd..df1f1a76a862 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -220,6 +221,10 @@ struct toshiba_acpi_dev { static struct toshiba_acpi_dev *toshiba_acpi; +static bool disable_hotkeys; +module_param(disable_hotkeys, bool, 0444); +MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation"); + static const struct acpi_device_id toshiba_device_ids[] = { {"TOS6200", 0}, {"TOS6207", 0}, @@ -2692,6 +2697,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) acpi_handle ec_handle; int error; + if (disable_hotkeys) { + pr_info("Hotkeys disabled by module parameter\n"); + return 0; + } + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { pr_info("WMI event detected, hotkeys will not be monitored\n"); return 0; From 2f9f26bd8614740b3c3b950394d945a99492a28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:13 +0100 Subject: [PATCH 12/47] dell-laptop: extract SMBIOS-related code to a separate module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract SMBIOS-related code from dell-laptop to a new kernel module, dell-smbios. The static specifier is removed from exported symbols, otherwise code is just moved around. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár [dvhart: Include linux/io.h in dell-smbios.c as caught by lkp] Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 12 +- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/dell-laptop.c | 163 +----------------------- drivers/platform/x86/dell-smbios.c | 194 +++++++++++++++++++++++++++++ drivers/platform/x86/dell-smbios.h | 50 ++++++++ 5 files changed, 257 insertions(+), 163 deletions(-) create mode 100644 drivers/platform/x86/dell-smbios.c create mode 100644 drivers/platform/x86/dell-smbios.h diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 69f93a576e45..3e4d9c3e83fd 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -91,10 +91,20 @@ 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 BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n 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/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index aaeeae81e3a9..d45d356b6e69 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -28,12 +28,11 @@ #include #include #include -#include #include #include #include -#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,112 +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) { @@ -2122,13 +1983,6 @@ static int __init dell_init(void) /* find if this machine support other functions */ dmi_check_system(dell_quirks); - dmi_walk(find_tokens, NULL); - - if (!da_tokens) { - pr_info("Unable to find dmi tokens\n"); - return -ENODEV; - } - ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; @@ -2141,16 +1995,6 @@ static int __init dell_init(void) if (ret) goto fail_platform_device2; - /* - * Allocate buffer below 4GB for SMI data--only 32-bit physical addr - * is passed to SMI handler. - */ - buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); - if (!buffer) { - ret = -ENOMEM; - goto fail_buffer; - } - ret = dell_setup_rfkill(); if (ret) { @@ -2208,15 +2052,12 @@ static int __init dell_init(void) fail_backlight: dell_cleanup_rfkill(); fail_rfkill: - free_page((unsigned long)buffer); -fail_buffer: platform_device_del(platform_device); fail_platform_device2: platform_device_put(platform_device); fail_platform_device1: platform_driver_unregister(&platform_driver); fail_platform_driver: - kfree(da_tokens); return ret; } @@ -2232,8 +2073,6 @@ static void __exit dell_exit(void) platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } - kfree(da_tokens); - free_page((unsigned long)buffer); } /* dell-rbtn.c driver export functions which will not work correctly (and could diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c new file mode 100644 index 000000000000..d1aae53dc7a7 --- /dev/null +++ b/drivers/platform/x86/dell-smbios.c @@ -0,0 +1,194 @@ +/* + * Common functions for kernel modules using Dell SMBIOS + * + * Copyright (c) Red Hat + * Copyright (c) 2014 Gabriele Mazzotta + * Copyright (c) 2014 Pali Rohár + * + * Based on documentation in the libsmbios package: + * Copyright (C) 2005-2014 Dell Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../firmware/dcdbas.h" +#include "dell-smbios.h" + +struct calling_interface_structure { + struct dmi_header header; + u16 cmdIOAddress; + u8 cmdIOCode; + u32 supportedCmds; + struct calling_interface_token tokens[]; +} __packed; + +struct calling_interface_buffer *buffer; +EXPORT_SYMBOL_GPL(buffer); +static DEFINE_MUTEX(buffer_mutex); + +static int da_command_address; +static int da_command_code; +static int da_num_tokens; +struct calling_interface_token *da_tokens; +EXPORT_SYMBOL_GPL(da_tokens); + +void get_buffer(void) +{ + mutex_lock(&buffer_mutex); + clear_buffer(); +} +EXPORT_SYMBOL_GPL(get_buffer); + +void clear_buffer(void) +{ + memset(buffer, 0, sizeof(struct calling_interface_buffer)); +} +EXPORT_SYMBOL_GPL(clear_buffer); + +void release_buffer(void) +{ + mutex_unlock(&buffer_mutex); +} +EXPORT_SYMBOL_GPL(release_buffer); + +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; +} +EXPORT_SYMBOL_GPL(dell_send_request); + +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; +} +EXPORT_SYMBOL_GPL(find_token_id); + +int find_token_location(int tokenid) +{ + int id; + + id = find_token_id(tokenid); + if (id == -1) + return -1; + + return da_tokens[id].location; +} +EXPORT_SYMBOL_GPL(find_token_location); + +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 __init dell_smbios_init(void) +{ + int ret; + + dmi_walk(find_tokens, NULL); + + if (!da_tokens) { + pr_info("Unable to find dmi tokens\n"); + return -ENODEV; + } + + /* + * Allocate buffer below 4GB for SMI data--only 32-bit physical addr + * is passed to SMI handler. + */ + buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); + if (!buffer) { + ret = -ENOMEM; + goto fail_buffer; + } + + return 0; + +fail_buffer: + kfree(da_tokens); + return ret; +} + +static void __exit dell_smbios_exit(void) +{ + kfree(da_tokens); + free_page((unsigned long)buffer); +} + +subsys_initcall(dell_smbios_init); +module_exit(dell_smbios_exit); + +MODULE_AUTHOR("Matthew Garrett "); +MODULE_AUTHOR("Gabriele Mazzotta "); +MODULE_AUTHOR("Pali Rohár "); +MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h new file mode 100644 index 000000000000..3bc9080e4c5d --- /dev/null +++ b/drivers/platform/x86/dell-smbios.h @@ -0,0 +1,50 @@ +/* + * Common functions for kernel modules using Dell SMBIOS + * + * Copyright (c) Red Hat + * Copyright (c) 2014 Gabriele Mazzotta + * Copyright (c) 2014 Pali Rohár + * + * Based on documentation in the libsmbios package: + * Copyright (C) 2005-2014 Dell Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _DELL_SMBIOS_H_ +#define _DELL_SMBIOS_H_ + +/* 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; + }; +}; + +extern struct calling_interface_buffer *buffer; +extern struct calling_interface_token *da_tokens; + +void get_buffer(void); +void clear_buffer(void); +void release_buffer(void); +struct calling_interface_buffer * +dell_send_request(struct calling_interface_buffer *buffer, + int class, int select); + +int find_token_id(int tokenid); +int find_token_location(int tokenid); +#endif From ee83c475415edd48b0739bee230b75454b82199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:14 +0100 Subject: [PATCH 13/47] dell-smbios: rename get_buffer() to dell_smbios_get_buffer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As get_buffer() is exported from the module, it has to be renamed to something less generic, so add a "dell_smbios_" prefix to the function name. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 26 +++++++++++++------------- drivers/platform/x86/dell-smbios.c | 4 ++-- drivers/platform/x86/dell-smbios.h | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index d45d356b6e69..575b0dfa4d37 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -416,7 +416,7 @@ static int dell_rfkill_set(void *data, bool blocked) int status; int ret; - get_buffer(); + dell_smbios_get_buffer(); dell_send_request(buffer, 17, 11); ret = buffer->output[0]; @@ -479,7 +479,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) int status; int ret; - get_buffer(); + dell_smbios_get_buffer(); dell_send_request(buffer, 17, 11); ret = buffer->output[0]; @@ -519,7 +519,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) int status; int ret; - get_buffer(); + dell_smbios_get_buffer(); dell_send_request(buffer, 17, 11); ret = buffer->output[0]; @@ -617,7 +617,7 @@ static void dell_update_rfkill(struct work_struct *ignored) int status; int ret; - get_buffer(); + dell_smbios_get_buffer(); dell_send_request(buffer, 17, 11); ret = buffer->output[0]; @@ -709,7 +709,7 @@ static int __init dell_setup_rfkill(void) if (!force_rfkill && !whitelisted) return 0; - get_buffer(); + dell_smbios_get_buffer(); dell_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -873,7 +873,7 @@ static int dell_send_intensity(struct backlight_device *bd) if (token == -1) return -ENODEV; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = token; buffer->input[1] = bd->props.brightness; @@ -897,7 +897,7 @@ static int dell_get_intensity(struct backlight_device *bd) if (token == -1) return -ENODEV; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = token; if (power_supply_is_system_supplied() > 0) @@ -1157,7 +1157,7 @@ static int kbd_get_info(struct kbd_info *info) u8 units; int ret; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = 0x0; dell_send_request(buffer, 4, 11); @@ -1245,7 +1245,7 @@ static int kbd_get_state(struct kbd_state *state) { int ret; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = 0x1; dell_send_request(buffer, 4, 11); @@ -1276,7 +1276,7 @@ static int kbd_set_state(struct kbd_state *state) { int ret; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = 0x2; buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; buffer->input[1] |= (state->triggers & 0xFF) << 16; @@ -1323,7 +1323,7 @@ static int kbd_set_token_bit(u8 bit) if (id == -1) return -EINVAL; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; buffer->input[1] = da_tokens[id].value; dell_send_request(buffer, 1, 0); @@ -1346,7 +1346,7 @@ static int kbd_get_token_bit(u8 bit) if (id == -1) return -EINVAL; - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; dell_send_request(buffer, 0, 0); ret = buffer->output[0]; @@ -2017,7 +2017,7 @@ static int __init dell_init(void) token = find_token_location(BRIGHTNESS_TOKEN); if (token != -1) { - get_buffer(); + dell_smbios_get_buffer(); buffer->input[0] = token; dell_send_request(buffer, 0, 2); if (buffer->output[0] == 0) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index d1aae53dc7a7..584443187ca6 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -41,12 +41,12 @@ static int da_num_tokens; struct calling_interface_token *da_tokens; EXPORT_SYMBOL_GPL(da_tokens); -void get_buffer(void) +void dell_smbios_get_buffer(void) { mutex_lock(&buffer_mutex); clear_buffer(); } -EXPORT_SYMBOL_GPL(get_buffer); +EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); void clear_buffer(void) { diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 3bc9080e4c5d..ace16c128a77 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -38,7 +38,7 @@ struct calling_interface_token { extern struct calling_interface_buffer *buffer; extern struct calling_interface_token *da_tokens; -void get_buffer(void); +void dell_smbios_get_buffer(void); void clear_buffer(void); void release_buffer(void); struct calling_interface_buffer * From b6aa7e1817a35b93550283707dc93c98d41813eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:15 +0100 Subject: [PATCH 14/47] dell-smbios: rename clear_buffer() to dell_smbios_clear_buffer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As clear_buffer() is exported from the module, it has to be renamed to something less generic, so add a "dell_smbios_" prefix to the function name. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 12 ++++++------ drivers/platform/x86/dell-smbios.c | 6 +++--- drivers/platform/x86/dell-smbios.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 575b0dfa4d37..90d75cecb984 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -425,7 +425,7 @@ static int dell_rfkill_set(void *data, bool blocked) if (ret != 0) goto out; - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = 0x2; dell_send_request(buffer, 17, 11); @@ -438,7 +438,7 @@ 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); @@ -456,7 +456,7 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, 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); } else { @@ -490,7 +490,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) return; } - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = 0x2; dell_send_request(buffer, 17, 11); @@ -525,7 +525,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) ret = buffer->output[0]; status = buffer->output[1]; - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = 0x2; dell_send_request(buffer, 17, 11); @@ -626,7 +626,7 @@ static void dell_update_rfkill(struct work_struct *ignored) if (ret != 0) goto out; - clear_buffer(); + dell_smbios_clear_buffer(); buffer->input[0] = 0x2; dell_send_request(buffer, 17, 11); diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 584443187ca6..2fcdfafb52ba 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -44,15 +44,15 @@ EXPORT_SYMBOL_GPL(da_tokens); void dell_smbios_get_buffer(void) { mutex_lock(&buffer_mutex); - clear_buffer(); + dell_smbios_clear_buffer(); } EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); -void clear_buffer(void) +void dell_smbios_clear_buffer(void) { memset(buffer, 0, sizeof(struct calling_interface_buffer)); } -EXPORT_SYMBOL_GPL(clear_buffer); +EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer); void release_buffer(void) { diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index ace16c128a77..c5e94742505b 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -39,7 +39,7 @@ extern struct calling_interface_buffer *buffer; extern struct calling_interface_token *da_tokens; void dell_smbios_get_buffer(void); -void clear_buffer(void); +void dell_smbios_clear_buffer(void); void release_buffer(void); struct calling_interface_buffer * dell_send_request(struct calling_interface_buffer *buffer, From cb16176380cca991dba162952941ad04ae760d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:16 +0100 Subject: [PATCH 15/47] dell-smbios: rename release_buffer() to dell_smbios_release_buffer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As release_buffer() is exported from the module, it has to be renamed to something less generic, so add a "dell_smbios_" prefix to the function name. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 28 ++++++++++++++-------------- drivers/platform/x86/dell-smbios.c | 4 ++-- drivers/platform/x86/dell-smbios.h | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 90d75cecb984..b47dc5a893ad 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -445,7 +445,7 @@ static int dell_rfkill_set(void *data, bool blocked) ret = buffer->output[0]; out: - release_buffer(); + dell_smbios_release_buffer(); return dell_smi_error(ret); } @@ -486,7 +486,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) status = buffer->output[1]; if (ret != 0 || !(status & BIT(0))) { - release_buffer(); + dell_smbios_release_buffer(); return; } @@ -497,7 +497,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) ret = buffer->output[0]; hwswitch = buffer->output[1]; - release_buffer(); + dell_smbios_release_buffer(); if (ret != 0) return; @@ -532,7 +532,7 @@ static int dell_debugfs_show(struct seq_file *s, void *data) hwswitch_ret = buffer->output[0]; hwswitch_state = buffer->output[1]; - release_buffer(); + dell_smbios_release_buffer(); seq_printf(s, "return:\t%d\n", ret); seq_printf(s, "status:\t0x%X\n", status); @@ -650,7 +650,7 @@ static void dell_update_rfkill(struct work_struct *ignored) } out: - release_buffer(); + dell_smbios_release_buffer(); } static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); @@ -713,7 +713,7 @@ static int __init dell_setup_rfkill(void) dell_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; - release_buffer(); + dell_smbios_release_buffer(); /* dell wireless info smbios call is not supported */ if (ret != 0) @@ -884,7 +884,7 @@ static int dell_send_intensity(struct backlight_device *bd) ret = dell_smi_error(buffer->output[0]); - release_buffer(); + dell_smbios_release_buffer(); return ret; } @@ -910,7 +910,7 @@ static int dell_get_intensity(struct backlight_device *bd) else ret = buffer->output[1]; - release_buffer(); + dell_smbios_release_buffer(); return ret; } @@ -1184,7 +1184,7 @@ static int kbd_get_info(struct kbd_info *info) info->days = (buffer->output[3] >> 24) & 0xFF; out: - release_buffer(); + dell_smbios_release_buffer(); return ret; } @@ -1268,7 +1268,7 @@ static int kbd_get_state(struct kbd_state *state) state->level = (buffer->output[2] >> 16) & 0xFF; out: - release_buffer(); + dell_smbios_release_buffer(); return ret; } @@ -1286,7 +1286,7 @@ static int kbd_set_state(struct kbd_state *state) buffer->input[2] |= (state->level & 0xFF) << 16; dell_send_request(buffer, 4, 11); ret = buffer->output[0]; - release_buffer(); + dell_smbios_release_buffer(); return dell_smi_error(ret); } @@ -1328,7 +1328,7 @@ static int kbd_set_token_bit(u8 bit) buffer->input[1] = da_tokens[id].value; dell_send_request(buffer, 1, 0); ret = buffer->output[0]; - release_buffer(); + dell_smbios_release_buffer(); return dell_smi_error(ret); } @@ -1351,7 +1351,7 @@ static int kbd_get_token_bit(u8 bit) dell_send_request(buffer, 0, 0); ret = buffer->output[0]; val = buffer->output[1]; - release_buffer(); + dell_smbios_release_buffer(); if (ret) return dell_smi_error(ret); @@ -2022,7 +2022,7 @@ static int __init dell_init(void) dell_send_request(buffer, 0, 2); if (buffer->output[0] == 0) max_intensity = buffer->output[3]; - release_buffer(); + dell_smbios_release_buffer(); } if (max_intensity) { diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 2fcdfafb52ba..194505b7f07a 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -54,11 +54,11 @@ void dell_smbios_clear_buffer(void) } EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer); -void release_buffer(void) +void dell_smbios_release_buffer(void) { mutex_unlock(&buffer_mutex); } -EXPORT_SYMBOL_GPL(release_buffer); +EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); struct calling_interface_buffer * dell_send_request(struct calling_interface_buffer *buffer, diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index c5e94742505b..85581037a547 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -40,7 +40,7 @@ extern struct calling_interface_token *da_tokens; void dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); -void release_buffer(void); +void dell_smbios_release_buffer(void); struct calling_interface_buffer * dell_send_request(struct calling_interface_buffer *buffer, int class, int select); From 2f262136159fedceb45b42336ae53f20bc0ff714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:17 +0100 Subject: [PATCH 16/47] dell-smbios: rename dell_send_request() to dell_smbios_send_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As dell_send_request() is exported from the module, its prefix should be consistent with other exported symbols, so change function name to dell_smbios_send_request(). Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 42 +++++++++++++++--------------- drivers/platform/x86/dell-smbios.c | 6 ++--- drivers/platform/x86/dell-smbios.h | 4 +-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index b47dc5a893ad..9210acf00d47 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -418,7 +418,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -428,7 +428,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; hwswitch = buffer->output[1]; @@ -441,7 +441,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio<<8) | (disable << 16)); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; out: @@ -458,7 +458,7 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, int block = rfkill_blocked(rfkill); dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio << 8) | (block << 16)); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); } else { /* No hw-switch, sync BIOS state to sw_state */ rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); @@ -481,7 +481,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -493,7 +493,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; hwswitch = buffer->output[1]; @@ -521,14 +521,14 @@ static int dell_debugfs_show(struct seq_file *s, void *data) dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); hwswitch_ret = buffer->output[0]; hwswitch_state = buffer->output[1]; @@ -619,7 +619,7 @@ static void dell_update_rfkill(struct work_struct *ignored) dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -629,7 +629,7 @@ static void dell_update_rfkill(struct work_struct *ignored) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; if (ret == 0 && (status & BIT(0))) @@ -710,7 +710,7 @@ static int __init dell_setup_rfkill(void) return 0; dell_smbios_get_buffer(); - dell_send_request(buffer, 17, 11); + dell_smbios_send_request(buffer, 17, 11); ret = buffer->output[0]; status = buffer->output[1]; dell_smbios_release_buffer(); @@ -878,9 +878,9 @@ static int dell_send_intensity(struct backlight_device *bd) buffer->input[1] = bd->props.brightness; if (power_supply_is_system_supplied() > 0) - dell_send_request(buffer, 1, 2); + dell_smbios_send_request(buffer, 1, 2); else - dell_send_request(buffer, 1, 1); + dell_smbios_send_request(buffer, 1, 1); ret = dell_smi_error(buffer->output[0]); @@ -901,9 +901,9 @@ static int dell_get_intensity(struct backlight_device *bd) buffer->input[0] = token; if (power_supply_is_system_supplied() > 0) - dell_send_request(buffer, 0, 2); + dell_smbios_send_request(buffer, 0, 2); else - dell_send_request(buffer, 0, 1); + dell_smbios_send_request(buffer, 0, 1); if (buffer->output[0]) ret = dell_smi_error(buffer->output[0]); @@ -1160,7 +1160,7 @@ static int kbd_get_info(struct kbd_info *info) dell_smbios_get_buffer(); buffer->input[0] = 0x0; - dell_send_request(buffer, 4, 11); + dell_smbios_send_request(buffer, 4, 11); ret = buffer->output[0]; if (ret) { @@ -1248,7 +1248,7 @@ static int kbd_get_state(struct kbd_state *state) dell_smbios_get_buffer(); buffer->input[0] = 0x1; - dell_send_request(buffer, 4, 11); + dell_smbios_send_request(buffer, 4, 11); ret = buffer->output[0]; if (ret) { @@ -1284,7 +1284,7 @@ static int kbd_set_state(struct kbd_state *state) buffer->input[1] |= (state->timeout_unit & 0x3) << 30; buffer->input[2] = state->als_setting & 0xFF; buffer->input[2] |= (state->level & 0xFF) << 16; - dell_send_request(buffer, 4, 11); + dell_smbios_send_request(buffer, 4, 11); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1326,7 +1326,7 @@ static int kbd_set_token_bit(u8 bit) dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; buffer->input[1] = da_tokens[id].value; - dell_send_request(buffer, 1, 0); + dell_smbios_send_request(buffer, 1, 0); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1348,7 +1348,7 @@ static int kbd_get_token_bit(u8 bit) dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; - dell_send_request(buffer, 0, 0); + dell_smbios_send_request(buffer, 0, 0); ret = buffer->output[0]; val = buffer->output[1]; dell_smbios_release_buffer(); @@ -2019,7 +2019,7 @@ static int __init dell_init(void) if (token != -1) { dell_smbios_get_buffer(); buffer->input[0] = token; - dell_send_request(buffer, 0, 2); + dell_smbios_send_request(buffer, 0, 2); if (buffer->output[0] == 0) max_intensity = buffer->output[3]; dell_smbios_release_buffer(); diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 194505b7f07a..b1038325a3fc 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -61,8 +61,8 @@ void dell_smbios_release_buffer(void) EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); struct calling_interface_buffer * -dell_send_request(struct calling_interface_buffer *buffer, - int class, int select) +dell_smbios_send_request(struct calling_interface_buffer *buffer, + int class, int select) { struct smi_cmd command; @@ -79,7 +79,7 @@ dell_send_request(struct calling_interface_buffer *buffer, return buffer; } -EXPORT_SYMBOL_GPL(dell_send_request); +EXPORT_SYMBOL_GPL(dell_smbios_send_request); int find_token_id(int tokenid) { diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 85581037a547..33ed9712430b 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -42,8 +42,8 @@ void dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); struct calling_interface_buffer * -dell_send_request(struct calling_interface_buffer *buffer, - int class, int select); +dell_smbios_send_request(struct calling_interface_buffer *buffer, + int class, int select); int find_token_id(int tokenid); int find_token_location(int tokenid); From 17070f242aa989c33b227e61ea060f768a77f2dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:18 +0100 Subject: [PATCH 17/47] dell-smbios: don't pass an SMBIOS buffer to dell_smbios_send_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passing an SMBIOS buffer pointer to dell_smbios_send_request() is redundant as it should always operate on the SMBIOS buffer exported from the module. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 42 +++++++++++++++--------------- drivers/platform/x86/dell-smbios.c | 3 +-- drivers/platform/x86/dell-smbios.h | 3 +-- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 9210acf00d47..0bb22114abce 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -418,7 +418,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_get_buffer(); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -428,7 +428,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; hwswitch = buffer->output[1]; @@ -441,7 +441,7 @@ static int dell_rfkill_set(void *data, bool blocked) dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio<<8) | (disable << 16)); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; out: @@ -458,7 +458,7 @@ static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, int block = rfkill_blocked(rfkill); dell_smbios_clear_buffer(); buffer->input[0] = (1 | (radio << 8) | (block << 16)); - dell_smbios_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))); @@ -481,7 +481,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) dell_smbios_get_buffer(); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -493,7 +493,7 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; hwswitch = buffer->output[1]; @@ -521,14 +521,14 @@ static int dell_debugfs_show(struct seq_file *s, void *data) dell_smbios_get_buffer(); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); hwswitch_ret = buffer->output[0]; hwswitch_state = buffer->output[1]; @@ -619,7 +619,7 @@ static void dell_update_rfkill(struct work_struct *ignored) dell_smbios_get_buffer(); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -629,7 +629,7 @@ static void dell_update_rfkill(struct work_struct *ignored) dell_smbios_clear_buffer(); buffer->input[0] = 0x2; - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; if (ret == 0 && (status & BIT(0))) @@ -710,7 +710,7 @@ static int __init dell_setup_rfkill(void) return 0; dell_smbios_get_buffer(); - dell_smbios_send_request(buffer, 17, 11); + dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; dell_smbios_release_buffer(); @@ -878,9 +878,9 @@ static int dell_send_intensity(struct backlight_device *bd) buffer->input[1] = bd->props.brightness; if (power_supply_is_system_supplied() > 0) - dell_smbios_send_request(buffer, 1, 2); + dell_smbios_send_request(1, 2); else - dell_smbios_send_request(buffer, 1, 1); + dell_smbios_send_request(1, 1); ret = dell_smi_error(buffer->output[0]); @@ -901,9 +901,9 @@ static int dell_get_intensity(struct backlight_device *bd) buffer->input[0] = token; if (power_supply_is_system_supplied() > 0) - dell_smbios_send_request(buffer, 0, 2); + dell_smbios_send_request(0, 2); else - dell_smbios_send_request(buffer, 0, 1); + dell_smbios_send_request(0, 1); if (buffer->output[0]) ret = dell_smi_error(buffer->output[0]); @@ -1160,7 +1160,7 @@ static int kbd_get_info(struct kbd_info *info) dell_smbios_get_buffer(); buffer->input[0] = 0x0; - dell_smbios_send_request(buffer, 4, 11); + dell_smbios_send_request(4, 11); ret = buffer->output[0]; if (ret) { @@ -1248,7 +1248,7 @@ static int kbd_get_state(struct kbd_state *state) dell_smbios_get_buffer(); buffer->input[0] = 0x1; - dell_smbios_send_request(buffer, 4, 11); + dell_smbios_send_request(4, 11); ret = buffer->output[0]; if (ret) { @@ -1284,7 +1284,7 @@ static int kbd_set_state(struct kbd_state *state) buffer->input[1] |= (state->timeout_unit & 0x3) << 30; buffer->input[2] = state->als_setting & 0xFF; buffer->input[2] |= (state->level & 0xFF) << 16; - dell_smbios_send_request(buffer, 4, 11); + dell_smbios_send_request(4, 11); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1326,7 +1326,7 @@ static int kbd_set_token_bit(u8 bit) dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; buffer->input[1] = da_tokens[id].value; - dell_smbios_send_request(buffer, 1, 0); + dell_smbios_send_request(1, 0); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1348,7 +1348,7 @@ static int kbd_get_token_bit(u8 bit) dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; - dell_smbios_send_request(buffer, 0, 0); + dell_smbios_send_request(0, 0); ret = buffer->output[0]; val = buffer->output[1]; dell_smbios_release_buffer(); @@ -2019,7 +2019,7 @@ static int __init dell_init(void) if (token != -1) { dell_smbios_get_buffer(); buffer->input[0] = token; - dell_smbios_send_request(buffer, 0, 2); + dell_smbios_send_request(0, 2); if (buffer->output[0] == 0) max_intensity = buffer->output[3]; dell_smbios_release_buffer(); diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index b1038325a3fc..ac1cbed12710 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -61,8 +61,7 @@ void dell_smbios_release_buffer(void) EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); struct calling_interface_buffer * -dell_smbios_send_request(struct calling_interface_buffer *buffer, - int class, int select) +dell_smbios_send_request(int class, int select) { struct smi_cmd command; diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 33ed9712430b..4220ac1fe703 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -42,8 +42,7 @@ void dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); struct calling_interface_buffer * -dell_smbios_send_request(struct calling_interface_buffer *buffer, - int class, int select); +dell_smbios_send_request(int class, int select); int find_token_id(int tokenid); int find_token_location(int tokenid); From c42831c8a9db32a5a0e2c6c31042014039f11739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:19 +0100 Subject: [PATCH 18/47] dell-smbios: don't return an SMBIOS buffer from dell_smbios_send_request() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An SMBIOS buffer pointer does not need to be returned by dell_smbios_send_request(), because SMBIOS call results are stored in the buffer exported by the module. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 5 +---- drivers/platform/x86/dell-smbios.h | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index ac1cbed12710..9dacb20b988e 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -60,8 +60,7 @@ void dell_smbios_release_buffer(void) } EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); -struct calling_interface_buffer * -dell_smbios_send_request(int class, int select) +void dell_smbios_send_request(int class, int select) { struct smi_cmd command; @@ -75,8 +74,6 @@ dell_smbios_send_request(int class, int select) buffer->select = select; dcdbas_smi_request(&command); - - return buffer; } EXPORT_SYMBOL_GPL(dell_smbios_send_request); diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 4220ac1fe703..80b5048f2bd2 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -41,8 +41,7 @@ extern struct calling_interface_token *da_tokens; void dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); -struct calling_interface_buffer * -dell_smbios_send_request(int class, int select); +void dell_smbios_send_request(int class, int select); int find_token_id(int tokenid); int find_token_location(int tokenid); From bc2104c27aad0c988d23c6abcd46f3313618bdbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:20 +0100 Subject: [PATCH 19/47] dell-smbios: return the SMBIOS buffer from dell_smbios_get_buffer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultimately, the SMBIOS buffer should not be exported from dell-smbios. Currently, dell-laptop accesses it directly using a global variable, so make dell_smbios_get_buffer() return a pointer to the SMBIOS buffer and replace all uses of the global variable with local variables. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 49 +++++++++++++++++++----------- drivers/platform/x86/dell-smbios.c | 3 +- drivers/platform/x86/dell-smbios.h | 2 +- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 0bb22114abce..5b200f29c55d 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -409,6 +409,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; @@ -416,7 +417,7 @@ static int dell_rfkill_set(void *data, bool blocked) int status; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); dell_smbios_send_request(17, 11); ret = buffer->output[0]; @@ -451,7 +452,8 @@ static int dell_rfkill_set(void *data, bool blocked) /* 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 */ @@ -474,12 +476,13 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, static void dell_rfkill_query(struct rfkill *rfkill, void *data) { + struct calling_interface_buffer *buffer; int radio = ((unsigned long)data & 0xF); int hwswitch; int status; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); dell_smbios_send_request(17, 11); ret = buffer->output[0]; @@ -514,12 +517,13 @@ static struct dentry *dell_laptop_dir; static int dell_debugfs_show(struct seq_file *s, void *data) { + struct calling_interface_buffer *buffer; int hwswitch_state; int hwswitch_ret; int status; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); dell_smbios_send_request(17, 11); ret = buffer->output[0]; @@ -613,11 +617,12 @@ static const struct file_operations dell_debugfs_fops = { static void dell_update_rfkill(struct work_struct *ignored) { + struct calling_interface_buffer *buffer; int hwswitch = 0; int status; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); dell_smbios_send_request(17, 11); ret = buffer->output[0]; @@ -637,16 +642,17 @@ static void dell_update_rfkill(struct work_struct *ignored) if (wifi_rfkill) { dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); - dell_rfkill_update_sw_state(wifi_rfkill, 1, status); + dell_rfkill_update_sw_state(wifi_rfkill, 1, status, buffer); } if (bluetooth_rfkill) { dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status, hwswitch); - dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status); + dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status, + buffer); } if (wwan_rfkill) { dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch); - dell_rfkill_update_sw_state(wwan_rfkill, 3, status); + dell_rfkill_update_sw_state(wwan_rfkill, 3, status, buffer); } out: @@ -694,6 +700,7 @@ static struct notifier_block dell_laptop_rbtn_notifier = { static int __init dell_setup_rfkill(void) { + struct calling_interface_buffer *buffer; int status, ret, whitelisted; const char *product; @@ -709,7 +716,7 @@ static int __init dell_setup_rfkill(void) if (!force_rfkill && !whitelisted) return 0; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); dell_smbios_send_request(17, 11); ret = buffer->output[0]; status = buffer->output[1]; @@ -866,6 +873,7 @@ static void dell_cleanup_rfkill(void) static int dell_send_intensity(struct backlight_device *bd) { + struct calling_interface_buffer *buffer; int token; int ret; @@ -873,7 +881,7 @@ static int dell_send_intensity(struct backlight_device *bd) if (token == -1) return -ENODEV; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = token; buffer->input[1] = bd->props.brightness; @@ -890,6 +898,7 @@ static int dell_send_intensity(struct backlight_device *bd) static int dell_get_intensity(struct backlight_device *bd) { + struct calling_interface_buffer *buffer; int token; int ret; @@ -897,7 +906,7 @@ static int dell_get_intensity(struct backlight_device *bd) if (token == -1) return -ENODEV; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = token; if (power_supply_is_system_supplied() > 0) @@ -1154,10 +1163,11 @@ static bool kbd_led_present; static int kbd_get_info(struct kbd_info *info) { + struct calling_interface_buffer *buffer; u8 units; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = 0x0; dell_smbios_send_request(4, 11); @@ -1243,9 +1253,10 @@ static int kbd_set_level(struct kbd_state *state, u8 level) static int kbd_get_state(struct kbd_state *state) { + struct calling_interface_buffer *buffer; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = 0x1; dell_smbios_send_request(4, 11); @@ -1274,9 +1285,10 @@ static int kbd_get_state(struct kbd_state *state) static int kbd_set_state(struct kbd_state *state) { + struct calling_interface_buffer *buffer; int ret; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = 0x2; buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; buffer->input[1] |= (state->triggers & 0xFF) << 16; @@ -1313,6 +1325,7 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) static int kbd_set_token_bit(u8 bit) { + struct calling_interface_buffer *buffer; int id; int ret; @@ -1323,7 +1336,7 @@ static int kbd_set_token_bit(u8 bit) if (id == -1) return -EINVAL; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; buffer->input[1] = da_tokens[id].value; dell_smbios_send_request(1, 0); @@ -1335,6 +1348,7 @@ static int kbd_set_token_bit(u8 bit) static int kbd_get_token_bit(u8 bit) { + struct calling_interface_buffer *buffer; int id; int ret; int val; @@ -1346,7 +1360,7 @@ static int kbd_get_token_bit(u8 bit) if (id == -1) return -EINVAL; - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = da_tokens[id].location; dell_smbios_send_request(0, 0); ret = buffer->output[0]; @@ -1972,6 +1986,7 @@ static void kbd_led_exit(void) static int __init dell_init(void) { + struct calling_interface_buffer *buffer; int max_intensity = 0; int token; int ret; @@ -2017,7 +2032,7 @@ static int __init dell_init(void) token = find_token_location(BRIGHTNESS_TOKEN); if (token != -1) { - dell_smbios_get_buffer(); + buffer = dell_smbios_get_buffer(); buffer->input[0] = token; dell_smbios_send_request(0, 2); if (buffer->output[0] == 0) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 9dacb20b988e..1427899c4f8f 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -41,10 +41,11 @@ static int da_num_tokens; struct calling_interface_token *da_tokens; EXPORT_SYMBOL_GPL(da_tokens); -void dell_smbios_get_buffer(void) +struct calling_interface_buffer *dell_smbios_get_buffer(void) { mutex_lock(&buffer_mutex); dell_smbios_clear_buffer(); + return buffer; } EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 80b5048f2bd2..f7a51f5ddeed 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -38,7 +38,7 @@ struct calling_interface_token { extern struct calling_interface_buffer *buffer; extern struct calling_interface_token *da_tokens; -void dell_smbios_get_buffer(void); +struct calling_interface_buffer *dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); void dell_smbios_send_request(int class, int select); From 92ebd0d1a80930c52eb091d497d4527c4fe556ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:21 +0100 Subject: [PATCH 20/47] dell-smbios: make the SMBIOS buffer static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As dell-laptop has been changed to always retrieve a pointer to the SMBIOS buffer using dell_smbios_get_buffer(), the SMBIOS buffer can be marked static. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 3 +-- drivers/platform/x86/dell-smbios.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 1427899c4f8f..2577cf6aff0f 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -31,8 +31,7 @@ struct calling_interface_structure { struct calling_interface_token tokens[]; } __packed; -struct calling_interface_buffer *buffer; -EXPORT_SYMBOL_GPL(buffer); +static struct calling_interface_buffer *buffer; static DEFINE_MUTEX(buffer_mutex); static int da_command_address; diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index f7a51f5ddeed..af653ff29b68 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -35,7 +35,6 @@ struct calling_interface_token { }; }; -extern struct calling_interface_buffer *buffer; extern struct calling_interface_token *da_tokens; struct calling_interface_buffer *dell_smbios_get_buffer(void); From 96f7ef90cc373f805a38f2a3e96a8b1948706954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:22 +0100 Subject: [PATCH 21/47] dell-smbios: implement new function for finding DMI table 0xDA tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultimately, the da_tokens table should not be exported from dell-smbios. Currently, in some cases, dell-laptop accesses that table's members directly, so implement a new function, dell_smbios_find_token(), which returns a pointer to an entry inside the da_tokens table with the given token ID (or NULL if it is not found). Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 13 +++++++++++++ drivers/platform/x86/dell-smbios.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 2577cf6aff0f..6a27e4c85a24 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -77,6 +77,19 @@ void dell_smbios_send_request(int class, int select) } EXPORT_SYMBOL_GPL(dell_smbios_send_request); +struct calling_interface_token *dell_smbios_find_token(int tokenid) +{ + int i; + + for (i = 0; i < da_num_tokens; i++) { + if (da_tokens[i].tokenID == tokenid) + return &da_tokens[i]; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(dell_smbios_find_token); + int find_token_id(int tokenid) { int i; diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index af653ff29b68..6f6dbe8b05d4 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -42,6 +42,8 @@ void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); void dell_smbios_send_request(int class, int select); +struct calling_interface_token *dell_smbios_find_token(int tokenid); + int find_token_id(int tokenid); int find_token_location(int tokenid); #endif From 63c4029bdfc220ec3a1fa9135f5db3bdcd93b502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:23 +0100 Subject: [PATCH 22/47] dell-laptop: use dell_smbios_find_token() instead of find_token_id() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all uses of find_token_id() with dell_smbios_find_token() to avoid directly accessing the da_tokens table. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 5b200f29c55d..4d1694d972b1 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1326,19 +1326,19 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) static int kbd_set_token_bit(u8 bit) { struct calling_interface_buffer *buffer; - int id; + struct calling_interface_token *token; int ret; if (bit >= ARRAY_SIZE(kbd_tokens)) return -EINVAL; - id = find_token_id(kbd_tokens[bit]); - if (id == -1) + token = dell_smbios_find_token(kbd_tokens[bit]); + if (!token) return -EINVAL; buffer = dell_smbios_get_buffer(); - buffer->input[0] = da_tokens[id].location; - buffer->input[1] = da_tokens[id].value; + buffer->input[0] = token->location; + buffer->input[1] = token->value; dell_smbios_send_request(1, 0); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1349,19 +1349,19 @@ static int kbd_set_token_bit(u8 bit) static int kbd_get_token_bit(u8 bit) { struct calling_interface_buffer *buffer; - int id; + struct calling_interface_token *token; int ret; int val; if (bit >= ARRAY_SIZE(kbd_tokens)) return -EINVAL; - id = find_token_id(kbd_tokens[bit]); - if (id == -1) + token = dell_smbios_find_token(kbd_tokens[bit]); + if (!token) return -EINVAL; buffer = dell_smbios_get_buffer(); - buffer->input[0] = da_tokens[id].location; + buffer->input[0] = token->location; dell_smbios_send_request(0, 0); ret = buffer->output[0]; val = buffer->output[1]; @@ -1370,7 +1370,7 @@ static int kbd_get_token_bit(u8 bit) if (ret) return dell_smi_error(ret); - return (val == da_tokens[id].value); + return (val == token->value); } static int kbd_get_first_active_token_bit(void) @@ -1472,7 +1472,7 @@ static inline void kbd_init_tokens(void) int i; for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) - if (find_token_id(kbd_tokens[i]) != -1) + if (dell_smbios_find_token(kbd_tokens[i])) kbd_token_bits |= BIT(i); } From f951d6e6faedcead91419b785f73a620d8ed191a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:24 +0100 Subject: [PATCH 23/47] dell-laptop: use dell_smbios_find_token() instead of find_token_location() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all uses of find_token_location() with dell_smbios_find_token() to avoid directly accessing the da_tokens table. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 4d1694d972b1..76064c817f3d 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -874,15 +874,15 @@ static void dell_cleanup_rfkill(void) static int dell_send_intensity(struct backlight_device *bd) { struct calling_interface_buffer *buffer; - int token; + struct calling_interface_token *token; int ret; - token = find_token_location(BRIGHTNESS_TOKEN); - if (token == -1) + token = dell_smbios_find_token(BRIGHTNESS_TOKEN); + if (!token) return -ENODEV; buffer = dell_smbios_get_buffer(); - buffer->input[0] = token; + buffer->input[0] = token->location; buffer->input[1] = bd->props.brightness; if (power_supply_is_system_supplied() > 0) @@ -899,15 +899,15 @@ static int dell_send_intensity(struct backlight_device *bd) static int dell_get_intensity(struct backlight_device *bd) { struct calling_interface_buffer *buffer; - int token; + struct calling_interface_token *token; int ret; - token = find_token_location(BRIGHTNESS_TOKEN); - if (token == -1) + token = dell_smbios_find_token(BRIGHTNESS_TOKEN); + if (!token) return -ENODEV; buffer = dell_smbios_get_buffer(); - buffer->input[0] = token; + buffer->input[0] = token->location; if (power_supply_is_system_supplied() > 0) dell_smbios_send_request(0, 2); @@ -1987,8 +1987,8 @@ static void kbd_led_exit(void) static int __init dell_init(void) { struct calling_interface_buffer *buffer; + struct calling_interface_token *token; int max_intensity = 0; - int token; int ret; if (!dmi_check_system(dell_device_table)) @@ -2030,10 +2030,10 @@ static int __init dell_init(void) if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return 0; - token = find_token_location(BRIGHTNESS_TOKEN); - if (token != -1) { + token = dell_smbios_find_token(BRIGHTNESS_TOKEN); + if (token) { buffer = dell_smbios_get_buffer(); - buffer->input[0] = token; + buffer->input[0] = token->location; dell_smbios_send_request(0, 2); if (buffer->output[0] == 0) max_intensity = buffer->output[3]; From 73511ff30c6dc5347ede4c2a2fa5ab22fae3f152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:25 +0100 Subject: [PATCH 24/47] dell-smbios: remove find_token_{id,location}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As dell-laptop has been changed to use dell_smbios_find_token() instead of find_token_id() and find_token_location(), these functions can be safely removed. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 25 ------------------------- drivers/platform/x86/dell-smbios.h | 3 --- 2 files changed, 28 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 6a27e4c85a24..c9efa9e017c1 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -90,31 +90,6 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid) } EXPORT_SYMBOL_GPL(dell_smbios_find_token); -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; -} -EXPORT_SYMBOL_GPL(find_token_id); - -int find_token_location(int tokenid) -{ - int id; - - id = find_token_id(tokenid); - if (id == -1) - return -1; - - return da_tokens[id].location; -} -EXPORT_SYMBOL_GPL(find_token_location); - static void __init parse_da_table(const struct dmi_header *dm) { /* Final token is a terminator, so we don't want to copy it */ diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 6f6dbe8b05d4..f17cf7b26f1d 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -43,7 +43,4 @@ void dell_smbios_release_buffer(void); void dell_smbios_send_request(int class, int select); struct calling_interface_token *dell_smbios_find_token(int tokenid); - -int find_token_id(int tokenid); -int find_token_location(int tokenid); #endif From b7bca2d7ff1a232466fa5447ec27e62bf02b310f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:26 +0100 Subject: [PATCH 25/47] dell-smbios: make da_tokens static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As dell-laptop has been changed to use dell_smbios_find_token() instead of directly accessing members of the da_tokens table, the latter can be marked static. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 3 +-- drivers/platform/x86/dell-smbios.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index c9efa9e017c1..2a4992a9c538 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -37,8 +37,7 @@ static DEFINE_MUTEX(buffer_mutex); static int da_command_address; static int da_command_code; static int da_num_tokens; -struct calling_interface_token *da_tokens; -EXPORT_SYMBOL_GPL(da_tokens); +static struct calling_interface_token *da_tokens; struct calling_interface_buffer *dell_smbios_get_buffer(void) { diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index f17cf7b26f1d..4f69b16f7769 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -35,8 +35,6 @@ struct calling_interface_token { }; }; -extern struct calling_interface_token *da_tokens; - struct calling_interface_buffer *dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); From cf0d7ea335966744f2a4fc6f882165b7dba54c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:27 +0100 Subject: [PATCH 26/47] dell-led: use dell_smbios_find_token() for finding mic DMI tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the advent of dell_smbios_find_token(), dell-led does not need to perform any DMI walking on its own, but it can rather ask dell-smbios to look up the DMI tokens it needs for changing the state of the microphone LED. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Acked-by: Jacek Anaszewski Signed-off-by: Darren Hart --- drivers/leds/Kconfig | 1 + drivers/leds/dell-led.c | 63 ++++++----------------------------------- 2 files changed, 10 insertions(+), 54 deletions(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 7f940c24a16b..4351cbe57221 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..bfa7511374bd 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -17,6 +17,7 @@ #include #include #include +#include "../platform/x86/dell-smbios.h" MODULE_AUTHOR("Louis Davis/Jim Dailey"); MODULE_DESCRIPTION("Dell LED Control Driver"); @@ -59,22 +60,6 @@ struct app_wmi_args { #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; @@ -112,43 +97,24 @@ static int dell_wmi_perform_query(struct app_wmi_args *args) 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 calling_interface_token *token; struct app_wmi_args args; - struct dell_bios_data_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; + if (!token) + return -ENODEV; + memset(&args, 0, sizeof(struct app_wmi_args)); args.class = 1; @@ -177,14 +143,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 +288,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) From 0c41a08e131d753af48ae6f052aed8d530b9c976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 22 Jan 2016 15:27:28 +0100 Subject: [PATCH 27/47] dell-led: use dell_smbios_send_request() for performing SMBIOS calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using the WMI wrapper, dell-led can take advantage of dell_smbios_send_request() for performing the SMBIOS calls required to change the state of the microphone LED. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Acked-by: Jacek Anaszewski Signed-off-by: Darren Hart --- drivers/leds/dell-led.c | 65 ++++------------------------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/drivers/leds/dell-led.c b/drivers/leds/dell-led.c index bfa7511374bd..b3d6e9c15cf9 100644 --- a/drivers/leds/dell-led.c +++ b/drivers/leds/dell-led.c @@ -43,64 +43,13 @@ 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 -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 int dell_micmute_led_set(int state) { + struct calling_interface_buffer *buffer; struct calling_interface_token *token; - struct app_wmi_args args; if (!wmi_has_guid(DELL_APP_GUID)) return -ENODEV; @@ -115,13 +64,11 @@ static int dell_micmute_led_set(int state) if (!token) return -ENODEV; - memset(&args, 0, sizeof(struct app_wmi_args)); - - args.class = 1; - args.arg1 = token->location; - args.arg2 = token->value; - - 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; } From 18b6f80f5095036bd2204c54c89a5a0f5a785e3d Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 15 Feb 2016 08:32:33 -0800 Subject: [PATCH 28/47] dell-wmi: Stop storing pointers to DMI tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dmi_walk function maps the DMI table, walks it, and unmaps it. This means that the dell_bios_hotkey_table that find_hk_type stores points to unmapped memory by the time it gets read. I've been able to trigger crashes caused by the stale pointer a couple of times, but never on a stock kernel. Fix it by generating the keymap in the dmi_walk callback instead of storing a pointer. Signed-off-by: Andy Lutomirski Acked-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 74 ++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 368e193c2741..d6ae69e0a787 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -120,7 +120,10 @@ struct dell_bios_hotkey_table { }; -static const struct dell_bios_hotkey_table *dell_bios_hotkey_table; +struct dell_dmi_results { + int err; + struct key_entry *keymap; +}; /* Uninitialized entries here are KEY_RESERVED == 0. */ static const u16 bios_to_linux_keycode[256] __initconst = { @@ -337,20 +340,34 @@ static void dell_wmi_notify(u32 value, void *context) kfree(obj); } -static const struct key_entry * __init dell_wmi_prepare_new_keymap(void) +static void __init handle_dmi_entry(const struct dmi_header *dm, + void *opaque) { - int hotkey_num = (dell_bios_hotkey_table->header.length - 4) / - sizeof(struct dell_bios_keymap_entry); + struct dell_dmi_results *results = opaque; + struct dell_bios_hotkey_table *table; struct key_entry *keymap; - int i; + int hotkey_num, i; + + if (results->err || results->keymap) + return; /* We already found the hotkey table. */ + + if (dm->type != 0xb2 || dm->length <= 6) + return; + + table = container_of(dm, struct dell_bios_hotkey_table, header); + + hotkey_num = (table->header.length - 4) / + sizeof(struct dell_bios_keymap_entry); keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); - if (!keymap) - return NULL; + if (!keymap) { + results->err = -ENOMEM; + return; + } for (i = 0; i < hotkey_num; i++) { const struct dell_bios_keymap_entry *bios_entry = - &dell_bios_hotkey_table->keymap[i]; + &table->keymap[i]; /* Uninitialized entries are 0 aka KEY_RESERVED. */ u16 keycode = (bios_entry->keycode < @@ -379,11 +396,12 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void) keymap[hotkey_num].type = KE_END; - return keymap; + results->keymap = keymap; } static int __init dell_wmi_input_setup(void) { + struct dell_dmi_results dmi_results = {}; int err; dell_wmi_input_dev = input_allocate_device(); @@ -394,20 +412,31 @@ static int __init dell_wmi_input_setup(void) dell_wmi_input_dev->phys = "wmi/input0"; dell_wmi_input_dev->id.bustype = BUS_HOST; - if (dell_new_hk_type) { - const struct key_entry *keymap = dell_wmi_prepare_new_keymap(); - if (!keymap) { - err = -ENOMEM; - goto err_free_dev; - } + if (dmi_walk(handle_dmi_entry, &dmi_results)) { + /* + * Historically, dell-wmi ignored dmi_walk errors. A failure + * is certainly surprising, but it probably just indicates + * a very old laptop. + */ + pr_warn("no DMI; using the old-style hotkey interface\n"); + } - err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL); + if (dmi_results.err) { + err = dmi_results.err; + goto err_free_dev; + } + + if (dmi_results.keymap) { + dell_new_hk_type = true; + + err = sparse_keymap_setup(dell_wmi_input_dev, + dmi_results.keymap, NULL); /* * Sparse keymap library makes a copy of keymap so we * don't need the original one that was allocated. */ - kfree(keymap); + kfree(dmi_results.keymap); } else { err = sparse_keymap_setup(dell_wmi_input_dev, dell_wmi_legacy_keymap, NULL); @@ -434,15 +463,6 @@ static void dell_wmi_input_destroy(void) input_unregister_device(dell_wmi_input_dev); } -static void __init find_hk_type(const struct dmi_header *dm, void *dummy) -{ - if (dm->type == 0xb2 && dm->length > 6) { - dell_new_hk_type = true; - dell_bios_hotkey_table = - container_of(dm, struct dell_bios_hotkey_table, header); - } -} - /* * Descriptor buffer is 128 byte long and contains: * @@ -524,8 +544,6 @@ static int __init dell_wmi_init(void) if (err) return err; - dmi_walk(find_hk_type, NULL); - err = dell_wmi_input_setup(); if (err) return err; From a570af4850043260b87fb1b8aa27a4484e648878 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 15 Feb 2016 08:32:34 -0800 Subject: [PATCH 29/47] dell-wmi, dell-laptop: depends DMI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dell-wmi and dell-laptop will compile but won't work right if DMI isn't selected. Signed-off-by: Andy Lutomirski Acked-by: Pali Rohár [arnd: Use depends instead of selects to avoid recursive dependencies] Signed-off-by: Arnd Bergmann Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3e4d9c3e83fd..a65d974f387a 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -105,6 +105,7 @@ config DELL_LAPTOP tristate "Dell Laptop Extras" depends on X86 depends on DELL_SMBIOS + depends on DMI depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n @@ -120,6 +121,7 @@ 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 select INPUT_SPARSEKMAP From b13de7019c1b67f0c1b987fc9fe82fcc371ba1d2 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 15 Feb 2016 08:32:35 -0800 Subject: [PATCH 30/47] dell-wmi: Clean up hotkey table size check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checking the table for a minimum size of 7 bytes makes no sense: any valid hotkey table has a size that's a multiple of 4. Clean this up: replace the hardcoded header length with a sizeof and change the check to ignore an empty hotkey table. The only behavior change is that a 7-byte table (which is nonsensical) will now be treated as absent instead of as valid but empty. Reported-by: Jean Delvare Signed-off-by: Andy Lutomirski Acked-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index d6ae69e0a787..32808a463325 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -351,13 +351,24 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, if (results->err || results->keymap) return; /* We already found the hotkey table. */ - if (dm->type != 0xb2 || dm->length <= 6) + if (dm->type != 0xb2) return; table = container_of(dm, struct dell_bios_hotkey_table, header); - hotkey_num = (table->header.length - 4) / + hotkey_num = (table->header.length - + sizeof(struct dell_bios_hotkey_table)) / sizeof(struct dell_bios_keymap_entry); + if (hotkey_num < 1) { + /* + * Historically, dell-wmi would ignore a DMI entry of + * fewer than 7 bytes. Sizes between 4 and 8 bytes are + * nonsensical (both the header and all entries are 4 + * bytes), so we approximate the old behavior by + * ignoring tables with fewer than one entry. + */ + return; + } keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); if (!keymap) { From a464afb9581f6a9eabce8a4aa0c70cb71e6bf4d9 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 15 Feb 2016 08:32:36 -0800 Subject: [PATCH 31/47] dell-wmi: Support new hotkeys on the XPS 13 9350 (Skylake) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XPS 13 9350 sends WMI keypress events that aren't enumerated in the DMI table. Add a table listing them. To avoid breaking things that worked before, these un-enumerated hotkeys won't be used if the DMI table maps them to something else. FWIW, it appears that the DMI table may be a legacy thing and we might want to rethink how we handle events in general. As an example, a whole lot of things map to KEY_PROG3 via the DMI table. This doesn't send keypress events for any of the new events. They appear to all be handled by other means (keyboard illumination is handled automatically and rfkill is handled by intel-hid). Signed-off-by: Andy Lutomirski Acked-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 71 +++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 32808a463325..e38258a82be5 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -169,6 +169,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = { [255] = KEY_PROG3, }; +/* + * These are applied if the 0xB2 DMI hotkey table is present and doesn't + * override them. + */ +static const struct key_entry dell_wmi_extra_keymap[] __initconst = { + /* Fn-lock */ + { KE_IGNORE, 0x151, { KEY_RESERVED } }, + + /* Change keyboard illumination */ + { KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } }, + + /* + * Radio disable (notify only -- there is no model for which the + * WMI event is supposed to trigger an action). + */ + { KE_IGNORE, 0x153, { KEY_RFKILL } }, + + /* RGB keyboard backlight control */ + { KE_IGNORE, 0x154, { KEY_RESERVED } }, + + /* Stealth mode toggle */ + { KE_IGNORE, 0x155, { KEY_RESERVED } }, +}; + static struct input_dev *dell_wmi_input_dev; static void dell_wmi_process_key(int reported_key) @@ -340,13 +364,27 @@ static void dell_wmi_notify(u32 value, void *context) kfree(obj); } +static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (keymap[i].code == scancode) + return true; + + return false; +} + static void __init handle_dmi_entry(const struct dmi_header *dm, + void *opaque) + { struct dell_dmi_results *results = opaque; struct dell_bios_hotkey_table *table; + int hotkey_num, i, pos = 0; struct key_entry *keymap; - int hotkey_num, i; + int num_bios_keys; if (results->err || results->keymap) return; /* We already found the hotkey table. */ @@ -370,7 +408,8 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, return; } - keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); + keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1, + sizeof(struct key_entry), GFP_KERNEL); if (!keymap) { results->err = -ENOMEM; return; @@ -398,14 +437,32 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, } if (keycode == KEY_KBDILLUMTOGGLE) - keymap[i].type = KE_IGNORE; + keymap[pos].type = KE_IGNORE; else - keymap[i].type = KE_KEY; - keymap[i].code = bios_entry->scancode; - keymap[i].keycode = keycode; + keymap[pos].type = KE_KEY; + keymap[pos].code = bios_entry->scancode; + keymap[pos].keycode = keycode; + + pos++; } - keymap[hotkey_num].type = KE_END; + num_bios_keys = pos; + + for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) { + const struct key_entry *entry = &dell_wmi_extra_keymap[i]; + + /* + * Check if we've already found this scancode. This takes + * quadratic time, but it doesn't matter unless the list + * of extra keys gets very long. + */ + if (!have_scancode(entry->code, keymap, num_bios_keys)) { + keymap[pos] = *entry; + pos++; + } + } + + keymap[pos].type = KE_END; results->keymap = keymap; } From 4d340c6b9cc7e6e5f6ad4fc27e837863015cdf5b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 15 Feb 2016 08:32:37 -0800 Subject: [PATCH 32/47] dell-rbtn: Add a comment about the XPS 13 9350 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On the XPS 13 9350, the dell-rbtn mechanism has a new device id, and the DSDT turns it off if a new enough _OSI is supported. Add a comment about why we don't bother supporting it. Signed-off-by: Andy Lutomirski Acked-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-rbtn.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c index cd410e392550..b51a2008d782 100644 --- a/drivers/platform/x86/dell-rbtn.c +++ b/drivers/platform/x86/dell-rbtn.c @@ -217,6 +217,21 @@ static void rbtn_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id rbtn_ids[] = { { "DELRBTN", 0 }, { "DELLABCE", 0 }, + + /* + * This driver can also handle the "DELLABC6" device that + * appears on the XPS 13 9350, but that device is disabled + * by the DSDT unless booted with acpi_osi="!Windows 2012" + * acpi_osi="!Windows 2013". Even if we boot that and bind + * the driver, we seem to have inconsistent behavior in + * which NetworkManager can get out of sync with the rfkill + * state. + * + * On the XPS 13 9350 and similar laptops, we're not supposed to + * use DELLABC6 at all. Instead, we handle the rfkill button + * via the intel-hid driver. + */ + { "", 0 }, }; From 479f3b62d6d05cf74427f61fbd92b1a54c8645aa Mon Sep 17 00:00:00 2001 From: Souvik Kumar Chakravarty Date: Wed, 17 Feb 2016 12:05:22 +0530 Subject: [PATCH 33/47] intel_telemetry_pltdrv: Change verbosity control bits Due to a recent fix in the firmware, the Punit verbosity control bits now adhere to the correct pattern. Hence remove the workaround and do a read-modify-write of the register. Signed-off-by: Souvik Kumar Chakravarty Signed-off-by: Darren Hart --- drivers/platform/x86/intel_telemetry_pltdrv.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index f97019b0106f..397119f83e82 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -1029,9 +1029,20 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit, mutex_lock(&(telm_conf->telem_trace_lock)); switch (telem_unit) { case TELEM_PSS: + ret = intel_punit_ipc_command( + IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, + 0, 0, NULL, &temp); + if (ret) { + pr_err("PSS TRACE_CTRL Read Failed\n"); + goto out; + } + + TELEM_CLEAR_VERBOSITY_BITS(temp); + TELEM_SET_VERBOSITY_BITS(temp, verbosity); + ret = intel_punit_ipc_command( IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, - 0, 0, &verbosity, NULL); + 0, 0, &temp, NULL); if (ret) { pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); goto out; From 4670768779876c0a9071c026ddabe1ab8e6c7805 Mon Sep 17 00:00:00 2001 From: Oleksandr Natalenko Date: Wed, 17 Feb 2016 13:35:46 +0200 Subject: [PATCH 34/47] asus-nb-wmi: add wapf=4 quirk for ASUS X75VD Wi-Fi on ASUS X75VD laptop does not work unless asus_nb_wmi module is loaded with wapf=4 option. Add quirk for this. Signed-off-by: Oleksandr Natalenko Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) 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 @@ -270,6 +270,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_wapf4, }, + { + .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", From 1a2f25d5e73f4f1ae985801a05ed37bbe0ea11f3 Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Thu, 18 Feb 2016 02:03:37 +0800 Subject: [PATCH 35/47] intel_pmc_ipc: Fix GCR register base address and length GCR register (pmc_cfg register) is at offset 0x1008, and remapping of 0x4 bytes is enough. Signed-off-by: Francois-Nicolas Muller Signed-off-by: Qipeng Zha Acked-by: Andy Shevchenko Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_ipc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 092519e37de6..3b0182c189d6 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -67,7 +67,8 @@ /* exported resources from IFWI */ #define PLAT_RESOURCE_IPC_INDEX 0 #define PLAT_RESOURCE_IPC_SIZE 0x1000 -#define PLAT_RESOURCE_GCR_SIZE 0x1000 +#define PLAT_RESOURCE_GCR_OFFSET 0x1008 +#define PLAT_RESOURCE_GCR_SIZE 0x4 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 @@ -766,7 +767,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) } ipcdev.ipc_base = addr; - ipcdev.gcr_base = res->start + size; + ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; dev_info(&pdev->dev, "ipc res: %pR\n", res); From 1f1ae997fd47d058522f32b91059111dbc4a2b54 Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Thu, 18 Feb 2016 02:03:38 +0800 Subject: [PATCH 36/47] intel_pmc_ipc: Avoid pending IPC1 command during legacy suspend During legacy suspend flow, IPC1 commands are being requested from opregion driver. But the PMC_IPC1 command will timeout as example: [ 281.444600] ipc_debug##: ipc_send_command: cmd=0x201ff, [ 281.444648] wbuf[0]=0x4ea6 [ 281.444668] wbuf[1]=0x0 [ 281.444674] wbuf[2]=0x0 [ 281.444676] wbuf[3]=0x0 [ 284.446467] pmc-ipc-plat INT34D2:00: IPC timed out, TS=0x4, CMD=0x200ff This is because before the opregion driver could send IPC1 commands, the PMC_IPC irq is already suspended. Which makes the IPC command to timeout. Solution: register pmc_ipc irq as IRQF_NO_SUSPEND Signed-off-by: Ananth Krishna R Signed-off-by: Bharath K Veera Signed-off-by: Qipeng Zha Acked-by: Andy Shevchenko Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_ipc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 3b0182c189d6..3fb1d85c70a8 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -825,7 +825,8 @@ static int ipc_plat_probe(struct platform_device *pdev) goto err_device; } - if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { + if (request_irq(ipcdev.irq, ioc, IRQF_NO_SUSPEND, + "intel_pmc_ipc", &ipcdev)) { dev_err(&pdev->dev, "Failed to request irq\n"); ret = -EBUSY; goto err_irq; From f52ab44fb748537e4e757d5cdb0a79ab847630c7 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 14 Feb 2016 15:00:52 -0500 Subject: [PATCH 37/47] platform/x86: Make intel_scu_ipc explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/platform/x86/Kconfig:config INTEL_SCU_IPC drivers/platform/x86/Kconfig: bool "Intel SCU IPC Support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_pci_driver() uses the same init level priority as builtin_pci_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We don't replace module.h with init.h since the file already has that. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Darren Hart --- drivers/platform/x86/intel_scu_ipc.c | 35 ++++------------------------ 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f94b730540e2..e81daff65f62 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -611,28 +610,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; } -/** - * ipc_remove - remove a bound IPC device - * @pdev: PCI device - * - * In practice the SCU is not removable but this function is also - * called for each device on a module unload or cleanup which is the - * path that will get used. - * - * Free up the mappings and release the PCI resources - */ -static void ipc_remove(struct pci_dev *pdev) -{ - struct intel_scu_ipc_dev *scu = pci_get_drvdata(pdev); - - mutex_lock(&ipclock); - scu->dev = NULL; - mutex_unlock(&ipclock); - - iounmap(scu->i2c_base); - intel_scu_devices_destroy(); -} - static const struct pci_device_id pci_ids[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT), @@ -650,17 +627,13 @@ static const struct pci_device_id pci_ids[] = { 0, } }; -MODULE_DEVICE_TABLE(pci, pci_ids); static struct pci_driver ipc_driver = { + .driver = { + .suppress_bind_attrs = true, + }, .name = "intel_scu_ipc", .id_table = pci_ids, .probe = ipc_probe, - .remove = ipc_remove, }; - -module_pci_driver(ipc_driver); - -MODULE_AUTHOR("Sreedhara DS "); -MODULE_DESCRIPTION("Intel SCU IPC driver"); -MODULE_LICENSE("GPL"); +builtin_pci_driver(ipc_driver); From e8b69a51b4e72a168e8b3bc5fcac39a7de339864 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Feb 2016 15:22:27 +0100 Subject: [PATCH 38/47] intel-hid: allocate correct amount of memory for private struct We want the size of the struct, not of a pointer to it. To be future proof, just dereference the pointer to get the desired type. Signed-off-by: Wolfram Sang Signed-off-by: Darren Hart --- drivers/platform/x86/intel-hid.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 20f0ad9bb9f3..9d15afe70b4f 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -181,8 +181,7 @@ static int intel_hid_probe(struct platform_device *device) return -ENODEV; } - priv = devm_kzalloc(&device->dev, - sizeof(struct intel_hid_priv *), GFP_KERNEL); + priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; dev_set_drvdata(&device->dev, priv); From b5df36cf474cc84028bee05f153a925d8243215f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 24 Feb 2016 14:23:32 +0100 Subject: [PATCH 39/47] fujitsu-laptop: Support radio toggle button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lifebook E734/E744/E754 has a radio toggle button which uses code 0x420. Map it to KEY_RFKILL. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c62caff93fd..ffc84cc7b1c7 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -114,6 +114,7 @@ #define KEY2_CODE 0x411 #define KEY3_CODE 0x412 #define KEY4_CODE 0x413 +#define KEY5_CODE 0x420 #define MAX_HOTKEY_RINGBUFFER_SIZE 100 #define RINGBUFFERSIZE 40 @@ -149,7 +150,7 @@ struct fujitsu_t { char phys[32]; struct backlight_device *bl_device; struct platform_device *pf_device; - int keycode1, keycode2, keycode3, keycode4; + int keycode1, keycode2, keycode3, keycode4, keycode5; unsigned int max_brightness; unsigned int brightness_changed; @@ -823,6 +824,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) set_bit(fujitsu->keycode2, input->keybit); set_bit(fujitsu->keycode3, input->keybit); set_bit(fujitsu->keycode4, input->keybit); + set_bit(fujitsu->keycode5, input->keybit); set_bit(KEY_UNKNOWN, input->keybit); error = input_register_device(input); @@ -962,6 +964,9 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) case KEY4_CODE: keycode = fujitsu->keycode4; break; + case KEY5_CODE: + keycode = fujitsu->keycode5; + break; case 0: keycode = 0; break; @@ -1072,6 +1077,7 @@ static int __init fujitsu_init(void) fujitsu->keycode2 = KEY_PROG2; fujitsu->keycode3 = KEY_PROG3; fujitsu->keycode4 = KEY_PROG4; + fujitsu->keycode5 = KEY_RFKILL; dmi_check_system(fujitsu_dmi_table); result = acpi_bus_register_driver(&acpi_fujitsu_driver); From 4db9675d927a71faa66e5ab128d2390d6329750b Mon Sep 17 00:00:00 2001 From: John Dahlstrom Date: Sat, 27 Feb 2016 00:09:58 -0600 Subject: [PATCH 40/47] ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list Some Lenovo ideapad models lack a physical rfkill switch. On Lenovo models ideapad Y700 Touch-15ISK and ideapad Y700-15ISK, ideapad-laptop would wrongly report all radios as blocked by hardware which caused wireless network connections to fail. Add these models without an rfkill switch to the no_hw_rfkill list. Signed-off-by: John Dahlstrom Cc: # 3.17.x-: 4fa9dab: ideapad_laptop: Lenovo G50-30 fix rfkill reports wireless blocked Cc: Signed-off-by: Darren Hart --- drivers/platform/x86/ideapad-laptop.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index d78ee151c9e4..be3bc2f4edd4 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -864,6 +864,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"), }, }, + { + .ident = "Lenovo ideapad Y700-15ISK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"), + }, + }, + { + .ident = "Lenovo ideapad Y700 Touch-15ISK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"), + }, + }, { .ident = "Lenovo ideapad Y700-17ISK", .matches = { From e8edf53b198f5656d5ae99685bc6c1f616662b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 4 Mar 2016 14:09:06 +0100 Subject: [PATCH 41/47] dell-laptop: move dell_smi_error() to dell-smbios MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dell_smi_error() method could be used by modules other than dell-laptop for convenient translation of SMBIOS request errors into errno values. Thus, move it to dell-smbios. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 14 -------------- drivers/platform/x86/dell-smbios.c | 16 ++++++++++++++++ drivers/platform/x86/dell-smbios.h | 2 ++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 76064c817f3d..cbafb95f694c 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -273,20 +273,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = { { } }; -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: * diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 2a4992a9c538..942572f183b5 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,21 @@ static int da_command_code; static int da_num_tokens; static struct calling_interface_token *da_tokens; +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; + } +} +EXPORT_SYMBOL_GPL(dell_smi_error); + struct calling_interface_buffer *dell_smbios_get_buffer(void) { mutex_lock(&buffer_mutex); diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 4f69b16f7769..52febe62d189 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -35,6 +35,8 @@ struct calling_interface_token { }; }; +int dell_smi_error(int value); + struct calling_interface_buffer *dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); void dell_smbios_release_buffer(void); From 0db2180fce6ada548f03c4f456ba2113753cdba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 4 Mar 2016 14:09:07 +0100 Subject: [PATCH 42/47] dell-smbios: rename dell_smi_error() to dell_smbios_error() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As dell_smi_error() is exported by dell-smbios, its prefix should be consistent with other exported symbols, so change function name to dell_smbios_error(). Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 16 ++++++++-------- drivers/platform/x86/dell-smbios.c | 4 ++-- drivers/platform/x86/dell-smbios.h | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index cbafb95f694c..2c2f02b2e08a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -433,7 +433,7 @@ static int dell_rfkill_set(void *data, bool blocked) out: dell_smbios_release_buffer(); - return dell_smi_error(ret); + return dell_smbios_error(ret); } /* Must be called with the buffer held */ @@ -876,7 +876,7 @@ static int dell_send_intensity(struct backlight_device *bd) else dell_smbios_send_request(1, 1); - ret = dell_smi_error(buffer->output[0]); + ret = dell_smbios_error(buffer->output[0]); dell_smbios_release_buffer(); return ret; @@ -901,7 +901,7 @@ static int dell_get_intensity(struct backlight_device *bd) dell_smbios_send_request(0, 1); if (buffer->output[0]) - ret = dell_smi_error(buffer->output[0]); + ret = dell_smbios_error(buffer->output[0]); else ret = buffer->output[1]; @@ -1160,7 +1160,7 @@ static int kbd_get_info(struct kbd_info *info) ret = buffer->output[0]; if (ret) { - ret = dell_smi_error(ret); + ret = dell_smbios_error(ret); goto out; } @@ -1249,7 +1249,7 @@ static int kbd_get_state(struct kbd_state *state) ret = buffer->output[0]; if (ret) { - ret = dell_smi_error(ret); + ret = dell_smbios_error(ret); goto out; } @@ -1286,7 +1286,7 @@ static int kbd_set_state(struct kbd_state *state) ret = buffer->output[0]; dell_smbios_release_buffer(); - return dell_smi_error(ret); + return dell_smbios_error(ret); } static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) @@ -1329,7 +1329,7 @@ static int kbd_set_token_bit(u8 bit) ret = buffer->output[0]; dell_smbios_release_buffer(); - return dell_smi_error(ret); + return dell_smbios_error(ret); } static int kbd_get_token_bit(u8 bit) @@ -1354,7 +1354,7 @@ static int kbd_get_token_bit(u8 bit) dell_smbios_release_buffer(); if (ret) - return dell_smi_error(ret); + return dell_smbios_error(ret); return (val == token->value); } diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index 942572f183b5..d2412ab097da 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -40,7 +40,7 @@ static int da_command_code; static int da_num_tokens; static struct calling_interface_token *da_tokens; -int dell_smi_error(int value) +int dell_smbios_error(int value) { switch (value) { case 0: /* Completed successfully */ @@ -53,7 +53,7 @@ int dell_smi_error(int value) return -EINVAL; } } -EXPORT_SYMBOL_GPL(dell_smi_error); +EXPORT_SYMBOL_GPL(dell_smbios_error); struct calling_interface_buffer *dell_smbios_get_buffer(void) { diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 52febe62d189..ec7d40ae5e6e 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -35,7 +35,7 @@ struct calling_interface_token { }; }; -int dell_smi_error(int value); +int dell_smbios_error(int value); struct calling_interface_buffer *dell_smbios_get_buffer(void); void dell_smbios_clear_buffer(void); From e09c4d5b15438bd86ff8bfb05d70f17915bb5979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 4 Mar 2016 14:09:08 +0100 Subject: [PATCH 43/47] dell-wmi: enable receiving WMI events on Dell Vostro V131 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some laptop models (e.g. Dell Vostro V131), WMI events are not generated until a specific SMBIOS request is issued to register an event listener [1]. As there seems to be no ACPI method or SMBIOS request to determine without possible side effects whether a given machine needs to issue this SMBIOS request in order to receive WMI events, DMI matching is used to whitelist the models which need it. [1] https://lists.us.dell.com/pipermail/libsmbios-devel/2015-July/000612.html Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/dell-wmi.c | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index a65d974f387a..ed2004be13cf 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -124,6 +124,7 @@ config DELL_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/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index e38258a82be5..65edd93df7de 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -37,6 +37,7 @@ #include #include #include +#include "dell-smbios.h" MODULE_AUTHOR("Matthew Garrett "); MODULE_AUTHOR("Pali Rohár "); @@ -47,10 +48,29 @@ MODULE_LICENSE("GPL"); #define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" static u32 dell_wmi_interface_version; +static bool wmi_requires_smbios_request; MODULE_ALIAS("wmi:"DELL_EVENT_GUID); MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); +static int __init dmi_matched(const struct dmi_system_id *dmi) +{ + wmi_requires_smbios_request = 1; + return 1; +} + +static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { + { + .callback = dmi_matched, + .ident = "Dell Vostro V131", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), + }, + }, + { } +}; + /* * Certain keys are flagged as KE_IGNORE. All of these are either * notifications (rather than requests for change) or are also sent @@ -597,6 +617,38 @@ static int __init dell_wmi_check_descriptor_buffer(void) return 0; } +/* + * According to Dell SMBIOS documentation: + * + * 17 3 Application Program Registration + * + * cbArg1 Application ID 1 = 0x00010000 + * cbArg2 Application ID 2 + * QUICKSET/DCP = 0x51534554 "QSET" + * ALS Driver = 0x416c7353 "AlsS" + * Latitude ON = 0x4c6f6e52 "LonR" + * cbArg3 Application version or revision number + * cbArg4 0 = Unregister application + * 1 = Register application + * cbRes1 Standard return codes (0, -1, -2) + */ + +static int dell_wmi_events_set_enabled(bool enable) +{ + struct calling_interface_buffer *buffer; + int ret; + + buffer = dell_smbios_get_buffer(); + buffer->input[0] = 0x10000; + buffer->input[1] = 0x51534554; + buffer->input[3] = enable; + dell_smbios_send_request(17, 3); + ret = buffer->output[0]; + dell_smbios_release_buffer(); + + return dell_smbios_error(ret); +} + static int __init dell_wmi_init(void) { int err; @@ -624,12 +676,26 @@ static int __init dell_wmi_init(void) return -ENODEV; } + dmi_check_system(dell_wmi_smbios_list); + + if (wmi_requires_smbios_request) { + err = dell_wmi_events_set_enabled(true); + if (err) { + pr_err("Failed to enable WMI events\n"); + wmi_remove_notify_handler(DELL_EVENT_GUID); + dell_wmi_input_destroy(); + return err; + } + } + return 0; } module_init(dell_wmi_init); static void __exit dell_wmi_exit(void) { + if (wmi_requires_smbios_request) + dell_wmi_events_set_enabled(false); wmi_remove_notify_handler(DELL_EVENT_GUID); dell_wmi_input_destroy(); } From 13f5059ac5a6b8a824f8657e2fcf084ebecef896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 4 Mar 2016 14:09:09 +0100 Subject: [PATCH 44/47] dell-wmi: properly process Dell Instant Launch hotkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On models on which an SMBIOS request needs to be issued in order for WMI events to be generated, pressing the Dell Instant Launch hotkey does not raise an i8042 interrupt - only a WMI event is generated (0xe025 on Dell Vostro V131). As that WMI event is the only way the kernel will be notified about pressing the Dell Instant Launch hotkey on such machines, the relevant keymap entry has to be changed to a KE_KEY one. However, the same WMI event should still be ignored on machines which do not require an SMBIOS request for enabling WMI, so filter it conditionally in dell_wmi_process_key(). Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 65edd93df7de..3ea959ecd635 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -111,7 +111,7 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe020, { KEY_MUTE } }, /* Shortcut and audio panel keys */ - { KE_IGNORE, 0xe025, { KEY_RESERVED } }, + { KE_KEY, 0xe025, { KEY_PROG4 } }, { KE_IGNORE, 0xe026, { KEY_RESERVED } }, { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, @@ -235,6 +235,9 @@ static void dell_wmi_process_key(int reported_key) acpi_video_handles_brightness_key_presses()) return; + if (reported_key == 0xe025 && !wmi_requires_smbios_request) + return; + sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); } From aaf3a5e77566ad186a85d28a0afd26b8dd0afd11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 4 Mar 2016 14:09:10 +0100 Subject: [PATCH 45/47] dell-wmi: support Dell Inspiron M5110 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to Dell Vostro V131, Dell Inspiron M5110 also requires an SMBIOS request to be issued in order for WMI events to be generated and does not raise an i8042 interrupt when the Dell Instant Launch hotkey is pressed. However, the event code for that hotkey on this machine is 0xe029, so add it to the legacy keymap. Signed-off-by: Michał Kępień Tested-by: Darek Stojaczyk Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 3ea959ecd635..15c6f1191aec 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -60,6 +60,14 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) } static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { + { + .callback = dmi_matched, + .ident = "Dell Inspiron M5110", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), + }, + }, { .callback = dmi_matched, .ident = "Dell Vostro V131", @@ -110,8 +118,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe020, { KEY_MUTE } }, - /* Shortcut and audio panel keys */ + /* Dell Instant Launch key */ { KE_KEY, 0xe025, { KEY_PROG4 } }, + { KE_KEY, 0xe029, { KEY_PROG4 } }, + + /* Audio panel key */ { KE_IGNORE, 0xe026, { KEY_RESERVED } }, { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, From c7805e5459f5cac2d99e901e276908c205c3fd3a Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 6 Mar 2016 23:38:36 +0100 Subject: [PATCH 46/47] hp-wmi: fix unregister order in hp_wmi_rfkill_setup() once again rfkill registration order in hp_wmi_rfkill_setup() is: 1) WiFi, 2) BT, 3) WWAN, 5) GPS. Unregistration when cleaning up on error return should happen in reverse order. This means that: If BT rfkill fails to be allocated we possibly need to first unregister WiFi rfkill before destroying it. The same goes with (WWAN, BT) and (GPS, WWAN) pairs. Also, if WWAN rfkill fails to register we need to (possibly) unregister BT not the GPS one. And if GPS rfkill fails to register we need to unregister WWAN not the BT one. We never need to unregister GPS rfkill here since if GPS rfkill registration succeeds this function returns without error so no cleanup is necessary. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Darren Hart --- drivers/platform/x86/hp-wmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fb4dd7b3ee71..78cebc0e358c 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -746,7 +746,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) (void *) HPWMI_BLUETOOTH); if (!bluetooth_rfkill) { err = -ENOMEM; - goto register_wifi_error; + goto register_bluetooth_error; } rfkill_init_sw_state(bluetooth_rfkill, hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); @@ -764,7 +764,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) (void *) HPWMI_WWAN); if (!wwan_rfkill) { err = -ENOMEM; - goto register_bluetooth_error; + goto register_wwan_error; } rfkill_init_sw_state(wwan_rfkill, hp_wmi_get_sw_state(HPWMI_WWAN)); @@ -782,7 +782,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) (void *) HPWMI_GPS); if (!gps_rfkill) { err = -ENOMEM; - goto register_wwan_error; + goto register_gps_error; } rfkill_init_sw_state(gps_rfkill, hp_wmi_get_sw_state(HPWMI_GPS)); @@ -797,13 +797,13 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) register_gps_error: rfkill_destroy(gps_rfkill); gps_rfkill = NULL; - if (bluetooth_rfkill) - rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); register_wwan_error: rfkill_destroy(wwan_rfkill); wwan_rfkill = NULL; - if (gps_rfkill) - rfkill_unregister(gps_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); register_bluetooth_error: rfkill_destroy(bluetooth_rfkill); bluetooth_rfkill = NULL; From fffcad87d4e7c5f6f6f6e5fc9d337bd6f197f80f Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 6 Mar 2016 23:40:19 +0100 Subject: [PATCH 47/47] hp-wmi: Remove GPS rfkill support via pre-2009 interface GPS rfkill support via pre-2009 WMI interface uses hp_wmi_get_sw_state() and hp_wmi_get_hw_state() to query its current hard and soft block state, respectively. In hp_wmi_get_sw_state() a mask is calculated which bit should be checked in an int value returned by firmware to get current block state: 0x200 << (r * 8) which with r being 3 for GPS results in overflow and mask of zero. The same goes for hp_wmi_get_hw_state(). This effectively means that GPS rfkill on this WMI interface is considered always both hard and soft blocked. Unfortunately, later when rfkill subsystem calls hp_wmi_set_block() to sync this block to hardware firmware at least on my old nc6400 gets confused and sets both hard and soft blocks on WiFi and BT. This happens for example on hp-wmi module load. Since due to overflow described above it is dubious that this ever worked correctly and HP laptops with modems having GPS support seem to all have been released well past year 2009 let's just remove GPS rfkill support via pre-2009 WMI interface. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Darren Hart --- drivers/platform/x86/hp-wmi.c | 38 +---------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 78cebc0e358c..6f145f2d004d 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -157,7 +157,6 @@ static struct platform_device *hp_wmi_platform_dev; static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *wwan_rfkill; -static struct rfkill *gps_rfkill; struct rfkill2_device { u8 id; @@ -613,10 +612,6 @@ static void hp_wmi_notify(u32 value, void *context) rfkill_set_states(wwan_rfkill, hp_wmi_get_sw_state(HPWMI_WWAN), hp_wmi_get_hw_state(HPWMI_WWAN)); - if (gps_rfkill) - rfkill_set_states(gps_rfkill, - hp_wmi_get_sw_state(HPWMI_GPS), - hp_wmi_get_hw_state(HPWMI_GPS)); break; case HPWMI_CPU_BATTERY_THROTTLE: pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); @@ -775,30 +770,8 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) goto register_wwan_error; } - if (wireless & 0x8) { - gps_rfkill = rfkill_alloc("hp-gps", &device->dev, - RFKILL_TYPE_GPS, - &hp_wmi_rfkill_ops, - (void *) HPWMI_GPS); - if (!gps_rfkill) { - err = -ENOMEM; - goto register_gps_error; - } - rfkill_init_sw_state(gps_rfkill, - hp_wmi_get_sw_state(HPWMI_GPS)); - rfkill_set_hw_state(gps_rfkill, - hp_wmi_get_hw_state(HPWMI_GPS)); - err = rfkill_register(gps_rfkill); - if (err) - goto register_gps_error; - } - return 0; -register_gps_error: - rfkill_destroy(gps_rfkill); - gps_rfkill = NULL; - if (wwan_rfkill) - rfkill_unregister(wwan_rfkill); + register_wwan_error: rfkill_destroy(wwan_rfkill); wwan_rfkill = NULL; @@ -907,7 +880,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wifi_rfkill = NULL; bluetooth_rfkill = NULL; wwan_rfkill = NULL; - gps_rfkill = NULL; rfkill2_count = 0; if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) @@ -960,10 +932,6 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) rfkill_unregister(wwan_rfkill); rfkill_destroy(wwan_rfkill); } - if (gps_rfkill) { - rfkill_unregister(gps_rfkill); - rfkill_destroy(gps_rfkill); - } return 0; } @@ -999,10 +967,6 @@ static int hp_wmi_resume_handler(struct device *device) rfkill_set_states(wwan_rfkill, hp_wmi_get_sw_state(HPWMI_WWAN), hp_wmi_get_hw_state(HPWMI_WWAN)); - if (gps_rfkill) - rfkill_set_states(gps_rfkill, - hp_wmi_get_sw_state(HPWMI_GPS), - hp_wmi_get_hw_state(HPWMI_GPS)); return 0; }