diff mbox

[v2,2/2] HID: asus: only support backlight when it's not driven by WMI

Message ID 20180522205542.11991-2-drake@endlessm.com (mailing list archive)
State Superseded, archived
Delegated to: Andy Shevchenko
Headers show

Commit Message

Daniel Drake May 22, 2018, 8:55 p.m. UTC
The Asus GL502VSK has the same 0B05:1837 keyboard as we've seen in
several Republic of Gamers laptops.

However, in this model, the keybard backlight control exposed by hid-asus
has no effect on the keyboard backlight. Instead, the keyboard
backlight is correctly driven by asus-wmi.

With two keyboard backlight devices available (and only the acer-wmi
one working), GNOME is picking the wrong one to drive in the UI.

Avoid this problem by not creating the backlight interface when we
detect a WMI-driven keyboard backlight.

We have also tested Asus GL702VMK which does have the hid-asus
backlight present, and it still works fine with this patch (WMI method
call returns UNSUPPORTED_METHOD).

Signed-off-by: Daniel Drake <drake@endlessm.com>
---
 drivers/hid/Kconfig    |  1 +
 drivers/hid/hid-asus.c | 24 +++++++++++++++++++++++-
 2 files changed, 24 insertions(+), 1 deletion(-)

Comments

Andy Shevchenko May 31, 2018, 10:43 a.m. UTC | #1
On Tue, May 22, 2018 at 11:55 PM, Daniel Drake <drake@endlessm.com> wrote:
> The Asus GL502VSK has the same 0B05:1837 keyboard as we've seen in
> several Republic of Gamers laptops.
>
> However, in this model, the keybard backlight control exposed by hid-asus
> has no effect on the keyboard backlight. Instead, the keyboard
> backlight is correctly driven by asus-wmi.
>
> With two keyboard backlight devices available (and only the acer-wmi
> one working), GNOME is picking the wrong one to drive in the UI.
>
> Avoid this problem by not creating the backlight interface when we
> detect a WMI-driven keyboard backlight.
>
> We have also tested Asus GL702VMK which does have the hid-asus
> backlight present, and it still works fine with this patch (WMI method
> call returns UNSUPPORTED_METHOD).
>
> Signed-off-by: Daniel Drake <drake@endlessm.com>
> ---
>  drivers/hid/Kconfig    |  1 +
>  drivers/hid/hid-asus.c | 24 +++++++++++++++++++++++-
>  2 files changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 0000434a1fbd..3c0d461bb830 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -149,6 +149,7 @@ config HID_APPLEIR
>  config HID_ASUS
>         tristate "Asus"
>         depends on LEDS_CLASS

> +       depends on ASUS_WMI

I'm not sure it's a good idea.

Rather you may use ifdef inside header which also provides a stub for
the function. But be careful with corner cases, like ASUS_WMI=m &&
HID_ASUS=y.

