From 78429e55e4057bdd0fbc6f969a669336f7be249e Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 29 Aug 2016 09:37:34 -0600 Subject: [PATCH 01/11] platform/x86: toshiba_acpi: Clean up variable declaration This patch moves all the multiple line variable declaration to a single line declaration (except variables being initialized) following the reverse tree order, to conform to the practices of the kernel. [dvhart: corrected a couple minor inconsistencies in declaration ordering] Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 9d60a40d8b3f..bbcb7c2ef62a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -321,10 +321,9 @@ static int write_acpi_int(const char *methodName, int val) static acpi_status tci_raw(struct toshiba_acpi_dev *dev, const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) { + union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1]; struct acpi_object_list params; - union acpi_object in_objs[TCI_WORDS]; struct acpi_buffer results; - union acpi_object out_objs[TCI_WORDS + 1]; acpi_status status; int i; @@ -387,9 +386,8 @@ static int sci_open(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; - acpi_status status; + acpi_status status = tci_raw(dev, in, out); - status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to open SCI failed\n"); return 0; @@ -425,9 +423,8 @@ static void sci_close(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; - acpi_status status; + acpi_status status = tci_raw(dev, in, out); - status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to close SCI failed\n"); return; @@ -509,7 +506,8 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) { struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev, led_dev); - u32 state, result; + u32 result; + u32 state; /* First request : initialize communication. */ if (!sci_open(dev)) @@ -672,9 +670,9 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) /* Eco Mode support */ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) { - acpi_status status; u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; + acpi_status status; dev->eco_supported = 0; dev->eco_led_registered = false; @@ -1282,9 +1280,9 @@ static struct proc_dir_entry *toshiba_proc_dir; /* LCD Brightness */ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) { + int brightness = 0; u32 result; u32 value; - int brightness = 0; if (dev->tr_backlight_supported) { int ret = get_tr_backlight_status(dev, &value); @@ -1377,7 +1375,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char cmd[42]; size_t len; - int levels = dev->backlight_dev->props.max_brightness + 1; + int levels; int value; len = min(count, sizeof(cmd) - 1); @@ -1385,6 +1383,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, return -EFAULT; cmd[len] = '\0'; + levels = dev->backlight_dev->props.max_brightness + 1; if (sscanf(cmd, " brightness : %i", &value) != 1 && value < 0 && value > levels) return -EINVAL; @@ -1447,10 +1446,8 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char *buffer; char *cmd; + int lcd_out, crt_out, tv_out; int remain = count; - int lcd_out = -1; - int crt_out = -1; - int tv_out = -1; int value; int ret; u32 video_out; @@ -1486,6 +1483,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, kfree(cmd); + lcd_out = crt_out = tv_out = -1; ret = get_video_status(dev, &video_out); if (!ret) { unsigned int new_video_out = video_out; @@ -1980,8 +1978,8 @@ static ssize_t usb_sleep_charge_store(struct device *dev, const char *buf, size_t count) { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); - u32 mode; int state; + u32 mode; int ret; ret = kstrtoint(buf, 0, &state); @@ -2021,9 +2019,8 @@ static ssize_t sleep_functions_on_battery_show(struct device *dev, char *buf) { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); + int bat_lvl, status; u32 state; - int bat_lvl; - int status; int ret; int tmp; From 513ee146f69c48db362189b6423e6c4ede4b3aad Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 29 Aug 2016 09:37:35 -0600 Subject: [PATCH 02/11] platform/x86: toshiba_acpi: Change error checking logic from TCI functions Currently the success/error checking logic is intermixed, making the code a bit cumbersome to understand. This patch changes the affected functions to first check for errors and take appropriate actions, then check for the supported features. This patch also separates the error check from the acpi_status and the tci_raw function call error check, as those two are completely unrelated and were nested in if/else statements. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 226 +++++++++++++++++----------- 1 file changed, 138 insertions(+), 88 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index bbcb7c2ef62a..158b3af866e3 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -476,10 +476,15 @@ static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query Illumination support failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->illumination_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->illumination_supported = 1; } static void toshiba_illumination_set(struct led_classdev *cdev, @@ -544,24 +549,28 @@ static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to query kbd illumination support failed\n"); - } else if (out[0] == TOS_SUCCESS) { - /* - * Check for keyboard backlight timeout max value, - * previous kbd backlight implementation set this to - * 0x3c0003, and now the new implementation set this - * to 0x3c001a, use this to distinguish between them. - */ - if (out[3] == SCI_KBD_TIME_MAX) - dev->kbd_type = 2; - else - dev->kbd_type = 1; - /* Get the current keyboard backlight mode */ - dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; - /* Get the current time (1-60 seconds) */ - dev->kbd_time = out[2] >> HCI_MISC_SHIFT; - /* Flag as supported */ - dev->kbd_illum_supported = 1; + return; } + + if (out[0] != TOS_SUCCESS) + return; + + /* + * Check for keyboard backlight timeout max value, + * previous kbd backlight implementation set this to + * 0x3c0003, and now the new implementation set this + * to 0x3c001a, use this to distinguish between them. + */ + if (out[3] == SCI_KBD_TIME_MAX) + dev->kbd_type = 2; + else + dev->kbd_type = 1; + /* Get the current keyboard backlight mode */ + dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; + /* Get the current time (1-60 seconds) */ + dev->kbd_time = out[2] >> HCI_MISC_SHIFT; + /* Flag as supported */ + dev->kbd_illum_supported = 1; } static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) @@ -680,7 +689,10 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); - } else if (out[0] == TOS_INPUT_DATA_ERROR) { + return; + } + + if (out[0] == TOS_INPUT_DATA_ERROR) { /* * If we receive 0x8300 (Input Data Error), it means that the * LED device is present, but that we just screwed the input @@ -692,10 +704,15 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) */ in[3] = 1; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->eco_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->eco_supported = 1; } } @@ -712,10 +729,11 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev) if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); return LED_OFF; - } else if (out[0] != TOS_SUCCESS) { - return LED_OFF; } + if (out[0] != TOS_SUCCESS) + return LED_OFF; + return out[2] ? LED_FULL : LED_OFF; } @@ -749,10 +767,15 @@ static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) * this call also serves as initialization */ status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query the accelerometer failed\n"); - else if (out[0] == TOS_SUCCESS) - dev->accelerometer_supported = 1; + return; + } + + if (out[0] != TOS_SUCCESS) + return; + + dev->accelerometer_supported = 1; } static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, @@ -767,15 +790,18 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, if (ACPI_FAILURE(status)) { pr_err("ACPI call to query the accelerometer failed\n"); return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *xy = out[2]; - *z = out[4]; - return 0; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *xy = out[2]; + *z = out[4]; + + return 0; } /* Sleep (Charge and Music) utilities support */ @@ -795,24 +821,29 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); sci_close(dev); return; - } else if (out[0] == TOS_NOT_SUPPORTED) { + } + + if (out[0] != TOS_SUCCESS) { sci_close(dev); return; - } else if (out[0] == TOS_SUCCESS) { - dev->usbsc_mode_base = out[4]; } + dev->usbsc_mode_base = out[4]; + in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); - } else if (out[0] == TOS_SUCCESS) { - dev->usbsc_bat_level = out[2]; - /* Flag as supported */ - dev->usb_sleep_charge_supported = 1; + return; } + if (out[0] != TOS_SUCCESS) + return; + + dev->usbsc_bat_level = out[2]; + /* Flag as supported */ + dev->usb_sleep_charge_supported = 1; } static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, @@ -866,14 +897,19 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB S&C battery level failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *mode = out[2]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *mode = out[2]; + + return 0; + } static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, @@ -890,9 +926,12 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to set USB S&C battery level failed\n"); - else if (out[0] == TOS_NOT_SUPPORTED) + return -EIO; + } + + if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; return out[0] == TOS_SUCCESS ? 0 : -EIO; @@ -913,14 +952,18 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Rapid Charge failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { - *state = out[2]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) + return -EIO; + + *state = out[2]; + + return 0; } static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, @@ -937,9 +980,12 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_RAPID_DSP; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to set USB Rapid Charge failed\n"); - else if (out[0] == TOS_NOT_SUPPORTED) + return -EIO; + } + + if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; @@ -1095,14 +1141,18 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get System type failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return -ENODEV; - } else if (out[0] == TOS_SUCCESS) { - *type = out[3]; - return 0; + return -EIO; } - return -EIO; + if (out[0] == TOS_NOT_SUPPORTED) + return -ENODEV; + + if (out[0] != TOS_SUCCESS) + return -EIO; + + *type = out[3]; + + return 0; } /* Wireless status (RFKill, WLAN, BT, WWAN) */ @@ -1152,7 +1202,6 @@ static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) */ in[3] = HCI_WIRELESS_WWAN; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to get WWAN status failed\n"); return; @@ -1172,7 +1221,6 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) in[3] = HCI_WIRELESS_WWAN_STATUS; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to set WWAN status failed\n"); return -EIO; @@ -1191,7 +1239,6 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) */ in[3] = HCI_WIRELESS_WWAN_POWER; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) { pr_err("ACPI call to set WWAN power failed\n"); return -EIO; @@ -1214,8 +1261,10 @@ static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) dev->max_cooling_method = 0; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { pr_err("ACPI call to get Cooling Method failed\n"); + return; + } if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) return; @@ -1299,10 +1348,10 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) pr_err("ACPI call to get LCD Brightness failed\n"); else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - if (result == TOS_SUCCESS) - return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); - return -EIO; + return result == TOS_SUCCESS ? + brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) : + -EIO; } static int get_lcd_brightness(struct backlight_device *bd) @@ -1323,15 +1372,15 @@ static int lcd_proc_show(struct seq_file *m, void *v) levels = dev->backlight_dev->props.max_brightness + 1; value = get_lcd_brightness(dev->backlight_dev); - if (value >= 0) { - seq_printf(m, "brightness: %d\n", value); - seq_printf(m, "brightness_levels: %d\n", levels); - return 0; + if (value < 0) { + pr_err("Error reading LCD brightness\n"); + return value; } - pr_err("Error reading LCD brightness\n"); + seq_printf(m, "brightness: %d\n", value); + seq_printf(m, "brightness_levels: %d\n", levels); - return -EIO; + return 0; } static int lcd_proc_open(struct inode *inode, struct file *file) @@ -1419,20 +1468,21 @@ static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) static int video_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; + int is_lcd, is_crt, is_tv; u32 value; - if (!get_video_status(dev, &value)) { - int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; - int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; - int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; + if (get_video_status(dev, &value)) + return -EIO; - seq_printf(m, "lcd_out: %d\n", is_lcd); - seq_printf(m, "crt_out: %d\n", is_crt); - seq_printf(m, "tv_out: %d\n", is_tv); - return 0; - } + is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; + is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; + is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; - return -EIO; + seq_printf(m, "lcd_out: %d\n", is_lcd); + seq_printf(m, "crt_out: %d\n", is_crt); + seq_printf(m, "tv_out: %d\n", is_tv); + + return 0; } static int video_proc_open(struct inode *inode, struct file *file) From fa1bc2a09f5f6c83eeb49686911565d9630ef054 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 29 Aug 2016 09:37:36 -0600 Subject: [PATCH 03/11] platform/x86: toshiba_acpi: Fix typo in *_cooling_method_set function This patch simply fixes a typo in the error string printed in the *_cooling_method_set function. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 158b3af866e3..074bf2fa1c55 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1291,7 +1291,7 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) u32 result = hci_write(dev, HCI_COOLING_METHOD, state); if (result == TOS_FAILURE) - pr_err("ACPI call to get Cooling Method failed\n"); + pr_err("ACPI call to set Cooling Method failed\n"); if (result == TOS_NOT_SUPPORTED) return -ENODEV; From 999d4376c62828b260fbb59d5ab6bc28918ca448 Mon Sep 17 00:00:00 2001 From: zino lin Date: Sun, 28 Aug 2016 16:12:06 +0800 Subject: [PATCH 04/11] platform/x86: asus-wmi: fix asus ux303ub brightness issue acpi_video0 doesn't work, asus-wmi brightness interface doesn't work, too. So, we use native brightness interface to handle the brightness adjustion, and add quirk_asus_ux303ub. Signed-off-by: zino lin Acked-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 3 +++ drivers/platform/x86/asus-wmi.h | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index adecc1c555f0..f4a60e75cd8a 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -87,6 +87,10 @@ static struct quirk_entry quirk_no_rfkill_wapf4 = { .no_rfkill = true, }; +static struct quirk_entry quirk_asus_ux303ub = { + .wmi_backlight_native = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -351,6 +355,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_no_rfkill, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX303UB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), + }, + .driver_data = &quirk_asus_ux303ub, + }, {}, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 7c093a0b78bb..ce6ca31a2d09 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2084,6 +2084,9 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_backlight_power) acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); + if (asus->driver->quirks->wmi_backlight_native) + acpi_video_set_dmi_backlight_type(acpi_backlight_native); + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 5de1df510ebd..5e220411056d 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -43,6 +43,7 @@ struct quirk_entry { bool scalar_panel_brightness; bool store_backlight_power; bool wmi_backlight_power; + bool wmi_backlight_native; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event From 6f7e357bf181b5a9da9daffcd40a64ee516a29e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Fri, 5 Aug 2016 23:57:10 +0300 Subject: [PATCH 05/11] platform/x86: asus-laptop: get rid of parse_arg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit parse_arg() duplicates the funcionality of kstrtoint() so use the latter function instead. There is no funcionality change except that in the case of input being too big -ERANGE will be returned instead of -EINVAL which is not bad because -ERANGE makes more sense here. The check for !count is already done by the sysfs core so no need to duplicate it again. Also, add some minor corrections to error handling to accommodate the change in return values (parse_arg returned count if everything succeeded whereas kstrtoint returns 0 in the same situation) As a result of this patch asus-laptop.ko size is reduced by almost 1%: add/remove: 0/1 grow/shrink: 1/6 up/down: 1/-149 (-148) function old new delta __UNIQUE_ID_vermagic0 69 70 +1 ls_switch_store 133 117 -16 ledd_store 175 159 -16 display_store 157 141 -16 ls_level_store 193 176 -17 gps_store 200 178 -22 sysfs_acpi_set.isra 148 125 -23 parse_arg.part 39 - -39 Total: Before=19160, After=19012, chg -0.77% Signed-off-by: Giedrius Statkevičius Signed-off-by: Darren Hart --- drivers/platform/x86/asus-laptop.c | 77 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 15f131146501..28551f5a2e07 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -932,30 +932,19 @@ static ssize_t infos_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(infos); -static int parse_arg(const char *buf, unsigned long count, int *val) -{ - if (!count) - return 0; - if (count > 31) - return -EINVAL; - if (sscanf(buf, "%i", val) != 1) - return -EINVAL; - return count; -} - static ssize_t sysfs_acpi_set(struct asus_laptop *asus, const char *buf, size_t count, const char *method) { int rv, value; - rv = parse_arg(buf, count, &value); - if (rv <= 0) + rv = kstrtoint(buf, 0, &value); + if (rv < 0) return rv; if (write_acpi_int(asus->handle, method, value)) return -ENODEV; - return rv; + return count; } /* @@ -975,15 +964,17 @@ static ssize_t ledd_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) { - if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { - pr_warn("LED display write failed\n"); - return -ENODEV; - } - asus->ledd_status = (u32) value; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; + + if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { + pr_warn("LED display write failed\n"); + return -ENODEV; } - return rv; + + asus->ledd_status = (u32) value; + return count; } static DEVICE_ATTR_RW(ledd); @@ -1148,10 +1139,12 @@ static ssize_t display_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) - asus_set_display(asus, value); - return rv; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; + + asus_set_display(asus, value); + return count; } static DEVICE_ATTR_WO(display); @@ -1190,11 +1183,12 @@ static ssize_t ls_switch_store(struct device *dev, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) - asus_als_switch(asus, value ? 1 : 0); + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; - return rv; + asus_als_switch(asus, value ? 1 : 0); + return count; } static DEVICE_ATTR_RW(ls_switch); @@ -1219,14 +1213,15 @@ static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr, struct asus_laptop *asus = dev_get_drvdata(dev); int rv, value; - rv = parse_arg(buf, count, &value); - if (rv > 0) { - value = (0 < value) ? ((15 < value) ? 15 : value) : 0; - /* 0 <= value <= 15 */ - asus_als_level(asus, value); - } + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; - return rv; + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + asus_als_level(asus, value); + + return count; } static DEVICE_ATTR_RW(ls_level); @@ -1301,14 +1296,14 @@ static ssize_t gps_store(struct device *dev, struct device_attribute *attr, int rv, value; int ret; - rv = parse_arg(buf, count, &value); - if (rv <= 0) - return -EINVAL; + rv = kstrtoint(buf, 0, &value); + if (rv < 0) + return rv; ret = asus_gps_switch(asus, !!value); if (ret) return ret; rfkill_set_sw_state(asus->gps.rfkill, !value); - return rv; + return count; } static DEVICE_ATTR_RW(gps); From 55455449982564da833d51b28bdd39a06ad28740 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 7 Sep 2016 09:28:13 -0600 Subject: [PATCH 06/11] platform/x86: toshiba_haps: Split ACPI and HDD protection error handling Currently the code checking for the ACPI status is mixed along with the actual HDD protection status check. This patch splits those two checks as they are not related, printing an error string in case the ACPI call failed, and then check for actual HDD protection status. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_haps.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c index 7f2afc6b5eb9..094f3a898d91 100644 --- a/drivers/platform/x86/toshiba_haps.c +++ b/drivers/platform/x86/toshiba_haps.c @@ -168,9 +168,13 @@ static int toshiba_haps_available(acpi_handle handle) * A non existent device as well as having (only) * Solid State Drives can cause the call to fail. */ - status = acpi_evaluate_integer(handle, "_STA", NULL, - &hdd_present); - if (ACPI_FAILURE(status) || !hdd_present) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &hdd_present); + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to query HDD protection failed\n"); + return 0; + } + + if (!hdd_present) { pr_info("HDD protection not available or using SSD\n"); return 0; } From baae5f91577ac6416b03c3d95815f52e1e244f3b Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 7 Sep 2016 09:28:14 -0600 Subject: [PATCH 07/11] platform/x86: toshiba_haps: Change logging level from info to debug Two of the internal functions are printing an info message, one whenever the HDD protection level changes, and another when the driver receives an ACPI event. This patch changes those two prints to debug, as that information is more pertaining to debuging purposes. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_haps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c index 094f3a898d91..b3dec521e2b6 100644 --- a/drivers/platform/x86/toshiba_haps.c +++ b/drivers/platform/x86/toshiba_haps.c @@ -59,7 +59,7 @@ static int toshiba_haps_protection_level(acpi_handle handle, int level) return -EIO; } - pr_info("HDD protection level set to: %d\n", level); + pr_debug("HDD protection level set to: %d\n", level); return 0; } @@ -141,7 +141,7 @@ static struct attribute_group haps_attr_group = { */ static void toshiba_haps_notify(struct acpi_device *device, u32 event) { - pr_info("Received event: 0x%x", event); + pr_debug("Received event: 0x%x", event); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), From 28e476d7438eedd3ecc7b5ebe6f2a3dfd21ca10e Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 7 Sep 2016 09:28:15 -0600 Subject: [PATCH 08/11] platform/x86: toshiba_bluetooth: Decouple an error checking status code This patch simply decouples the error checking of the ACPI status and the actual BT status, as those two were nested in an if/else check, but are completely unrelated. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_bluetooth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index 5db495dd018e..be1d137c6079 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -80,7 +80,9 @@ static int toshiba_bluetooth_present(acpi_handle handle) if (ACPI_FAILURE(result)) { pr_err("ACPI call to query Bluetooth presence failed\n"); return -ENXIO; - } else if (!bt_present) { + } + + if (!bt_present) { pr_info("Bluetooth device not present\n"); return -ENODEV; } From b5643539b82559b858b8efe3fc8343f66cf9a0b5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 12 Sep 2016 17:48:17 +0200 Subject: [PATCH 09/11] platform/x86: asus-wmi: Filter buggy scan codes on ASUS Q500A Some revisions of the ASUS Q500A series have a keyboard related issue which is reproducible only after Windows with installed ASUS tools is started. In this case the Linux side will have a blocked keyboard or report incorrect or incomplete hotkey events. To make Linux work properly again, a complete power down (unplug power supply and remove battery) is needed. Linux/atkbd after a clean start will get the following code on VOLUME_UP key: {0xe0, 0x30, 0xe0, 0xb0}. After Windows, the same key will generate this codes: {0xe1, 0x23, 0xe0, 0x30, 0xe0, 0xb0}. As result atkdb will be confused by buggy codes. This patch is filtering this buggy code out. https://bugzilla.kernel.org/show_bug.cgi?id=119391 Signed-off-by: Oleksij Rempel Cc: Alex Henrie Cc: Dmitry Torokhov Cc: Corentin Chary Cc: acpi4asus-user@lists.sourceforge.net Cc: platform-driver-x86@vger.kernel.org Cc: linux-kernel@vger.kernel.org [dvhart: Add return after pr_warn to avoid false confirmation of filter] Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 45 ++++++++++++++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 4 +++ 2 files changed, 49 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index f4a60e75cd8a..26e4cbc34db8 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "asus-wmi.h" @@ -55,10 +56,34 @@ MODULE_PARM_DESC(wapf, "WAPF value"); static struct quirk_entry *quirks; +static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + bool ret = false; + + if (str & I8042_STR_AUXDATA) + return false; + + if (unlikely(data == 0xe1)) { + extended = true; + ret = true; + } else if (unlikely(extended)) { + extended = false; + ret = true; + } + + return ret; +} + static struct quirk_entry quirk_asus_unknown = { .wapf = 0, }; +static struct quirk_entry quirk_asus_q500a = { + .i8042_filter = asus_q500a_i8042_filter, +}; + /* * For those machines that need software to control bt/wifi status * and can't adjust brightness through ACPI interface @@ -98,6 +123,15 @@ static int dmi_matched(const struct dmi_system_id *dmi) } static const struct dmi_system_id asus_quirks[] = { + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. Q500A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"), + }, + .driver_data = &quirk_asus_q500a, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. U32U", @@ -369,6 +403,8 @@ static const struct dmi_system_id asus_quirks[] = { static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) { + int ret; + quirks = &quirk_asus_unknown; dmi_check_system(asus_quirks); @@ -380,6 +416,15 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) quirks->wapf = wapf; else wapf = quirks->wapf; + + if (quirks->i8042_filter) { + ret = i8042_install_filter(quirks->i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + return; + } + pr_info("Using i8042 filter function for receiving events\n"); + } } static const struct key_entry asus_nb_wmi_keymap[] = { diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 5e220411056d..0e19014e9f54 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -28,6 +28,7 @@ #define _ASUS_WMI_H_ #include +#include #define ASUS_WMI_KEY_IGNORE (-1) #define ASUS_WMI_BRN_DOWN 0x20 @@ -52,6 +53,9 @@ struct quirk_entry { * and let the ACPI interrupt to send out the key event. */ int no_display_toggle; + + bool (*i8042_filter)(unsigned char data, unsigned char str, + struct serio *serio); }; struct asus_wmi_driver { From ea1a76bad8c9d0e7d91e7e4c9adf98fe3c7f09b7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 24 Sep 2016 11:54:08 +0800 Subject: [PATCH 10/11] platform/x86: intel_pmc_ipc: Convert to use platform_device_register_full Use platform_device_register_full() instead of open-coded. Signed-off-by: Axel Lin Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_ipc.c | 108 ++++++++------------------- 1 file changed, 32 insertions(+), 76 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index b86e1bcaa055..665a9a19adcb 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -522,48 +522,36 @@ static struct resource telemetry_res[] = { static int ipc_create_punit_device(void) { struct platform_device *pdev; - int ret; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = PUNIT_DEVICE_NAME, + .id = -1, + .res = punit_res_array, + .num_res = ARRAY_SIZE(punit_res_array), + }; - pdev = platform_device_alloc(PUNIT_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, "Failed to alloc punit platform device\n"); - return -ENOMEM; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - pdev->dev.parent = ipcdev.dev; - ret = platform_device_add_resources(pdev, punit_res_array, - ARRAY_SIZE(punit_res_array)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add platform punit resources\n"); - goto err; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, "Failed to add punit platform device\n"); - goto err; - } ipcdev.punit_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_tco_device(void) { struct platform_device *pdev; struct resource *res; - int ret; - - pdev = platform_device_alloc(TCO_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, "Failed to alloc tco platform device\n"); - return -ENOMEM; - } - - pdev->dev.parent = ipcdev.dev; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = TCO_DEVICE_NAME, + .id = -1, + .res = tco_res, + .num_res = ARRAY_SIZE(tco_res), + .data = &tco_info, + .size_data = sizeof(tco_info), + }; res = tco_res + TCO_RESOURCE_ACPI_IO; res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET; @@ -577,45 +565,26 @@ static int ipc_create_tco_device(void) res->start = ipcdev.gcr_base + TCO_PMC_OFFSET; res->end = res->start + TCO_PMC_SIZE - 1; - ret = platform_device_add_resources(pdev, tco_res, ARRAY_SIZE(tco_res)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform resources\n"); - goto err; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = platform_device_add_data(pdev, &tco_info, sizeof(tco_info)); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform data\n"); - goto err; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, "Failed to add tco platform device\n"); - goto err; - } ipcdev.tco_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_telemetry_device(void) { struct platform_device *pdev; struct resource *res; - int ret; - - pdev = platform_device_alloc(TELEMETRY_DEVICE_NAME, -1); - if (!pdev) { - dev_err(ipcdev.dev, - "Failed to allocate telemetry platform device\n"); - return -ENOMEM; - } - - pdev->dev.parent = ipcdev.dev; + const struct platform_device_info pdevinfo = { + .parent = ipcdev.dev, + .name = TELEMETRY_DEVICE_NAME, + .id = -1, + .res = telemetry_res, + .num_res = ARRAY_SIZE(telemetry_res), + }; res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; res->start = ipcdev.telem_punit_ssram_base; @@ -625,26 +594,13 @@ static int ipc_create_telemetry_device(void) res->start = ipcdev.telem_pmc_ssram_base; res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; - ret = platform_device_add_resources(pdev, telemetry_res, - ARRAY_SIZE(telemetry_res)); - if (ret) { - dev_err(ipcdev.dev, - "Failed to add telemetry platform resources\n"); - goto err; - } + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); - ret = platform_device_add(pdev); - if (ret) { - dev_err(ipcdev.dev, - "Failed to add telemetry platform device\n"); - goto err; - } ipcdev.telemetry_dev = pdev; return 0; -err: - platform_device_put(pdev); - return ret; } static int ipc_create_pmc_devices(void) From 127595ed21c1bb24e20d488914b70ca7a643f7a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Oct 2016 13:12:58 +0200 Subject: [PATCH 11/11] platform/x86: intel_pmc_core: avoid boot time warning for !CONFIG_DEBUGFS_FS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While looking at a patch that introduced a compile-time warning "‘pmc_core_dev_state_get’ defined but not used" (I sent a patch for debugfs to fix it), I noticed that the same patch caused it in intel_pmc_core also introduced a bogus run-time warning: "PMC Core: debugfs register failed". The problem is the IS_ERR_OR_NULL() check that as usual gets things wrong: when CONFIG_DEBUGFS_FS is disabled, debugfs_create_dir() fails with an error code, and we don't need to warn about it, unlike the case in which it returns NULL. This reverts the driver to the previous state of not warning about CONFIG_DEBUGFS_FS being disabled. I chose not to restore the driver to making a runtime error in debugfs fatal in pmc_core_probe(). Fixes: df2294fb6428 ("intel_pmc_core: Convert to DEFINE_DEBUGFS_ATTRIBUTE") Signed-off-by: Arnd Bergmann Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 520b58a04daa..e8b1b836ca2d 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -100,7 +100,7 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) struct dentry *dir, *file; dir = debugfs_create_dir("pmc_core", NULL); - if (IS_ERR_OR_NULL(dir)) + if (!dir) return -ENOMEM; pmcdev->dbgfs_dir = dir;