From 93ed249075599497fa0667d1b9873d66831fd0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 24 Feb 2017 11:33:06 +0100 Subject: [PATCH 001/108] platform/x86: intel-hid: simplify enabling/disabling HID events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI method HDSM takes a single integer argument. Use acpi_execute_simple_method() instead of acpi_evaluate_object() for calling that ACPI method to simplify code and reduce the number of local variables inside intel_hid_set_enable(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Alex Hung --- drivers/platform/x86/intel-hid.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index bcf438f38781..4d1c5eb3a96d 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -79,12 +79,10 @@ struct intel_hid_priv { static int intel_hid_set_enable(struct device *device, int enable) { - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; acpi_status status; - arg0.integer.value = enable; - status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL); + status = acpi_execute_simple_method(ACPI_HANDLE(device), "HDSM", + enable); if (ACPI_FAILURE(status)) { dev_warn(device, "failed to %sable hotkeys\n", enable ? "en" : "dis"); From 99a75e7b05c764b82a1ba4b632c66d1b58b8fff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 24 Feb 2017 11:33:07 +0100 Subject: [PATCH 002/108] platform/x86: intel-hid: make intel_hid_set_enable() take a boolean argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the integer value passed to intel_hid_set_enable() is always explicitly passed and is used solely as a boolean value, make it a bool. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Alex Hung --- drivers/platform/x86/intel-hid.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 4d1c5eb3a96d..89d1d98e3214 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -77,7 +77,7 @@ struct intel_hid_priv { struct input_dev *array; }; -static int intel_hid_set_enable(struct device *device, int enable) +static int intel_hid_set_enable(struct device *device, bool enable) { acpi_status status; @@ -118,7 +118,7 @@ static void intel_button_array_enable(struct device *device, bool enable) static int intel_hid_pl_suspend_handler(struct device *device) { - intel_hid_set_enable(device, 0); + intel_hid_set_enable(device, false); intel_button_array_enable(device, false); return 0; @@ -126,7 +126,7 @@ static int intel_hid_pl_suspend_handler(struct device *device) static int intel_hid_pl_resume_handler(struct device *device) { - intel_hid_set_enable(device, 1); + intel_hid_set_enable(device, true); intel_button_array_enable(device, true); return 0; @@ -275,7 +275,7 @@ static int intel_hid_probe(struct platform_device *device) goto err_remove_input; } - err = intel_hid_set_enable(&device->dev, 1); + err = intel_hid_set_enable(&device->dev, true); if (err) goto err_remove_notify; @@ -306,7 +306,7 @@ static int intel_hid_remove(struct platform_device *device) acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); intel_hid_input_destroy(device); - intel_hid_set_enable(&device->dev, 0); + intel_hid_set_enable(&device->dev, false); intel_button_array_enable(&device->dev, false); /* From 175cc9b72fb5ca65dfb79e7c2500304476486717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 24 Feb 2017 11:33:08 +0100 Subject: [PATCH 003/108] platform/x86: intel-hid: use devm_input_allocate_device() for HID events input device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_hid_input_setup() is only called from the platform driver's .probe callback. Use the devm variant of input_allocate_device() for allocating memory for the HID events input device in order to simplify two error paths and get rid of intel_hid_input_destroy(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Alex Hung --- drivers/platform/x86/intel-hid.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 89d1d98e3214..b17f33b832c2 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -144,28 +144,20 @@ static int intel_hid_input_setup(struct platform_device *device) struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); int ret; - priv->input_dev = input_allocate_device(); + priv->input_dev = devm_input_allocate_device(&device->dev); if (!priv->input_dev) return -ENOMEM; ret = sparse_keymap_setup(priv->input_dev, intel_hid_keymap, NULL); if (ret) - goto err_free_device; + return ret; priv->input_dev->dev.parent = &device->dev; priv->input_dev->name = "Intel HID events"; priv->input_dev->id.bustype = BUS_HOST; set_bit(KEY_RFKILL, priv->input_dev->keybit); - ret = input_register_device(priv->input_dev); - if (ret) - goto err_free_device; - - return 0; - -err_free_device: - input_free_device(priv->input_dev); - return ret; + return input_register_device(priv->input_dev); } static int intel_button_array_input_setup(struct platform_device *device) @@ -189,13 +181,6 @@ static int intel_button_array_input_setup(struct platform_device *device) return input_register_device(priv->array); } -static void intel_hid_input_destroy(struct platform_device *device) -{ - struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); - - input_unregister_device(priv->input_dev); -} - static void notify_handler(acpi_handle handle, u32 event, void *context) { struct platform_device *device = context; @@ -270,10 +255,8 @@ static int intel_hid_probe(struct platform_device *device) ACPI_DEVICE_NOTIFY, notify_handler, device); - if (ACPI_FAILURE(status)) { - err = -EBUSY; - goto err_remove_input; - } + if (ACPI_FAILURE(status)) + return -EBUSY; err = intel_hid_set_enable(&device->dev, true); if (err) @@ -294,9 +277,6 @@ static int intel_hid_probe(struct platform_device *device) err_remove_notify: acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); -err_remove_input: - intel_hid_input_destroy(device); - return err; } @@ -305,7 +285,6 @@ static int intel_hid_remove(struct platform_device *device) acpi_handle handle = ACPI_HANDLE(&device->dev); acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); - intel_hid_input_destroy(device); intel_hid_set_enable(&device->dev, false); intel_button_array_enable(&device->dev, false); From faf667efdbe5f6c8d6962aab8680680838678097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 24 Feb 2017 11:33:09 +0100 Subject: [PATCH 004/108] platform/x86: intel-hid: remove redundant set_bit() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove redundant set_bit() call for KEY_RFKILL as it is already made by sparse_keymap_setup() due to KEY_RFKILL being assigned to event code 8 in intel_hid_keymap. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Alex Hung --- drivers/platform/x86/intel-hid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index b17f33b832c2..5eab31659cba 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -155,7 +155,6 @@ static int intel_hid_input_setup(struct platform_device *device) priv->input_dev->dev.parent = &device->dev; priv->input_dev->name = "Intel HID events"; priv->input_dev->id.bustype = BUS_HOST; - set_bit(KEY_RFKILL, priv->input_dev->keybit); return input_register_device(priv->input_dev); } From 149c8c75b38be528b8648d907195f188bc8fb0fb Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 28 Feb 2017 17:10:56 +0100 Subject: [PATCH 005/108] platform/x86: thinkpad_acpi: guard generic hotkey case Currently when dispatching hotkeys we check if the scancode is in the range of 0 and TPACPI_HOTKEY_MAP_LEN, although the bottom 20 entries in the hotkey keymap are already adaptive keycodes. Therefore we introduce a TP_ACPI_HOTKEYSCAN_ADAPTIVE_START and ensure that we are in the range 0 and ADAPTIVE_START for the generic keycode case. Signed-off-by: Christian Kellner Reviewed-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko --- drivers/platform/x86/thinkpad_acpi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 1d18b32628ec..e2b962f0fdc4 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1922,7 +1922,9 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_UNK7, TP_ACPI_HOTKEYSCAN_UNK8, - TP_ACPI_HOTKEYSCAN_MUTE2, + /* Adaptive keyboard keycodes */ + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START, + TP_ACPI_HOTKEYSCAN_MUTE2 = TP_ACPI_HOTKEYSCAN_ADAPTIVE_START, TP_ACPI_HOTKEYSCAN_BRIGHTNESS_ZERO, TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL, TP_ACPI_HOTKEYSCAN_CLOUD, @@ -3656,7 +3658,6 @@ static const int adaptive_keyboard_modes[] = { #define DFR_CHANGE_ROW 0x101 #define DFR_SHOW_QUICKVIEW_ROW 0x102 #define FIRST_ADAPTIVE_KEY 0x103 -#define ADAPTIVE_KEY_OFFSET 0x020 /* press Fn key a while second, it will switch to Function Mode. Then * release Fn key, previous mode be restored. @@ -3747,12 +3748,13 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) default: if (scancode < FIRST_ADAPTIVE_KEY || scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN - - ADAPTIVE_KEY_OFFSET) { + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { pr_info("Unhandled adaptive keyboard key: 0x%x\n", scancode); return false; } - keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + ADAPTIVE_KEY_OFFSET]; + keycode = hotkey_keycode_map[scancode - FIRST_ADAPTIVE_KEY + + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START]; if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); @@ -3778,7 +3780,7 @@ static bool hotkey_notify_hotkey(const u32 hkey, *ignore_acpi_ev = false; /* HKEY event 0x1001 is scancode 0x00 */ - if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) { + if (scancode > 0 && scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { tpacpi_input_send_key_masked(scancode); From 696c6523ec8f2a8f30f3dffef7e382f0fe5c2010 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 28 Feb 2017 17:10:57 +0100 Subject: [PATCH 006/108] platform/x86: thinkpad_acpi: add mapping for new hotkeys The T470, X270 emits new hkey events in the 0x1311 - 0x1315 range. According to the user manual they should launch a user selected favorite application (star icon, 0x1311), snipping tool (0x1312, currently ignored), enable/disable bluetooth (0x1314) and open they keyboard settings (0x1315). The third nibble (0xf00) is used to differentiate between the original hotkeys, the adaptive keyboard codes and the new, additional ones. Signed-off-by: Christian Kellner Reviewed-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko --- drivers/platform/x86/thinkpad_acpi.c | 91 ++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e2b962f0fdc4..7b6cb0c69b02 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1945,6 +1945,15 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_CAMERA_MODE, TP_ACPI_HOTKEYSCAN_ROTATE_DISPLAY, + /* Lenovo extended keymap, starting at 0x1300 */ + TP_ACPI_HOTKEYSCAN_EXTENDED_START, + /* first new observed key (star, favorites) is 0x1311 */ + TP_ACPI_HOTKEYSCAN_STAR = 69, + TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2, + TP_ACPI_HOTKEYSCAN_UNK25, + TP_ACPI_HOTKEYSCAN_BLUETOOTH, + TP_ACPI_HOTKEYSCAN_KEYBOARD, + /* Hotkey keymap size */ TPACPI_HOTKEY_MAP_LEN }; @@ -3252,6 +3261,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + + /* No assignment, used for newer Lenovo models */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN + }, /* Generic keymap for Lenovo ThinkPads */ @@ -3337,6 +3355,29 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_RESERVED, /* Microphone cancellation */ KEY_RESERVED, /* Camera mode */ KEY_RESERVED, /* Rotate display, 0x116 */ + + /* + * These are found in 2017 models (e.g. T470s, X270). + * The lowest known value is 0x311, which according to + * the manual should launch a user defined favorite + * application. + * + * The offset for these is TP_ACPI_HOTKEYSCAN_EXTENDED_START, + * corresponding to 0x34. + */ + + /* (assignments unknown, please report if found) */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, + + KEY_FAVORITES, /* Favorite app, 0x311 */ + KEY_RESERVED, /* Clipping tool */ + KEY_RESERVED, + KEY_BLUETOOTH, /* Bluetooth */ + KEY_KEYBOARD /* Keyboard, 0x315 */ }, }; @@ -3747,8 +3788,9 @@ static bool adaptive_keyboard_hotkey_notify_hotkey(unsigned int scancode) default: if (scancode < FIRST_ADAPTIVE_KEY || - scancode >= FIRST_ADAPTIVE_KEY + TPACPI_HOTKEY_MAP_LEN - - TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { + scancode >= FIRST_ADAPTIVE_KEY + + TP_ACPI_HOTKEYSCAN_EXTENDED_START - + TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { pr_info("Unhandled adaptive keyboard key: 0x%x\n", scancode); return false; @@ -3779,19 +3821,44 @@ static bool hotkey_notify_hotkey(const u32 hkey, *send_acpi_ev = true; *ignore_acpi_ev = false; - /* HKEY event 0x1001 is scancode 0x00 */ - if (scancode > 0 && scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { - scancode--; - if (!(hotkey_source_mask & (1 << scancode))) { - tpacpi_input_send_key_masked(scancode); - *send_acpi_ev = false; - } else { - *ignore_acpi_ev = true; + /* + * Original events are in the 0x10XX range, the adaptive keyboard + * found in 2014 X1 Carbon emits events are of 0x11XX. In 2017 + * models, additional keys are emitted through 0x13XX. + */ + switch ((hkey >> 8) & 0xf) { + case 0: + if (scancode > 0 && + scancode <= TP_ACPI_HOTKEYSCAN_ADAPTIVE_START) { + /* HKEY event 0x1001 is scancode 0x00 */ + scancode--; + if (!(hotkey_source_mask & (1 << scancode))) { + tpacpi_input_send_key_masked(scancode); + *send_acpi_ev = false; + } else { + *ignore_acpi_ev = true; + } + return true; } - return true; - } else { + break; + + case 1: return adaptive_keyboard_hotkey_notify_hotkey(scancode); + + case 3: + /* Extended keycodes start at 0x300 and our offset into the map + * TP_ACPI_HOTKEYSCAN_EXTENDED_START. The calculated scancode + * will be positive, but might not be in the correct range. + */ + scancode -= (0x300 - TP_ACPI_HOTKEYSCAN_EXTENDED_START); + if (scancode >= TP_ACPI_HOTKEYSCAN_EXTENDED_START && + scancode < TPACPI_HOTKEY_MAP_LEN) { + tpacpi_input_send_key(scancode); + return true; + } + break; } + return false; } From 1f3bc53d843f92d6e7e7cf56ee79acec918e6421 Mon Sep 17 00:00:00 2001 From: Sven Rebhan Date: Tue, 21 Feb 2017 20:53:48 +0100 Subject: [PATCH 007/108] platform/x86: ideapad-laptop: Add IdeaPad 310-15IKB to no_hw_rfkill Like other Lenovo models the IdeaPad 310-15IKB does not have an hw rfkill switch. This results in hard-blocked radios after boot, resulting in always blocked radios rendering them unusable. Add the IdeaPad 310-15IKB to the no_hw_rfkill DMI list and allows using the built-in radios. Signed-off-by: Sven Rebhan [andy: massaged commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index f46ece2ce3c4..cc6d91e18683 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -871,6 +871,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"), }, }, + { + .ident = "Lenovo ideapad 310-15IKB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad 310-15IKB"), + }, + }, { .ident = "Lenovo ideapad Y700-15ACZ", .matches = { From 5efc800463bc340abf6b5e7abd84f7a9522a428d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 1 Mar 2017 07:42:53 +0100 Subject: [PATCH 008/108] platform/x86: fujitsu-laptop: decrease indentation in acpi_fujitsu_bl_notify() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_fujitsu_bl_notify() is pretty deeply nested, which hurts readability. Strip off one level of indentation by returning early when the event code supplied as argument is not ACPI_FUJITSU_NOTIFY_CODE1. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 64 ++++++++++++++------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index e12cc3504d48..b19f6e1c0173 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -795,40 +795,42 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) input = fujitsu_bl->input; - switch (event) { - case ACPI_FUJITSU_NOTIFY_CODE1: - keycode = 0; - oldb = fujitsu_bl->brightness_level; - get_lcd_level(); - newb = fujitsu_bl->brightness_level; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "brightness button event [%i -> %i (%i)]\n", - oldb, newb, fujitsu_bl->brightness_changed); - - if (oldb < newb) { - if (disable_brightness_adjust != 1) { - if (use_alt_lcd_levels) - set_lcd_level_alt(newb); - else - set_lcd_level(newb); - } - keycode = KEY_BRIGHTNESSUP; - } else if (oldb > newb) { - if (disable_brightness_adjust != 1) { - if (use_alt_lcd_levels) - set_lcd_level_alt(newb); - else - set_lcd_level(newb); - } - keycode = KEY_BRIGHTNESSDOWN; - } - break; - default: + if (event != ACPI_FUJITSU_NOTIFY_CODE1) { keycode = KEY_UNKNOWN; vdbg_printk(FUJLAPTOP_DBG_WARN, "unsupported event [0x%x]\n", event); - break; + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; + } + + keycode = 0; + oldb = fujitsu_bl->brightness_level; + get_lcd_level(); + newb = fujitsu_bl->brightness_level; + + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "brightness button event [%i -> %i (%i)]\n", + oldb, newb, fujitsu_bl->brightness_changed); + + if (oldb < newb) { + if (disable_brightness_adjust != 1) { + if (use_alt_lcd_levels) + set_lcd_level_alt(newb); + else + set_lcd_level(newb); + } + keycode = KEY_BRIGHTNESSUP; + } else if (oldb > newb) { + if (disable_brightness_adjust != 1) { + if (use_alt_lcd_levels) + set_lcd_level_alt(newb); + else + set_lcd_level(newb); + } + keycode = KEY_BRIGHTNESSDOWN; } if (keycode != 0) { From d2aa3ae86daca0486da4301702e709b2d519b6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 1 Mar 2017 07:42:54 +0100 Subject: [PATCH 009/108] platform/x86: fujitsu-laptop: simplify brightness key event generation logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning early when there is no brightness change allows removal of a duplicate code block, makes the purpose of the following code clearer and allows the condition surrounding key event generation to be removed. Local integer variables can also be declared in a single line. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 40 ++++++++++----------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b19f6e1c0173..4a5e7b60a672 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -790,8 +790,7 @@ static int acpi_fujitsu_bl_remove(struct acpi_device *device) static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) { struct input_dev *input; - int keycode; - int oldb, newb; + int oldb, newb, keycode; input = fujitsu_bl->input; @@ -806,7 +805,6 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) return; } - keycode = 0; oldb = fujitsu_bl->brightness_level; get_lcd_level(); newb = fujitsu_bl->brightness_level; @@ -815,30 +813,22 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) "brightness button event [%i -> %i (%i)]\n", oldb, newb, fujitsu_bl->brightness_changed); - if (oldb < newb) { - if (disable_brightness_adjust != 1) { - if (use_alt_lcd_levels) - set_lcd_level_alt(newb); - else - set_lcd_level(newb); - } - keycode = KEY_BRIGHTNESSUP; - } else if (oldb > newb) { - if (disable_brightness_adjust != 1) { - if (use_alt_lcd_levels) - set_lcd_level_alt(newb); - else - set_lcd_level(newb); - } - keycode = KEY_BRIGHTNESSDOWN; + if (oldb == newb) + return; + + if (disable_brightness_adjust != 1) { + if (use_alt_lcd_levels) + set_lcd_level_alt(newb); + else + set_lcd_level(newb); } - if (keycode != 0) { - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); - } + keycode = oldb < newb ? KEY_BRIGHTNESSUP : KEY_BRIGHTNESSDOWN; + + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); } /* ACPI device for hotkey handling */ From b8d69c16a0bdc2cae1ad709f0a9e6a2484c457a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 10 Mar 2017 11:50:33 +0100 Subject: [PATCH 010/108] platform/x86: fujitsu-laptop: register backlight device in a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move code responsible for backlight device registration to a separate function in order to simplify error handling and decrease indentation. Simplify initialization of struct backlight_properties. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 38 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 4a5e7b60a672..897438f81f09 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -685,6 +685,25 @@ static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { /* ACPI device for LCD brightness control */ +static int fujitsu_backlight_register(void) +{ + struct backlight_properties props = { + .brightness = fujitsu_bl->brightness_level, + .max_brightness = fujitsu_bl->max_brightness - 1, + .type = BACKLIGHT_PLATFORM + }; + struct backlight_device *bd; + + bd = backlight_device_register("fujitsu-laptop", NULL, NULL, + &fujitsu_bl_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); + + fujitsu_bl->bl_device = bd; + + return 0; +} + static int acpi_fujitsu_bl_add(struct acpi_device *device) { int state = 0; @@ -1184,7 +1203,7 @@ MODULE_DEVICE_TABLE(acpi, fujitsu_ids); static int __init fujitsu_init(void) { - int ret, max_brightness; + int ret; if (acpi_disabled) return -ENODEV; @@ -1224,22 +1243,9 @@ static int __init fujitsu_init(void) /* Register backlight stuff */ if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { - struct backlight_properties props; - - memset(&props, 0, sizeof(struct backlight_properties)); - max_brightness = fujitsu_bl->max_brightness; - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = max_brightness - 1; - fujitsu_bl->bl_device = backlight_device_register("fujitsu-laptop", - NULL, NULL, - &fujitsu_bl_ops, - &props); - if (IS_ERR(fujitsu_bl->bl_device)) { - ret = PTR_ERR(fujitsu_bl->bl_device); - fujitsu_bl->bl_device = NULL; + ret = fujitsu_backlight_register(); + if (ret) goto fail_sysfs_group; - } - fujitsu_bl->bl_device->props.brightness = fujitsu_bl->brightness_level; } ret = platform_driver_register(&fujitsu_pf_driver); From 1877e267b39eceac0499af11993bfe00819bb65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 10 Mar 2017 11:50:34 +0100 Subject: [PATCH 011/108] platform/x86: fujitsu-laptop: sync backlight power status in acpi_fujitsu_laptop_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Registering an ACPI driver does not mean the device it handles has to exist. As the code which syncs backlight power status uses call_fext_func(), it needs the FUJ02E3 ACPI device to be present, so ensure that code is only run once the FUJ02E3 device is detected. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 897438f81f09..d96f739f8d85 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -947,6 +947,14 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) /* Suspect this is a keymap of the application panel, print it */ pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); + /* Sync backlight power status */ + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) + fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; + else + fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; + } + #if IS_ENABLED(CONFIG_LEDS_CLASS) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = led_classdev_register(&fujitsu_bl->pf_device->dev, @@ -1264,14 +1272,6 @@ static int __init fujitsu_init(void) if (ret) goto fail_laptop1; - /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ - if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { - if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) - fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; - else - fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; - } - pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); return 0; From aea3137c2cb641e69b80ee5b3c376120034e458d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 10 Mar 2017 11:50:35 +0100 Subject: [PATCH 012/108] platform/x86: fujitsu-laptop: only register backlight device if FUJ02B1 is present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the backlight device registered by fujitsu-laptop relies on the FUJ02B1 ACPI device being present, only register the backlight device once that ACPI device is detected. Suggested-by: Alan Jenkins Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index d96f739f8d85..eccfb8a67e66 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -781,6 +781,12 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(); + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + error = fujitsu_backlight_register(); + if (error) + goto err_unregister_input_dev; + } + return 0; err_unregister_input_dev: @@ -797,6 +803,7 @@ static int acpi_fujitsu_bl_remove(struct acpi_device *device) struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); struct input_dev *input = fujitsu_bl->input; + backlight_device_unregister(fujitsu_bl->bl_device); input_unregister_device(input); fujitsu_bl->acpi_handle = NULL; @@ -948,7 +955,8 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); /* Sync backlight power status */ - if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + if (fujitsu_bl->bl_device && + acpi_video_get_backlight_type() == acpi_backlight_vendor) { if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; else @@ -1248,17 +1256,9 @@ static int __init fujitsu_init(void) if (ret) goto fail_platform_device2; - /* Register backlight stuff */ - - if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { - ret = fujitsu_backlight_register(); - if (ret) - goto fail_sysfs_group; - } - ret = platform_driver_register(&fujitsu_pf_driver); if (ret) - goto fail_backlight; + goto fail_sysfs_group; /* Register laptop driver */ @@ -1280,8 +1280,6 @@ fail_laptop1: kfree(fujitsu_laptop); fail_laptop: platform_driver_unregister(&fujitsu_pf_driver); -fail_backlight: - backlight_device_unregister(fujitsu_bl->bl_device); fail_sysfs_group: sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, &fujitsu_pf_attribute_group); @@ -1305,8 +1303,6 @@ static void __exit fujitsu_cleanup(void) platform_driver_unregister(&fujitsu_pf_driver); - backlight_device_unregister(fujitsu_bl->bl_device); - sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, &fujitsu_pf_attribute_group); From c2cddd4f7d686ae7185af44885894202b5c8af63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 10 Mar 2017 11:50:36 +0100 Subject: [PATCH 013/108] platform/x86: fujitsu-laptop: cleanup error labels in fujitsu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Error labels currently used in fujitsu_init() are really hard to follow: some (fail_laptop) indicate which operation has failed, others (fail_sysfs_group) indicate where unrolling should start and the rest (fail_platform_driver) is simply confusing. Change them to follow the pattern used throughout the rest of the module, i.e. make every label indicate the first unrolling operation it leads to. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Jonathan Woithe --- drivers/platform/x86/fujitsu-laptop.c | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index eccfb8a67e66..3c795d591de0 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1236,60 +1236,60 @@ static int __init fujitsu_init(void) ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); if (ret) - goto fail_acpi; + goto err_free_fujitsu_bl; /* Register platform stuff */ fujitsu_bl->pf_device = platform_device_alloc("fujitsu-laptop", -1); if (!fujitsu_bl->pf_device) { ret = -ENOMEM; - goto fail_platform_driver; + goto err_unregister_acpi; } ret = platform_device_add(fujitsu_bl->pf_device); if (ret) - goto fail_platform_device1; + goto err_put_platform_device; ret = sysfs_create_group(&fujitsu_bl->pf_device->dev.kobj, &fujitsu_pf_attribute_group); if (ret) - goto fail_platform_device2; + goto err_del_platform_device; ret = platform_driver_register(&fujitsu_pf_driver); if (ret) - goto fail_sysfs_group; + goto err_remove_sysfs_group; /* Register laptop driver */ fujitsu_laptop = kzalloc(sizeof(struct fujitsu_laptop), GFP_KERNEL); if (!fujitsu_laptop) { ret = -ENOMEM; - goto fail_laptop; + goto err_unregister_platform_driver; } ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver); if (ret) - goto fail_laptop1; + goto err_free_fujitsu_laptop; pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); return 0; -fail_laptop1: +err_free_fujitsu_laptop: kfree(fujitsu_laptop); -fail_laptop: +err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); -fail_sysfs_group: +err_remove_sysfs_group: sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, &fujitsu_pf_attribute_group); -fail_platform_device2: +err_del_platform_device: platform_device_del(fujitsu_bl->pf_device); -fail_platform_device1: +err_put_platform_device: platform_device_put(fujitsu_bl->pf_device); -fail_platform_driver: +err_unregister_acpi: acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); -fail_acpi: +err_free_fujitsu_bl: kfree(fujitsu_bl); return ret; From cd1aaef0b2846cead3662d37d82384660a7bbd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:37 +0100 Subject: [PATCH 014/108] platform/x86: acer-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index dac0fbe87460..8a27f0be1aec 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1987,7 +1987,7 @@ static int __init acer_wmi_input_setup(void) acer_wmi_notify, NULL); if (ACPI_FAILURE(status)) { err = -EIO; - goto err_free_keymap; + goto err_free_dev; } err = input_register_device(acer_wmi_input_dev); @@ -1998,8 +1998,6 @@ static int __init acer_wmi_input_setup(void) err_uninstall_notifier: wmi_remove_notify_handler(ACERWMID_EVENT_GUID); -err_free_keymap: - sparse_keymap_free(acer_wmi_input_dev); err_free_dev: input_free_device(acer_wmi_input_dev); return err; @@ -2008,7 +2006,6 @@ err_free_dev: static void acer_wmi_input_destroy(void) { wmi_remove_notify_handler(ACERWMID_EVENT_GUID); - sparse_keymap_free(acer_wmi_input_dev); input_unregister_device(acer_wmi_input_dev); } From f118b312bdd729b33165c6614e2370f019baad6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:38 +0100 Subject: [PATCH 015/108] platform/x86: asus-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-laptop.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 28551f5a2e07..c4768be24ba9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1516,14 +1516,12 @@ static int asus_input_init(struct asus_laptop *asus) error = input_register_device(input); if (error) { pr_warn("Unable to register input device\n"); - goto err_free_keymap; + goto err_free_dev; } asus->inputdev = input; return 0; -err_free_keymap: - sparse_keymap_free(input); err_free_dev: input_free_device(input); return error; @@ -1531,10 +1529,8 @@ err_free_dev: static void asus_input_exit(struct asus_laptop *asus) { - if (asus->inputdev) { - sparse_keymap_free(asus->inputdev); + if (asus->inputdev) input_unregister_device(asus->inputdev); - } asus->inputdev = NULL; } From c2ef3a1c97adbe26d1a10d878e353436a3978409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:39 +0100 Subject: [PATCH 016/108] platform/x86: asus-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-wmi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8fe5890bf539..d817e6327fec 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -269,12 +269,10 @@ static int asus_wmi_input_init(struct asus_wmi *asus) err = input_register_device(asus->inputdev); if (err) - goto err_free_keymap; + goto err_free_dev; return 0; -err_free_keymap: - sparse_keymap_free(asus->inputdev); err_free_dev: input_free_device(asus->inputdev); return err; @@ -282,10 +280,8 @@ err_free_dev: static void asus_wmi_input_exit(struct asus_wmi *asus) { - if (asus->inputdev) { - sparse_keymap_free(asus->inputdev); + if (asus->inputdev) input_unregister_device(asus->inputdev); - } asus->inputdev = NULL; } From 469b0170450e7cbb0230b22036622005906b878a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:40 +0100 Subject: [PATCH 017/108] platform/x86: dell-wmi-aio: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-wmi-aio.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c index dbc97a33bbc8..50c2078715d6 100644 --- a/drivers/platform/x86/dell-wmi-aio.c +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -152,12 +152,10 @@ static int __init dell_wmi_aio_input_setup(void) err = input_register_device(dell_wmi_aio_input_dev); if (err) { pr_info("Unable to register input device\n"); - goto err_free_keymap; + goto err_free_dev; } return 0; -err_free_keymap: - sparse_keymap_free(dell_wmi_aio_input_dev); err_free_dev: input_free_device(dell_wmi_aio_input_dev); return err; @@ -192,7 +190,6 @@ static int __init dell_wmi_aio_init(void) err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); if (err) { pr_err("Unable to register notify handler - %d\n", err); - sparse_keymap_free(dell_wmi_aio_input_dev); input_unregister_device(dell_wmi_aio_input_dev); return err; } @@ -206,7 +203,6 @@ static void __exit dell_wmi_aio_exit(void) guid = dell_wmi_aio_find(); wmi_remove_notify_handler(guid); - sparse_keymap_free(dell_wmi_aio_input_dev); input_unregister_device(dell_wmi_aio_input_dev); } From 815edfe7ad887323c6d261dce3a0589d49671d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:41 +0100 Subject: [PATCH 018/108] platform/x86: dell-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). As this reduces dell_wmi_input_destroy() to one line, replace all calls to that function with direct calls to input_unregister_device(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-wmi.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 75e637047d36..d921b26267e9 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -603,23 +603,15 @@ static int __init dell_wmi_input_setup(void) err = input_register_device(dell_wmi_input_dev); if (err) - goto err_free_keymap; + goto err_free_dev; return 0; - err_free_keymap: - sparse_keymap_free(dell_wmi_input_dev); err_free_dev: input_free_device(dell_wmi_input_dev); return err; } -static void dell_wmi_input_destroy(void) -{ - sparse_keymap_free(dell_wmi_input_dev); - input_unregister_device(dell_wmi_input_dev); -} - /* * Descriptor buffer is 128 byte long and contains: * @@ -740,7 +732,7 @@ static int __init dell_wmi_init(void) status = wmi_install_notify_handler(DELL_EVENT_GUID, dell_wmi_notify, NULL); if (ACPI_FAILURE(status)) { - dell_wmi_input_destroy(); + input_unregister_device(dell_wmi_input_dev); pr_err("Unable to register notify handler - %d\n", status); return -ENODEV; } @@ -752,7 +744,7 @@ static int __init dell_wmi_init(void) if (err) { pr_err("Failed to enable WMI events\n"); wmi_remove_notify_handler(DELL_EVENT_GUID); - dell_wmi_input_destroy(); + input_unregister_device(dell_wmi_input_dev); return err; } } @@ -766,6 +758,6 @@ 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(); + input_unregister_device(dell_wmi_input_dev); } module_exit(dell_wmi_exit); From de3c91c1ce073445e9cab5ad43fb038f896919b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:42 +0100 Subject: [PATCH 019/108] platform/x86: eeepc-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/eeepc-laptop.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 8cdf315f9730..6f11c51b7e60 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1205,14 +1205,12 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc) error = input_register_device(input); if (error) { pr_err("Unable to register input device\n"); - goto err_free_keymap; + goto err_free_dev; } eeepc->inputdev = input; return 0; -err_free_keymap: - sparse_keymap_free(input); err_free_dev: input_free_device(input); return error; @@ -1220,10 +1218,8 @@ err_free_dev: static void eeepc_input_exit(struct eeepc_laptop *eeepc) { - if (eeepc->inputdev) { - sparse_keymap_free(eeepc->inputdev); + if (eeepc->inputdev) input_unregister_device(eeepc->inputdev); - } eeepc->inputdev = NULL; } From 3a3c1115ce55f02e6185338808a4b7959b46e334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:43 +0100 Subject: [PATCH 020/108] platform/x86: hp-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 96ffda493266..7abf92d0ba81 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -673,7 +673,7 @@ static int __init hp_wmi_input_setup(void) status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); if (ACPI_FAILURE(status)) { err = -EIO; - goto err_free_keymap; + goto err_free_dev; } err = input_register_device(hp_wmi_input_dev); @@ -684,8 +684,6 @@ static int __init hp_wmi_input_setup(void) err_uninstall_notifier: wmi_remove_notify_handler(HPWMI_EVENT_GUID); - err_free_keymap: - sparse_keymap_free(hp_wmi_input_dev); err_free_dev: input_free_device(hp_wmi_input_dev); return err; @@ -694,7 +692,6 @@ static int __init hp_wmi_input_setup(void) static void hp_wmi_input_destroy(void) { wmi_remove_notify_handler(HPWMI_EVENT_GUID); - sparse_keymap_free(hp_wmi_input_dev); input_unregister_device(hp_wmi_input_dev); } From c973d4b578a46f8fb822bed2d3a0d3a752d02ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:44 +0100 Subject: [PATCH 021/108] platform/x86: ideapad-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index cc6d91e18683..ca5eeb4d417d 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -604,14 +604,12 @@ static int ideapad_input_init(struct ideapad_private *priv) error = input_register_device(inputdev); if (error) { pr_err("Unable to register input device\n"); - goto err_free_keymap; + goto err_free_dev; } priv->inputdev = inputdev; return 0; -err_free_keymap: - sparse_keymap_free(inputdev); err_free_dev: input_free_device(inputdev); return error; @@ -619,7 +617,6 @@ err_free_dev: static void ideapad_input_exit(struct ideapad_private *priv) { - sparse_keymap_free(priv->inputdev); input_unregister_device(priv->inputdev); priv->inputdev = NULL; } From 7cb8aa8cafbe9ebc5ecd7ac6125264c958db48ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:45 +0100 Subject: [PATCH 022/108] platform/x86: msi-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). As this reduces msi_laptop_input_destroy() to one line, replace all calls to that function with direct calls to input_unregister_device(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/msi-laptop.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 42317704629d..9e90827c176a 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -976,23 +976,15 @@ static int __init msi_laptop_input_setup(void) err = input_register_device(msi_laptop_input_dev); if (err) - goto err_free_keymap; + goto err_free_dev; return 0; -err_free_keymap: - sparse_keymap_free(msi_laptop_input_dev); err_free_dev: input_free_device(msi_laptop_input_dev); return err; } -static void msi_laptop_input_destroy(void) -{ - sparse_keymap_free(msi_laptop_input_dev); - input_unregister_device(msi_laptop_input_dev); -} - static int __init load_scm_model_init(struct platform_device *sdev) { u8 data; @@ -1037,7 +1029,7 @@ static int __init load_scm_model_init(struct platform_device *sdev) return 0; fail_filter: - msi_laptop_input_destroy(); + input_unregister_device(msi_laptop_input_dev); fail_input: rfkill_cleanup(); @@ -1158,7 +1150,7 @@ static void __exit msi_cleanup(void) { if (quirks->load_scm_model) { i8042_remove_filter(msi_laptop_i8042_filter); - msi_laptop_input_destroy(); + input_unregister_device(msi_laptop_input_dev); cancel_delayed_work_sync(&msi_rfkill_dwork); cancel_work_sync(&msi_rfkill_work); rfkill_cleanup(); From 0788e3375ae33c5a175ba3d394b995d4fdc823b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:46 +0100 Subject: [PATCH 023/108] platform/x86: msi-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/msi-wmi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 9a32f8627ecc..f6209b739ec0 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -281,14 +281,12 @@ static int __init msi_wmi_input_setup(void) err = input_register_device(msi_wmi_input_dev); if (err) - goto err_free_keymap; + goto err_free_dev; last_pressed = 0; return 0; -err_free_keymap: - sparse_keymap_free(msi_wmi_input_dev); err_free_dev: input_free_device(msi_wmi_input_dev); return err; @@ -342,10 +340,8 @@ err_uninstall_handler: if (event_wmi) wmi_remove_notify_handler(event_wmi->guid); err_free_input: - if (event_wmi) { - sparse_keymap_free(msi_wmi_input_dev); + if (event_wmi) input_unregister_device(msi_wmi_input_dev); - } return err; } @@ -353,7 +349,6 @@ static void __exit msi_wmi_exit(void) { if (event_wmi) { wmi_remove_notify_handler(event_wmi->guid); - sparse_keymap_free(msi_wmi_input_dev); input_unregister_device(msi_wmi_input_dev); } backlight_device_unregister(backlight); From b09b9195b3722928918a5e612f7aec5719a061bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:47 +0100 Subject: [PATCH 024/108] platform/x86: panasonic-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). As this reduces acpi_pcc_destroy_input() to one line, replace all calls to that function with direct calls to input_unregister_device(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/panasonic-laptop.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 59b8eb626dcc..975f4e100dbd 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -520,29 +520,17 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) if (error) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to register input device\n")); - goto err_free_keymap; + goto err_free_dev; } pcc->input_dev = input_dev; return 0; - err_free_keymap: - sparse_keymap_free(input_dev); err_free_dev: input_free_device(input_dev); return error; } -static void acpi_pcc_destroy_input(struct pcc_acpi *pcc) -{ - sparse_keymap_free(pcc->input_dev); - input_unregister_device(pcc->input_dev); - /* - * No need to input_free_device() since core input API refcounts - * and free()s the device. - */ -} - /* kernel module interface */ #ifdef CONFIG_PM_SLEEP @@ -640,7 +628,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) out_backlight: backlight_device_unregister(pcc->backlight); out_input: - acpi_pcc_destroy_input(pcc); + input_unregister_device(pcc->input_dev); out_sinf: kfree(pcc->sinf); out_hotkey: @@ -660,7 +648,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device) backlight_device_unregister(pcc->backlight); - acpi_pcc_destroy_input(pcc); + input_unregister_device(pcc->input_dev); kfree(pcc->sinf); kfree(pcc); From 3f2e1a323a8391a142943ebbc862de5633a381e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:48 +0100 Subject: [PATCH 025/108] platform/x86: topstar-laptop: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/topstar-laptop.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index e597de05e6c2..70205d222da9 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -113,14 +113,12 @@ static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) error = input_register_device(input); if (error) { pr_err("Unable to register input device\n"); - goto err_free_keymap; + goto err_free_dev; } hkey->inputdev = input; return 0; - err_free_keymap: - sparse_keymap_free(input); err_free_dev: input_free_device(input); return error; @@ -157,7 +155,6 @@ static int acpi_topstar_remove(struct acpi_device *device) acpi_topstar_fncx_switch(device, false); - sparse_keymap_free(tps_hkey->inputdev); input_unregister_device(tps_hkey->inputdev); kfree(tps_hkey); From c6d973f474cfdc4d9f0f18b7f539c5cc7847188d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:49 +0100 Subject: [PATCH 026/108] platform/x86: toshiba-wmi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/toshiba-wmi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/toshiba-wmi.c b/drivers/platform/x86/toshiba-wmi.c index 2df07ee8f3c3..440528676170 100644 --- a/drivers/platform/x86/toshiba-wmi.c +++ b/drivers/platform/x86/toshiba-wmi.c @@ -96,7 +96,7 @@ static int __init toshiba_wmi_input_setup(void) toshiba_wmi_notify, NULL); if (ACPI_FAILURE(status)) { err = -EIO; - goto err_free_keymap; + goto err_free_dev; } err = input_register_device(toshiba_wmi_input_dev); @@ -107,8 +107,6 @@ static int __init toshiba_wmi_input_setup(void) err_remove_notifier: wmi_remove_notify_handler(WMI_EVENT_GUID); - err_free_keymap: - sparse_keymap_free(toshiba_wmi_input_dev); err_free_dev: input_free_device(toshiba_wmi_input_dev); return err; @@ -117,7 +115,6 @@ static int __init toshiba_wmi_input_setup(void) static void toshiba_wmi_input_destroy(void) { wmi_remove_notify_handler(WMI_EVENT_GUID); - sparse_keymap_free(toshiba_wmi_input_dev); input_unregister_device(toshiba_wmi_input_dev); } From db8f95d0141926a673484d228cd4040f5b10972f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 13:11:50 +0100 Subject: [PATCH 027/108] platform/x86: toshiba_acpi: remove sparse_keymap_free() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As sparse_keymap_setup() now uses a managed memory allocation for the keymap copy it creates, the latter is freed automatically. Remove all calls to sparse_keymap_free(). Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko --- drivers/platform/x86/toshiba_acpi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 074bf2fa1c55..d0daf75cbed1 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2849,7 +2849,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) error = i8042_install_filter(toshiba_acpi_i8042_filter); if (error) { pr_err("Error installing key filter\n"); - goto err_free_keymap; + goto err_free_dev; } dev->ntfy_supported = 1; @@ -2880,8 +2880,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) err_remove_filter: if (dev->ntfy_supported) i8042_remove_filter(toshiba_acpi_i8042_filter); - err_free_keymap: - sparse_keymap_free(dev->hotkey_dev); err_free_dev: input_free_device(dev->hotkey_dev); dev->hotkey_dev = NULL; @@ -3018,10 +3016,8 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) cancel_work_sync(&dev->hotkey_work); } - if (dev->hotkey_dev) { + if (dev->hotkey_dev) input_unregister_device(dev->hotkey_dev); - sparse_keymap_free(dev->hotkey_dev); - } backlight_device_unregister(dev->backlight_dev); From 1fe55309462cc9b2dcefe6eb91e7adeba5e59e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 9 Mar 2017 10:36:51 +0100 Subject: [PATCH 028/108] platform/x86: intel-hid: do not set parents of input devices explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit devm_input_allocate_device() already causes the supplied struct device to be set as the parent of the input device, so doing it again is redundant. Signed-off-by: Michał Kępień Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Alex Hung --- drivers/platform/x86/intel-hid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index 5eab31659cba..b40059aba856 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -152,7 +152,6 @@ static int intel_hid_input_setup(struct platform_device *device) if (ret) return ret; - priv->input_dev->dev.parent = &device->dev; priv->input_dev->name = "Intel HID events"; priv->input_dev->id.bustype = BUS_HOST; @@ -173,7 +172,6 @@ static int intel_button_array_input_setup(struct platform_device *device) if (ret) return ret; - priv->array->dev.parent = &device->dev; priv->array->name = "Intel HID 5 button array"; priv->array->id.bustype = BUS_HOST; From 999ddbdf3c8354077660efbac9ab91c12187d6d2 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 10 Feb 2017 18:48:37 +0100 Subject: [PATCH 029/108] platform/x86: eeepc-laptop: Skip unknown key messages 0x50 0x51 Otherwise those are printed several times when (un)plugging the AC connector. Signed-off-by: Pau Espin Pedrol Acked-by: Dmitry Torokhov Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/eeepc-laptop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6f11c51b7e60..2426399e1e04 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -150,6 +150,8 @@ static const struct key_entry eeepc_keymap[] = { { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */ { KE_KEY, 0x38, { KEY_F14 } }, + { KE_IGNORE, 0x50, { KEY_RESERVED } }, /* AC plugged */ + { KE_IGNORE, 0x51, { KEY_RESERVED } }, /* AC unplugged */ { KE_END, 0 }, }; From 78b2602fbb0e3fe33599ced64b74b73a681b1e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 14 Mar 2017 11:26:27 +0100 Subject: [PATCH 030/108] platform/x86: fujitsu-laptop: remove backlight-related attributes from the platform device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting backlight level using a vendor-specific interface should only be possible when using the latter is either explicitly requested by the user or automatically selected by the kernel. fujitsu-laptop violates that premise by unconditionally attaching three backlight-related attributes to the platform device it registers. Remove the offending attributes from the platform device. Update module comments to reflect this change. Signed-off-by: Michał Kępień Tested-by: Jonathan Woithe Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 90 +-------------------------- 1 file changed, 3 insertions(+), 87 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 3c795d591de0..9b9348af7626 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -32,18 +32,9 @@ * features made available on a range of Fujitsu laptops including the * P2xxx/P5xxx/S6xxx/S7xxx series. * - * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; - * others may be added at a later date. - * - * lcd_level - Screen brightness: contains a single integer in the - * range 0..7. (rw) - * - * In addition to these platform device attributes the driver - * registers itself in the Linux backlight control subsystem and is - * available to userspace under /sys/class/backlight/fujitsu-laptop/. - * - * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are - * also supported by this driver. + * This driver implements a vendor-specific backlight control interface for + * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu + * laptops. * * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and * P8010. It should work on most P-series and S-series Lifebooks, but @@ -489,74 +480,6 @@ static const struct backlight_ops fujitsu_bl_ops = { .update_status = bl_update_status, }; -/* Platform LCD brightness device */ - -static ssize_t -show_max_brightness(struct device *dev, - struct device_attribute *attr, char *buf) -{ - - int ret; - - ret = get_max_brightness(); - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret); -} - -static ssize_t -show_brightness_changed(struct device *dev, - struct device_attribute *attr, char *buf) -{ - - int ret; - - ret = fujitsu_bl->brightness_changed; - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret); -} - -static ssize_t show_lcd_level(struct device *dev, - struct device_attribute *attr, char *buf) -{ - - int ret; - - ret = get_lcd_level(); - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret); -} - -static ssize_t store_lcd_level(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - - int level, ret; - - if (sscanf(buf, "%i", &level) != 1 - || (level < 0 || level >= fujitsu_bl->max_brightness)) - return -EINVAL; - - if (use_alt_lcd_levels) - ret = set_lcd_level_alt(level); - else - ret = set_lcd_level(level); - if (ret < 0) - return ret; - - ret = get_lcd_level(); - if (ret < 0) - return ret; - - return count; -} - static ssize_t ignore_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -600,18 +523,11 @@ show_radios_state(struct device *dev, return sprintf(buf, "killed\n"); } -static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); -static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, - ignore_store); -static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); static struct attribute *fujitsu_pf_attributes[] = { - &dev_attr_brightness_changed.attr, - &dev_attr_max_brightness.attr, - &dev_attr_lcd_level.attr, &dev_attr_lid.attr, &dev_attr_dock.attr, &dev_attr_radios.attr, From b0c4b9c64e7ca4eaf39996429e98d97725d7098e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 14 Mar 2017 11:26:28 +0100 Subject: [PATCH 031/108] platform/x86: fujitsu-laptop: simplify platform device attribute definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the DEVICE_ATTR_RO() macro to get rid of ignore_store() and shorten attribute definitions. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Tested-by: Jonathan Woithe Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 28 +++++++++------------------ 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 9b9348af7626..9719c821d64f 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -480,16 +480,8 @@ static const struct backlight_ops fujitsu_bl_ops = { .update_status = bl_update_status, }; -static ssize_t -ignore_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - return count; -} - -static ssize_t -show_lid_state(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t lid_show(struct device *dev, struct device_attribute *attr, + char *buf) { if (!(fujitsu_laptop->flags_supported & FLAG_LID)) return sprintf(buf, "unknown\n"); @@ -499,9 +491,8 @@ show_lid_state(struct device *dev, return sprintf(buf, "closed\n"); } -static ssize_t -show_dock_state(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t dock_show(struct device *dev, struct device_attribute *attr, + char *buf) { if (!(fujitsu_laptop->flags_supported & FLAG_DOCK)) return sprintf(buf, "unknown\n"); @@ -511,9 +502,8 @@ show_dock_state(struct device *dev, return sprintf(buf, "undocked\n"); } -static ssize_t -show_radios_state(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t radios_show(struct device *dev, struct device_attribute *attr, + char *buf) { if (!(fujitsu_laptop->flags_supported & FLAG_RFKILL)) return sprintf(buf, "unknown\n"); @@ -523,9 +513,9 @@ show_radios_state(struct device *dev, return sprintf(buf, "killed\n"); } -static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); -static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); -static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); +static DEVICE_ATTR_RO(lid); +static DEVICE_ATTR_RO(dock); +static DEVICE_ATTR_RO(radios); static struct attribute *fujitsu_pf_attributes[] = { &dev_attr_lid.attr, From d811b511c18d9349a3880a4a7fff4c9c1169ac03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 14 Mar 2017 11:26:29 +0100 Subject: [PATCH 032/108] platform/x86: fujitsu-laptop: add and remove platform device in separate functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Platform device handling adds a lot of complexity to fujitsu_init(), which hinders its readability. Extract code responsible for adding and removing the platform device to separate functions. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Tested-by: Jonathan Woithe Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 66 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 9719c821d64f..421402a19bb9 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -765,6 +765,40 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) /* ACPI device for hotkey handling */ +static int fujitsu_laptop_platform_add(void) +{ + int ret; + + fujitsu_bl->pf_device = platform_device_alloc("fujitsu-laptop", -1); + if (!fujitsu_bl->pf_device) + return -ENOMEM; + + ret = platform_device_add(fujitsu_bl->pf_device); + if (ret) + goto err_put_platform_device; + + ret = sysfs_create_group(&fujitsu_bl->pf_device->dev.kobj, + &fujitsu_pf_attribute_group); + if (ret) + goto err_del_platform_device; + + return 0; + +err_del_platform_device: + platform_device_del(fujitsu_bl->pf_device); +err_put_platform_device: + platform_device_put(fujitsu_bl->pf_device); + + return ret; +} + +static void fujitsu_laptop_platform_remove(void) +{ + sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, + &fujitsu_pf_attribute_group); + platform_device_unregister(fujitsu_bl->pf_device); +} + static int acpi_fujitsu_laptop_add(struct acpi_device *device) { int result = 0; @@ -1146,25 +1180,13 @@ static int __init fujitsu_init(void) /* Register platform stuff */ - fujitsu_bl->pf_device = platform_device_alloc("fujitsu-laptop", -1); - if (!fujitsu_bl->pf_device) { - ret = -ENOMEM; + ret = fujitsu_laptop_platform_add(); + if (ret) goto err_unregister_acpi; - } - - ret = platform_device_add(fujitsu_bl->pf_device); - if (ret) - goto err_put_platform_device; - - ret = - sysfs_create_group(&fujitsu_bl->pf_device->dev.kobj, - &fujitsu_pf_attribute_group); - if (ret) - goto err_del_platform_device; ret = platform_driver_register(&fujitsu_pf_driver); if (ret) - goto err_remove_sysfs_group; + goto err_remove_platform_device; /* Register laptop driver */ @@ -1186,13 +1208,8 @@ err_free_fujitsu_laptop: kfree(fujitsu_laptop); err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); -err_remove_sysfs_group: - sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, - &fujitsu_pf_attribute_group); -err_del_platform_device: - platform_device_del(fujitsu_bl->pf_device); -err_put_platform_device: - platform_device_put(fujitsu_bl->pf_device); +err_remove_platform_device: + fujitsu_laptop_platform_remove(); err_unregister_acpi: acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); err_free_fujitsu_bl: @@ -1209,10 +1226,7 @@ static void __exit fujitsu_cleanup(void) platform_driver_unregister(&fujitsu_pf_driver); - sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, - &fujitsu_pf_attribute_group); - - platform_device_unregister(fujitsu_bl->pf_device); + fujitsu_laptop_platform_remove(); acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); From c33f4c044d2bb99bb42e1315ede267843dd81d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 14 Mar 2017 11:26:30 +0100 Subject: [PATCH 033/108] platform/x86: fujitsu-laptop: only register platform device if FUJ02E3 is present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform device registered by fujitsu-laptop is registered unconditionally while sysfs attributes attached to it depend on the FUJ02E3 ACPI device being present. Fix this by moving platform device creation and removal to acpi_fujitsu_laptop_add() and acpi_fujitsu_laptop_remove(), respectively. Signed-off-by: Michał Kępień Tested-by: Jonathan Woithe Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 421402a19bb9..a2641cb79df9 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -903,6 +903,10 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; } + error = fujitsu_laptop_platform_add(); + if (error) + goto err_unregister_input_dev; + #if IS_ENABLED(CONFIG_LEDS_CLASS) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = led_classdev_register(&fujitsu_bl->pf_device->dev, @@ -994,6 +998,8 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) led_classdev_unregister(&eco_led); #endif + fujitsu_laptop_platform_remove(); + input_unregister_device(input); kfifo_free(&fujitsu_laptop->fifo); @@ -1180,13 +1186,9 @@ static int __init fujitsu_init(void) /* Register platform stuff */ - ret = fujitsu_laptop_platform_add(); - if (ret) - goto err_unregister_acpi; - ret = platform_driver_register(&fujitsu_pf_driver); if (ret) - goto err_remove_platform_device; + goto err_unregister_acpi; /* Register laptop driver */ @@ -1208,8 +1210,6 @@ err_free_fujitsu_laptop: kfree(fujitsu_laptop); err_unregister_platform_driver: platform_driver_unregister(&fujitsu_pf_driver); -err_remove_platform_device: - fujitsu_laptop_platform_remove(); err_unregister_acpi: acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); err_free_fujitsu_bl: @@ -1226,8 +1226,6 @@ static void __exit fujitsu_cleanup(void) platform_driver_unregister(&fujitsu_pf_driver); - fujitsu_laptop_platform_remove(); - acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); kfree(fujitsu_bl); From 979800e73d2fcda96cda5076f3425f823fdda0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Tue, 14 Mar 2017 11:26:31 +0100 Subject: [PATCH 034/108] platform/x86: fujitsu-laptop: remove pf_device field from struct fujitsu_bl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both struct fujitsu_bl and struct fujitsu_laptop have a pf_device field. Up until now the latter has been redundant, which is logically incorrect because the primary function of the platform device created by fujitsu-laptop is to provide laptop-related (not brightness-related) attributes to userspace. Remove the pf_device field from struct fujitsu_bl and make all module code use the pf_device field of struct fujitsu_laptop instead. Suggested-by: Alan Jenkins Signed-off-by: Michał Kępień Tested-by: Jonathan Woithe Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index a2641cb79df9..f3ccef3d5a1e 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -138,7 +138,6 @@ struct fujitsu_bl { struct input_dev *input; char phys[32]; struct backlight_device *bl_device; - struct platform_device *pf_device; int keycode1, keycode2, keycode3, keycode4, keycode5; unsigned int max_brightness; @@ -769,15 +768,15 @@ static int fujitsu_laptop_platform_add(void) { int ret; - fujitsu_bl->pf_device = platform_device_alloc("fujitsu-laptop", -1); - if (!fujitsu_bl->pf_device) + fujitsu_laptop->pf_device = platform_device_alloc("fujitsu-laptop", -1); + if (!fujitsu_laptop->pf_device) return -ENOMEM; - ret = platform_device_add(fujitsu_bl->pf_device); + ret = platform_device_add(fujitsu_laptop->pf_device); if (ret) goto err_put_platform_device; - ret = sysfs_create_group(&fujitsu_bl->pf_device->dev.kobj, + ret = sysfs_create_group(&fujitsu_laptop->pf_device->dev.kobj, &fujitsu_pf_attribute_group); if (ret) goto err_del_platform_device; @@ -785,18 +784,18 @@ static int fujitsu_laptop_platform_add(void) return 0; err_del_platform_device: - platform_device_del(fujitsu_bl->pf_device); + platform_device_del(fujitsu_laptop->pf_device); err_put_platform_device: - platform_device_put(fujitsu_bl->pf_device); + platform_device_put(fujitsu_laptop->pf_device); return ret; } static void fujitsu_laptop_platform_remove(void) { - sysfs_remove_group(&fujitsu_bl->pf_device->dev.kobj, + sysfs_remove_group(&fujitsu_laptop->pf_device->dev.kobj, &fujitsu_pf_attribute_group); - platform_device_unregister(fujitsu_bl->pf_device); + platform_device_unregister(fujitsu_laptop->pf_device); } static int acpi_fujitsu_laptop_add(struct acpi_device *device) @@ -909,7 +908,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) #if IS_ENABLED(CONFIG_LEDS_CLASS) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { - result = led_classdev_register(&fujitsu_bl->pf_device->dev, + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, &logolamp_led); if (result == 0) { fujitsu_laptop->logolamp_registered = 1; @@ -921,7 +920,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { - result = led_classdev_register(&fujitsu_bl->pf_device->dev, + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, &kblamps_led); if (result == 0) { fujitsu_laptop->kblamps_registered = 1; @@ -938,7 +937,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) * that an RF LED is present. */ if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { - result = led_classdev_register(&fujitsu_bl->pf_device->dev, + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, &radio_led); if (result == 0) { fujitsu_laptop->radio_led_registered = 1; @@ -955,7 +954,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) */ if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { - result = led_classdev_register(&fujitsu_bl->pf_device->dev, + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, &eco_led); if (result == 0) { fujitsu_laptop->eco_led_registered = 1; From 504b02593fc5c24575d7d50d1b388b5ecf9354ee Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Mar 2017 11:55:32 +0100 Subject: [PATCH 035/108] platform/x86: dell-*: Add a generic dell-laptop notifier chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are several cases where events handled in one of the dell-* drivers need to be propagated to another dell-* driver. This commit adds 3 generic functions: dell_laptop_register_notifier() dell_laptop_unregister_notifier() dell_laptop_call_notifier() It currently only defines 1 action: DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED Which is intended to propagate kbd_backlight_brightness_changed wmi events from dell-wmi to dell-laptop (which contains the actual kbd backlight driver). These functions are put in dell-smbios as both dell-wmi and dell-laptop use smbios functions and I do not want to put the notifier head in either driver, as that will make the 2 drivers depend on each other. Signed-off-by: Hans de Goede Acked-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-smbios.c | 20 ++++++++++++++++++++ drivers/platform/x86/dell-smbios.h | 11 +++++++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c index d2412ab097da..0a5723468bff 100644 --- a/drivers/platform/x86/dell-smbios.c +++ b/drivers/platform/x86/dell-smbios.c @@ -105,6 +105,26 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid) } EXPORT_SYMBOL_GPL(dell_smbios_find_token); +static BLOCKING_NOTIFIER_HEAD(dell_laptop_chain_head); + +int dell_laptop_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&dell_laptop_chain_head, nb); +} +EXPORT_SYMBOL_GPL(dell_laptop_register_notifier); + +int dell_laptop_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&dell_laptop_chain_head, nb); +} +EXPORT_SYMBOL_GPL(dell_laptop_unregister_notifier); + +void dell_laptop_call_notifier(unsigned long action, void *data) +{ + blocking_notifier_call_chain(&dell_laptop_chain_head, action, data); +} +EXPORT_SYMBOL_GPL(dell_laptop_call_notifier); + 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 ec7d40ae5e6e..45cbc2292cd3 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -16,6 +16,8 @@ #ifndef _DELL_SMBIOS_H_ #define _DELL_SMBIOS_H_ +struct notifier_block; + /* This structure will be modified by the firmware when we enter * system management mode, hence the volatiles */ @@ -43,4 +45,13 @@ 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); + +enum dell_laptop_notifier_actions { + DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, +}; + +int dell_laptop_register_notifier(struct notifier_block *nb); +int dell_laptop_unregister_notifier(struct notifier_block *nb); +void dell_laptop_call_notifier(unsigned long action, void *data); + #endif From 1c7e28246e986a789a55f52ff681bf8d5d1dcada Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Mar 2017 11:55:33 +0100 Subject: [PATCH 036/108] platform/x86: dell-laptop: Refactor kbd_led_triggers_store() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return -EINVAL immediately on invalid input, rather then doing the straight path in an if block and returning -EINVAL at the end of the function. Signed-off-by: Hans de Goede Reviewed-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 63 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index f57dd282a002..4de7aa04653f 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1666,38 +1666,39 @@ static ssize_t kbd_led_triggers_store(struct device *dev, } } - if (trigger_bit != -1) { - new_state = state; - if (trigger[0] == '+') - new_state.triggers |= BIT(trigger_bit); - else { - new_state.triggers &= ~BIT(trigger_bit); - /* NOTE: trackstick bit (2) must be disabled when - * disabling touchpad bit (1), otherwise touchpad - * bit (1) will not be disabled */ - if (trigger_bit == 1) - new_state.triggers &= ~BIT(2); - } - if ((kbd_info.triggers & new_state.triggers) != - new_state.triggers) - return -EINVAL; - if (new_state.triggers && !triggers_enabled) { - new_state.mode_bit = KBD_MODE_BIT_TRIGGER; - kbd_set_level(&new_state, kbd_previous_level); - } else if (new_state.triggers == 0) { - kbd_set_level(&new_state, 0); - } - if (!(kbd_info.modes & BIT(new_state.mode_bit))) - return -EINVAL; - ret = kbd_set_state_safe(&new_state, &state); - if (ret) - return ret; - if (new_state.mode_bit != KBD_MODE_BIT_OFF) - kbd_previous_mode_bit = new_state.mode_bit; - return count; - } + if (trigger_bit == -1) + return -EINVAL; - return -EINVAL; + new_state = state; + if (trigger[0] == '+') + new_state.triggers |= BIT(trigger_bit); + else { + new_state.triggers &= ~BIT(trigger_bit); + /* + * NOTE: trackstick bit (2) must be disabled when + * disabling touchpad bit (1), otherwise touchpad + * bit (1) will not be disabled + */ + if (trigger_bit == 1) + new_state.triggers &= ~BIT(2); + } + if ((kbd_info.triggers & new_state.triggers) != + new_state.triggers) + return -EINVAL; + if (new_state.triggers && !triggers_enabled) { + new_state.mode_bit = KBD_MODE_BIT_TRIGGER; + kbd_set_level(&new_state, kbd_previous_level); + } else if (new_state.triggers == 0) { + kbd_set_level(&new_state, 0); + } + if (!(kbd_info.modes & BIT(new_state.mode_bit))) + return -EINVAL; + ret = kbd_set_state_safe(&new_state, &state); + if (ret) + return ret; + if (new_state.mode_bit != KBD_MODE_BIT_OFF) + kbd_previous_mode_bit = new_state.mode_bit; + return count; } static ssize_t kbd_led_triggers_show(struct device *dev, From e5bf5df7858e2339d277427129139995628c49a7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Mar 2017 11:55:34 +0100 Subject: [PATCH 037/108] platform/x86: dell-laptop: Protect kbd_state against races MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The kbd led code has multiple entry points each of which modifies the kbd_state by reading it, modifying a copy, writing the copy and on error setting the modified copy writing back the original state. This is racy, so add a mutex protection the read-modify-write cycle on each of the entry points. Signed-off-by: Hans de Goede Reviewed-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 112 +++++++++++++++++++---------- 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 4de7aa04653f..da185fb2a621 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1139,6 +1139,7 @@ static u8 kbd_previous_level; static u8 kbd_previous_mode_bit; static bool kbd_led_present; +static DEFINE_MUTEX(kbd_led_mutex); /* * NOTE: there are three ways to set the keyboard backlight level. @@ -1568,9 +1569,11 @@ static ssize_t kbd_led_timeout_store(struct device *dev, } } + mutex_lock(&kbd_led_mutex); + ret = kbd_get_state(&state); if (ret) - return ret; + goto out; new_state = state; new_state.timeout_value = value; @@ -1578,9 +1581,12 @@ static ssize_t kbd_led_timeout_store(struct device *dev, ret = kbd_set_state_safe(&new_state, &state); if (ret) - return ret; + goto out; - return count; + ret = count; +out: + mutex_unlock(&kbd_led_mutex); + return ret; } static ssize_t kbd_led_timeout_show(struct device *dev, @@ -1640,9 +1646,11 @@ static ssize_t kbd_led_triggers_store(struct device *dev, if (trigger[0] != '+' && trigger[0] != '-') return -EINVAL; + mutex_lock(&kbd_led_mutex); + ret = kbd_get_state(&state); if (ret) - return ret; + goto out; if (kbd_triggers_supported) triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit); @@ -1656,18 +1664,24 @@ static ssize_t kbd_led_triggers_store(struct device *dev, if (strcmp(trigger+1, kbd_led_triggers[i]) != 0) continue; if (trigger[0] == '+' && - triggers_enabled && (state.triggers & BIT(i))) - return count; + triggers_enabled && (state.triggers & BIT(i))) { + ret = count; + goto out; + } if (trigger[0] == '-' && - (!triggers_enabled || !(state.triggers & BIT(i)))) - return count; + (!triggers_enabled || !(state.triggers & BIT(i)))) { + ret = count; + goto out; + } trigger_bit = i; break; } } - if (trigger_bit == -1) - return -EINVAL; + if (trigger_bit == -1) { + ret = -EINVAL; + goto out; + } new_state = state; if (trigger[0] == '+') @@ -1683,22 +1697,29 @@ static ssize_t kbd_led_triggers_store(struct device *dev, new_state.triggers &= ~BIT(2); } if ((kbd_info.triggers & new_state.triggers) != - new_state.triggers) - return -EINVAL; + new_state.triggers) { + ret = -EINVAL; + goto out; + } if (new_state.triggers && !triggers_enabled) { new_state.mode_bit = KBD_MODE_BIT_TRIGGER; kbd_set_level(&new_state, kbd_previous_level); } else if (new_state.triggers == 0) { kbd_set_level(&new_state, 0); } - if (!(kbd_info.modes & BIT(new_state.mode_bit))) - return -EINVAL; + if (!(kbd_info.modes & BIT(new_state.mode_bit))) { + ret = -EINVAL; + goto out; + } ret = kbd_set_state_safe(&new_state, &state); if (ret) - return ret; + goto out; if (new_state.mode_bit != KBD_MODE_BIT_OFF) kbd_previous_mode_bit = new_state.mode_bit; - return count; + ret = count; +out: + mutex_unlock(&kbd_led_mutex); + return ret; } static ssize_t kbd_led_triggers_show(struct device *dev, @@ -1755,12 +1776,16 @@ static ssize_t kbd_led_als_enabled_store(struct device *dev, if (ret) return ret; + mutex_lock(&kbd_led_mutex); + ret = kbd_get_state(&state); if (ret) - return ret; + goto out; - if (enable == kbd_is_als_mode_bit(state.mode_bit)) - return count; + if (enable == kbd_is_als_mode_bit(state.mode_bit)) { + ret = count; + goto out; + } new_state = state; @@ -1780,15 +1805,20 @@ static ssize_t kbd_led_als_enabled_store(struct device *dev, new_state.mode_bit = KBD_MODE_BIT_ON; } } - if (!(kbd_info.modes & BIT(new_state.mode_bit))) - return -EINVAL; + if (!(kbd_info.modes & BIT(new_state.mode_bit))) { + ret = -EINVAL; + goto out; + } ret = kbd_set_state_safe(&new_state, &state); if (ret) - return ret; + goto out; kbd_previous_mode_bit = new_state.mode_bit; - return count; + ret = count; +out: + mutex_unlock(&kbd_led_mutex); + return ret; } static ssize_t kbd_led_als_enabled_show(struct device *dev, @@ -1823,18 +1853,23 @@ static ssize_t kbd_led_als_setting_store(struct device *dev, if (ret) return ret; + mutex_lock(&kbd_led_mutex); + ret = kbd_get_state(&state); if (ret) - return ret; + goto out; new_state = state; new_state.als_setting = setting; ret = kbd_set_state_safe(&new_state, &state); if (ret) - return ret; + goto out; - return count; + ret = count; +out: + mutex_unlock(&kbd_led_mutex); + return ret; } static ssize_t kbd_led_als_setting_show(struct device *dev, @@ -1919,27 +1954,32 @@ static int kbd_led_level_set(struct led_classdev *led_cdev, u16 num; int ret; + mutex_lock(&kbd_led_mutex); + if (kbd_get_max_level()) { ret = kbd_get_state(&state); if (ret) - return ret; + goto out; new_state = state; ret = kbd_set_level(&new_state, value); if (ret) - return ret; - return kbd_set_state_safe(&new_state, &state); - } - - if (kbd_get_valid_token_counts()) { + goto out; + ret = kbd_set_state_safe(&new_state, &state); + } else if (kbd_get_valid_token_counts()) { for (num = kbd_token_bits; num != 0 && value > 0; --value) num &= num - 1; /* clear the first bit set */ if (num == 0) - return 0; - return kbd_set_token_bit(ffs(num) - 1); + ret = 0; + else + ret = kbd_set_token_bit(ffs(num) - 1); + } else { + pr_warn("Keyboard brightness level control not supported\n"); + ret = -ENXIO; } - pr_warn("Keyboard brightness level control not supported\n"); - return -ENXIO; +out: + mutex_unlock(&kbd_led_mutex); + return ret; } static struct led_classdev kbd_led = { From 9c656b07997f518ab407dd990aaf55f358337bd6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Mar 2017 11:55:35 +0100 Subject: [PATCH 038/108] platform/x86: dell-*: Call new led hw_changed API on kbd brightness change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make dell-wmi notify on hotkey kbd brightness changes, listen for this in dell-laptop and call led_classdev_notify_brightness_hw_changed. This will allow userspace to monitor (poll) for brightness changes on these LEDs caused by the hotkey. Signed-off-by: Hans de Goede Acked-by: Pali Rohár Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/dell-laptop.c | 32 +++++++++++++++++++++++++++++- drivers/platform/x86/dell-wmi.c | 4 ++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index da185fb2a621..1cd258b790e8 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1984,6 +1984,7 @@ out: static struct led_classdev kbd_led = { .name = "dell::kbd_backlight", + .flags = LED_BRIGHT_HW_CHANGED, .brightness_set_blocking = kbd_led_level_set, .brightness_get = kbd_led_level_get, .groups = kbd_led_groups, @@ -1991,6 +1992,8 @@ static struct led_classdev kbd_led = { static int __init kbd_led_init(struct device *dev) { + int ret; + kbd_init(); if (!kbd_led_present) return -ENODEV; @@ -2002,7 +2005,11 @@ static int __init kbd_led_init(struct device *dev) if (kbd_led.max_brightness) kbd_led.max_brightness--; } - return led_classdev_register(dev, &kbd_led); + ret = led_classdev_register(dev, &kbd_led); + if (ret) + kbd_led_present = false; + + return ret; } static void brightness_set_exit(struct led_classdev *led_cdev, @@ -2019,6 +2026,26 @@ static void kbd_led_exit(void) led_classdev_unregister(&kbd_led); } +static int dell_laptop_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + switch (action) { + case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED: + if (!kbd_led_present) + break; + + led_classdev_notify_brightness_hw_changed(&kbd_led, + kbd_led_level_get(&kbd_led)); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block dell_laptop_notifier = { + .notifier_call = dell_laptop_notifier_call, +}; + static int __init dell_init(void) { struct calling_interface_buffer *buffer; @@ -2062,6 +2089,8 @@ static int __init dell_init(void) debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, &dell_debugfs_fops); + dell_laptop_register_notifier(&dell_laptop_notifier); + if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return 0; @@ -2113,6 +2142,7 @@ fail_platform_driver: static void __exit dell_exit(void) { + dell_laptop_unregister_notifier(&dell_laptop_notifier); debugfs_remove_recursive(dell_laptop_dir); if (quirks && quirks->touchpad_led) touchpad_led_exit(); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index d921b26267e9..8a64c7967753 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -329,6 +329,10 @@ static void dell_wmi_process_key(int type, int code) if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request) return; + if (key->keycode == KEY_KBDILLUMTOGGLE) + dell_laptop_call_notifier( + DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL); + sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); } From ae3111585e750403003e876eecd88d5db882940f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 22 Mar 2017 16:55:53 +0100 Subject: [PATCH 039/108] platform/x86: silead_dmi: Constify properties arrays Now that device_add_properties takes a const property_entry * rather then a non-const one we can constify the properties arrays. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 02e11fdbf375..c3909d248568 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -22,10 +22,10 @@ struct silead_ts_dmi_data { const char *acpi_name; - struct property_entry *properties; + const struct property_entry *properties; }; -static struct property_entry cube_iwork8_air_props[] = { +static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), PROPERTY_ENTRY_U32("touchscreen-size-y", 900), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), @@ -39,7 +39,7 @@ static const struct silead_ts_dmi_data cube_iwork8_air_data = { .properties = cube_iwork8_air_props, }; -static struct property_entry jumper_ezpad_mini3_props[] = { +static const struct property_entry jumper_ezpad_mini3_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), From 6b8e7d8f6881109dedfcf721d72f6bc822f4c580 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 22 Mar 2017 16:55:54 +0100 Subject: [PATCH 040/108] platform/x86: silead_dmi: Add entry for Insyde 7W tablets Add an entry providing the necessary info to make the touchscreen work on various tablets based on the Insyde 7W whitebox tablet. This has been tested on a DEXP Ursus 7W tablet. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index c3909d248568..26b388db565a 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -53,6 +53,19 @@ static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { .properties = jumper_ezpad_mini3_props, }; +static const struct property_entry dexp_ursus_7w_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 890), + PROPERTY_ENTRY_U32("touchscreen-size-y", 630), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data dexp_ursus_7w_data = { + .acpi_name = "MSSL1680:00", + .properties = dexp_ursus_7w_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -72,6 +85,14 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), }, }, + { + /* DEXP Ursus 7W */ + .driver_data = (void *)&dexp_ursus_7w_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "7W"), + }, + }, { }, }; From 7d134e43a2ac729888bb752f8dba5f8bbb5c938a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:17 +0100 Subject: [PATCH 041/108] platform/x86: fujitsu-laptop: refactor backlight input device setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify error handling in acpi_fujitsu_bl_add() by moving code responsible for setting up the input device to a separate function. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 64 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f3ccef3d5a1e..2b0dcf989e2a 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -590,6 +590,41 @@ static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { /* ACPI device for LCD brightness control */ +static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) +{ + struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); + struct input_dev *input; + int error; + + fujitsu_bl->input = input = input_allocate_device(); + if (!input) + return -ENOMEM; + + snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys), + "%s/video/input0", acpi_device_hid(device)); + + input->name = acpi_device_name(device); + input->phys = fujitsu_bl->phys; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->dev.parent = &device->dev; + input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_BRIGHTNESSUP, input->keybit); + set_bit(KEY_BRIGHTNESSDOWN, input->keybit); + set_bit(KEY_UNKNOWN, input->keybit); + + error = input_register_device(input); + if (error) + goto err_free_input_dev; + + return 0; + +err_free_input_dev: + input_free_device(input); + + return error; +} + static int fujitsu_backlight_register(void) { struct backlight_properties props = { @@ -612,7 +647,6 @@ static int fujitsu_backlight_register(void) static int acpi_fujitsu_bl_add(struct acpi_device *device) { int state = 0; - struct input_dev *input; int error; if (!device) @@ -623,28 +657,9 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); device->driver_data = fujitsu_bl; - fujitsu_bl->input = input = input_allocate_device(); - if (!input) { - error = -ENOMEM; - goto err_stop; - } - - snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys), - "%s/video/input0", acpi_device_hid(device)); - - input->name = acpi_device_name(device); - input->phys = fujitsu_bl->phys; - input->id.bustype = BUS_HOST; - input->id.product = 0x06; - input->dev.parent = &device->dev; - input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_BRIGHTNESSUP, input->keybit); - set_bit(KEY_BRIGHTNESSDOWN, input->keybit); - set_bit(KEY_UNKNOWN, input->keybit); - - error = input_register_device(input); + error = acpi_fujitsu_bl_input_setup(device); if (error) - goto err_free_input_dev; + goto err_stop; error = acpi_bus_update_power(fujitsu_bl->acpi_handle, &state); if (error) { @@ -695,10 +710,7 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) return 0; err_unregister_input_dev: - input_unregister_device(input); - input = NULL; -err_free_input_dev: - input_free_device(input); + input_unregister_device(fujitsu_bl->input); err_stop: return error; } From f8a399dcfae913e773cbef6a940755953cdd70a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:18 +0100 Subject: [PATCH 042/108] platform/x86: fujitsu-laptop: switch to a managed backlight input device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a managed input device for brightness events in order to simplify two error paths and one cleanup function while also reducing the number of local variables required. Remove double assignment to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 47 ++++++++------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 2b0dcf989e2a..68e338c6a876 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -593,36 +593,24 @@ static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) { struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); - struct input_dev *input; - int error; - fujitsu_bl->input = input = input_allocate_device(); - if (!input) + fujitsu_bl->input = devm_input_allocate_device(&device->dev); + if (!fujitsu_bl->input) return -ENOMEM; snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys), "%s/video/input0", acpi_device_hid(device)); - input->name = acpi_device_name(device); - input->phys = fujitsu_bl->phys; - input->id.bustype = BUS_HOST; - input->id.product = 0x06; - input->dev.parent = &device->dev; - input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_BRIGHTNESSUP, input->keybit); - set_bit(KEY_BRIGHTNESSDOWN, input->keybit); - set_bit(KEY_UNKNOWN, input->keybit); + fujitsu_bl->input->name = acpi_device_name(device); + fujitsu_bl->input->phys = fujitsu_bl->phys; + fujitsu_bl->input->id.bustype = BUS_HOST; + fujitsu_bl->input->id.product = 0x06; + fujitsu_bl->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_BRIGHTNESSUP, fujitsu_bl->input->keybit); + set_bit(KEY_BRIGHTNESSDOWN, fujitsu_bl->input->keybit); + set_bit(KEY_UNKNOWN, fujitsu_bl->input->keybit); - error = input_register_device(input); - if (error) - goto err_free_input_dev; - - return 0; - -err_free_input_dev: - input_free_device(input); - - return error; + return input_register_device(fujitsu_bl->input); } static int fujitsu_backlight_register(void) @@ -659,12 +647,12 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) error = acpi_fujitsu_bl_input_setup(device); if (error) - goto err_stop; + return error; error = acpi_bus_update_power(fujitsu_bl->acpi_handle, &state); if (error) { pr_err("Error reading power state\n"); - goto err_unregister_input_dev; + return error; } pr_info("ACPI: %s [%s] (%s)\n", @@ -704,24 +692,17 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { error = fujitsu_backlight_register(); if (error) - goto err_unregister_input_dev; + return error; } return 0; - -err_unregister_input_dev: - input_unregister_device(fujitsu_bl->input); -err_stop: - return error; } static int acpi_fujitsu_bl_remove(struct acpi_device *device) { struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); - struct input_dev *input = fujitsu_bl->input; backlight_device_unregister(fujitsu_bl->bl_device); - input_unregister_device(input); fujitsu_bl->acpi_handle = NULL; From f22526723775f4de1b37335a63b80fb2b00ba4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:19 +0100 Subject: [PATCH 043/108] platform/x86: fujitsu-laptop: use a sparse keymap for brightness key events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify brightness key event generation by using a sparse keymap. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/fujitsu-laptop.c | 31 +++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e1bffc9bb194..5602bdfcad65 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -183,6 +183,7 @@ config FUJITSU_LAPTOP depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on LEDS_CLASS || LEDS_CLASS=n + select INPUT_SPARSEKMAP ---help--- This is a driver for laptops built by Fujitsu: diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 68e338c6a876..3483ac37bee5 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -590,9 +591,16 @@ static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { /* ACPI device for LCD brightness control */ +static const struct key_entry keymap_backlight[] = { + { KE_KEY, true, { KEY_BRIGHTNESSUP } }, + { KE_KEY, false, { KEY_BRIGHTNESSDOWN } }, + { KE_END, 0 } +}; + static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) { struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); + int ret; fujitsu_bl->input = devm_input_allocate_device(&device->dev); if (!fujitsu_bl->input) @@ -605,10 +613,10 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) fujitsu_bl->input->phys = fujitsu_bl->phys; fujitsu_bl->input->id.bustype = BUS_HOST; fujitsu_bl->input->id.product = 0x06; - fujitsu_bl->input->evbit[0] = BIT(EV_KEY); - set_bit(KEY_BRIGHTNESSUP, fujitsu_bl->input->keybit); - set_bit(KEY_BRIGHTNESSDOWN, fujitsu_bl->input->keybit); - set_bit(KEY_UNKNOWN, fujitsu_bl->input->keybit); + + ret = sparse_keymap_setup(fujitsu_bl->input, keymap_backlight, NULL); + if (ret) + return ret; return input_register_device(fujitsu_bl->input); } @@ -714,18 +722,14 @@ static int acpi_fujitsu_bl_remove(struct acpi_device *device) static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) { struct input_dev *input; - int oldb, newb, keycode; + int oldb, newb; input = fujitsu_bl->input; if (event != ACPI_FUJITSU_NOTIFY_CODE1) { - keycode = KEY_UNKNOWN; vdbg_printk(FUJLAPTOP_DBG_WARN, "unsupported event [0x%x]\n", event); - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); + sparse_keymap_report_event(input, -1, 1, true); return; } @@ -747,12 +751,7 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) set_lcd_level(newb); } - keycode = oldb < newb ? KEY_BRIGHTNESSUP : KEY_BRIGHTNESSDOWN; - - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); + sparse_keymap_report_event(input, oldb < newb, 1, true); } /* ACPI device for hotkey handling */ From 11182dbca5cd5270efac5af610c9f483cbc233da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:20 +0100 Subject: [PATCH 044/108] platform/x86: fujitsu-laptop: refactor hotkey input device setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify error handling in acpi_fujitsu_laptop_add() by moving code responsible for setting up the input device to a separate function. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 74 ++++++++++++++++----------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 3483ac37bee5..b1a08d83330b 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -756,6 +756,46 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) /* ACPI device for hotkey handling */ +static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) +{ + struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); + struct input_dev *input; + int error; + + fujitsu_laptop->input = input = input_allocate_device(); + if (!input) + return -ENOMEM; + + snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys), + "%s/video/input0", acpi_device_hid(device)); + + input->name = acpi_device_name(device); + input->phys = fujitsu_laptop->phys; + input->id.bustype = BUS_HOST; + input->id.product = 0x06; + input->dev.parent = &device->dev; + + set_bit(EV_KEY, input->evbit); + set_bit(fujitsu_bl->keycode1, input->keybit); + set_bit(fujitsu_bl->keycode2, input->keybit); + set_bit(fujitsu_bl->keycode3, input->keybit); + set_bit(fujitsu_bl->keycode4, input->keybit); + set_bit(fujitsu_bl->keycode5, input->keybit); + set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit); + set_bit(KEY_UNKNOWN, input->keybit); + + error = input_register_device(input); + if (error) + goto err_free_input_dev; + + return 0; + +err_free_input_dev: + input_free_device(input); + + return error; +} + static int fujitsu_laptop_platform_add(void) { int ret; @@ -794,7 +834,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) { int result = 0; int state = 0; - struct input_dev *input; int error; int i; @@ -816,33 +855,9 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) goto err_stop; } - fujitsu_laptop->input = input = input_allocate_device(); - if (!input) { - error = -ENOMEM; - goto err_free_fifo; - } - - snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys), - "%s/video/input0", acpi_device_hid(device)); - - input->name = acpi_device_name(device); - input->phys = fujitsu_laptop->phys; - input->id.bustype = BUS_HOST; - input->id.product = 0x06; - input->dev.parent = &device->dev; - - set_bit(EV_KEY, input->evbit); - set_bit(fujitsu_bl->keycode1, input->keybit); - set_bit(fujitsu_bl->keycode2, input->keybit); - set_bit(fujitsu_bl->keycode3, input->keybit); - set_bit(fujitsu_bl->keycode4, input->keybit); - set_bit(fujitsu_bl->keycode5, input->keybit); - set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit); - set_bit(KEY_UNKNOWN, input->keybit); - - error = input_register_device(input); + error = acpi_fujitsu_laptop_input_setup(device); if (error) - goto err_free_input_dev; + goto err_free_fifo; error = acpi_bus_update_power(fujitsu_laptop->acpi_handle, &state); if (error) { @@ -960,10 +975,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) return result; err_unregister_input_dev: - input_unregister_device(input); - input = NULL; -err_free_input_dev: - input_free_device(input); + input_unregister_device(fujitsu_laptop->input); err_free_fifo: kfifo_free(&fujitsu_laptop->fifo); err_stop: From f66735f8f8fb8d18e41288a74e73dc5e354331c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:21 +0100 Subject: [PATCH 045/108] platform/x86: fujitsu-laptop: switch to a managed hotkey input device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a managed input device for hotkey events in order to simplify two error paths and one cleanup function while also reducing the number of local variables required. Remove double assignment to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 51 +++++++++------------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b1a08d83330b..74da588ed871 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -759,41 +759,29 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); - struct input_dev *input; - int error; - fujitsu_laptop->input = input = input_allocate_device(); - if (!input) + fujitsu_laptop->input = devm_input_allocate_device(&device->dev); + if (!fujitsu_laptop->input) return -ENOMEM; snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys), "%s/video/input0", acpi_device_hid(device)); - input->name = acpi_device_name(device); - input->phys = fujitsu_laptop->phys; - input->id.bustype = BUS_HOST; - input->id.product = 0x06; - input->dev.parent = &device->dev; + fujitsu_laptop->input->name = acpi_device_name(device); + fujitsu_laptop->input->phys = fujitsu_laptop->phys; + fujitsu_laptop->input->id.bustype = BUS_HOST; + fujitsu_laptop->input->id.product = 0x06; - set_bit(EV_KEY, input->evbit); - set_bit(fujitsu_bl->keycode1, input->keybit); - set_bit(fujitsu_bl->keycode2, input->keybit); - set_bit(fujitsu_bl->keycode3, input->keybit); - set_bit(fujitsu_bl->keycode4, input->keybit); - set_bit(fujitsu_bl->keycode5, input->keybit); - set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit); - set_bit(KEY_UNKNOWN, input->keybit); + set_bit(EV_KEY, fujitsu_laptop->input->evbit); + set_bit(fujitsu_bl->keycode1, fujitsu_laptop->input->keybit); + set_bit(fujitsu_bl->keycode2, fujitsu_laptop->input->keybit); + set_bit(fujitsu_bl->keycode3, fujitsu_laptop->input->keybit); + set_bit(fujitsu_bl->keycode4, fujitsu_laptop->input->keybit); + set_bit(fujitsu_bl->keycode5, fujitsu_laptop->input->keybit); + set_bit(KEY_TOUCHPAD_TOGGLE, fujitsu_laptop->input->keybit); + set_bit(KEY_UNKNOWN, fujitsu_laptop->input->keybit); - error = input_register_device(input); - if (error) - goto err_free_input_dev; - - return 0; - -err_free_input_dev: - input_free_device(input); - - return error; + return input_register_device(fujitsu_laptop->input); } static int fujitsu_laptop_platform_add(void) @@ -862,7 +850,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) error = acpi_bus_update_power(fujitsu_laptop->acpi_handle, &state); if (error) { pr_err("Error reading power state\n"); - goto err_unregister_input_dev; + goto err_free_fifo; } pr_info("ACPI: %s [%s] (%s)\n", @@ -911,7 +899,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) error = fujitsu_laptop_platform_add(); if (error) - goto err_unregister_input_dev; + goto err_free_fifo; #if IS_ENABLED(CONFIG_LEDS_CLASS) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { @@ -974,8 +962,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) return result; -err_unregister_input_dev: - input_unregister_device(fujitsu_laptop->input); err_free_fifo: kfifo_free(&fujitsu_laptop->fifo); err_stop: @@ -985,7 +971,6 @@ err_stop: static int acpi_fujitsu_laptop_remove(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); - struct input_dev *input = fujitsu_laptop->input; #if IS_ENABLED(CONFIG_LEDS_CLASS) if (fujitsu_laptop->logolamp_registered) @@ -1003,8 +988,6 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) fujitsu_laptop_platform_remove(); - input_unregister_device(input); - kfifo_free(&fujitsu_laptop->fifo); fujitsu_laptop->acpi_handle = NULL; From 527483a8e1cf6c78b4e15545d57013d9a958482a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:22 +0100 Subject: [PATCH 046/108] platform/x86: fujitsu-laptop: use a sparse keymap for hotkey event generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify hotkey event generation by using a sparse keymap. As sparse keymap operates on scancodes instead of keycodes, adjust variable names and debug messages accordingly. This patch only handles the default keymap for clarity. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe [dvhart: correct flag passed to call_fext_func in acpi_fujitsu_laptop_notify] Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 111 ++++++++++---------------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 74da588ed871..979f160babcd 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -756,9 +756,22 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) /* ACPI device for hotkey handling */ +static const struct key_entry keymap_default[] = { + { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, + { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, + { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, + { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, + { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, + { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } }, + { KE_END, 0 } +}; + +static const struct key_entry *keymap = keymap_default; + static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); + int ret; fujitsu_laptop->input = devm_input_allocate_device(&device->dev); if (!fujitsu_laptop->input) @@ -772,14 +785,9 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) fujitsu_laptop->input->id.bustype = BUS_HOST; fujitsu_laptop->input->id.product = 0x06; - set_bit(EV_KEY, fujitsu_laptop->input->evbit); - set_bit(fujitsu_bl->keycode1, fujitsu_laptop->input->keybit); - set_bit(fujitsu_bl->keycode2, fujitsu_laptop->input->keybit); - set_bit(fujitsu_bl->keycode3, fujitsu_laptop->input->keybit); - set_bit(fujitsu_bl->keycode4, fujitsu_laptop->input->keybit); - set_bit(fujitsu_bl->keycode5, fujitsu_laptop->input->keybit); - set_bit(KEY_TOUCHPAD_TOGGLE, fujitsu_laptop->input->keybit); - set_bit(KEY_UNKNOWN, fujitsu_laptop->input->keybit); + ret = sparse_keymap_setup(fujitsu_laptop->input, keymap, NULL); + if (ret) + return ret; return input_register_device(fujitsu_laptop->input); } @@ -995,61 +1003,54 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) return 0; } -static void acpi_fujitsu_laptop_press(int keycode) +static void acpi_fujitsu_laptop_press(int scancode) { struct input_dev *input = fujitsu_laptop->input; int status; status = kfifo_in_locked(&fujitsu_laptop->fifo, - (unsigned char *)&keycode, sizeof(keycode), + (unsigned char *)&scancode, sizeof(scancode), &fujitsu_laptop->fifo_lock); - if (status != sizeof(keycode)) { + if (status != sizeof(scancode)) { vdbg_printk(FUJLAPTOP_DBG_WARN, - "Could not push keycode [0x%x]\n", keycode); + "Could not push scancode [0x%x]\n", scancode); return; } - input_report_key(input, keycode, 1); - input_sync(input); + sparse_keymap_report_event(input, scancode, 1, false); vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Push keycode into ringbuffer [%d]\n", keycode); + "Push scancode into ringbuffer [0x%x]\n", scancode); } static void acpi_fujitsu_laptop_release(void) { struct input_dev *input = fujitsu_laptop->input; - int keycode, status; + int scancode, status; while (true) { status = kfifo_out_locked(&fujitsu_laptop->fifo, - (unsigned char *)&keycode, - sizeof(keycode), + (unsigned char *)&scancode, + sizeof(scancode), &fujitsu_laptop->fifo_lock); - if (status != sizeof(keycode)) + if (status != sizeof(scancode)) return; - input_report_key(input, keycode, 0); - input_sync(input); + sparse_keymap_report_event(input, scancode, 0, false); vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Pop keycode from ringbuffer [%d]\n", keycode); + "Pop scancode from ringbuffer [0x%x]\n", scancode); } } static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) { struct input_dev *input; - int keycode; - unsigned int irb = 1; - int i; + int scancode, i = 0; + unsigned int irb; input = fujitsu_laptop->input; if (event != ACPI_FUJITSU_NOTIFY_CODE1) { - keycode = KEY_UNKNOWN; vdbg_printk(FUJLAPTOP_DBG_WARN, "Unsupported event [0x%x]\n", event); - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); + sparse_keymap_report_event(input, -1, 1, true); return; } @@ -1057,40 +1058,16 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) fujitsu_laptop->flags_state = call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0); - i = 0; - while ((irb = - call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { - switch (irb & 0x4ff) { - case KEY1_CODE: - keycode = fujitsu_bl->keycode1; - break; - case KEY2_CODE: - keycode = fujitsu_bl->keycode2; - break; - case KEY3_CODE: - keycode = fujitsu_bl->keycode3; - break; - case KEY4_CODE: - keycode = fujitsu_bl->keycode4; - break; - case KEY5_CODE: - keycode = fujitsu_bl->keycode5; - break; - case 0: - keycode = 0; - break; - default: + while ((irb = call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && + i++ < MAX_HOTKEY_RINGBUFFER_SIZE) { + scancode = irb & 0x4ff; + if (sparse_keymap_entry_from_scancode(input, scancode)) + acpi_fujitsu_laptop_press(scancode); + else if (scancode == 0) + acpi_fujitsu_laptop_release(); + else vdbg_printk(FUJLAPTOP_DBG_WARN, "Unknown GIRB result [%x]\n", irb); - keycode = -1; - break; - } - - if (keycode > 0) - acpi_fujitsu_laptop_press(keycode); - else if (keycode == 0) - acpi_fujitsu_laptop_release(); } /* On some models (first seen on the Skylake-based Lifebook @@ -1098,14 +1075,8 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) * handled in software; its state is queried using FUNC_FLAGS */ if ((fujitsu_laptop->flags_supported & BIT(26)) && - (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) { - keycode = KEY_TOUCHPAD_TOGGLE; - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); - } - + (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) + sparse_keymap_report_event(input, BIT(26), 1, true); } /* Initialization */ From f8c94ecd8f6adf241f7cbfdc3e004e94b0238fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:23 +0100 Subject: [PATCH 047/108] platform/x86: fujitsu-laptop: model-dependent sparse keymap overrides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some laptop models need to have different keycodes assigned to hotkey scancodes. Change the sparse keymap upon a DMI match, before the hotkey input device is setup. Instead of using three different callbacks in the DMI match table, simplify code by using the driver_data field of struct dmi_system_id to supply the requested keymap to a common callback. Also merge keymaps for S6410 and S6420 as they are identical. Rename fujitsu_dmi_table to fujitsu_laptop_dmi_table to emphasize it is no longer used by the backlight part of fujitsu-laptop. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 111 +++++++++++++------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 979f160babcd..877def0001f1 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -534,61 +534,6 @@ static struct platform_driver fujitsu_pf_driver = { } }; -static void __init dmi_check_cb_common(const struct dmi_system_id *id) -{ - pr_info("Identified laptop model '%s'\n", id->ident); -} - -static int __init dmi_check_cb_s6410(const struct dmi_system_id *id) -{ - dmi_check_cb_common(id); - fujitsu_bl->keycode1 = KEY_SCREENLOCK; /* "Lock" */ - fujitsu_bl->keycode2 = KEY_HELP; /* "Mobility Center" */ - return 1; -} - -static int __init dmi_check_cb_s6420(const struct dmi_system_id *id) -{ - dmi_check_cb_common(id); - fujitsu_bl->keycode1 = KEY_SCREENLOCK; /* "Lock" */ - fujitsu_bl->keycode2 = KEY_HELP; /* "Mobility Center" */ - return 1; -} - -static int __init dmi_check_cb_p8010(const struct dmi_system_id *id) -{ - dmi_check_cb_common(id); - fujitsu_bl->keycode1 = KEY_HELP; /* "Support" */ - fujitsu_bl->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ - fujitsu_bl->keycode4 = KEY_WWW; /* "Internet" */ - return 1; -} - -static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { - { - .ident = "Fujitsu Siemens S6410", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), - }, - .callback = dmi_check_cb_s6410}, - { - .ident = "Fujitsu Siemens S6420", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), - }, - .callback = dmi_check_cb_s6420}, - { - .ident = "Fujitsu LifeBook P8010", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), - }, - .callback = dmi_check_cb_p8010}, - {} -}; - /* ACPI device for LCD brightness control */ static const struct key_entry keymap_backlight[] = { @@ -766,8 +711,62 @@ static const struct key_entry keymap_default[] = { { KE_END, 0 } }; +static const struct key_entry keymap_s64x0[] = { + { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */ + { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */ + { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, + { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, + { KE_END, 0 } +}; + +static const struct key_entry keymap_p8010[] = { + { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */ + { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, + { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */ + { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */ + { KE_END, 0 } +}; + static const struct key_entry *keymap = keymap_default; +static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id) +{ + pr_info("Identified laptop model '%s'\n", id->ident); + keymap = id->driver_data; + return 1; +} + +static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { + { + .callback = fujitsu_laptop_dmi_keymap_override, + .ident = "Fujitsu Siemens S6410", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), + }, + .driver_data = (void *)keymap_s64x0 + }, + { + .callback = fujitsu_laptop_dmi_keymap_override, + .ident = "Fujitsu Siemens S6420", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), + }, + .driver_data = (void *)keymap_s64x0 + }, + { + .callback = fujitsu_laptop_dmi_keymap_override, + .ident = "Fujitsu LifeBook P8010", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), + }, + .driver_data = (void *)keymap_p8010 + }, + {} +}; + static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); @@ -785,6 +784,7 @@ static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) fujitsu_laptop->input->id.bustype = BUS_HOST; fujitsu_laptop->input->id.product = 0x06; + dmi_check_system(fujitsu_laptop_dmi_table); ret = sparse_keymap_setup(fujitsu_laptop->input, keymap, NULL); if (ret) return ret; @@ -1135,7 +1135,6 @@ static int __init fujitsu_init(void) fujitsu_bl->keycode3 = KEY_PROG3; fujitsu_bl->keycode4 = KEY_PROG4; fujitsu_bl->keycode5 = KEY_RFKILL; - dmi_check_system(fujitsu_dmi_table); ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); if (ret) From 1cf034ccf93852c299288415e4105043d02227d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 20 Mar 2017 10:32:24 +0100 Subject: [PATCH 048/108] platform/x86: fujitsu-laptop: remove keycode fields from struct fujitsu_bl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the keycode[1-5] fields from struct fujitsu_bl as they are not needed any more as a result of the sparse keymap migration. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 877def0001f1..f66da4b0c31a 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -139,7 +139,6 @@ struct fujitsu_bl { struct input_dev *input; char phys[32]; struct backlight_device *bl_device; - int keycode1, keycode2, keycode3, keycode4, keycode5; unsigned int max_brightness; unsigned int brightness_changed; @@ -1130,11 +1129,6 @@ static int __init fujitsu_init(void) fujitsu_bl = kzalloc(sizeof(struct fujitsu_bl), GFP_KERNEL); if (!fujitsu_bl) return -ENOMEM; - fujitsu_bl->keycode1 = KEY_PROG1; - fujitsu_bl->keycode2 = KEY_PROG2; - fujitsu_bl->keycode3 = KEY_PROG3; - fujitsu_bl->keycode4 = KEY_PROG4; - fujitsu_bl->keycode5 = KEY_RFKILL; ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); if (ret) From b10664105df0d26d1150f90ac508be0125fe5b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 3 Apr 2017 11:38:57 +0200 Subject: [PATCH 049/108] platform/x86: fujitsu-laptop: clean up local variables in call_fext_func() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set values of FUNC call parameters in a designated initializer. Do not initialize status and handle variables as the values these are initialized to have no influence on execution flow. Use an array variable instead of the address of the first element of that array. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f66da4b0c31a..ca1491ff659e 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -219,16 +219,16 @@ static u32 dbg_level = 0x03; static int call_fext_func(int cmd, int arg0, int arg1, int arg2) { - acpi_status status = AE_OK; union acpi_object params[4] = { - { .type = ACPI_TYPE_INTEGER }, - { .type = ACPI_TYPE_INTEGER }, - { .type = ACPI_TYPE_INTEGER }, - { .type = ACPI_TYPE_INTEGER } + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = cmd }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg0 }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg1 }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg2 } }; - struct acpi_object_list arg_list = { 4, ¶ms[0] }; + struct acpi_object_list arg_list = { 4, params }; unsigned long long value; - acpi_handle handle = NULL; + acpi_status status; + acpi_handle handle; status = acpi_get_handle(fujitsu_laptop->acpi_handle, "FUNC", &handle); if (ACPI_FAILURE(status)) { @@ -237,11 +237,6 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) return -ENODEV; } - params[0].integer.value = cmd; - params[1].integer.value = arg0; - params[2].integer.value = arg1; - params[3].integer.value = arg2; - status = acpi_evaluate_integer(handle, NULL, &arg_list, &value); if (ACPI_FAILURE(status)) { vdbg_printk(FUJLAPTOP_DBG_WARN, From 17e23555616116e1668e83029d26354c2479c78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 3 Apr 2017 11:38:58 +0200 Subject: [PATCH 050/108] platform/x86: fujitsu-laptop: simplify call_fext_func() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_evaluate_integer() takes a pathname parameter which contains the name of the entity to evaluate underneath the given handle, so calling acpi_get_handle() beforehand is redundant. Replace the call to acpi_get_handle() with a call to acpi_evaluate_integer(), thus eliminating the need for a local variable storing the handle. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index ca1491ff659e..e5413d268b24 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -228,20 +228,11 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) struct acpi_object_list arg_list = { 4, params }; unsigned long long value; acpi_status status; - acpi_handle handle; - status = acpi_get_handle(fujitsu_laptop->acpi_handle, "FUNC", &handle); + status = acpi_evaluate_integer(fujitsu_laptop->acpi_handle, "FUNC", + &arg_list, &value); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, - "FUNC interface is not present\n"); - return -ENODEV; - } - - status = acpi_evaluate_integer(handle, NULL, &arg_list, &value); - if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", - cmd, arg0, arg1, arg2); + vdbg_printk(FUJLAPTOP_DBG_ERROR, "FUNC interface is not present\n"); return -ENODEV; } From f68e492c068872b7174a7fdde27f9119ba04aee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 3 Apr 2017 11:38:59 +0200 Subject: [PATCH 051/108] platform/x86: fujitsu-laptop: rename call_fext_func() arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename call_fext_func() arguments so that each argument's name signifies its role: - cmd -> func: sub-function to call (flags, buttons etc.), - arg0 -> op: operation to perform (get, set, get capabilities etc.), - arg1 -> feature: feature to act on (e.g. which LED), if relevant, - arg2 -> state: state to set (e.g. LED on or off), if relevant. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index e5413d268b24..26149f58dba7 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -217,13 +217,13 @@ static u32 dbg_level = 0x03; /* Fujitsu ACPI interface function */ -static int call_fext_func(int cmd, int arg0, int arg1, int arg2) +static int call_fext_func(int func, int op, int feature, int state) { union acpi_object params[4] = { - { .integer.type = ACPI_TYPE_INTEGER, .integer.value = cmd }, - { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg0 }, - { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg1 }, - { .integer.type = ACPI_TYPE_INTEGER, .integer.value = arg2 } + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature }, + { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state } }; struct acpi_object_list arg_list = { 4, params }; unsigned long long value; @@ -236,9 +236,8 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) return -ENODEV; } - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", - cmd, arg0, arg1, arg2, (int)value); + vdbg_printk(FUJLAPTOP_DBG_TRACE, "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", + func, op, feature, state, (int)value); return value; } From f35823619db8bbaa2afea8705f239c3cecb9d22f Mon Sep 17 00:00:00 2001 From: Santeri Toivonen Date: Tue, 4 Apr 2017 21:09:00 +0300 Subject: [PATCH 052/108] platform/x86: asus-nb-wmi: Add wapf4 quirk for the X302UA Asus laptop X302UA starts up with Wi-Fi disabled, without a way to enable it. Set wapf=4 to fix the problem. Signed-off-by: Santeri Toivonen Signed-off-by: Darren Hart (VMware) --- 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 dea98ffb6f60..1ae58d906536 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -142,6 +142,15 @@ static const struct dmi_system_id asus_quirks[] = { */ .driver_data = &quirk_asus_wapf4, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X302UA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"), + }, + .driver_data = &quirk_asus_wapf4, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X401U", From e1053963984318f67c60c629664c5f09b93cc1c4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 3 Apr 2017 20:25:13 -0700 Subject: [PATCH 053/108] platform/x86: silead_dmi - do not treat all devices as i2c_clients I2C bus has both i2c clients and adapter devices, so we must be careful in notifier code and verify that we are actually dealing with an i2c client before using it as such. Fixes: cef9dd85acd7 ("platform/x86: add support for devices with Silead...") Signed-off-by: Dmitry Torokhov Reviewed-by: Hans de Goede [andy: simplified silead_ts_dmi_add_props() change] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 26b388db565a..7564cc6529e7 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -96,9 +96,9 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { { }, }; -static void silead_ts_dmi_add_props(struct device *dev) +static void silead_ts_dmi_add_props(struct i2c_client *client) { - struct i2c_client *client = to_i2c_client(dev); + struct device *dev = &client->dev; const struct dmi_system_id *dmi_id; const struct silead_ts_dmi_data *ts_data; int error; @@ -120,10 +120,13 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; + struct i2c_client *client; switch (action) { case BUS_NOTIFY_ADD_DEVICE: - silead_ts_dmi_add_props(dev); + client = i2c_verify_client(dev); + if (client) + silead_ts_dmi_add_props(client); break; default: From f22265b61585c18c4aaa37e0bcc7f72a6db7a715 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 3 Apr 2017 20:25:14 -0700 Subject: [PATCH 054/108] platform/x86: silead_dmi - abort early if DMI does not match There is no point in registering I2C bus notifier if DMI data does not match. Signed-off-by: Dmitry Torokhov Reviewed-by: Hans de Goede [andy: updated due to previous patch changed] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/silead_dmi.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 7564cc6529e7..3ff70ae57856 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -96,21 +96,16 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { { }, }; +static const struct silead_ts_dmi_data *silead_ts_data; + static void silead_ts_dmi_add_props(struct i2c_client *client) { struct device *dev = &client->dev; - const struct dmi_system_id *dmi_id; - const struct silead_ts_dmi_data *ts_data; int error; - dmi_id = dmi_first_match(silead_ts_dmi_table); - if (!dmi_id) - return; - - ts_data = dmi_id->driver_data; if (has_acpi_companion(dev) && - !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { - error = device_add_properties(dev, ts_data->properties); + !strncmp(silead_ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { + error = device_add_properties(dev, silead_ts_data->properties); if (error) dev_err(dev, "failed to add properties: %d\n", error); } @@ -142,8 +137,15 @@ static struct notifier_block silead_ts_dmi_notifier = { static int __init silead_ts_dmi_init(void) { + const struct dmi_system_id *dmi_id; int error; + dmi_id = dmi_first_match(silead_ts_dmi_table); + if (!dmi_id) + return 0; /* Not an error */ + + silead_ts_data = dmi_id->driver_data; + error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier); if (error) pr_err("%s: failed to register i2c bus notifier: %d\n", From ac207ded45f52b2a122eb947f3e1ab908c4a7ce8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2017 19:05:24 +0300 Subject: [PATCH 055/108] platform/x86: intel_scu_ipc: Platform data is mandatory Fail ->probe() if there is no platform data supplied. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_scu_ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index e81daff65f62..d789fe1baf17 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -579,6 +579,8 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -EBUSY; pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data; + if (!pdata) + return -ENODEV; scu->dev = &pdev->dev; scu->irq_mode = pdata->irq_mode; From 822e423e62d0f07574e3aaaa7e2c15ffab7815cc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2017 19:05:25 +0300 Subject: [PATCH 056/108] platform/x86: intel_scu_ipc: Rearrange init sequence Device pointer is used as a flag that everything is prepared. Nevertheless the assignment happened quite before and there is a window when a caller can get weird results or even crashes since not all fields are initialized yet. Rearrange initialization sequence in ->probe() to prepare everything before use. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_scu_ipc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index d789fe1baf17..8a34c1e7536f 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -582,7 +582,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!pdata) return -ENODEV; - scu->dev = &pdev->dev; scu->irq_mode = pdata->irq_mode; err = pcim_enable_device(pdev); @@ -595,17 +594,20 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) init_completion(&scu->cmd_complete); - err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc", - scu); - if (err) - return err; - scu->ipc_base = pcim_iomap_table(pdev)[0]; scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len); if (!scu->i2c_base) return -ENOMEM; + err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc", + scu); + if (err) + return err; + + /* Assign device at last */ + scu->dev = &pdev->dev; + intel_scu_devices_create(); pci_set_drvdata(pdev, scu); From 07ac1af3fc3e11f5b0948597aaad78d30c45a289 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2017 19:05:26 +0300 Subject: [PATCH 057/108] platform/x86: intel_scu_ipc: Remove redundant subarch check The driver is bound to the devices based on their PCI IDs. There is no need to do an additional check. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_scu_ipc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 8a34c1e7536f..6d626a8878c7 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -566,15 +566,10 @@ static irqreturn_t ioc(int irq, void *dev_id) */ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int platform; /* Platform type */ int err; struct intel_scu_ipc_dev *scu = &ipcdev; struct intel_scu_ipc_pdata_t *pdata; - platform = intel_mid_identify_cpu(); - if (platform == 0) - return -ENODEV; - if (scu->dev) /* We support only one SCU */ return -EBUSY; From 74bc77a3db0f68609c4c7641e010fd85e4c77a36 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2017 19:05:27 +0300 Subject: [PATCH 058/108] platform/x86: intel_scu_ipc: Introduce SCU_DEVICE() macro For better maintainability and readability introduce a macro for device ID table. No functional change intended. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_scu_ipc.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 6d626a8878c7..f9d3eb505a0b 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -609,22 +609,14 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; } +#define SCU_DEVICE(id, pdata) {PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&pdata} + static const struct pci_device_id pci_ids[] = { - { - PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT), - (kernel_ulong_t)&intel_scu_ipc_lincroft_pdata, - }, { - PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PENWELL), - (kernel_ulong_t)&intel_scu_ipc_penwell_pdata, - }, { - PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CLOVERVIEW), - (kernel_ulong_t)&intel_scu_ipc_penwell_pdata, - }, { - PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER), - (kernel_ulong_t)&intel_scu_ipc_tangier_pdata, - }, { - 0, - } + SCU_DEVICE(PCI_DEVICE_ID_LINCROFT, intel_scu_ipc_lincroft_pdata), + SCU_DEVICE(PCI_DEVICE_ID_PENWELL, intel_scu_ipc_penwell_pdata), + SCU_DEVICE(PCI_DEVICE_ID_CLOVERVIEW, intel_scu_ipc_penwell_pdata), + SCU_DEVICE(PCI_DEVICE_ID_TANGIER, intel_scu_ipc_tangier_pdata), + {} }; static struct pci_driver ipc_driver = { From d27a7e299daaf5d984cd671db99424660895586d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Apr 2017 19:05:28 +0300 Subject: [PATCH 059/108] platform/x86: intel_scu_ipc: Introduce intel_scu_ipc_raw_command() A new call to SCU intel_scu_ipc_raw_command() writes SPTR and DPTR registers before sending a command. Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel_scu_ipc.h | 8 +++- drivers/platform/x86/intel_scu_ipc.c | 63 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h index 4fb1d0abef95..81d3d8776fd9 100644 --- a/arch/x86/include/asm/intel_scu_ipc.h +++ b/arch/x86/include/asm/intel_scu_ipc.h @@ -3,6 +3,9 @@ #include +#define IPCMSG_INDIRECT_READ 0x02 +#define IPCMSG_INDIRECT_WRITE 0x05 + #define IPCMSG_COLD_OFF 0x80 /* Only for Tangier */ #define IPCMSG_WARM_RESET 0xF0 @@ -45,7 +48,10 @@ int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask); /* Issue commands to the SCU with or without data */ int intel_scu_ipc_simple_command(int cmd, int sub); int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, - u32 *out, int outlen); + u32 *out, int outlen); +int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen, + u32 *out, int outlen, u32 dptr, u32 sptr); + /* I2C control api */ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data); diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f9d3eb505a0b..f7cf981502cd 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -491,6 +491,69 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, } EXPORT_SYMBOL(intel_scu_ipc_command); +#define IPC_SPTR 0x08 +#define IPC_DPTR 0x0C + +/** + * intel_scu_ipc_raw_command() - IPC command with data and pointers + * @cmd: IPC command code. + * @sub: IPC command sub type. + * @in: input data of this IPC command. + * @inlen: input data length in dwords. + * @out: output data of this IPC command. + * @outlen: output data length in dwords. + * @sptr: data writing to SPTR register. + * @dptr: data writing to DPTR register. + * + * Send an IPC command to SCU with input/output data and source/dest pointers. + * + * Return: an IPC error code or 0 on success. + */ +int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen, + u32 *out, int outlen, u32 dptr, u32 sptr) +{ + struct intel_scu_ipc_dev *scu = &ipcdev; + int inbuflen = DIV_ROUND_UP(inlen, 4); + u32 inbuf[4]; + int i, err; + + /* Up to 16 bytes */ + if (inbuflen > 4) + return -EINVAL; + + mutex_lock(&ipclock); + if (scu->dev == NULL) { + mutex_unlock(&ipclock); + return -ENODEV; + } + + writel(dptr, scu->ipc_base + IPC_DPTR); + writel(sptr, scu->ipc_base + IPC_SPTR); + + /* + * SRAM controller doesn't support 8-bit writes, it only + * supports 32-bit writes, so we have to copy input data into + * the temporary buffer, and SCU FW will use the inlen to + * determine the actual input data length in the temporary + * buffer. + */ + memcpy(inbuf, in, inlen); + + for (i = 0; i < inbuflen; i++) + ipc_data_writel(scu, inbuf[i], 4 * i); + + ipc_command(scu, (inlen << 16) | (sub << 12) | cmd); + err = intel_scu_ipc_check_status(scu); + if (!err) { + for (i = 0; i < outlen; i++) + *out++ = ipc_data_readl(scu, 4 * i); + } + + mutex_unlock(&ipclock); + return err; +} +EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command); + /* I2C commands */ #define IPC_I2C_WRITE 1 /* I2C Write command */ #define IPC_I2C_READ 2 /* I2C Read command */ From 09b29e1eda78d81218cf2304495c551d7714e0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 6 Apr 2017 08:46:10 +0200 Subject: [PATCH 060/108] platform/x86: fujitsu-laptop: update debug message logged by call_fext_func() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update debug message logged when the acpi_evaluate_integer() call inside call_fext_func() fails so that it covers a broader set of possible errors. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 26149f58dba7..928778ccc4c1 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -232,7 +232,7 @@ static int call_fext_func(int func, int op, int feature, int state) status = acpi_evaluate_integer(fujitsu_laptop->acpi_handle, "FUNC", &arg_list, &value); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "FUNC interface is not present\n"); + vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate FUNC\n"); return -ENODEV; } From 07acf62a40f2410a00ed058db225c8f959ff8695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:00 +0200 Subject: [PATCH 061/108] platform/x86: fujitsu-laptop: only handle backlight when appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backlight part of fujitsu-laptop is only used by laptops which are incapable of using the standard ACPI video interface for handling brightness changes. Conversely, on laptops which are capable of using the latter, no vendor-specific ACPI calls should be made unless explicitly requested by the user. Bail out immediately from acpi_fujitsu_bl_add() unless using the vendor-specific interface was either explicitly requested by the user or automatically selected by the kernel. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 928778ccc4c1..5e3e9511caaf 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -574,6 +574,9 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) int state = 0; int error; + if (acpi_video_get_backlight_type() != acpi_backlight_vendor) + return -ENODEV; + if (!device) return -EINVAL; @@ -626,11 +629,9 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(); - if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { - error = fujitsu_backlight_register(); - if (error) - return error; - } + error = fujitsu_backlight_register(); + if (error) + return error; return 0; } From a1aabd5f3609dfa460050402c677620312bc2876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:01 +0200 Subject: [PATCH 062/108] platform/x86: fujitsu-laptop: switch to a managed backlight device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a managed backlight device to get rid of acpi_fujitsu_bl_remove(). Change the parent of the backlight device from NULL to the FUJ02B1 ACPI device as the latter is required for the backlight device to work. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 5e3e9511caaf..f90b129ff2c2 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -550,17 +550,18 @@ static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) return input_register_device(fujitsu_bl->input); } -static int fujitsu_backlight_register(void) +static int fujitsu_backlight_register(struct acpi_device *device) { - struct backlight_properties props = { + const struct backlight_properties props = { .brightness = fujitsu_bl->brightness_level, .max_brightness = fujitsu_bl->max_brightness - 1, .type = BACKLIGHT_PLATFORM }; struct backlight_device *bd; - bd = backlight_device_register("fujitsu-laptop", NULL, NULL, - &fujitsu_bl_ops, &props); + bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop", + &device->dev, NULL, + &fujitsu_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -629,24 +630,13 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(); - error = fujitsu_backlight_register(); + error = fujitsu_backlight_register(device); if (error) return error; return 0; } -static int acpi_fujitsu_bl_remove(struct acpi_device *device) -{ - struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device); - - backlight_device_unregister(fujitsu_bl->bl_device); - - fujitsu_bl->acpi_handle = NULL; - - return 0; -} - /* Brightness notify */ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) @@ -1077,7 +1067,6 @@ static struct acpi_driver acpi_fujitsu_bl_driver = { .ids = fujitsu_bl_device_ids, .ops = { .add = acpi_fujitsu_bl_add, - .remove = acpi_fujitsu_bl_remove, .notify = acpi_fujitsu_bl_notify, }, }; From e32c50ba5ae9f2b817e72aa8609ec25ab29b20dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:02 +0200 Subject: [PATCH 063/108] platform/x86: fujitsu-laptop: merge set_lcd_level_alt() into set_lcd_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on the value of the use_alt_lcd_levels module parameter, one of two functions is used for setting LCD brightness level. These functions are almost identical and only differ in the name of the ACPI method they call. Instead of checking the value of use_alt_lcd_levels at each call site, move that check to set_lcd_level() and get rid of set_lcd_level_alt(). Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 52 ++++++++------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f90b129ff2c2..46d4f7265d20 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -345,41 +345,26 @@ static int set_lcd_level(int level) { acpi_status status = AE_OK; acpi_handle handle = NULL; + char *method; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n", - level); - - if (level < 0 || level >= fujitsu_bl->max_brightness) - return -EINVAL; - - status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBLL", &handle); - if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); - return -ENODEV; + switch (use_alt_lcd_levels) { + case 1: + method = "SBL2"; + break; + default: + method = "SBLL"; + break; } - - status = acpi_execute_simple_method(handle, NULL, level); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return 0; -} - -static int set_lcd_level_alt(int level) -{ - acpi_status status = AE_OK; - acpi_handle handle = NULL; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n", - level); + vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via %s [%d]\n", + method, level); if (level < 0 || level >= fujitsu_bl->max_brightness) return -EINVAL; - status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBL2", &handle); + status = acpi_get_handle(fujitsu_bl->acpi_handle, method, &handle); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); + vdbg_printk(FUJLAPTOP_DBG_ERROR, "%s not present\n", method); return -ENODEV; } @@ -448,10 +433,7 @@ static int bl_update_status(struct backlight_device *b) "Unable to adjust backlight power, error code %i\n", ret); - if (use_alt_lcd_levels) - ret = set_lcd_level_alt(b->props.brightness); - else - ret = set_lcd_level(b->props.brightness); + ret = set_lcd_level(b->props.brightness); if (ret != 0) vdbg_printk(FUJLAPTOP_DBG_ERROR, "Unable to adjust LCD brightness, error code %i\n", @@ -664,12 +646,8 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) if (oldb == newb) return; - if (disable_brightness_adjust != 1) { - if (use_alt_lcd_levels) - set_lcd_level_alt(newb); - else - set_lcd_level(newb); - } + if (disable_brightness_adjust != 1) + set_lcd_level(newb); sparse_keymap_report_event(input, oldb < newb, 1, true); } From a8779c35b6b4a68489037d804df91c8d2b136218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:03 +0200 Subject: [PATCH 064/108] platform/x86: fujitsu-laptop: simplify set_lcd_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_execute_simple_method() takes a method parameter which tells it to look for the given method underneath the given handle, so calling acpi_get_handle() beforehand is redundant. Replace the call to acpi_get_handle() with a call to acpi_execute_simple_method(), thus eliminating the need for a local variable storing the handle. Update debug message to reflect this change. Also do not assign a default value to status as it has no influence on execution flow. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 46d4f7265d20..066ffe734a5f 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -343,8 +343,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev) static int set_lcd_level(int level) { - acpi_status status = AE_OK; - acpi_handle handle = NULL; + acpi_status status; char *method; switch (use_alt_lcd_levels) { @@ -362,16 +361,14 @@ static int set_lcd_level(int level) if (level < 0 || level >= fujitsu_bl->max_brightness) return -EINVAL; - status = acpi_get_handle(fujitsu_bl->acpi_handle, method, &handle); + status = acpi_execute_simple_method(fujitsu_bl->acpi_handle, method, + level); if (ACPI_FAILURE(status)) { - vdbg_printk(FUJLAPTOP_DBG_ERROR, "%s not present\n", method); + vdbg_printk(FUJLAPTOP_DBG_ERROR, "Failed to evaluate %s\n", + method); return -ENODEV; } - status = acpi_execute_simple_method(handle, NULL, level); - if (ACPI_FAILURE(status)) - return -ENODEV; - return 0; } From bd079a2cc5afe3d980f054a72bc08dbbe17c216c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:04 +0200 Subject: [PATCH 065/108] platform/x86: fujitsu-laptop: sync brightness in set_lcd_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using brightness keys and backlight device's sysfs interface alternately, an incorrect input event might be generated for a brightness key press. Consider the following sequence of events: 1. Set backlight brightness to 6 using brightness keys. 2. Write 4 to /sys/class/backlight/fujitsu-laptop/brightness. 3. Press the "brightness up" key. The input event generated in this scenario would be KEY_BRIGHTNESSDOWN, because before step 3 brightness_level would still be at 6. As the new brightness level is established using GBLL, it would evaluate to 5 (SBLL/SBL2 sets it to 4 in step 2 and pressing the "brightness up" key increases it by 1). This in turn would cause acpi_fujitsu_bl_notify() to observe a 6 -> 5 change, i.e. a decrease in brightness, while screen brightness would in fact be increased. Fix this by updating brightness_level in set_lcd_level. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 066ffe734a5f..4c3bba0ceb04 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -369,6 +369,8 @@ static int set_lcd_level(int level) return -ENODEV; } + fujitsu_bl->brightness_level = level; + return 0; } From e06e4831d51decc23419b6c3d045f9c8c876da7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:05 +0200 Subject: [PATCH 066/108] platform/x86: fujitsu-laptop: clean up use_alt_lcd_levels handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value of each module parameter can be changed on the fly via sysfs. However, the current way of handling use_alt_lcd_levels prevents the user from dynamically switching from a value of 0 or 1 back to autodetection as the latter is only performed upon ACPI device instantiation. Fix this by moving autodetection (in a simplified form) to set_lcd_level() and changing module parameter type to int. Do not announce autodetection results in a debug message as current value of use_alt_lcd_levels can simply be read from sysfs. Clarify module parameter description. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 4c3bba0ceb04..e79a8cf8d705 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -347,6 +347,12 @@ static int set_lcd_level(int level) char *method; switch (use_alt_lcd_levels) { + case -1: + if (acpi_has_method(fujitsu_bl->acpi_handle, "SBL2")) + method = "SBL2"; + else + method = "SBLL"; + break; case 1: method = "SBL2"; break; @@ -591,21 +597,10 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) pr_err("_INI Method failed\n"); } - if (use_alt_lcd_levels == -1) { - if (acpi_has_method(NULL, "\\_SB.PCI0.LPCB.FJEX.SBL2")) - use_alt_lcd_levels = 1; - else - use_alt_lcd_levels = 0; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as %i\n", - use_alt_lcd_levels); - } - /* do config (detect defaults) */ - use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; - vdbg_printk(FUJLAPTOP_DBG_INFO, - "config: [alt interface: %d], [adjust disable: %d]\n", - use_alt_lcd_levels, disable_brightness_adjust); + vdbg_printk(FUJLAPTOP_DBG_INFO, "config: [adjust disable: %d]\n", + disable_brightness_adjust); if (get_max_brightness() <= 0) fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; @@ -1138,9 +1133,8 @@ static void __exit fujitsu_cleanup(void) module_init(fujitsu_init); module_exit(fujitsu_cleanup); -module_param(use_alt_lcd_levels, uint, 0644); -MODULE_PARM_DESC(use_alt_lcd_levels, - "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); +module_param(use_alt_lcd_levels, int, 0644); +MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)"); module_param(disable_brightness_adjust, uint, 0644); MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG From b4bb0cfdb00e97f8a4804dc93777a65869084078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:06 +0200 Subject: [PATCH 067/108] platform/x86: fujitsu-laptop: make disable_brightness_adjust a boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to the way the disable_brightness_adjust module parameter is currently handled in acpi_fujitsu_bl_add(), it can only be set to either 0 or 1, which effectively makes it a boolean. Emphasize that by changing module parameter type to bool. Do not announce parameter value in a debug message as it can be dynamically changed via sysfs and its current value can also be read from there. Clean up module parameter description. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index e79a8cf8d705..e7459197eb27 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -147,7 +147,7 @@ struct fujitsu_bl { static struct fujitsu_bl *fujitsu_bl; static int use_alt_lcd_levels = -1; -static int disable_brightness_adjust = -1; +static bool disable_brightness_adjust; /* Device used to access hotkeys and other features on the laptop */ struct fujitsu_laptop { @@ -597,11 +597,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) pr_err("_INI Method failed\n"); } - /* do config (detect defaults) */ - disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; - vdbg_printk(FUJLAPTOP_DBG_INFO, "config: [adjust disable: %d]\n", - disable_brightness_adjust); - if (get_max_brightness() <= 0) fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(); @@ -640,7 +635,7 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) if (oldb == newb) return; - if (disable_brightness_adjust != 1) + if (!disable_brightness_adjust) set_lcd_level(newb); sparse_keymap_report_event(input, oldb < newb, 1, true); @@ -1135,8 +1130,8 @@ module_exit(fujitsu_cleanup); module_param(use_alt_lcd_levels, int, 0644); MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)"); -module_param(disable_brightness_adjust, uint, 0644); -MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); +module_param(disable_brightness_adjust, bool, 0644); +MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment"); #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG module_param_named(debug, dbg_level, uint, 0644); MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); From f7c4c3fad5937bef41696d39422fb7773accf912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:07 +0200 Subject: [PATCH 068/108] platform/x86: fujitsu-laptop: ignore errors when setting backlight power MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not all Fujitsu laptops support controlling backlight power through the FUJ02E3 ACPI device. Remove the debug message informing about a failed attempt to set backlight power as it may be confusing and the return value of call_fext_func() is logged anyway. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index e7459197eb27..66a5eecf77d3 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -430,13 +430,9 @@ static int bl_update_status(struct backlight_device *b) { int ret; if (b->props.power == FB_BLANK_POWERDOWN) - ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); + call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); else - ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); - if (ret != 0) - vdbg_printk(FUJLAPTOP_DBG_ERROR, - "Unable to adjust backlight power, error code %i\n", - ret); + call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); ret = set_lcd_level(b->props.brightness); if (ret != 0) From d75a4a972ad1ed6d1326c63ae2fb0f9586161b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:08 +0200 Subject: [PATCH 069/108] platform/x86: fujitsu-laptop: do not log set_lcd_level() failures in bl_update_status() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any set_lcd_level() call can fail for one of two reasons: either requested brightness is outside the allowed range or the ACPI method used for setting brightness level is not available. For bl_update_status(), the first case is handled by backlight core, which means bl_update_status() will not even be called if requested brightness is outside the allowed range. The second case will be logged anyway by set_lcd_level() itself, so there is no point in generating another message in bl_update_status(). Remove the superfluous debug message along with a local variable that is now redundant. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 66a5eecf77d3..af36b15515ed 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -428,18 +428,12 @@ static int bl_get_brightness(struct backlight_device *b) static int bl_update_status(struct backlight_device *b) { - int ret; if (b->props.power == FB_BLANK_POWERDOWN) call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); else call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); - ret = set_lcd_level(b->props.brightness); - if (ret != 0) - vdbg_printk(FUJLAPTOP_DBG_ERROR, - "Unable to adjust LCD brightness, error code %i\n", - ret); - return ret; + return set_lcd_level(b->props.brightness); } static const struct backlight_ops fujitsu_bl_ops = { From 5959ddd02be4e435da866ee065187f5c8bccea28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:09 +0200 Subject: [PATCH 070/108] platform/x86: fujitsu-laptop: account for backlight power when determining brightness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment for the get_brightness backlight device callback in include/linux/backlight.h states that it should "return the current backlight brightness (accounting for power, fb_blank etc.)". fujitsu-laptop violates that premise by simply returning the value to which ACPI function GBLL evaluates to. Make sure 0 is returned when backlight power is turned off. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index af36b15515ed..b88172134063 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -423,7 +423,7 @@ static int get_max_brightness(void) static int bl_get_brightness(struct backlight_device *b) { - return get_lcd_level(); + return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(); } static int bl_update_status(struct backlight_device *b) From 5c495d6201fb0efafcf6e26b3c82a7bd01ec1b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Wed, 5 Apr 2017 08:49:10 +0200 Subject: [PATCH 071/108] platform/x86: fujitsu-laptop: remove redundant fields from struct fujitsu_bl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dev field of struct fujitsu_bl is assigned in acpi_fujitsu_bl_add(), but never used afterwards. brightness_changed is set in get_lcd_level() and then its value is only printed in a debug message, so it does not influence execution flow. Remove both fields as they are redundant. Update the aforementioned debug message. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b88172134063..84b561415875 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -135,13 +135,10 @@ /* Device controlling the backlight and associated keys */ struct fujitsu_bl { acpi_handle acpi_handle; - struct acpi_device *dev; struct input_dev *input; char phys[32]; struct backlight_device *bl_device; - unsigned int max_brightness; - unsigned int brightness_changed; unsigned int brightness_level; }; @@ -394,11 +391,6 @@ static int get_lcd_level(void) fujitsu_bl->brightness_level = state & 0x0fffffff; - if (state & 0x80000000) - fujitsu_bl->brightness_changed = 1; - else - fujitsu_bl->brightness_changed = 0; - return fujitsu_bl->brightness_level; } @@ -577,8 +569,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); - fujitsu_bl->dev = device; - if (acpi_has_method(device->handle, METHOD_NAME__INI)) { vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); if (ACPI_FAILURE @@ -618,9 +608,8 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) get_lcd_level(); newb = fujitsu_bl->brightness_level; - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "brightness button event [%i -> %i (%i)]\n", - oldb, newb, fujitsu_bl->brightness_changed); + vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i]\n", + oldb, newb); if (oldb == newb) return; From 5b7bb3a79da05a5f49445c13f240e286a3d5b8a8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 9 Apr 2017 11:07:44 +0200 Subject: [PATCH 072/108] platform/x86: silead_dmi: Add touchscreen info for Surftab Wintron 7.0 Add touchscreen info for the Trekstor Surftab Wintron 7.0 ST70416-6 tablet. Signed-off-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/silead_dmi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c index 3ff70ae57856..a3a57d93cf06 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/silead_dmi.c @@ -66,6 +66,20 @@ static const struct silead_ts_dmi_data dexp_ursus_7w_data = { .properties = dexp_ursus_7w_props, }; +static const struct property_entry surftab_wintron70_st70416_6_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 884), + PROPERTY_ENTRY_U32("touchscreen-size-y", 632), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1686-surftab-wintron70-st70416-6.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = { + .acpi_name = "MSSL1680:00", + .properties = surftab_wintron70_st70416_6_props, +}; + static const struct dmi_system_id silead_ts_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -93,6 +107,16 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "7W"), }, }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6 */ + .driver_data = (void *)&surftab_wintron70_st70416_6_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + }, + }, { }, }; From 05aa43cce0e287a87e686931d65707953bc60d07 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 6 Apr 2017 17:32:16 +0100 Subject: [PATCH 073/108] platform/x86: hp-wireless: add Xiaomi's hardware id to the supported list The airplane mode button on Xiaomi's new laptops are the same as HP laptops. This is tested on Xiaomi Notebook Air 13. Signed-off-by: Alex Hung [dvhart: Dropped module init/exit info messages] Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/hp-wireless.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c index 988eedbd7c63..d860ea0d0e60 100644 --- a/drivers/platform/x86/hp-wireless.c +++ b/drivers/platform/x86/hp-wireless.c @@ -1,7 +1,7 @@ /* - * hp-wireless button for Windows 8 + * Airplane mode button for HP & Xiaomi laptops * - * Copyright (C) 2014 Alex Hung + * Copyright (C) 2014-2017 Alex Hung * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,11 +29,13 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alex Hung"); MODULE_ALIAS("acpi*:HPQ6001:*"); +MODULE_ALIAS("acpi*:WSTADEF:*"); static struct input_dev *hpwl_input_dev; static const struct acpi_device_id hpwl_ids[] = { {"HPQ6001", 0}, + {"WSTADEF", 0}, {"", 0}, }; @@ -112,7 +114,6 @@ static int __init hpwl_init(void) { int err; - pr_info("Initializing HPQ6001 module\n"); err = acpi_bus_register_driver(&hpwl_driver); if (err) pr_err("Unable to register HP wireless control driver.\n"); @@ -122,7 +123,6 @@ static int __init hpwl_init(void) static void __exit hpwl_exit(void) { - pr_info("Exiting HPQ6001 module\n"); acpi_bus_unregister_driver(&hpwl_driver); } From c7dfc2facbd69dad89b75e13c608da709668dcd0 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sun, 9 Apr 2017 15:56:07 +0200 Subject: [PATCH 074/108] platform/x86: hp-wmi: Fix error value for hp_wmi_tablet_state hp_wmi_tablet_state() fails to return the correct error code when hp_wmi_perform_query() returns the HP WMI query specific error code that is a positive value. Signed-off-by: Carlo Caione Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/hp-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 7abf92d0ba81..9db502c42b5c 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -290,7 +290,7 @@ static int hp_wmi_tablet_state(void) int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return ret; + return -EINVAL; return (state & 0x4) ? 1 : 0; } From 298747b7579f5bbbced793d997b333fd10a24921 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sun, 9 Apr 2017 15:56:08 +0200 Subject: [PATCH 075/108] platform/x86: hp-wmi: Fix detection for dock and tablet mode The current driver code is not checking for the error values returned by 'hp_wmi_dock_state()' and 'hp_wmi_tablet_state()' before passing the returned values down to 'input_report_switch()'. This error code is being translated to '1' in the input subsystem, reporting the wrong status. The biggest problem caused by this issue is that several laptops are wrongly reported by the driver as docked, preventing them to be put to sleep using the LID (and in most cases they are not even dockable). With this patch we create the report switches only if we are able to read the dock and tablet mode status correctly from ACPI. Signed-off-by: Carlo Caione Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/hp-wmi.c | 40 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 9db502c42b5c..5c5efccf9f19 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -572,10 +572,12 @@ static void hp_wmi_notify(u32 value, void *context) switch (event_id) { case HPWMI_DOCK_EVENT: - input_report_switch(hp_wmi_input_dev, SW_DOCK, - hp_wmi_dock_state()); - input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, - hp_wmi_tablet_state()); + if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) + input_report_switch(hp_wmi_input_dev, SW_DOCK, + hp_wmi_dock_state()); + if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, + hp_wmi_tablet_state()); input_sync(hp_wmi_input_dev); break; case HPWMI_PARK_HDD: @@ -644,6 +646,7 @@ static int __init hp_wmi_input_setup(void) { acpi_status status; int err; + int val; hp_wmi_input_dev = input_allocate_device(); if (!hp_wmi_input_dev) @@ -654,17 +657,26 @@ static int __init hp_wmi_input_setup(void) hp_wmi_input_dev->id.bustype = BUS_HOST; __set_bit(EV_SW, hp_wmi_input_dev->evbit); - __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); - __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); + + /* Dock */ + val = hp_wmi_dock_state(); + if (!(val < 0)) { + __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); + input_report_switch(hp_wmi_input_dev, SW_DOCK, val); + } + + /* Tablet mode */ + val = hp_wmi_tablet_state(); + if (!(val < 0)) { + __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val); + } err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); if (err) goto err_free_dev; /* Set initial hardware state */ - input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); - input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, - hp_wmi_tablet_state()); input_sync(hp_wmi_input_dev); if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later()) @@ -947,10 +959,12 @@ static int hp_wmi_resume_handler(struct device *device) * changed. */ if (hp_wmi_input_dev) { - input_report_switch(hp_wmi_input_dev, SW_DOCK, - hp_wmi_dock_state()); - input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, - hp_wmi_tablet_state()); + if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) + input_report_switch(hp_wmi_input_dev, SW_DOCK, + hp_wmi_dock_state()); + if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) + input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, + hp_wmi_tablet_state()); input_sync(hp_wmi_input_dev); } From 1cd706df8a9c93f4c7234f285e316a239d6d27ea Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 6 Apr 2017 09:24:36 +0200 Subject: [PATCH 076/108] platform/x86: Add Intel Cherry Trail ACPI INT33FE device driver The INT33FE ACPI device has a CRS table with I2cSerialBusV2 resources for 3 devices: Maxim MAX17047 Fuel Gauge Controller, FUSB302 USB Type-C Controller and PI3USB30532 USB switch. This commit adds a driver for this ACPI device which instantiates i2c-clients for these, so that the standard i2c drivers for these chips can bind to the them. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 13 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_cht_int33fe.c | 143 +++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 drivers/platform/x86/intel_cht_int33fe.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 5602bdfcad65..6b33db6c9d22 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -781,6 +781,19 @@ config ACPI_CMPC keys as input device, backlight device, tablet and accelerometer devices. +config INTEL_CHT_INT33FE + tristate "Intel Cherry Trail ACPI INT33FE Driver" + depends on X86 && ACPI + ---help--- + This driver add support for the INT33FE ACPI device found on + some Intel Cherry Trail devices. + + The INT33FE ACPI device has a CRS table with I2cSerialBusV2 + resources for 3 devices: Maxim MAX17047 Fuel Gauge Controller, + FUSB302 USB Type-C Controller and PI3USB30532 USB switch. + This driver instantiates i2c-clients for these, so that standard + i2c drivers for these chips can bind to the them. + config INTEL_HID_EVENT tristate "INTEL HID Event" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 776b3a7a4984..182a3ed6605a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o +obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c new file mode 100644 index 000000000000..6a1b2ca5b6fe --- /dev/null +++ b/drivers/platform/x86/intel_cht_int33fe.c @@ -0,0 +1,143 @@ +/* + * Intel Cherry Trail ACPI INT33FE pseudo device driver + * + * Copyright (C) 2017 Hans de Goede + * + * 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. + * + * Some Intel Cherry Trail based device which ship with Windows 10, have + * this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2 + * resources, for 4 different chips attached to various i2c busses: + * 1. The Whiskey Cove pmic, which is also described by the INT34D3 ACPI device + * 2. Maxim MAX17047 Fuel Gauge Controller + * 3. FUSB302 USB Type-C Controller + * 4. PI3USB30532 USB switch + * + * So this driver is a stub / pseudo driver whose only purpose is to + * instantiate i2c-clients for chips 2 - 4, so that standard i2c drivers + * for these chips can bind to the them. + */ + +#include +#include +#include +#include +#include + +#define EXPECTED_PTYPE 4 + +struct cht_int33fe_data { + struct i2c_client *max17047; + struct i2c_client *fusb302; + struct i2c_client *pi3usb30532; +}; + +static int cht_int33fe_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct i2c_board_info board_info; + struct cht_int33fe_data *data; + unsigned long long ptyp; + acpi_status status; + int fusb302_irq; + + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Error getting PTYPE\n"); + return -ENODEV; + } + + /* + * The same ACPI HID is used for different configurations check PTYP + * to ensure that we are dealing with the expected config. + */ + if (ptyp != EXPECTED_PTYPE) + return -ENODEV; + + /* The FUSB302 uses the irq at index 1 and is the only irq user */ + fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1); + if (fusb302_irq < 0) { + if (fusb302_irq != -EPROBE_DEFER) + dev_err(dev, "Error getting FUSB302 irq\n"); + return fusb302_irq; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + + data->max17047 = i2c_acpi_new_device(dev, 1, &board_info); + if (!data->max17047) + return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "fusb302", I2C_NAME_SIZE); + board_info.irq = fusb302_irq; + + data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); + if (!data->fusb302) + goto out_unregister_max17047; + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); + + data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); + if (!data->pi3usb30532) + goto out_unregister_fusb302; + + i2c_set_clientdata(client, data); + + return 0; + +out_unregister_fusb302: + i2c_unregister_device(data->fusb302); + +out_unregister_max17047: + i2c_unregister_device(data->max17047); + + return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */ +} + +static int cht_int33fe_remove(struct i2c_client *i2c) +{ + struct cht_int33fe_data *data = i2c_get_clientdata(i2c); + + i2c_unregister_device(data->pi3usb30532); + i2c_unregister_device(data->fusb302); + i2c_unregister_device(data->max17047); + + return 0; +} + +static const struct i2c_device_id cht_int33fe_i2c_id[] = { + { } +}; +MODULE_DEVICE_TABLE(i2c, cht_int33fe_i2c_id); + +static const struct acpi_device_id cht_int33fe_acpi_ids[] = { + { "INT33FE", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); + +static struct i2c_driver cht_int33fe_driver = { + .driver = { + .name = "Intel Cherry Trail ACPI INT33FE driver", + .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), + }, + .probe_new = cht_int33fe_probe, + .remove = cht_int33fe_remove, + .id_table = cht_int33fe_i2c_id, + .disable_i2c_core_irq_mapping = true, +}; + +module_i2c_driver(cht_int33fe_driver); + +MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); From b899830506740faf509f3bb51d3d1e50102aed40 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 18 Apr 2017 15:49:06 +0200 Subject: [PATCH 077/108] platform/x86: intel-hid: Add missing ->thaw callback The intel-hid driver is missing a PM ->thaw callback allowing the device to go back to the operational state after creating a hibernation image or when there is an image restoration error during resume. The lack of the ->thaw callback basically means that all events signaled by the device are discarded after a hibernation image has been created which may be problematic, for example, if the image cannot be saved (eg. due to an I/O issue with storage). Signed-off-by: Rafael J. Wysocki Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/intel-hid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index b40059aba856..63ba2cbd04c2 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -134,6 +134,7 @@ static int intel_hid_pl_resume_handler(struct device *device) static const struct dev_pm_ops intel_hid_pl_pm_ops = { .freeze = intel_hid_pl_suspend_handler, + .thaw = intel_hid_pl_resume_handler, .restore = intel_hid_pl_resume_handler, .suspend = intel_hid_pl_suspend_handler, .resume = intel_hid_pl_resume_handler, From d89bcc83e7090ac09c3f9712d9b9db9f1f1d8189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:08 +0200 Subject: [PATCH 078/108] platform/x86: fujitsu-laptop: select LEDS_CLASS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow common subsystem practice of selecting LEDS_CLASS instead of riddling module code with #ifdefs. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 2 +- drivers/platform/x86/fujitsu-laptop.c | 14 +------------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6b33db6c9d22..687f07872ae5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -182,8 +182,8 @@ config FUJITSU_LAPTOP depends on INPUT depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on LEDS_CLASS || LEDS_CLASS=n select INPUT_SPARSEKMAP + select LEDS_CLASS ---help--- This is a driver for laptops built by Fujitsu: diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 84b561415875..ab554a298bce 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -59,11 +59,9 @@ #include #include #include +#include #include #include -#if IS_ENABLED(CONFIG_LEDS_CLASS) -#include -#endif #include #define FUJITSU_DRIVER_VERSION "0.6.0" @@ -94,7 +92,6 @@ #define FLAG_LID 0x100 #define FLAG_DOCK 0x200 -#if IS_ENABLED(CONFIG_LEDS_CLASS) /* FUNC interface - LED control */ #define FUNC_LED_OFF 0x1 #define FUNC_LED_ON 0x30001 @@ -104,7 +101,6 @@ #define RADIO_LED_ON 0x20 #define ECO_LED 0x10000 #define ECO_LED_ON 0x80000 -#endif /* Hotkey details */ #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ @@ -165,7 +161,6 @@ struct fujitsu_laptop { static struct fujitsu_laptop *fujitsu_laptop; -#if IS_ENABLED(CONFIG_LEDS_CLASS) static enum led_brightness logolamp_get(struct led_classdev *cdev); static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness); @@ -206,7 +201,6 @@ static struct led_classdev eco_led = { .brightness_get = eco_led_get, .brightness_set_blocking = eco_led_set }; -#endif #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG static u32 dbg_level = 0x03; @@ -238,7 +232,6 @@ static int call_fext_func(int func, int op, int feature, int state) return value; } -#if IS_ENABLED(CONFIG_LEDS_CLASS) /* LED class callbacks */ static int logolamp_set(struct led_classdev *cdev, @@ -334,7 +327,6 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev) return brightness; } -#endif /* Hardware access for LCD brightness control */ @@ -830,7 +822,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; -#if IS_ENABLED(CONFIG_LEDS_CLASS) if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = led_classdev_register(&fujitsu_laptop->pf_device->dev, &logolamp_led); @@ -887,7 +878,6 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) result); } } -#endif return result; @@ -901,7 +891,6 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); -#if IS_ENABLED(CONFIG_LEDS_CLASS) if (fujitsu_laptop->logolamp_registered) led_classdev_unregister(&logolamp_led); @@ -913,7 +902,6 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) if (fujitsu_laptop->eco_led_registered) led_classdev_unregister(&eco_led); -#endif fujitsu_laptop_platform_remove(); From 7adb7b129ac0359b49a8406376a5aee8ce754b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:09 +0200 Subject: [PATCH 079/108] platform/x86: fujitsu-laptop: refactor LED registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move a long section of code responsible for registering LEDs out of acpi_fujitsu_laptop_add() to improve readability and ensure proper cleanup of platform device and kfifo e.g. when two supported LEDs are detected, the first one gets registered successfully but the second one does not. This makes the result variable in acpi_fujitsu_laptop_add() redundant, so remove it. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 128 ++++++++++++++------------ 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index ab554a298bce..e018b21d41da 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -739,9 +739,72 @@ static void fujitsu_laptop_platform_remove(void) platform_device_unregister(fujitsu_laptop->pf_device); } -static int acpi_fujitsu_laptop_add(struct acpi_device *device) +static int acpi_fujitsu_laptop_leds_register(void) { int result = 0; + + if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, + &logolamp_led); + if (result == 0) { + fujitsu_laptop->logolamp_registered = 1; + } else { + pr_err("Could not register LED handler for logo lamp, error %i\n", + result); + } + } + + if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && + (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, + &kblamps_led); + if (result == 0) { + fujitsu_laptop->kblamps_registered = 1; + } else { + pr_err("Could not register LED handler for keyboard lamps, error %i\n", + result); + } + } + + /* + * BTNI bit 24 seems to indicate the presence of a radio toggle + * button in place of a slide switch, and all such machines appear + * to also have an RF LED. Therefore use bit 24 as an indicator + * that an RF LED is present. + */ + if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, + &radio_led); + if (result == 0) { + fujitsu_laptop->radio_led_registered = 1; + } else { + pr_err("Could not register LED handler for radio LED, error %i\n", + result); + } + } + + /* Support for eco led is not always signaled in bit corresponding + * to the bit used to control the led. According to the DSDT table, + * bit 14 seems to indicate presence of said led as well. + * Confirm by testing the status. + */ + if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && + (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { + result = led_classdev_register(&fujitsu_laptop->pf_device->dev, + &eco_led); + if (result == 0) { + fujitsu_laptop->eco_led_registered = 1; + } else { + pr_err("Could not register LED handler for eco LED, error %i\n", + result); + } + } + + return result; +} + +static int acpi_fujitsu_laptop_add(struct acpi_device *device) +{ int state = 0; int error; int i; @@ -822,65 +885,14 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; - if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &logolamp_led); - if (result == 0) { - fujitsu_laptop->logolamp_registered = 1; - } else { - pr_err("Could not register LED handler for logo lamp, error %i\n", - result); - } - } + error = acpi_fujitsu_laptop_leds_register(); + if (error) + goto err_remove_platform_device; - if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && - (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &kblamps_led); - if (result == 0) { - fujitsu_laptop->kblamps_registered = 1; - } else { - pr_err("Could not register LED handler for keyboard lamps, error %i\n", - result); - } - } - - /* - * BTNI bit 24 seems to indicate the presence of a radio toggle - * button in place of a slide switch, and all such machines appear - * to also have an RF LED. Therefore use bit 24 as an indicator - * that an RF LED is present. - */ - if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &radio_led); - if (result == 0) { - fujitsu_laptop->radio_led_registered = 1; - } else { - pr_err("Could not register LED handler for radio LED, error %i\n", - result); - } - } - - /* Support for eco led is not always signaled in bit corresponding - * to the bit used to control the led. According to the DSDT table, - * bit 14 seems to indicate presence of said led as well. - * Confirm by testing the status. - */ - if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && - (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &eco_led); - if (result == 0) { - fujitsu_laptop->eco_led_registered = 1; - } else { - pr_err("Could not register LED handler for eco LED, error %i\n", - result); - } - } - - return result; + return 0; +err_remove_platform_device: + fujitsu_laptop_platform_remove(); err_free_fifo: kfifo_free(&fujitsu_laptop->fifo); err_stop: From e33ca45ca8fe130d10dda07391c967a8a3851f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:10 +0200 Subject: [PATCH 080/108] platform/x86: fujitsu-laptop: reorganize LED-related code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move around LED definitions and callbacks to eliminate the need for forward declarations and ensure code is organized LED-wise, not action-wise. Reorder assignments inside designated initializers so that they are in the same order as struct led_classdev fields in include/linux/leds.h. Adjust whitespace to make checkpatch happy. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 261 ++++++++++++-------------- 1 file changed, 124 insertions(+), 137 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index e018b21d41da..22909063e9c4 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -161,47 +161,6 @@ struct fujitsu_laptop { static struct fujitsu_laptop *fujitsu_laptop; -static enum led_brightness logolamp_get(struct led_classdev *cdev); -static int logolamp_set(struct led_classdev *cdev, - enum led_brightness brightness); - -static struct led_classdev logolamp_led = { - .name = "fujitsu::logolamp", - .brightness_get = logolamp_get, - .brightness_set_blocking = logolamp_set -}; - -static enum led_brightness kblamps_get(struct led_classdev *cdev); -static int kblamps_set(struct led_classdev *cdev, - enum led_brightness brightness); - -static struct led_classdev kblamps_led = { - .name = "fujitsu::kblamps", - .brightness_get = kblamps_get, - .brightness_set_blocking = kblamps_set -}; - -static enum led_brightness radio_led_get(struct led_classdev *cdev); -static int radio_led_set(struct led_classdev *cdev, - enum led_brightness brightness); - -static struct led_classdev radio_led = { - .name = "fujitsu::radio_led", - .default_trigger = "rfkill-any", - .brightness_get = radio_led_get, - .brightness_set_blocking = radio_led_set -}; - -static enum led_brightness eco_led_get(struct led_classdev *cdev); -static int eco_led_set(struct led_classdev *cdev, - enum led_brightness brightness); - -static struct led_classdev eco_led = { - .name = "fujitsu::eco_led", - .brightness_get = eco_led_get, - .brightness_set_blocking = eco_led_set -}; - #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG static u32 dbg_level = 0x03; #endif @@ -232,102 +191,6 @@ static int call_fext_func(int func, int op, int feature, int state) return value; } -/* LED class callbacks */ - -static int logolamp_set(struct led_classdev *cdev, - enum led_brightness brightness) -{ - int poweron = FUNC_LED_ON, always = FUNC_LED_ON; - int ret; - - if (brightness < LED_HALF) - poweron = FUNC_LED_OFF; - - if (brightness < LED_FULL) - always = FUNC_LED_OFF; - - ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); - if (ret < 0) - return ret; - - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); -} - -static int kblamps_set(struct led_classdev *cdev, - enum led_brightness brightness) -{ - if (brightness >= LED_FULL) - return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); - else - return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); -} - -static int radio_led_set(struct led_classdev *cdev, - enum led_brightness brightness) -{ - if (brightness >= LED_FULL) - return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON); - else - return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0); -} - -static int eco_led_set(struct led_classdev *cdev, - enum led_brightness brightness) -{ - int curr; - - curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); - if (brightness >= LED_FULL) - return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); - else - return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); -} - -static enum led_brightness logolamp_get(struct led_classdev *cdev) -{ - int ret; - - ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); - if (ret == FUNC_LED_ON) - return LED_FULL; - - ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); - if (ret == FUNC_LED_ON) - return LED_HALF; - - return LED_OFF; -} - -static enum led_brightness kblamps_get(struct led_classdev *cdev) -{ - enum led_brightness brightness = LED_OFF; - - if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) - brightness = LED_FULL; - - return brightness; -} - -static enum led_brightness radio_led_get(struct led_classdev *cdev) -{ - enum led_brightness brightness = LED_OFF; - - if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) - brightness = LED_FULL; - - return brightness; -} - -static enum led_brightness eco_led_get(struct led_classdev *cdev) -{ - enum led_brightness brightness = LED_OFF; - - if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) - brightness = LED_FULL; - - return brightness; -} - /* Hardware access for LCD brightness control */ static int set_lcd_level(int level) @@ -739,6 +602,130 @@ static void fujitsu_laptop_platform_remove(void) platform_device_unregister(fujitsu_laptop->pf_device); } +static int logolamp_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int poweron = FUNC_LED_ON, always = FUNC_LED_ON; + int ret; + + if (brightness < LED_HALF) + poweron = FUNC_LED_OFF; + + if (brightness < LED_FULL) + always = FUNC_LED_OFF; + + ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); + if (ret < 0) + return ret; + + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); +} + +static enum led_brightness logolamp_get(struct led_classdev *cdev) +{ + int ret; + + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + if (ret == FUNC_LED_ON) + return LED_FULL; + + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + if (ret == FUNC_LED_ON) + return LED_HALF; + + return LED_OFF; +} + +static struct led_classdev logolamp_led = { + .name = "fujitsu::logolamp", + .brightness_set_blocking = logolamp_set, + .brightness_get = logolamp_get +}; + +static int kblamps_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) + return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + FUNC_LED_ON); + else + return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, + FUNC_LED_OFF); +} + +static enum led_brightness kblamps_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) + brightness = LED_FULL; + + return brightness; +} + +static struct led_classdev kblamps_led = { + .name = "fujitsu::kblamps", + .brightness_set_blocking = kblamps_set, + .brightness_get = kblamps_get +}; + +static int radio_led_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) + return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, + RADIO_LED_ON); + else + return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0); +} + +static enum led_brightness radio_led_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) + brightness = LED_FULL; + + return brightness; +} + +static struct led_classdev radio_led = { + .name = "fujitsu::radio_led", + .brightness_set_blocking = radio_led_set, + .brightness_get = radio_led_get, + .default_trigger = "rfkill-any" +}; + +static int eco_led_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int curr; + + curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); + if (brightness >= LED_FULL) + return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, + curr | ECO_LED_ON); + else + return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, + curr & ~ECO_LED_ON); +} + +static enum led_brightness eco_led_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) + brightness = LED_FULL; + + return brightness; +} + +static struct led_classdev eco_led = { + .name = "fujitsu::eco_led", + .brightness_set_blocking = eco_led_set, + .brightness_get = eco_led_get +}; + static int acpi_fujitsu_laptop_leds_register(void) { int result = 0; From 81f6821f3f7e231b83dca1fb44bf9ddaa3313421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:11 +0200 Subject: [PATCH 081/108] platform/x86: fujitsu-laptop: switch to managed LED class devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_led_classdev_register() for registering LED class devices in order to simplify cleanup and remove LED-related fields with the "_registered" suffix from struct fujitsu_laptop. This also fixes a cleanup bug: with non-managed LED class devices, if e.g. two supported LEDs are detected, the first one gets registered successfully but the second one does not, acpi_fujitsu_laptop_add() will return an error, but the successfully registered LED will never get unregistered. Change the parent device for LED class devices to the FUJ02E3 ACPI device due to this being the logically correct relationship as LED class devices do not depend on any facility provided by the platform device registered by fujitsu-laptop, which was their parent until now. Each managed LED class device is automatically unregistered when the last reference to its parent device is dropped. Taking the parent change described above into account, LED class devices registered by fujitsu-laptop will be unregistered after acpi_fujitsu_laptop_remove() is called. During unregistration, LED brightness is reset to LED_OFF by LED core, so do not set the acpi_handle field of struct fujitsu_laptop to NULL inside acpi_fujitsu_laptop_remove() to prevent call_fext_func() from generating errors upon module removal. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 55 ++++++--------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 22909063e9c4..c3e8df425e23 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -153,10 +153,6 @@ struct fujitsu_laptop { spinlock_t fifo_lock; int flags_supported; int flags_state; - int logolamp_registered; - int kblamps_registered; - int radio_led_registered; - int eco_led_registered; }; static struct fujitsu_laptop *fujitsu_laptop; @@ -726,31 +722,24 @@ static struct led_classdev eco_led = { .brightness_get = eco_led_get }; -static int acpi_fujitsu_laptop_leds_register(void) +static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) { int result = 0; if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &logolamp_led); - if (result == 0) { - fujitsu_laptop->logolamp_registered = 1; - } else { + result = devm_led_classdev_register(&device->dev, + &logolamp_led); + if (result) pr_err("Could not register LED handler for logo lamp, error %i\n", result); - } } if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &kblamps_led); - if (result == 0) { - fujitsu_laptop->kblamps_registered = 1; - } else { + result = devm_led_classdev_register(&device->dev, &kblamps_led); + if (result) pr_err("Could not register LED handler for keyboard lamps, error %i\n", result); - } } /* @@ -760,14 +749,10 @@ static int acpi_fujitsu_laptop_leds_register(void) * that an RF LED is present. */ if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &radio_led); - if (result == 0) { - fujitsu_laptop->radio_led_registered = 1; - } else { + result = devm_led_classdev_register(&device->dev, &radio_led); + if (result) pr_err("Could not register LED handler for radio LED, error %i\n", result); - } } /* Support for eco led is not always signaled in bit corresponding @@ -777,14 +762,10 @@ static int acpi_fujitsu_laptop_leds_register(void) */ if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { - result = led_classdev_register(&fujitsu_laptop->pf_device->dev, - &eco_led); - if (result == 0) { - fujitsu_laptop->eco_led_registered = 1; - } else { + result = devm_led_classdev_register(&device->dev, &eco_led); + if (result) pr_err("Could not register LED handler for eco LED, error %i\n", result); - } } return result; @@ -872,7 +853,7 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) if (error) goto err_free_fifo; - error = acpi_fujitsu_laptop_leds_register(); + error = acpi_fujitsu_laptop_leds_register(device); if (error) goto err_remove_platform_device; @@ -890,24 +871,10 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) { struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device); - if (fujitsu_laptop->logolamp_registered) - led_classdev_unregister(&logolamp_led); - - if (fujitsu_laptop->kblamps_registered) - led_classdev_unregister(&kblamps_led); - - if (fujitsu_laptop->radio_led_registered) - led_classdev_unregister(&radio_led); - - if (fujitsu_laptop->eco_led_registered) - led_classdev_unregister(&eco_led); - fujitsu_laptop_platform_remove(); kfifo_free(&fujitsu_laptop->fifo); - fujitsu_laptop->acpi_handle = NULL; - return 0; } From 30943e1484aab78d83ddfb706bca65c5d8092bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:12 +0200 Subject: [PATCH 082/108] platform/x86: fujitsu-laptop: do not log LED registration failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If acpi_fujitsu_laptop_leds_register() returns an error, the latter will become the return value of acpi_fujitsu_laptop_add(), which in turn will be reported by driver core. Simplify code by replacing pr_err() calls with return statements. Return 0 instead of result when no errors occur in order to make the code easier to read. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index c3e8df425e23..7d0d1e046d21 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -724,22 +724,20 @@ static struct led_classdev eco_led = { static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) { - int result = 0; + int result; if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { result = devm_led_classdev_register(&device->dev, &logolamp_led); if (result) - pr_err("Could not register LED handler for logo lamp, error %i\n", - result); + return result; } if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { result = devm_led_classdev_register(&device->dev, &kblamps_led); if (result) - pr_err("Could not register LED handler for keyboard lamps, error %i\n", - result); + return result; } /* @@ -751,8 +749,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { result = devm_led_classdev_register(&device->dev, &radio_led); if (result) - pr_err("Could not register LED handler for radio LED, error %i\n", - result); + return result; } /* Support for eco led is not always signaled in bit corresponding @@ -764,11 +761,10 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { result = devm_led_classdev_register(&device->dev, &eco_led); if (result) - pr_err("Could not register LED handler for eco LED, error %i\n", - result); + return result; } - return result; + return 0; } static int acpi_fujitsu_laptop_add(struct acpi_device *device) From d1c7073bce91fec5af71a8026636a0735f0c867c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Fri, 7 Apr 2017 15:07:13 +0200 Subject: [PATCH 083/108] platform/x86: fujitsu-laptop: simplify error handling in acpi_fujitsu_laptop_add() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As LED class devices registered by fujitsu-laptop no longer depend on the platform device, two function calls inside acpi_fujitsu_laptop_add() can be rearranged in order to simplify error handling. Signed-off-by: Michał Kępień Reviewed-by: Jonathan Woithe Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/fujitsu-laptop.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 7d0d1e046d21..7f49d92914c9 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -845,18 +845,16 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; } + error = acpi_fujitsu_laptop_leds_register(device); + if (error) + goto err_free_fifo; + error = fujitsu_laptop_platform_add(); if (error) goto err_free_fifo; - error = acpi_fujitsu_laptop_leds_register(device); - if (error) - goto err_remove_platform_device; - return 0; -err_remove_platform_device: - fujitsu_laptop_platform_remove(); err_free_fifo: kfifo_free(&fujitsu_laptop->fifo); err_stop: From d313876925f3e7a480a02773fd333bcab9202d5e Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 19 Apr 2017 22:36:39 +0200 Subject: [PATCH 084/108] platform/x86: hp-wmi: Do not shadow error values All the helper functions (i.e. hp_wmi_dock_state, hp_wmi_tablet_state, ...) using hp_wmi_perform_query to perform an HP WMI query shadow the returned value in case of error. We return -EINVAL only when the HP WMI query returns a positive value (the specific error code) to not mix this up with the actual value returned by the helper function. Suggested-by: Andy Shevchenko Signed-off-by: Carlo Caione Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/hp-wmi.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 5c5efccf9f19..5ca9328ba296 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -248,7 +248,7 @@ static int hp_wmi_display_state(void) int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return state; } @@ -258,7 +258,7 @@ static int hp_wmi_hddtemp_state(void) int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return state; } @@ -268,7 +268,7 @@ static int hp_wmi_als_state(void) int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return state; } @@ -279,7 +279,7 @@ static int hp_wmi_dock_state(void) sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return state & 0x1; } @@ -290,7 +290,7 @@ static int hp_wmi_tablet_state(void) int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return (state & 0x4) ? 1 : 0; } @@ -323,7 +323,7 @@ static int __init hp_wmi_enable_hotkeys(void) int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value, sizeof(value), 0); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return 0; } @@ -336,7 +336,7 @@ static int hp_wmi_set_block(void *data, bool blocked) ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &query, sizeof(query), 0); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return 0; } @@ -428,7 +428,7 @@ static int hp_wmi_post_code_state(void) int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state, sizeof(state), sizeof(state)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return state; } @@ -494,7 +494,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, sizeof(tmp), sizeof(tmp)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return count; } @@ -515,7 +515,7 @@ static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp, sizeof(tmp), sizeof(tmp)); if (ret) - return -EINVAL; + return ret < 0 ? ret : -EINVAL; return count; } From 3bf9310a573d923483526b25c6ec32233748a989 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Thu, 13 Apr 2017 11:05:42 -0700 Subject: [PATCH 085/108] platform/x86: hp-wmi: Cleanup local variable declarations Declare like types on one line. Order declarations in decreasing length where possible. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 5ca9328ba296..e772105ea967 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -346,15 +346,14 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) { + int mask = 0x200 << (r * 8); int wireless = 0; - int mask; + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, sizeof(wireless), sizeof(wireless)); /* TBD: Pass error */ - mask = 0x200 << (r * 8); - if (wireless & mask) return false; else @@ -363,15 +362,14 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) { + int mask = 0x800 << (r * 8); int wireless = 0; - int mask; + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, sizeof(wireless), sizeof(wireless)); /* TBD: Pass error */ - mask = 0x800 << (r * 8); - if (wireless & mask) return false; else @@ -395,8 +393,8 @@ static const struct rfkill_ops hp_wmi_rfkill2_ops = { static int hp_wmi_rfkill2_refresh(void) { - int err, i; struct bios_rfkill2_state state; + int err, i; err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 0, sizeof(state)); @@ -502,9 +500,9 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + long unsigned int tmp2; int ret; u32 tmp; - long unsigned int tmp2; ret = kstrtoul(buf, 10, &tmp2); if (ret || tmp2 != 1) @@ -530,11 +528,11 @@ static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode); static void hp_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; u32 event_id, event_data; + union acpi_object *obj; int key_code = 0, ret; - u32 *location; acpi_status status; + u32 *location; status = wmi_get_event_data(value, &response); if (status != AE_OK) { @@ -645,8 +643,7 @@ static void hp_wmi_notify(u32 value, void *context) static int __init hp_wmi_input_setup(void) { acpi_status status; - int err; - int val; + int err, val; hp_wmi_input_dev = input_allocate_device(); if (!hp_wmi_input_dev) @@ -719,8 +716,7 @@ static void cleanup_sysfs(struct platform_device *device) static int __init hp_wmi_rfkill_setup(struct platform_device *device) { - int err; - int wireless = 0; + int err, wireless = 0; err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, sizeof(wireless), sizeof(wireless)); @@ -804,8 +800,9 @@ register_wifi_error: static int __init hp_wmi_rfkill2_setup(struct platform_device *device) { - int err, i; struct bios_rfkill2_state state; + int err, i; + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 0, sizeof(state)); if (err) @@ -1002,9 +999,9 @@ static struct platform_driver hp_wmi_driver = { static int __init hp_wmi_init(void) { - int err; int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); + int err; if (!bios_capable && !event_capable) return -ENODEV; From d8193cff33906e24ac1830ecb2ca95833d058a3a Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 15:42:01 -0700 Subject: [PATCH 086/108] platform/x86: hp-wmi: Standardize enum usage for constants Use enums consistently throughout the hp-wmi driver for groups of related constants. Use hex and align the assignment within groups. Move the *QUERY constants into an enum, create a new enum defining the READ, WRITE, and ODM constants and use them instead of 0 and 1 at the call sites. Set the command directly instead of using the ternary operator since both 1 and 3 as previously documented would result in the command being set to 0x2. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 132 +++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 58 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index e772105ea967..2073f1e97970 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -48,41 +48,29 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" -#define HPWMI_DISPLAY_QUERY 0x1 -#define HPWMI_HDDTEMP_QUERY 0x2 -#define HPWMI_ALS_QUERY 0x3 -#define HPWMI_HARDWARE_QUERY 0x4 -#define HPWMI_WIRELESS_QUERY 0x5 -#define HPWMI_BIOS_QUERY 0x9 -#define HPWMI_FEATURE_QUERY 0xb -#define HPWMI_HOTKEY_QUERY 0xc -#define HPWMI_FEATURE2_QUERY 0xd -#define HPWMI_WIRELESS2_QUERY 0x1b -#define HPWMI_POSTCODEERROR_QUERY 0x2a - enum hp_wmi_radio { - HPWMI_WIFI = 0, - HPWMI_BLUETOOTH = 1, - HPWMI_WWAN = 2, - HPWMI_GPS = 3, + HPWMI_WIFI = 0x0, + HPWMI_BLUETOOTH = 0x1, + HPWMI_WWAN = 0x2, + HPWMI_GPS = 0x3, }; enum hp_wmi_event_ids { - HPWMI_DOCK_EVENT = 1, - HPWMI_PARK_HDD = 2, - HPWMI_SMART_ADAPTER = 3, - HPWMI_BEZEL_BUTTON = 4, - HPWMI_WIRELESS = 5, - HPWMI_CPU_BATTERY_THROTTLE = 6, - HPWMI_LOCK_SWITCH = 7, - HPWMI_LID_SWITCH = 8, - HPWMI_SCREEN_ROTATION = 9, - HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A, - HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B, - HPWMI_PROXIMITY_SENSOR = 0x0C, - HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, - HPWMI_PEAKSHIFT_PERIOD = 0x0F, - HPWMI_BATTERY_CHARGE_PERIOD = 0x10, + HPWMI_DOCK_EVENT = 0x01, + HPWMI_PARK_HDD = 0x02, + HPWMI_SMART_ADAPTER = 0x03, + HPWMI_BEZEL_BUTTON = 0x04, + HPWMI_WIRELESS = 0x05, + HPWMI_CPU_BATTERY_THROTTLE = 0x06, + HPWMI_LOCK_SWITCH = 0x07, + HPWMI_LID_SWITCH = 0x08, + HPWMI_SCREEN_ROTATION = 0x09, + HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A, + HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B, + HPWMI_PROXIMITY_SENSOR = 0x0C, + HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, + HPWMI_PEAKSHIFT_PERIOD = 0x0F, + HPWMI_BATTERY_CHARGE_PERIOD = 0x10, }; struct bios_args { @@ -93,6 +81,34 @@ struct bios_args { u32 data; }; +enum hp_wmi_commandtype { + HPWMI_DISPLAY_QUERY = 0x01, + HPWMI_HDDTEMP_QUERY = 0x02, + HPWMI_ALS_QUERY = 0x03, + HPWMI_HARDWARE_QUERY = 0x04, + HPWMI_WIRELESS_QUERY = 0x05, + HPWMI_BATTERY_QUERY = 0x07, + HPWMI_BIOS_QUERY = 0x09, + HPWMI_FEATURE_QUERY = 0x0b, + HPWMI_HOTKEY_QUERY = 0x0c, + HPWMI_FEATURE2_QUERY = 0x0d, + HPWMI_WIRELESS2_QUERY = 0x1b, + HPWMI_POSTCODEERROR_QUERY = 0x2a, +}; + +enum hp_wmi_command { + HPWMI_READ = 0x01, + HPWMI_WRITE = 0x02, + HPWMI_ODM = 0x03, +}; + +#define BIOS_ARGS_INIT(write, ctype, size) \ + (struct bios_args) { .signature = 0x55434553, \ + .command = (write) ? 0x2 : 0x1, \ + .commandtype = (ctype), \ + .datasize = (size), \ + .data = 0 } + struct bios_return { u32 sigpass; u32 return_code; @@ -170,8 +186,8 @@ static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; /* * hp_wmi_perform_query * - * query: The commandtype -> What should be queried - * write: The command -> 0 read, 1 write, 3 ODM specific + * query: The commandtype (enum hp_wmi_commandtype) + * write: The command (enum hp_wmi_command) * buffer: Buffer used as input and/or output * insize: Size of input buffer * outsize: Size of output buffer @@ -182,20 +198,20 @@ static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; * -EINVAL if the output buffer size exceeds buffersize * * Note: The buffersize must at least be the maximum of the input and output - * size. E.g. Battery info query (0x7) is defined to have 1 byte input + * size. E.g. Battery info query is defined to have 1 byte input * and 128 byte output. The caller would do: * buffer = kzalloc(128, GFP_KERNEL); - * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) + * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128) */ -static int hp_wmi_perform_query(int query, int write, void *buffer, - int insize, int outsize) +static int hp_wmi_perform_query(int query, enum hp_wmi_command command, + void *buffer, int insize, int outsize) { struct bios_return *bios_return; int actual_outsize; union acpi_object *obj; struct bios_args args = { .signature = 0x55434553, - .command = write ? 0x2 : 0x1, + .command = command, .commandtype = query, .datasize = insize, .data = 0, @@ -245,7 +261,7 @@ static int hp_wmi_perform_query(int query, int write, void *buffer, static int hp_wmi_display_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -255,7 +271,7 @@ static int hp_wmi_display_state(void) static int hp_wmi_hddtemp_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -265,7 +281,7 @@ static int hp_wmi_hddtemp_state(void) static int hp_wmi_als_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -275,7 +291,7 @@ static int hp_wmi_als_state(void) static int hp_wmi_dock_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) @@ -287,7 +303,7 @@ static int hp_wmi_dock_state(void) static int hp_wmi_tablet_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -298,7 +314,7 @@ static int hp_wmi_tablet_state(void) static int __init hp_wmi_bios_2008_later(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (!ret) return 1; @@ -309,7 +325,7 @@ static int __init hp_wmi_bios_2008_later(void) static int __init hp_wmi_bios_2009_later(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (!ret) return 1; @@ -320,7 +336,7 @@ static int __init hp_wmi_bios_2009_later(void) static int __init hp_wmi_enable_hotkeys(void) { int value = 0x6e; - int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value, + int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value, sizeof(value), 0); if (ret) return ret < 0 ? ret : -EINVAL; @@ -333,7 +349,7 @@ static int hp_wmi_set_block(void *data, bool blocked) int query = BIT(r + 8) | ((!blocked) << r); int ret; - ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, + ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &query, sizeof(query), 0); if (ret) return ret < 0 ? ret : -EINVAL; @@ -349,7 +365,7 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) int mask = 0x200 << (r * 8); int wireless = 0; - hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, &wireless, sizeof(wireless), sizeof(wireless)); /* TBD: Pass error */ @@ -365,7 +381,7 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) int mask = 0x800 << (r * 8); int wireless = 0; - hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, &wireless, sizeof(wireless), sizeof(wireless)); /* TBD: Pass error */ @@ -381,7 +397,7 @@ static int hp_wmi_rfkill2_set_block(void *data, bool blocked) int rfkill_id = (int)(long)data; char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; - if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, + if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE, buffer, sizeof(buffer), 0)) return -EINVAL; return 0; @@ -396,7 +412,7 @@ static int hp_wmi_rfkill2_refresh(void) struct bios_rfkill2_state state; int err, i; - err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 0, sizeof(state)); if (err) return err; @@ -423,7 +439,7 @@ static int hp_wmi_rfkill2_refresh(void) static int hp_wmi_post_code_state(void) { int state = 0; - int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state, + int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_READ, &state, sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -489,7 +505,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u32 tmp = simple_strtoul(buf, NULL, 10); - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp, sizeof(tmp), sizeof(tmp)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -510,7 +526,7 @@ static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, /* Clear the POST error code. It is kept until until cleared. */ tmp = (u32) tmp2; - ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp, + ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp, sizeof(tmp), sizeof(tmp)); if (ret) return ret < 0 ? ret : -EINVAL; @@ -583,7 +599,7 @@ static void hp_wmi_notify(u32 value, void *context) case HPWMI_SMART_ADAPTER: break; case HPWMI_BEZEL_BUTTON: - ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, + ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, HPWMI_READ, &key_code, sizeof(key_code), sizeof(key_code)); @@ -718,12 +734,12 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) { int err, wireless = 0; - err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, &wireless, sizeof(wireless), sizeof(wireless)); if (err) return err; - err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless, + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless, sizeof(wireless), 0); if (err) return err; @@ -803,7 +819,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device) struct bios_rfkill2_state state; int err, i; - err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 0, sizeof(state)); if (err) return err; From ea621d9fe372b4a6ca2b513c13a37c24a668c35f Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 16:26:06 -0700 Subject: [PATCH 087/108] platform/x86: hp-wmi: Refactor redundant HPWMI_READ functions Several functions perform the same WMI read int with different query arguments. Refactor this into a single hp_wmi_read_int function. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 82 ++++++++++------------------------- 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 2073f1e97970..eb6d0a0e1392 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -258,55 +258,35 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, return 0; } -static int hp_wmi_display_state(void) +static int hp_wmi_read_int(int query) { - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); - if (ret) - return ret < 0 ? ret : -EINVAL; - return state; -} + int val = 0, ret; -static int hp_wmi_hddtemp_state(void) -{ - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); - if (ret) - return ret < 0 ? ret : -EINVAL; - return state; -} + ret = hp_wmi_perform_query(query, HPWMI_READ, &val, + sizeof(val), sizeof(val)); -static int hp_wmi_als_state(void) -{ - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); if (ret) return ret < 0 ? ret : -EINVAL; - return state; + + return val; } static int hp_wmi_dock_state(void) { - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); + int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); - if (ret) - return ret < 0 ? ret : -EINVAL; + if (state < 0) + return state; return state & 0x1; } static int hp_wmi_tablet_state(void) { - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); - if (ret) - return ret < 0 ? ret : -EINVAL; + int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); + + if (state < 0) + return state; return (state & 0x4) ? 1 : 0; } @@ -436,20 +416,10 @@ static int hp_wmi_rfkill2_refresh(void) return 0; } -static int hp_wmi_post_code_state(void) -{ - int state = 0; - int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_READ, &state, - sizeof(state), sizeof(state)); - if (ret) - return ret < 0 ? ret : -EINVAL; - return state; -} - static ssize_t show_display(struct device *dev, struct device_attribute *attr, char *buf) { - int value = hp_wmi_display_state(); + int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); if (value < 0) return -EINVAL; return sprintf(buf, "%d\n", value); @@ -458,7 +428,7 @@ static ssize_t show_display(struct device *dev, struct device_attribute *attr, static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, char *buf) { - int value = hp_wmi_hddtemp_state(); + int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); if (value < 0) return -EINVAL; return sprintf(buf, "%d\n", value); @@ -467,7 +437,7 @@ static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, static ssize_t show_als(struct device *dev, struct device_attribute *attr, char *buf) { - int value = hp_wmi_als_state(); + int value = hp_wmi_read_int(HPWMI_ALS_QUERY); if (value < 0) return -EINVAL; return sprintf(buf, "%d\n", value); @@ -495,7 +465,7 @@ static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, char *buf) { /* Get the POST error code of previous boot failure. */ - int value = hp_wmi_post_code_state(); + int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); if (value < 0) return -EINVAL; return sprintf(buf, "0x%x\n", value); @@ -546,9 +516,9 @@ static void hp_wmi_notify(u32 value, void *context) struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; u32 event_id, event_data; union acpi_object *obj; - int key_code = 0, ret; acpi_status status; u32 *location; + int key_code; status = wmi_get_event_data(value, &response); if (status != AE_OK) { @@ -599,11 +569,8 @@ static void hp_wmi_notify(u32 value, void *context) case HPWMI_SMART_ADAPTER: break; case HPWMI_BEZEL_BUTTON: - ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, HPWMI_READ, - &key_code, - sizeof(key_code), - sizeof(key_code)); - if (ret) + key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY); + if (key_code < 0) break; if (!sparse_keymap_report_event(hp_wmi_input_dev, @@ -732,12 +699,11 @@ static void cleanup_sysfs(struct platform_device *device) static int __init hp_wmi_rfkill_setup(struct platform_device *device) { - int err, wireless = 0; + int err, wireless; - err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, &wireless, - sizeof(wireless), sizeof(wireless)); - if (err) - return err; + wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); + if (wireless) + return wireless; err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless, sizeof(wireless), 0); From c7ef144c12033052c956ca9d80b2dfc19c73d939 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 18:00:01 -0700 Subject: [PATCH 088/108] platform/x86: hp-wmi: Cleanup wireless get_(hw|sw)state functions Use the new hp_wmi_read_int() function and add a WARN_ONCE() to the TBD regarding passing the error through. These are used in a null return function unfortunately. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index eb6d0a0e1392..577805987d35 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -343,33 +343,25 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) { int mask = 0x200 << (r * 8); - int wireless = 0; - hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, - &wireless, sizeof(wireless), - sizeof(wireless)); + int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); + /* TBD: Pass error */ + WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY"); - if (wireless & mask) - return false; - else - return true; + return !(wireless & mask); } static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) { int mask = 0x800 << (r * 8); - int wireless = 0; - hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_READ, - &wireless, sizeof(wireless), - sizeof(wireless)); + int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); + /* TBD: Pass error */ + WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY"); - if (wireless & mask) - return false; - else - return true; + return !(wireless & mask); } static int hp_wmi_rfkill2_set_block(void *data, bool blocked) From f9cf3b2880cc41ec2b44aa24fa156bffe934f9c7 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 17:03:38 -0700 Subject: [PATCH 089/108] platform/x86: hp-wmi: Refactor dock and tablet state fetchers Both dock and tablet use the HPWMI_HARDWARE_QUERY, but require different masks. Rather than using two functions with magic masks, define the masks, and use a common accessor. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 577805987d35..9b71829843ad 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -102,6 +102,11 @@ enum hp_wmi_command { HPWMI_ODM = 0x03, }; +enum hp_wmi_hardware_mask { + HPWMI_DOCK_MASK = 0x01, + HPWMI_TABLET_MASK = 0x04, +}; + #define BIOS_ARGS_INIT(write, ctype, size) \ (struct bios_args) { .signature = 0x55434553, \ .command = (write) ? 0x2 : 0x1, \ @@ -271,7 +276,7 @@ static int hp_wmi_read_int(int query) return val; } -static int hp_wmi_dock_state(void) +static int hp_wmi_hw_state(int mask) { int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); @@ -281,16 +286,6 @@ static int hp_wmi_dock_state(void) return state & 0x1; } -static int hp_wmi_tablet_state(void) -{ - int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); - - if (state < 0) - return state; - - return (state & 0x4) ? 1 : 0; -} - static int __init hp_wmi_bios_2008_later(void) { int state = 0; @@ -438,7 +433,7 @@ static ssize_t show_als(struct device *dev, struct device_attribute *attr, static ssize_t show_dock(struct device *dev, struct device_attribute *attr, char *buf) { - int value = hp_wmi_dock_state(); + int value = hp_wmi_hw_state(HPWMI_DOCK_MASK); if (value < 0) return -EINVAL; return sprintf(buf, "%d\n", value); @@ -447,7 +442,7 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr, static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, char *buf) { - int value = hp_wmi_tablet_state(); + int value = hp_wmi_hw_state(HPWMI_TABLET_MASK); if (value < 0) return -EINVAL; return sprintf(buf, "%d\n", value); @@ -550,10 +545,10 @@ static void hp_wmi_notify(u32 value, void *context) case HPWMI_DOCK_EVENT: if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) input_report_switch(hp_wmi_input_dev, SW_DOCK, - hp_wmi_dock_state()); + hp_wmi_hw_state(HPWMI_DOCK_MASK)); if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, - hp_wmi_tablet_state()); + hp_wmi_hw_state(HPWMI_TABLET_MASK)); input_sync(hp_wmi_input_dev); break; case HPWMI_PARK_HDD: @@ -631,14 +626,14 @@ static int __init hp_wmi_input_setup(void) __set_bit(EV_SW, hp_wmi_input_dev->evbit); /* Dock */ - val = hp_wmi_dock_state(); + val = hp_wmi_hw_state(HPWMI_DOCK_MASK); if (!(val < 0)) { __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); input_report_switch(hp_wmi_input_dev, SW_DOCK, val); } /* Tablet mode */ - val = hp_wmi_tablet_state(); + val = hp_wmi_hw_state(HPWMI_TABLET_MASK); if (!(val < 0)) { __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val); @@ -932,10 +927,10 @@ static int hp_wmi_resume_handler(struct device *device) if (hp_wmi_input_dev) { if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) input_report_switch(hp_wmi_input_dev, SW_DOCK, - hp_wmi_dock_state()); + hp_wmi_hw_state(HPWMI_DOCK_MASK)); if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, - hp_wmi_tablet_state()); + hp_wmi_hw_state(HPWMI_TABLET_MASK)); input_sync(hp_wmi_input_dev); } From c21ee12f460c33fcc12fe162c9ab98f3c58073aa Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 17:26:38 -0700 Subject: [PATCH 090/108] platform/x86: hp-wmi: Use DEVICE_ATTR_(RO|RW) helper macros Use the DEVICE_ATTR_(RO|RW) macros, ranaming the show and store functions accordingly. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 9b71829843ad..d1e3af23a147 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -403,7 +403,7 @@ static int hp_wmi_rfkill2_refresh(void) return 0; } -static ssize_t show_display(struct device *dev, struct device_attribute *attr, +static ssize_t display_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); @@ -412,7 +412,7 @@ static ssize_t show_display(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } -static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, +static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); @@ -421,7 +421,7 @@ static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } -static ssize_t show_als(struct device *dev, struct device_attribute *attr, +static ssize_t als_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_ALS_QUERY); @@ -430,7 +430,7 @@ static ssize_t show_als(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } -static ssize_t show_dock(struct device *dev, struct device_attribute *attr, +static ssize_t dock_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_hw_state(HPWMI_DOCK_MASK); @@ -439,8 +439,8 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } -static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t tablet_show(struct device *dev, struct device_attribute *attr, + char *buf) { int value = hp_wmi_hw_state(HPWMI_TABLET_MASK); if (value < 0) @@ -448,8 +448,8 @@ static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", value); } -static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t postcode_show(struct device *dev, struct device_attribute *attr, + char *buf) { /* Get the POST error code of previous boot failure. */ int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); @@ -458,8 +458,8 @@ static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, return sprintf(buf, "0x%x\n", value); } -static ssize_t set_als(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t als_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { u32 tmp = simple_strtoul(buf, NULL, 10); int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp, @@ -470,8 +470,8 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t postcode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { long unsigned int tmp2; int ret; @@ -491,12 +491,12 @@ static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); -static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); -static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); -static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); -static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); -static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode); +static DEVICE_ATTR_RO(display); +static DEVICE_ATTR_RO(hddtemp); +static DEVICE_ATTR_RW(als); +static DEVICE_ATTR_RO(dock); +static DEVICE_ATTR_RO(tablet); +static DEVICE_ATTR_RW(postcode); static void hp_wmi_notify(u32 value, void *context) { From a055f9ecb5b4d0cb8b33ba664363a2ed7804a6c7 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 18:11:33 -0700 Subject: [PATCH 091/108] platform/x86: hp-wmi: Do not shadow errors in sysfs show functions The new hp_wmi_read_int function returns a negative value in case of error, pass this on directly rather than always replacing it with -EINVAL. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index d1e3af23a147..e685018670c0 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -408,7 +408,7 @@ static ssize_t display_show(struct device *dev, struct device_attribute *attr, { int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "%d\n", value); } @@ -417,7 +417,7 @@ static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr, { int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "%d\n", value); } @@ -426,7 +426,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr, { int value = hp_wmi_read_int(HPWMI_ALS_QUERY); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "%d\n", value); } @@ -435,7 +435,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr, { int value = hp_wmi_hw_state(HPWMI_DOCK_MASK); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "%d\n", value); } @@ -444,7 +444,7 @@ static ssize_t tablet_show(struct device *dev, struct device_attribute *attr, { int value = hp_wmi_hw_state(HPWMI_TABLET_MASK); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "%d\n", value); } @@ -454,7 +454,7 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr, /* Get the POST error code of previous boot failure. */ int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); if (value < 0) - return -EINVAL; + return value; return sprintf(buf, "0x%x\n", value); } From 527376c89caf59537d8e5c9f14d7caa940bd563b Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Wed, 19 Apr 2017 18:54:45 -0700 Subject: [PATCH 092/108] platform/x86: hp-wmi: Cleanup exit paths Several exit paths were more complex than they needed to be. Remove superfluous conditionals, use labels common cleanup, do not shadow negative error codes. Signed-off-by: Darren Hart (VMware) Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko --- drivers/platform/x86/hp-wmi.c | 63 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index e685018670c0..0df4209648d1 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -223,7 +223,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, }; struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - u32 rc; + int ret = 0; if (WARN_ON(insize > sizeof(args.data))) return -EINVAL; @@ -235,32 +235,32 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command, if (!obj) return -EINVAL; - else if (obj->type != ACPI_TYPE_BUFFER) { - kfree(obj); - return -EINVAL; + + if (obj->type != ACPI_TYPE_BUFFER) { + ret = -EINVAL; + goto out_free; } bios_return = (struct bios_return *)obj->buffer.pointer; - rc = bios_return->return_code; + ret = bios_return->return_code; - if (rc) { - if (rc != HPWMI_RET_UNKNOWN_CMDTYPE) - pr_warn("query 0x%x returned error 0x%x\n", query, rc); - kfree(obj); - return rc; + if (ret) { + if (ret != HPWMI_RET_UNKNOWN_CMDTYPE) + pr_warn("query 0x%x returned error 0x%x\n", query, ret); + goto out_free; } - if (!outsize) { - /* ignore output data */ - kfree(obj); - return 0; - } + /* Ignore output data of zero size */ + if (!outsize) + goto out_free; actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); memset(buffer + actual_outsize, 0, outsize - actual_outsize); + +out_free: kfree(obj); - return 0; + return ret; } static int hp_wmi_read_int(int query) @@ -313,9 +313,8 @@ static int __init hp_wmi_enable_hotkeys(void) int value = 0x6e; int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value, sizeof(value), 0); - if (ret) - return ret < 0 ? ret : -EINVAL; - return 0; + + return ret <= 0 ? ret : -EINVAL; } static int hp_wmi_set_block(void *data, bool blocked) @@ -326,9 +325,8 @@ static int hp_wmi_set_block(void *data, bool blocked) ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &query, sizeof(query), 0); - if (ret) - return ret < 0 ? ret : -EINVAL; - return 0; + + return ret <= 0 ? ret : -EINVAL; } static const struct rfkill_ops hp_wmi_rfkill_ops = { @@ -363,11 +361,12 @@ static int hp_wmi_rfkill2_set_block(void *data, bool blocked) { int rfkill_id = (int)(long)data; char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; + int ret; - if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE, - buffer, sizeof(buffer), 0)) - return -EINVAL; - return 0; + ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE, + buffer, sizeof(buffer), 0); + + return ret <= 0 ? ret : -EINVAL; } static const struct rfkill_ops hp_wmi_rfkill2_ops = { @@ -478,13 +477,17 @@ static ssize_t postcode_store(struct device *dev, struct device_attribute *attr, u32 tmp; ret = kstrtoul(buf, 10, &tmp2); - if (ret || tmp2 != 1) - return -EINVAL; + if (!ret && tmp2 != 1) + ret = -EINVAL; + if (ret) + goto out; /* Clear the POST error code. It is kept until until cleared. */ tmp = (u32) tmp2; ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp, sizeof(tmp), sizeof(tmp)); + +out: if (ret) return ret < 0 ? ret : -EINVAL; @@ -689,7 +692,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) int err, wireless; wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); - if (wireless) + if (wireless < 0) return wireless; err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless, @@ -775,7 +778,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device) err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 0, sizeof(state)); if (err) - return err; + return err < 0 ? err : -EINVAL; if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { pr_warn("unable to parse 0x1b query output\n"); From 58688a7525b6b4224347f5d1c16d92e4a3db2559 Mon Sep 17 00:00:00 2001 From: Tobias Regnery Date: Thu, 20 Apr 2017 14:51:59 +0200 Subject: [PATCH 093/108] platform/x86: INT33FE: add i2c dependency With CONFIG_I2C=m and CONFIG_INTEL_CHT_INT33FE=y we see the following link errors: drivers/built-in.o: In function 'cht_int33fe_remove': intel_cht_int33fe.c:(.text+0x391f6e): undefined reference to 'i2c_unregister_device' intel_cht_int33fe.c:(.text+0x391f76): undefined reference to 'i2c_unregister_device' intel_cht_int33fe.c:(.text+0x391f7d): undefined reference to 'i2c_unregister_device' drivers/built-in.o: In function 'cht_int33fe_probe': intel_cht_int33fe.c:(.text+0x392147): undefined reference to 'i2c_acpi_new_device' intel_cht_int33fe.c:(.text+0x392185): undefined reference to 'i2c_acpi_new_device' intel_cht_int33fe.c:(.text+0x3921bd): undefined reference to 'i2c_acpi_new_device' intel_cht_int33fe.c:(.text+0x3921d9): undefined reference to 'i2c_unregister_device' intel_cht_int33fe.c:(.text+0x3921e8): undefined reference to 'i2c_unregister_device' drivers/built-in.o: In function 'cht_int33fe_driver_init': intel_cht_int33fe.c:(.init.text+0x2386d): undefined reference to 'i2c_register_driver' drivers/built-in.o: In function 'cht_int33fe_driver_exit': intel_cht_int33fe.c:(.exit.text+0x206e): undefined reference to 'i2c_del_driver' Fix this by adding a kconfig dependency on the I2C subsystem. Fixes: 1cd706df8a9c ("platform/x86: Add Intel Cherry Trail ACPI INT33FE device driver") Signed-off-by: Tobias Regnery Reviewed-by: Hans de Goede Signed-off-by: Darren Hart (VMware) --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 687f07872ae5..9e5b2c2a50d6 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -783,7 +783,7 @@ config ACPI_CMPC config INTEL_CHT_INT33FE tristate "Intel Cherry Trail ACPI INT33FE Driver" - depends on X86 && ACPI + depends on X86 && ACPI && I2C ---help--- This driver add support for the INT33FE ACPI device found on some Intel Cherry Trail devices. From 8d9e29972836b75eb74f533594999500a4c7cc19 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 24 Apr 2017 23:35:21 +0200 Subject: [PATCH 094/108] platform/x86: intel-vbtn: add volume up and down Tested on HP Elite X2 1012 G1. Matches event report of Lenovo Helix 2 (https://www.spinics.net/lists/ibm-acpi-devel/msg03982.html). Signed-off-by: Maarten Maathuis [andy: fixed indentation of comments and massaged title of the change] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 554e82ebe83c..c2035e121ac2 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -37,6 +37,10 @@ static const struct acpi_device_id intel_vbtn_ids[] = { static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC0, { KEY_POWER } }, /* power key press */ { KE_KEY, 0xC1, { KEY_POWER } }, /* power key release */ + { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ + { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ + { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ + { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ { KE_END }, }; From 0b8dba15e909990e275631fa57255e74bbc766fc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 19 Apr 2017 22:27:31 +0300 Subject: [PATCH 095/108] platform/x86: hp-wireless: reuse module_acpi_driver There is a macro to register and unregister modules in simple cases, Let's use it and clean up the driver. Cc: Alex Hung Signed-off-by: Andy Shevchenko Reviewed-by: Darren Hart (VMware) --- drivers/platform/x86/hp-wireless.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c index d860ea0d0e60..d6ea5e998fb8 100644 --- a/drivers/platform/x86/hp-wireless.c +++ b/drivers/platform/x86/hp-wireless.c @@ -110,21 +110,4 @@ static struct acpi_driver hpwl_driver = { }, }; -static int __init hpwl_init(void) -{ - int err; - - err = acpi_bus_register_driver(&hpwl_driver); - if (err) - pr_err("Unable to register HP wireless control driver.\n"); - - return err; -} - -static void __exit hpwl_exit(void) -{ - acpi_bus_unregister_driver(&hpwl_driver); -} - -module_init(hpwl_init); -module_exit(hpwl_exit); +module_acpi_driver(hpwl_driver); From 90a864b965e452ee2a15ed7b13f47142aeb4a40b Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 9 Mar 2017 11:19:56 +0530 Subject: [PATCH 096/108] platform/x86: dell-laptop: Handle return error form dell_get_intensity. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here, This patch is to handle a return error from dell_get_intensity. This change is done using Coccinelle. Signed-off-by: Arvind Yadav Acked-by: Pali Rohár Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 47fe6264cadf..296cb9632a71 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -2151,11 +2151,17 @@ static int __init dell_init(void) dell_backlight_device->props.brightness = dell_get_intensity(dell_backlight_device); + if (dell_backlight_device->props.brightness < 0) { + ret = dell_backlight_device->props.brightness; + goto fail_get_brightness; + } backlight_update_status(dell_backlight_device); } return 0; +fail_get_brightness: + backlight_device_unregister(dell_backlight_device); fail_backlight: dell_cleanup_rfkill(); fail_rfkill: From 9216e0dcb5533a999d544d0af8661118e0588e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sun, 23 Apr 2017 21:40:47 +0200 Subject: [PATCH 097/108] platform/x86: dell-laptop: Add keyboard backlight timeout AC settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When changing keyboard backlight state on new Dell laptops, firmware expects a new timeout AC value filled in Set New State SMBIOS call. Without it any change of keyboard backlight state on new Dell laptops fails. And user can see following error message in dmesg: dell_laptop: Setting old previous keyboard state failed leds dell::kbd_backlight: Setting an LED's brightness failed (-6) This patch adds support for retrieving current timeout AC values and also updating them. Current timeout value in sysfs is displayed based on current AC status, like current display brightness value. Detection if Dell laptop supports or not new timeout AC settings is done by checking existence of Keyboard Backlight with AC SMBIOS token (0x0451). Signed-off-by: Pali Rohár Acked-by: Mario Limonciello Tested-by: Arcadiy Ivanov [andy: fixed merge conflict with defined constants] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-laptop.c | 59 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 296cb9632a71..ec202094bd50 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -45,6 +45,7 @@ #define KBD_LED_AUTO_100_TOKEN 0x02F6 #define GLOBAL_MIC_MUTE_ENABLE 0x0364 #define GLOBAL_MIC_MUTE_DISABLE 0x0365 +#define KBD_LED_AC_TOKEN 0x0451 struct quirk_entry { u8 touchpad_led; @@ -1027,7 +1028,7 @@ static void touchpad_led_exit(void) * bit 2 Pointing stick * bit 3 Any mouse * bits 4-7 Reserved for future use - * cbRES2, byte3 Current Timeout + * cbRES2, byte3 Current Timeout on battery * bits 7:6 Timeout units indicator: * 00b Seconds * 01b Minutes @@ -1039,6 +1040,15 @@ static void touchpad_led_exit(void) * cbRES3, byte0 Current setting of ALS value that turns the light on or off. * cbRES3, byte1 Current ALS reading * cbRES3, byte2 Current keyboard light level. + * cbRES3, byte3 Current timeout on AC Power + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * Bits 5:0 Timeout value (0-63) in sec/min/hr/day + * NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2 + * are set upon return from the upon return from the [Get Feature information] call. * * cbArg1 0x2 = Set New State * cbRES1 Standard return codes (0, -1, -2) @@ -1061,7 +1071,7 @@ static void touchpad_led_exit(void) * bit 2 Pointing stick * bit 3 Any mouse * bits 4-7 Reserved for future use - * cbArg2, byte3 Desired Timeout + * cbArg2, byte3 Desired Timeout on battery * bits 7:6 Timeout units indicator: * 00b Seconds * 01b Minutes @@ -1070,6 +1080,13 @@ static void touchpad_led_exit(void) * bits 5:0 Timeout value (0-63) in sec/min/hr/day * cbArg3, byte0 Desired setting of ALS value that turns the light on or off. * cbArg3, byte2 Desired keyboard light level. + * cbArg3, byte3 Desired Timeout on AC power + * bits 7:6 Timeout units indicator: + * 00b Seconds + * 01b Minutes + * 10b Hours + * 11b Days + * bits 5:0 Timeout value (0-63) in sec/min/hr/day */ @@ -1115,6 +1132,8 @@ struct kbd_state { u8 triggers; u8 timeout_value; u8 timeout_unit; + u8 timeout_value_ac; + u8 timeout_unit_ac; u8 als_setting; u8 als_value; u8 level; @@ -1134,6 +1153,7 @@ static u16 kbd_token_bits; static struct kbd_info kbd_info; static bool kbd_als_supported; static bool kbd_triggers_supported; +static bool kbd_timeout_ac_supported; static u8 kbd_mode_levels[16]; static int kbd_mode_levels_count; @@ -1273,6 +1293,8 @@ static int kbd_get_state(struct kbd_state *state) state->als_setting = buffer->output[2] & 0xFF; state->als_value = (buffer->output[2] >> 8) & 0xFF; state->level = (buffer->output[2] >> 16) & 0xFF; + state->timeout_value_ac = (buffer->output[2] >> 24) & 0x3F; + state->timeout_unit_ac = (buffer->output[2] >> 30) & 0x3; out: dell_smbios_release_buffer(); @@ -1292,6 +1314,8 @@ 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; + buffer->input[2] |= (state->timeout_value_ac & 0x3F) << 24; + buffer->input[2] |= (state->timeout_unit_ac & 0x3) << 30; dell_smbios_send_request(4, 11); ret = buffer->output[0]; dell_smbios_release_buffer(); @@ -1398,6 +1422,13 @@ static inline int kbd_init_info(void) if (ret) return ret; + /* NOTE: Old models without KBD_LED_AC_TOKEN token supports only one + * timeout value which is shared for both battery and AC power + * settings. So do not try to set AC values on old models. + */ + if (dell_smbios_find_token(KBD_LED_AC_TOKEN)) + kbd_timeout_ac_supported = true; + kbd_get_state(&state); /* NOTE: timeout value is stored in 6 bits so max value is 63 */ @@ -1579,8 +1610,14 @@ static ssize_t kbd_led_timeout_store(struct device *dev, goto out; new_state = state; - new_state.timeout_value = value; - new_state.timeout_unit = unit; + + if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) { + new_state.timeout_value_ac = value; + new_state.timeout_unit_ac = unit; + } else { + new_state.timeout_value = value; + new_state.timeout_unit = unit; + } ret = kbd_set_state_safe(&new_state, &state); if (ret) @@ -1596,16 +1633,26 @@ static ssize_t kbd_led_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct kbd_state state; + int value; int ret; int len; + u8 unit; ret = kbd_get_state(&state); if (ret) return ret; - len = sprintf(buf, "%d", state.timeout_value); + if (kbd_timeout_ac_supported && power_supply_is_system_supplied() > 0) { + value = state.timeout_value_ac; + unit = state.timeout_unit_ac; + } else { + value = state.timeout_value; + unit = state.timeout_unit; + } - switch (state.timeout_unit) { + len = sprintf(buf, "%d", value); + + switch (unit) { case KBD_TIMEOUT_SECONDS: return len + sprintf(buf+len, "s\n"); case KBD_TIMEOUT_MINUTES: From e6749c89b4b0acaeddf4909eb75b7f6c8a4c15b2 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:16 -0700 Subject: [PATCH 098/108] platform/x86: intel_pmc_ipc: fix gcr offset According to Broxton APL spec, PMC MIMO resources for Global Control Registers(GCR) are located at 4K(0x1000) offset from IPC base address. In this driver, PLAT_RESOURCE_GCR_OFFSET macro defines the offset of GCR region base address from IPC base address and its current value of 0x1008 is incorrect because it points to location for PMC_CFG register and not the GCR base address itself. GCR Base = IPC1 Base + 0x1000. This patch fixes this offset issue. Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 0651d47b8eeb..0a3359240227 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -82,7 +82,7 @@ /* exported resources from IFWI */ #define PLAT_RESOURCE_IPC_INDEX 0 #define PLAT_RESOURCE_IPC_SIZE 0x1000 -#define PLAT_RESOURCE_GCR_OFFSET 0x1008 +#define PLAT_RESOURCE_GCR_OFFSET 0x1000 #define PLAT_RESOURCE_GCR_SIZE 0x1000 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 From 496702068597ff29092e724301f77b91864454b3 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:17 -0700 Subject: [PATCH 099/108] platform/x86: intel_pmc_ipc: Add pmc gcr read/write/update api's This patch adds API's to read/write/update PMC GC registers. PMC dependent devices like iTCO_wdt, Telemetry has requirement to acces GCR registers. These API's can be used for this purpose. Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel_pmc_ipc.h | 21 +++++ drivers/platform/x86/intel_pmc_ipc.c | 115 +++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h index 4291b6a5ddf7..8402efef10ad 100644 --- a/arch/x86/include/asm/intel_pmc_ipc.h +++ b/arch/x86/include/asm/intel_pmc_ipc.h @@ -23,6 +23,9 @@ #define IPC_ERR_EMSECURITY 6 #define IPC_ERR_UNSIGNEDKERNEL 7 +/* GCR reg offsets from gcr base*/ +#define PMC_GCR_PMC_CFG_REG 0x08 + #if IS_ENABLED(CONFIG_INTEL_PMC_IPC) int intel_pmc_ipc_simple_command(int cmd, int sub); @@ -31,6 +34,9 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, u32 outlen); int intel_pmc_s0ix_counter_read(u64 *data); +int intel_pmc_gcr_read(u32 offset, u32 *data); +int intel_pmc_gcr_write(u32 offset, u32 data); +int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val); #else @@ -56,6 +62,21 @@ static inline int intel_pmc_s0ix_counter_read(u64 *data) return -EINVAL; } +static inline int intel_pmc_gcr_read(u32 offset, u32 *data) +{ + return -EINVAL; +} + +static inline int intel_pmc_gcr_write(u32 offset, u32 data) +{ + return -EINVAL; +} + +static inline int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val) +{ + return -EINVAL; +} + #endif /*CONFIG_INTEL_PMC_IPC*/ #endif diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 0a3359240227..a0c773b3910e 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -128,6 +128,7 @@ static struct intel_pmc_ipc_dev { /* gcr */ resource_size_t gcr_base; int gcr_size; + void __iomem *gcr_mem_base; bool has_gcr_regs; /* punit */ @@ -199,6 +200,119 @@ static inline u64 gcr_data_readq(u32 offset) return readq(ipcdev.ipc_base + offset); } +static inline int is_gcr_valid(u32 offset) +{ + if (!ipcdev.has_gcr_regs) + return -EACCES; + + if (offset > PLAT_RESOURCE_GCR_SIZE) + return -EINVAL; + + return 0; +} + +/** + * intel_pmc_gcr_read() - Read PMC GCR register + * @offset: offset of GCR register from GCR address base + * @data: data pointer for storing the register output + * + * Reads the PMC GCR register of given offset. + * + * Return: negative value on error or 0 on success. + */ +int intel_pmc_gcr_read(u32 offset, u32 *data) +{ + int ret; + + mutex_lock(&ipclock); + + ret = is_gcr_valid(offset); + if (ret < 0) { + mutex_unlock(&ipclock); + return ret; + } + + *data = readl(ipcdev.gcr_mem_base + offset); + + mutex_unlock(&ipclock); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_read); + +/** + * intel_pmc_gcr_write() - Write PMC GCR register + * @offset: offset of GCR register from GCR address base + * @data: register update value + * + * Writes the PMC GCR register of given offset with given + * value. + * + * Return: negative value on error or 0 on success. + */ +int intel_pmc_gcr_write(u32 offset, u32 data) +{ + int ret; + + mutex_lock(&ipclock); + + ret = is_gcr_valid(offset); + if (ret < 0) { + mutex_unlock(&ipclock); + return ret; + } + + writel(data, ipcdev.gcr_mem_base + offset); + + mutex_unlock(&ipclock); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_write); + +/** + * intel_pmc_gcr_update() - Update PMC GCR register bits + * @offset: offset of GCR register from GCR address base + * @mask: bit mask for update operation + * @val: update value + * + * Updates the bits of given GCR register as specified by + * @mask and @val. + * + * Return: negative value on error or 0 on success. + */ +int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val) +{ + u32 new_val; + int ret = 0; + + mutex_lock(&ipclock); + + ret = is_gcr_valid(offset); + if (ret < 0) + goto gcr_ipc_unlock; + + new_val = readl(ipcdev.gcr_mem_base + offset); + + new_val &= ~mask; + new_val |= val & mask; + + writel(new_val, ipcdev.gcr_mem_base + offset); + + new_val = readl(ipcdev.gcr_mem_base + offset); + + /* check whether the bit update is successful */ + if ((new_val & mask) != (val & mask)) { + ret = -EIO; + goto gcr_ipc_unlock; + } + +gcr_ipc_unlock: + mutex_unlock(&ipclock); + return ret; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); + static int intel_pmc_ipc_check_status(void) { int status; @@ -747,6 +861,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) ipcdev.ipc_base = addr; ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; + ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET; ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; dev_info(&pdev->dev, "ipc res: %pR\n", res); From f583a884afecb16fcb8200ebb9956ea369aff57f Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:18 -0700 Subject: [PATCH 100/108] watchdog: iTCO_wdt: cleanup set/unset no_reboot_bit functions iTCO_wdt no_reboot_bit set/unset functions has lot of common code between them. So merging these two functions into a single update function would remove these unnecessary code duplications. This patch fixes this issue by creating a no_reboot_bit update function to handle both set/unset functions. Also checking for iTCO version every time you make no_reboot_bit set/unset call is inefficient and makes the code look complex. This can be improved by performing this check once during device probe and selecting the appropriate no_reboot_bit update function. This patch fixes this issue by splitting the update function into multiple helper functions. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Guenter Roeck Signed-off-by: Andy Shevchenko --- drivers/watchdog/iTCO_wdt.c | 87 ++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 3d0abc0d59b4..a62993381c52 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -106,6 +106,8 @@ struct iTCO_wdt_private { struct pci_dev *pci_dev; /* whether or not the watchdog has been suspended */ bool suspended; + /* no reboot update function pointer */ + int (*update_no_reboot_bit)(void *p, bool set); }; /* module parameters */ @@ -170,48 +172,61 @@ static inline u32 no_reboot_bit(struct iTCO_wdt_private *p) return enable_bit; } -static void iTCO_wdt_set_NO_REBOOT_bit(struct iTCO_wdt_private *p) +static int update_no_reboot_bit_def(void *priv, bool set) { - u32 val32; - - /* Set the NO_REBOOT bit: this disables reboots */ - if (p->iTCO_version >= 2) { - val32 = readl(p->gcs_pmc); - val32 |= no_reboot_bit(p); - writel(val32, p->gcs_pmc); - } else if (p->iTCO_version == 1) { - pci_read_config_dword(p->pci_dev, 0xd4, &val32); - val32 |= no_reboot_bit(p); - pci_write_config_dword(p->pci_dev, 0xd4, val32); - } + return 0; } -static int iTCO_wdt_unset_NO_REBOOT_bit(struct iTCO_wdt_private *p) +static int update_no_reboot_bit_pci(void *priv, bool set) { - u32 enable_bit = no_reboot_bit(p); - u32 val32 = 0; + struct iTCO_wdt_private *p = priv; + u32 val32 = 0, newval32 = 0; - /* Unset the NO_REBOOT bit: this enables reboots */ - if (p->iTCO_version >= 2) { - val32 = readl(p->gcs_pmc); - val32 &= ~enable_bit; - writel(val32, p->gcs_pmc); + pci_read_config_dword(p->pci_dev, 0xd4, &val32); + if (set) + val32 |= no_reboot_bit(p); + else + val32 &= ~no_reboot_bit(p); + pci_write_config_dword(p->pci_dev, 0xd4, val32); + pci_read_config_dword(p->pci_dev, 0xd4, &newval32); - val32 = readl(p->gcs_pmc); - } else if (p->iTCO_version == 1) { - pci_read_config_dword(p->pci_dev, 0xd4, &val32); - val32 &= ~enable_bit; - pci_write_config_dword(p->pci_dev, 0xd4, val32); - - pci_read_config_dword(p->pci_dev, 0xd4, &val32); - } - - if (val32 & enable_bit) + /* make sure the update is successful */ + if (val32 != newval32) return -EIO; return 0; } +static int update_no_reboot_bit_mem(void *priv, bool set) +{ + struct iTCO_wdt_private *p = priv; + u32 val32 = 0, newval32 = 0; + + val32 = readl(p->gcs_pmc); + if (set) + val32 |= no_reboot_bit(p); + else + val32 &= ~no_reboot_bit(p); + writel(val32, p->gcs_pmc); + newval32 = readl(p->gcs_pmc); + + /* make sure the update is successful */ + if (val32 != newval32) + return -EIO; + + return 0; +} + +static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p) +{ + if (p->iTCO_version >= 2) + p->update_no_reboot_bit = update_no_reboot_bit_mem; + else if (p->iTCO_version == 1) + p->update_no_reboot_bit = update_no_reboot_bit_pci; + else + p->update_no_reboot_bit = update_no_reboot_bit_def; +} + static int iTCO_wdt_start(struct watchdog_device *wd_dev) { struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); @@ -222,7 +237,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev) iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout); /* disable chipset's NO_REBOOT bit */ - if (iTCO_wdt_unset_NO_REBOOT_bit(p)) { + if (p->update_no_reboot_bit(p, false)) { spin_unlock(&p->io_lock); pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); return -EIO; @@ -263,7 +278,7 @@ static int iTCO_wdt_stop(struct watchdog_device *wd_dev) val = inw(TCO1_CNT(p)); /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - iTCO_wdt_set_NO_REBOOT_bit(p); + p->update_no_reboot_bit(p, true); spin_unlock(&p->io_lock); @@ -428,6 +443,8 @@ static int iTCO_wdt_probe(struct platform_device *pdev) p->iTCO_version = pdata->version; p->pci_dev = to_pci_dev(dev->parent); + iTCO_wdt_no_reboot_bit_setup(p); + /* * Get the Memory-Mapped GCS or PMC register, we need it for the * NO_REBOOT flag (TCO v2 and v3). @@ -442,14 +459,14 @@ static int iTCO_wdt_probe(struct platform_device *pdev) } /* Check chipset's NO_REBOOT bit */ - if (iTCO_wdt_unset_NO_REBOOT_bit(p) && + if (p->update_no_reboot_bit(p, false) && iTCO_vendor_check_noreboot_on()) { pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); return -ENODEV; /* Cannot reset NO_REBOOT bit */ } /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - iTCO_wdt_set_NO_REBOOT_bit(p); + p->update_no_reboot_bit(p, true); /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ if (!devm_request_region(dev, p->smi_res->start, From 140c91b26ebc48d80c6ac3ef06953b17d7fb3785 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:19 -0700 Subject: [PATCH 101/108] watchdog: iTCO_wdt: Add PMC specific noreboot update api In some SoCs, setting noreboot bit needs modification to PMC GC registers. But not all PMC drivers allow other drivers to memory map their GC region. This could create mem request conflict in watchdog driver. So this patch adds facility to allow PMC drivers to pass noreboot update function to watchdog drivers via platform data. Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Guenter Roeck Signed-off-by: Andy Shevchenko --- drivers/watchdog/iTCO_wdt.c | 25 ++++++++++++++++++------- include/linux/platform_data/itco_wdt.h | 4 ++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index a62993381c52..347f0389b089 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -106,6 +106,8 @@ struct iTCO_wdt_private { struct pci_dev *pci_dev; /* whether or not the watchdog has been suspended */ bool suspended; + /* no reboot API private data */ + void *no_reboot_priv; /* no reboot update function pointer */ int (*update_no_reboot_bit)(void *p, bool set); }; @@ -217,14 +219,23 @@ static int update_no_reboot_bit_mem(void *priv, bool set) return 0; } -static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p) +static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p, + struct itco_wdt_platform_data *pdata) { + if (pdata->update_no_reboot_bit) { + p->update_no_reboot_bit = pdata->update_no_reboot_bit; + p->no_reboot_priv = pdata->no_reboot_priv; + return; + } + if (p->iTCO_version >= 2) p->update_no_reboot_bit = update_no_reboot_bit_mem; else if (p->iTCO_version == 1) p->update_no_reboot_bit = update_no_reboot_bit_pci; else p->update_no_reboot_bit = update_no_reboot_bit_def; + + p->no_reboot_priv = p; } static int iTCO_wdt_start(struct watchdog_device *wd_dev) @@ -237,7 +248,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev) iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout); /* disable chipset's NO_REBOOT bit */ - if (p->update_no_reboot_bit(p, false)) { + if (p->update_no_reboot_bit(p->no_reboot_priv, false)) { spin_unlock(&p->io_lock); pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); return -EIO; @@ -278,7 +289,7 @@ static int iTCO_wdt_stop(struct watchdog_device *wd_dev) val = inw(TCO1_CNT(p)); /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - p->update_no_reboot_bit(p, true); + p->update_no_reboot_bit(p->no_reboot_priv, true); spin_unlock(&p->io_lock); @@ -443,13 +454,13 @@ static int iTCO_wdt_probe(struct platform_device *pdev) p->iTCO_version = pdata->version; p->pci_dev = to_pci_dev(dev->parent); - iTCO_wdt_no_reboot_bit_setup(p); + iTCO_wdt_no_reboot_bit_setup(p, pdata); /* * Get the Memory-Mapped GCS or PMC register, we need it for the * NO_REBOOT flag (TCO v2 and v3). */ - if (p->iTCO_version >= 2) { + if (p->iTCO_version >= 2 && !pdata->update_no_reboot_bit) { p->gcs_pmc_res = platform_get_resource(pdev, IORESOURCE_MEM, ICH_RES_MEM_GCS_PMC); @@ -459,14 +470,14 @@ static int iTCO_wdt_probe(struct platform_device *pdev) } /* Check chipset's NO_REBOOT bit */ - if (p->update_no_reboot_bit(p, false) && + if (p->update_no_reboot_bit(p->no_reboot_priv, false) && iTCO_vendor_check_noreboot_on()) { pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); return -ENODEV; /* Cannot reset NO_REBOOT bit */ } /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - p->update_no_reboot_bit(p, true); + p->update_no_reboot_bit(p->no_reboot_priv, true); /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ if (!devm_request_region(dev, p->smi_res->start, diff --git a/include/linux/platform_data/itco_wdt.h b/include/linux/platform_data/itco_wdt.h index f16542c77ff7..0e95527edf25 100644 --- a/include/linux/platform_data/itco_wdt.h +++ b/include/linux/platform_data/itco_wdt.h @@ -14,6 +14,10 @@ struct itco_wdt_platform_data { char name[32]; unsigned int version; + /* private data to be passed to update_no_reboot_bit API */ + void *no_reboot_priv; + /* pointer for platform specific no reboot update function */ + int (*update_no_reboot_bit)(void *priv, bool set); }; #endif /* _ITCO_WDT_H_ */ From 9d855d468dc655d10be6cb52e36aa0bbfa6f515d Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:20 -0700 Subject: [PATCH 102/108] platform/x86: intel_pmc_ipc: Fix iTCO_wdt GCS memory mapping failure iTCO_wdt driver need access to PMC_CFG GCR register to modify the noreboot setting. Currently, this is done by passing PMC_CFG reg address as memory resource to watchdog driver and allowing it directly modify the PMC_CFG register. But currently PMC driver also has requirement to memory map the entire GCR register space in this driver. This causes mem request failure in watchdog driver. So this patch fixes this issue by adding API to update noreboot flag and passes them to watchdog driver via platform data. Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_ipc.c | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index a0c773b3910e..0a39b0f17bbe 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -112,6 +112,13 @@ #define TCO_PMC_OFFSET 0x8 #define TCO_PMC_SIZE 0x4 +/* PMC register bit definitions */ + +/* PMC_CFG_REG bit masks */ +#define PMC_CFG_NO_REBOOT_MASK (1 << 4) +#define PMC_CFG_NO_REBOOT_EN (1 << 4) +#define PMC_CFG_NO_REBOOT_DIS (0 << 4) + static struct intel_pmc_ipc_dev { struct device *dev; void __iomem *ipc_base; @@ -126,8 +133,6 @@ static struct intel_pmc_ipc_dev { struct platform_device *tco_dev; /* gcr */ - resource_size_t gcr_base; - int gcr_size; void __iomem *gcr_mem_base; bool has_gcr_regs; @@ -313,6 +318,14 @@ gcr_ipc_unlock: } EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); +static int update_no_reboot_bit(void *priv, bool set) +{ + u32 value = set ? PMC_CFG_NO_REBOOT_EN : PMC_CFG_NO_REBOOT_DIS; + + return intel_pmc_gcr_update(PMC_GCR_PMC_CFG_REG, + PMC_CFG_NO_REBOOT_MASK, value); +} + static int intel_pmc_ipc_check_status(void) { int status; @@ -630,15 +643,13 @@ static struct resource tco_res[] = { { .flags = IORESOURCE_IO, }, - /* GCS */ - { - .flags = IORESOURCE_MEM, - }, }; static struct itco_wdt_platform_data tco_info = { .name = "Apollo Lake SoC", .version = 5, + .no_reboot_priv = &ipcdev, + .update_no_reboot_bit = update_no_reboot_bit, }; #define TELEMETRY_RESOURCE_PUNIT_SSRAM 0 @@ -695,10 +706,6 @@ static int ipc_create_tco_device(void) res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET; res->end = res->start + SMI_EN_SIZE - 1; - res = tco_res + TCO_RESOURCE_GCR_MEM; - res->start = ipcdev.gcr_base + TCO_PMC_OFFSET; - res->end = res->start + TCO_PMC_SIZE - 1; - pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) return PTR_ERR(pdev); @@ -860,9 +867,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) } ipcdev.ipc_base = addr; - ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET; - ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; dev_info(&pdev->dev, "ipc res: %pR\n", res); ipcdev.telem_res_inval = 0; From 62a7b9c859d09af860c71cfbea4381061975ca72 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Sun, 9 Apr 2017 15:00:21 -0700 Subject: [PATCH 103/108] platform/x86: intel_pmc_ipc: use gcr mem base for S0ix counter read To maintain the uniformity in accessing GCR registers, this patch modifies the S0ix counter read function to use GCR address base instead of ipc address base. Signed-off-by: Kuppuswamy Sathyanarayanan Reviewed-by: Rajneesh Bhardwaj Tested-by: Shanth Murthy Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel_pmc_ipc.h | 2 ++ drivers/platform/x86/intel_pmc_ipc.c | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h index 8402efef10ad..fac89eb78a6b 100644 --- a/arch/x86/include/asm/intel_pmc_ipc.h +++ b/arch/x86/include/asm/intel_pmc_ipc.h @@ -25,6 +25,8 @@ /* GCR reg offsets from gcr base*/ #define PMC_GCR_PMC_CFG_REG 0x08 +#define PMC_GCR_TELEM_DEEP_S0IX_REG 0x78 +#define PMC_GCR_TELEM_SHLW_S0IX_REG 0x80 #if IS_ENABLED(CONFIG_INTEL_PMC_IPC) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 0a39b0f17bbe..e4d4dfe3e1d1 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -57,10 +57,6 @@ #define IPC_WRITE_BUFFER 0x80 #define IPC_READ_BUFFER 0x90 -/* PMC Global Control Registers */ -#define GCR_TELEM_DEEP_S0IX_OFFSET 0x1078 -#define GCR_TELEM_SHLW_S0IX_OFFSET 0x1080 - /* Residency with clock rate at 19.2MHz to usecs */ #define S0IX_RESIDENCY_IN_USECS(d, s) \ ({ \ @@ -202,7 +198,7 @@ static inline u32 ipc_data_readl(u32 offset) static inline u64 gcr_data_readq(u32 offset) { - return readq(ipcdev.ipc_base + offset); + return readq(ipcdev.gcr_mem_base + offset); } static inline int is_gcr_valid(u32 offset) @@ -902,8 +898,8 @@ int intel_pmc_s0ix_counter_read(u64 *data) if (!ipcdev.has_gcr_regs) return -EACCES; - deep = gcr_data_readq(GCR_TELEM_DEEP_S0IX_OFFSET); - shlw = gcr_data_readq(GCR_TELEM_SHLW_S0IX_OFFSET); + deep = gcr_data_readq(PMC_GCR_TELEM_DEEP_S0IX_REG); + shlw = gcr_data_readq(PMC_GCR_TELEM_SHLW_S0IX_REG); *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); From ccc7179f4d9467947c94f4302d61cd5143842fcd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 21 Feb 2017 20:53:48 +0100 Subject: [PATCH 104/108] platform/x86: ideapad-laptop: Add IdeaPad V310-15ISK to no_hw_rfkill Like other Lenovo models the IdeaPad V310-15ISK does not have an hw rfkill switch. This results in hard-blocked radios after boot, resulting in always blocked radios rendering them unusable. Add the IdeaPad V310-15ISK to the no_hw_rfkill DMI list and allows using the built-in radios. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index ca5eeb4d417d..24ca9fbe31cc 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -868,6 +868,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"), }, }, + { + .ident = "Lenovo V310-15ISK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"), + }, + }, { .ident = "Lenovo ideapad 310-15IKB", .matches = { From f9ac89f5ad613b462339e845aeb8494646fd9be2 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Fri, 28 Apr 2017 16:23:59 +0800 Subject: [PATCH 105/108] platform/x86: acer-wmi: setup accelerometer when ACPI device was found The 98d610c3739a patch was introduced since v4.11-rc1 that it causes that the accelerometer input device will not be created on workable machines because the HID string comparing logic is wrong. And, the patch doesn't prevent that the accelerometer input device be created on the machines that have no BST0001. That's because the acpi_get_devices() returns success even it didn't find any match device. This patch fixed the HID string comparing logic of BST0001 device. And, it also makes sure that the acpi_get_devices() returns acpi_handle for BST0001. Fixes: 98d610c3739a ("acer-wmi: setup accelerometer when machine has appropriate notify event") Reference: https://bugzilla.kernel.org/show_bug.cgi?id=193761 Reported-by: Samuel Sieb Signed-off-by: "Lee, Chun-Yi" Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 8a27f0be1aec..79fa5ab3fd00 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1896,7 +1896,7 @@ static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, if (!strcmp(ctx, "SENR")) { if (acpi_bus_get_device(ah, &dev)) return AE_OK; - if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev))) + if (strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev))) return AE_OK; } else return AE_OK; @@ -1917,8 +1917,7 @@ static int __init acer_wmi_get_handle(const char *name, const char *prop, handle = NULL; status = acpi_get_devices(prop, acer_wmi_get_handle_cb, (void *)name, &handle); - - if (ACPI_SUCCESS(status)) { + if (ACPI_SUCCESS(status) && handle) { *ah = handle; return 0; } else { @@ -2287,8 +2286,8 @@ static int __init acer_wmi_init(void) if (err) return err; err = acer_wmi_accel_setup(); - if (err) - return err; + if (err && err != -ENODEV) + pr_warn("Cannot enable accelerometer\n"); } err = platform_driver_register(&acer_platform_driver); From a8fe342856e5bce71a43201eb2870bd059483d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lefaure?= Date: Fri, 21 Apr 2017 22:19:45 -0400 Subject: [PATCH 106/108] platform/x86: asus-wmi: fix cpufv sysfs file permission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cpufv sysfs file is defined as readable by anyone even if the attribute does not have a show function. The result of every read is an IO error. This file should be write only. Signed-off-by: Jérémy Lefaure Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d817e6327fec..a92255400d5c 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1757,7 +1757,7 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME); ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE); -static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, +static ssize_t cpufv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value, rv; @@ -1774,7 +1774,7 @@ static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); +static DEVICE_ATTR_WO(cpufv); static struct attribute *platform_attributes[] = { &dev_attr_cpufv.attr, From e9b615186805e2c18a0ac76aca62c1543ecfdbb8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 28 Apr 2017 16:19:49 +0200 Subject: [PATCH 107/108] platform/x86: asus-wmi: try to set als by default some laptops, for example ASUS UX330UAK, have brocken als_get function but working als_set funktion. In this case, ALS will stay turned off. Method (WMNB, 3, Serialized) { ... If (Local0 == 0x53545344) { ... If (IIA0 == 0x00050001) { If (!ALSP) { Return (0x02) } Local0 = (GALS & 0x10) <<<---- bug, should be: (GALS () & 0x10) If (Local0) { Return (0x00050001) } Else { Return (0x00050000) } } ..... If (Local0 == 0x53564544) { ... If (IIA0 == 0x00050001) { Return (ALSC (IIA1)) } ...... Method (GALS, 0, NotSerialized) { Local0 = Zero Local0 |= 0x20 If (ALAE) { Local0 |= 0x10 } Local1 = 0x0A Local1 <<= 0x08 Local0 |= Local1 Return (Local0) } Since it works without problems on Windows I assume ASUS WMI driver for Win never trying to get ALS state, and instead it is setting it by default to ON. This patch will do the same. Turn ALS on by default. Signed-off-by: Oleksij Rempel Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 12 ++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + 3 files changed, 26 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 1ae58d906536..5269a01d9bdd 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -111,6 +111,10 @@ static struct quirk_entry quirk_asus_x550lb = { .xusb2pr = 0x01D9, }; +static struct quirk_entry quirk_asus_ux330uak = { + .wmi_force_als_set = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { pr_info("Identified laptop model '%s'\n", dmi->ident); @@ -376,6 +380,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_ux303ub, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX330UAK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), + }, + .driver_data = &quirk_asus_ux330uak, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X550LB", diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index a92255400d5c..6c7d86074b38 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1104,6 +1104,15 @@ static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) orig_ports_available, ports_available); } +/* + * Some devices dont support or have borcken get_als method + * but still support set method. + */ +static void asus_wmi_set_als(void) +{ + asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL); +} + /* * Hwmon device */ @@ -2113,6 +2122,9 @@ static int asus_wmi_add(struct platform_device *pdev) goto fail_rfkill; } + if (asus->driver->quirks->wmi_force_als_set) + asus_wmi_set_als(); + /* Some Asus desktop boards export an acpi-video backlight interface, stop this from showing up */ chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index c9589d9342bb..6c1311f4b04d 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -44,6 +44,7 @@ struct quirk_entry { bool store_backlight_power; bool wmi_backlight_power; bool wmi_backlight_native; + bool wmi_force_als_set; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event From 6df97f85611cafc3ba9c093931a5fa3bc7dea897 Mon Sep 17 00:00:00 2001 From: "Darren Hart (VMware)" Date: Fri, 28 Apr 2017 09:36:28 -0700 Subject: [PATCH 108/108] platform/x86: Make SILEAD_DMI depend on TOUCHSCREEN_SILEAD SILEAD_DMI provides platform specific data for the TOUCHSCREEN_SILEAD driver. Make this explicitly clear in the Kconfig depends. Remove INPUT as this is implied by TOUCHSCREEN_SILEAD. Signed-off-by: Darren Hart (VMware) Cc: Hans de Goede Cc: Andy Shevchenko Cc: Jean Delvare Reviewed-by: Dmitry Torokhov --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 9e5b2c2a50d6..af077fc83e02 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1101,7 +1101,7 @@ config INTEL_TURBO_MAX_3 config SILEAD_DMI bool "Tablets with Silead touchscreens" - depends on ACPI && DMI && I2C=y && INPUT + depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- Certain ACPI based tablets with Silead touchscreens do not have enough data in ACPI tables for the touchscreen driver to handle