>         ---help---
>         Support for Asus notebook built-in keyboard and touchpad via i2c, and
>         the Asus Republic of Gamers laptop keyboard special keys.
> diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
> index 88a5672f42cd..c42af8511b38 100644
> --- a/drivers/hid/hid-asus.c
> +++ b/drivers/hid/hid-asus.c
> @@ -26,6 +26,7 @@
>   * any later version.
>   */
>
> +#include <linux/asus-wmi.h>
>  #include <linux/dmi.h>
>  #include <linux/hid.h>
>  #include <linux/module.h>
> @@ -349,6 +350,25 @@ static void asus_kbd_backlight_work(struct work_struct *work)
>                 hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
>  }
>
> +/* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
> + * precedence. We only activate HID-based backlight control when the
> + * WMI control is not available.
> + */
> +static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
> +{
> +       u32 value;
> +       int ret;
> +
> +       ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
> +                                      ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
> +       hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
> +
> +       if (ret != 0)
> +               return false;
> +
> +       return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
> +}
> +
>  static int asus_kbd_register_leds(struct hid_device *hdev)
>  {
>         struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
> @@ -436,7 +456,9 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
>
>         drvdata->input = input;
>
> -       if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
> +       if (drvdata->enable_backlight &&
> +           !asus_kbd_wmi_led_control_present(hdev) &&
> +           asus_kbd_register_leds(hdev))
>                 hid_warn(hdev, "Failed to initialize backlight.\n");
>
>         return 0;
> --
> 2.17.0
>
Benjamin Tissoires May 31, 2018, 11:43 a.m. UTC | #2
On Thu, May 31, 2018 at 12:43 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Tue, May 22, 2018 at 11:55 PM, Daniel Drake <drake@endlessm.com> wrote:
>> The Asus GL502VSK has the same 0B05:1837 keyboard as we've seen in
>> several Republic of Gamers laptops.
>>
>> However, in this model, the keybard backlight control exposed by hid-asus
>> has no effect on the keyboard backlight. Instead, the keyboard
>> backlight is correctly driven by asus-wmi.
>>
>> With two keyboard backlight devices available (and only the acer-wmi
>> one working), GNOME is picking the wrong one to drive in the UI.
>>
>> Avoid this problem by not creating the backlight interface when we
>> detect a WMI-driven keyboard backlight.
>>
>> We have also tested Asus GL702VMK which does have the hid-asus
>> backlight present, and it still works fine with this patch (WMI method
>> call returns UNSUPPORTED_METHOD).
>>
>> Signed-off-by: Daniel Drake <drake@endlessm.com>
>> ---
>>  drivers/hid/Kconfig    |  1 +
>>  drivers/hid/hid-asus.c | 24 +++++++++++++++++++++++-
>>  2 files changed, 24 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
>> index 0000434a1fbd..3c0d461bb830 100644
>> --- a/drivers/hid/Kconfig
>> +++ b/drivers/hid/Kconfig
>> @@ -149,6 +149,7 @@ config HID_APPLEIR
>>  config HID_ASUS
>>         tristate "Asus"
>>         depends on LEDS_CLASS
>
>> +       depends on ASUS_WMI
>
> I'm not sure it's a good idea.
>
> Rather you may use ifdef inside header which also provides a stub for
> the function. But be careful with corner cases, like ASUS_WMI=m &&
> HID_ASUS=y.

I wonder if the report descriptors are not enough to provide the
information that the keyboard backlights are driven by wmi instead of
plain HID (or if there is any register that tells us that the
backlights are not handled by HID).
If not, then I have nothing against the approach.

Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Cheers,
Benjamin

>
>>         ---help---
>>         Support for Asus notebook built-in keyboard and touchpad via i2c, and
>>         the Asus Republic of Gamers laptop keyboard special keys.
>> diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
>> index 88a5672f42cd..c42af8511b38 100644
>> --- a/drivers/hid/hid-asus.c
>> +++ b/drivers/hid/hid-asus.c
>> @@ -26,6 +26,7 @@
>>   * any later version.
>>   */
>>
>> +#include <linux/asus-wmi.h>
>>  #include <linux/dmi.h>
>>  #include <linux/hid.h>
>>  #include <linux/module.h>
>> @@ -349,6 +350,25 @@ static void asus_kbd_backlight_work(struct work_struct *work)
>>                 hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
>>  }
>>
>> +/* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
>> + * precedence. We only activate HID-based backlight control when the
>> + * WMI control is not available.
>> + */
>> +static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
>> +{
>> +       u32 value;
>> +       int ret;
>> +
>> +       ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
>> +                                      ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
>> +       hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
>> +
>> +       if (ret != 0)
>> +               return false;
>> +
>> +       return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
>> +}
>> +
>>  static int asus_kbd_register_leds(struct hid_device *hdev)
>>  {
>>         struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
>> @@ -436,7 +456,9 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
>>
>>         drvdata->input = input;
>>
>> -       if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
>> +       if (drvdata->enable_backlight &&
>> +           !asus_kbd_wmi_led_control_present(hdev) &&
>> +           asus_kbd_register_leds(hdev))
>>                 hid_warn(hdev, "Failed to initialize backlight.\n");
>>
>>         return 0;
>> --
>> 2.17.0
>>
>
>
>
> --
> With Best Regards,
> Andy Shevchenko
Daniel Drake June 1, 2018, 9:28 p.m. UTC | #3
On Thu, May 31, 2018 at 4:43 AM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>> +       depends on ASUS_WMI
>
> I'm not sure it's a good idea.
>
> Rather you may use ifdef inside header which also provides a stub for
> the function. But be careful with corner cases, like ASUS_WMI=m &&
> HID_ASUS=y.

What do you see as wrong with it? The driver already depends on e.g.
LEDS_CLASS for the functionality that it sometimes uses there.

In my opinion the ideal solution to the corner cases you mention is
the Kconfig "depends on" which is exactly what the patch is
proposing...

Daniel
Andy Shevchenko June 2, 2018, 2:08 p.m. UTC | #4
On Sat, Jun 2, 2018 at 12:28 AM, Daniel Drake <drake@endlessm.com> wrote:
> On Thu, May 31, 2018 at 4:43 AM, Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>>> +       depends on ASUS_WMI
>>
>> I'm not sure it's a good idea.
>>
>> Rather you may use ifdef inside header which also provides a stub for
>> the function. But be careful with corner cases, like ASUS_WMI=m &&
>> HID_ASUS=y.
>
> What do you see as wrong with it? The driver already depends on e.g.
> LEDS_CLASS for the functionality that it sometimes uses there.
>
> In my opinion the ideal solution to the corner cases you mention is
> the Kconfig "depends on" which is exactly what the patch is
> proposing...

depends on in this case adds less generic dependency to the more generic module.
Thus, we imply that we have more users when dependency is satisfied
than otherwise.
Which is simply not true.

Thus, you add a bulk dependency to unsuspecting users w/o any need.
Daniel Drake June 5, 2018, 5:33 p.m. UTC | #5
On Sat, Jun 2, 2018 at 8:08 AM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Sat, Jun 2, 2018 at 12:28 AM, Daniel Drake <drake@endlessm.com> wrote:
>> On Thu, May 31, 2018 at 4:43 AM, Andy Shevchenko
>> <andy.shevchenko@gmail.com> wrote:
>>>> +       depends on ASUS_WMI
>>>
>>> I'm not sure it's a good idea.
>>>
>>> Rather you may use ifdef inside header which also provides a stub for
>>> the function. But be careful with corner cases, like ASUS_WMI=m &&
>>> HID_ASUS=y.
>>
>> What do you see as wrong with it? The driver already depends on e.g.
>> LEDS_CLASS for the functionality that it sometimes uses there.
>>
>> In my opinion the ideal solution to the corner cases you mention is
>> the Kconfig "depends on" which is exactly what the patch is
>> proposing...
>
> depends on in this case adds less generic dependency to the more generic module.
> Thus, we imply that we have more users when dependency is satisfied
> than otherwise.
> Which is simply not true.
>
> Thus, you add a bulk dependency to unsuspecting users w/o any need.

I'm not familiar with this argument, but I'm happy to work on a
solution along these lines.

Upon initial attempt I can't find a clean approach that avoids the
corner cases that you mentioned though.

Specifically in the case of HID_ASUS=y and ASUS_WMI=m, we cannot try
to branch out to the newly exposed asus-wmi functionality since we
cannot have the kernel binary depend on a module.

Are you envisioning something like this code in hid-asus?

static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
{
#if defined(CONFIG_HID_ASUS) && defined(CONFIG_ASUS_WMI_MODULE)
    return 0;
#elif defined(CONFIG_ASUS_WMI) || defined(CONFIG_ASUS_WMI_MODULE)
    u32 value;
    int ret;

    ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
                       ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
    hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);

    if (ret != 0)
        return false;

    return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
#endif
}

