The DSTS method detection fails, as nothing is returned if method is not defined in WMNB. As a result the control of keyboard backlight is not functional for TUF Gaming series laptops (at the time the only functionality of the driver on this model implemented with WMI methods). Patch was tested on a newer TUF Gaming FX505GM and older K54C model. FX505GM: Method (WMNB, 3, Serialized) { ... If ((Local0 == 0x53545344)) { ... Return (Zero) } ... // No return } K54C: Method (WMNB, 3, Serialized) { ... If ((Local0 == 0x53545344)) { ... Return (0x02) } ... Return (0xFFFFFFFE) } The non-existing method ASUS_WMI_METHODID_DSTS=0x53544344 (actually it is DCTS in little endian ASCII) is selected in asus->dsts. One way to fix this would be to call both for every known device ID until some answers - this would increase module load time. Another option is to check some device that is known to exist on every model - none known at the time. Last option, which is implemented, is to check for presence of the ASUS7000 device in ACPI tree (it is a dummy device), which is the condition used for loading the vendor driver for this model. This might not fix every affected model ever produced, but it likely does not introduce any regressions. The patch introduces a quirk that is enabled when ASUS7000 is found. Scope (_SB) { Device (ATK) { Name (_HID, "ASUS7000") // _HID: Hardware ID } } Signed-off-by: Yurii Pavlovskyi <yurii.pavlovskyi@xxxxxxxxx> --- drivers/platform/x86/asus-nb-wmi.c | 5 +++++ drivers/platform/x86/asus-wmi.c | 16 +++++++++++++--- drivers/platform/x86/asus-wmi.h | 5 +++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index b6f2ff95c3ed..cc5f0765a8d9 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -28,6 +28,7 @@ #include <linux/fb.h> #include <linux/dmi.h> #include <linux/i8042.h> +#include <linux/acpi.h> #include "asus-wmi.h" @@ -434,6 +435,10 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) } pr_info("Using i8042 filter function for receiving events\n"); } + + if (acpi_dev_found("ASUS7000")) { + driver->quirks->force_dsts = true; + } } static const struct key_entry asus_nb_wmi_keymap[] = { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index cfccfc0b8c2f..58890d87d50c 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -24,7 +24,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define PR KBUILD_MODNAME ": " #include <linux/kernel.h> #include <linux/module.h> @@ -1885,11 +1885,21 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) * Note, on most Eeepc, there is no way to check if a method exist * or note, while on notebooks, they returns 0xFFFFFFFE on failure, * but once again, SPEC may probably be used for that kind of things. + * + * Additionally at least TUF Gaming series laptops return 0 for unknown + * methods, so the detection in this way is not possible and method must + * be forced. Likely the presence of ACPI device ASUS7000 indicates + * this. */ - if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) + if (asus->driver->quirks->force_dsts) { + pr_info(PR "DSTS method forced\n"); + asus->dsts_id = ASUS_WMI_METHODID_DSTS2; + } else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, + 0, 0, NULL)) { asus->dsts_id = ASUS_WMI_METHODID_DSTS; - else + } else { asus->dsts_id = ASUS_WMI_METHODID_DSTS2; + } /* CWAP allow to define the behavior of the Fn+F2 key, * this method doesn't seems to be present on Eee PCs */ diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 6c1311f4b04d..94056da02fde 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -54,6 +54,11 @@ struct quirk_entry { */ int no_display_toggle; u32 xusb2pr; + /** + * Force DSTS instead of DSCS and skip detection. Useful if WMNB + * returns nothing on unknown method call. + */ + bool force_dsts; bool (*i8042_filter)(unsigned char data, unsigned char str, struct serio *serio); -- 2.17.1