Thanks
Daniel
Andy Shevchenko June 5, 2018, 9:16 p.m. UTC | #6
On Tue, Jun 5, 2018 at 8:33 PM, Daniel Drake <drake@endlessm.com> wrote:
> On Sat, Jun 2, 2018 at 8:08 AM, Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>> On Sat, Jun 2, 2018 at 12:28 AM, Daniel Drake <drake@endlessm.com> wrote:
>>> On Thu, May 31, 2018 at 4:43 AM, Andy Shevchenko
>>> <andy.shevchenko@gmail.com> wrote:
>>>>> +       depends on ASUS_WMI
>>>>
>>>> I'm not sure it's a good idea.
>>>>
>>>> Rather you may use ifdef inside header which also provides a stub for
>>>> the function. But be careful with corner cases, like ASUS_WMI=m &&
>>>> HID_ASUS=y.
>>>
>>> What do you see as wrong with it? The driver already depends on e.g.
>>> LEDS_CLASS for the functionality that it sometimes uses there.
>>>
>>> In my opinion the ideal solution to the corner cases you mention is
>>> the Kconfig "depends on" which is exactly what the patch is
>>> proposing...
>>
>> depends on in this case adds less generic dependency to the more generic module.
>> Thus, we imply that we have more users when dependency is satisfied
>> than otherwise.
>> Which is simply not true.
>>
>> Thus, you add a bulk dependency to unsuspecting users w/o any need.
>
> I'm not familiar with this argument, but I'm happy to work on a
> solution along these lines.

This what comes from Linus and other maintainers who care about kernel
being high modularized.

> Upon initial attempt I can't find a clean approach that avoids the
> corner cases that you mentioned though.
>
> Specifically in the case of HID_ASUS=y and ASUS_WMI=m, we cannot try
> to branch out to the newly exposed asus-wmi functionality since we
> cannot have the kernel binary depend on a module.
>
> Are you envisioning something like this code in hid-asus?

No, no. Not uglifying it with #ifdefs.

Like I said earlier one part of the solution is to add #ifdef into
asus-wmi.h which you include here.
The other part is to carefully crafted Kconfig line for dependency
that allows you to handle that corner case. I don't remember by hart
how to cook that, but we have some examples in kernel.
I would check if I can find one. Though you may try to find yourself as well.

>
> static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
> {
> #if defined(CONFIG_HID_ASUS) && defined(CONFIG_ASUS_WMI_MODULE)
>     return 0;
> #elif defined(CONFIG_ASUS_WMI) || defined(CONFIG_ASUS_WMI_MODULE)
>     u32 value;
>     int ret;
>
>     ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
>                        ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
>     hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
>
>     if (ret != 0)
>         return false;
>
>     return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
> #endif
> }
Daniel Drake June 14, 2018, 5:18 p.m. UTC | #7
On Tue, Jun 5, 2018 at 3:16 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> The other part is to carefully crafted Kconfig line for dependency
> that allows you to handle that corner case. I don't remember by hart
> how to cook that, but we have some examples in kernel.
> I would check if I can find one. Though you may try to find yourself as well.

I have looked through many Kconfig files under drivers as examples,
and I can't see any way to write the "depends on" line to enforce the
specific required logic of disallowing HID_ASUS=y combined with
ASUS_WMI=m, other than the approach that I already put in the patch:

config HID_ASUS
    tristate "Asus"
    depends on LEDS_CLASS
    depends on ASUS_WMI

The alternative is to use "select", but that also deviates away from
your suggestion, and I don't think it's right. Plus "select ASUS_WMI"
causes this circular dependency:

drivers/platform/x86/Kconfig:627:error: recursive dependency detected!
drivers/platform/x86/Kconfig:627:    symbol ASUS_WMI is selected by HID_ASUS
drivers/hid/Kconfig:149:    symbol HID_ASUS depends on LEDS_CLASS
drivers/leds/Kconfig:16:    symbol LEDS_CLASS is selected by ASUS_WMI
For a resolution refer to Documentation/kbuild/kconfig-language.txt
subsection "Kconfig recursive dependency limitations"

So if you do prefer "select" we would have to make it like this:

config HID_ASUS
    tristate "Asus"
    select LEDS_CLASS
    select ASUS_WMI

Thanks for your input

Daniel
Daniel Drake July 17, 2018, 2:11 p.m. UTC | #8
Hi Andy,

On Thu, Jun 14, 2018 at 12:18 PM, Daniel Drake <drake@endlessm.com> wrote:
> On Tue, Jun 5, 2018 at 3:16 PM, Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>> The other part is to carefully crafted Kconfig line for dependency
>> that allows you to handle that corner case. I don't remember by hart
>> how to cook that, but we have some examples in kernel.
>> I would check if I can find one. Though you may try to find yourself as well.
>
> I have looked through many Kconfig files under drivers as examples,
> and I can't see any way to write the "depends on" line to enforce the
> specific required logic of disallowing HID_ASUS=y combined with
> ASUS_WMI=m, other than the approach that I already put in the patch:
>
> config HID_ASUS
>     tristate "Asus"
>     depends on LEDS_CLASS
>     depends on ASUS_WMI
>
> The alternative is to use "select", but that also deviates away from
> your suggestion, and I don't think it's right. Plus "select ASUS_WMI"
> causes this circular dependency:
>
> drivers/platform/x86/Kconfig:627:error: recursive dependency detected!
> drivers/platform/x86/Kconfig:627:    symbol ASUS_WMI is selected by HID_ASUS
> drivers/hid/Kconfig:149:    symbol HID_ASUS depends on LEDS_CLASS
> drivers/leds/Kconfig:16:    symbol LEDS_CLASS is selected by ASUS_WMI
> For a resolution refer to Documentation/kbuild/kconfig-language.txt
> subsection "Kconfig recursive dependency limitations"
>
> So if you do prefer "select" we would have to make it like this:
>
> config HID_ASUS
>     tristate "Asus"
>     select LEDS_CLASS
>     select ASUS_WMI

This fix is still blocked on your feedback/review. Any clarifications?

Thanks
Daniel
Andy Shevchenko July 30, 2018, 6:06 p.m. UTC | #9
On Tue, Jul 17, 2018 at 5:11 PM, Daniel Drake <drake@endlessm.com> wrote:
> Hi Andy,
>
> On Thu, Jun 14, 2018 at 12:18 PM, Daniel Drake <drake@endlessm.com> wrote:
>> On Tue, Jun 5, 2018 at 3:16 PM, Andy Shevchenko
>> <andy.shevchenko@gmail.com> wrote:
>>> The other part is to carefully crafted Kconfig line for dependency
>>> that allows you to handle that corner case. I don't remember by hart
>>> how to cook that, but we have some examples in kernel.
>>> I would check if I can find one. Though you may try to find yourself as well.
>>
>> I have looked through many Kconfig files under drivers as examples,
>> and I can't see any way to write the "depends on" line to enforce the
>> specific required logic of disallowing HID_ASUS=y combined with
>> ASUS_WMI=m, other than the approach that I already put in the patch:
>>
>> config HID_ASUS
>>     tristate "Asus"
>>     depends on LEDS_CLASS
>>     depends on ASUS_WMI
>>
>> The alternative is to use "select", but that also deviates away from
>> your suggestion, and I don't think it's right. Plus "select ASUS_WMI"
>> causes this circular dependency:
>>
>> drivers/platform/x86/Kconfig:627:error: recursive dependency detected!
>> drivers/platform/x86/Kconfig:627:    symbol ASUS_WMI is selected by HID_ASUS
>> drivers/hid/Kconfig:149:    symbol HID_ASUS depends on LEDS_CLASS
>> drivers/leds/Kconfig:16:    symbol LEDS_CLASS is selected by ASUS_WMI
>> For a resolution refer to Documentation/kbuild/kconfig-language.txt
>> subsection "Kconfig recursive dependency limitations"
>>
>> So if you do prefer "select" we would have to make it like this:
>>
>> config HID_ASUS
>>     tristate "Asus"
>>     select LEDS_CLASS
>>     select ASUS_WMI
>

> This fix is still blocked on your feedback/review. Any clarifications?

I guess you are looking something like below with corresponding header
that provides stubs in case it's not enabled.

        depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)
Daniel Drake July 31, 2018, 2:22 a.m. UTC | #10
On Mon, Jul 30, 2018 at 1:06 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> I guess you are looking something like below with corresponding header
> that provides stubs in case it's not enabled.
>
>         depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)

I can make config HID_ASUS
  depends on ASUS_WMI=y || (ASUS_WMI=m && m)

and the corner case you raise (HID_ASUS=y and ASUS_WMI=m) can not be selected.

And there is no need to add any stub headers as far as I can see, but
I must admit I still don't understand why this type of dependency
statement is preferred over a simple "depends on ASUS_WMI". Am I
missing something?

Thanks
Daniel
diff mbox

Patch

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 0000434a1fbd..3c0d461bb830 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -149,6 +149,7 @@  config HID_APPLEIR
 config HID_ASUS
 	tristate "Asus"
 	depends on LEDS_CLASS
+	depends on ASUS_WMI
 	---help---
 	Support for Asus notebook built-in keyboard and touchpad via i2c, and
 	the Asus Republic of Gamers laptop keyboard special keys.
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 88a5672f42cd..c42af8511b38 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -26,6 +26,7 @@ 
  * any later version.
  */
 
+#include <linux/asus-wmi.h>
 #include <linux/dmi.h>
 #include <linux/hid.h>
 #include <linux/module.h>
@@ -349,6 +350,25 @@  static void asus_kbd_backlight_work(struct work_struct *work)
 		hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
 }
 
+/* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
+ * precedence. We only activate HID-based backlight control when the
+ * WMI control is not available.
+ */
+static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
+{
+	u32 value;
+	int ret;
+
+	ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2,
+				       ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
+	hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
+
+	if (ret != 0)
+		return false;
+
+	return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
+}
+
 static int asus_kbd_register_leds(struct hid_device *hdev)
 {
 	struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
@@ -436,7 +456,9 @@  static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
 
 	drvdata->input = input;
 
-	if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
+	if (drvdata->enable_backlight &&
+	    !asus_kbd_wmi_led_control_present(hdev) &&
+	    asus_kbd_register_leds(hdev))
 		hid_warn(hdev, "Failed to initialize backlight.\n");
 
 	return 0;