From: Hans de Goede <hidden> Date: 2021-02-20 12:26:30
Hi All,
Here is v2 of my series with mute LED handling fixes and improvements
for the hid-lenovo driver.
This time I've added the LED folks to the Cc in case they have any input,
but there is nothing controversial in here wrt use of the LED API.
The following patches were changed or are new in version 2 of the
series, see the individual patches for detaisl:
[PATCH v2 2/7] HID: lenovo: Fix lenovo_led_set_tp10ubkbd() error handling
[PATCH v2 4/7] HID: lenovo: Remove lenovo_led_brightness_get()
[PATCH v2 5/7] HID: lenovo: Set LEDs max_brightness value
Regards,
Hans
Hans de Goede (7):
HID: lenovo: Use brightness_set_blocking callback for setting LEDs
brightness
HID: lenovo: Fix lenovo_led_set_tp10ubkbd() error handling
HID: lenovo: Check hid_get_drvdata() returns non NULL in
lenovo_event()
HID: lenovo: Remove lenovo_led_brightness_get()
HID: lenovo: Set LEDs max_brightness value
HID: lenovo: Map mic-mute button to KEY_F20 instead of KEY_MICMUTE
HID: lenovo: Set default_trigger-s for the mute and micmute LEDs
drivers/hid/hid-lenovo.c | 61 ++++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 30 deletions(-)
--
2.30.1
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:30
The lenovo_led_brightness_set function may sleep, so we should have the
the led_class_dev's brightness_set_blocking callback point to it, rather
then the regular brightness_set callback.
When toggle through sysfs this is not a problem, but the brightness_set
callback may be called from atomic context when using LED-triggers.
Fixes: bc04b37ea0ec ("HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support")
Signed-off-by: Hans de Goede <redacted>
---
drivers/hid/hid-lenovo.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:30
Fix the following issues with lenovo_led_set_tp10ubkbd() error handling:
1. On success hid_hw_raw_request() returns the number of bytes send.
So we should check for (ret != 3) rather then for (ret != 0).
2. Actually propagate errors to the caller.
3. Since the LEDs are part of an USB keyboard-dock the mute LEDs can go
away at any time. Don't log an error when ret == -ENODEV and set the
LED_HW_PLUGGABLE flag to avoid errors getting logged when the USB gets
disconnected.
Fixes: bc04b37ea0ec ("HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support")
Signed-off-by: Hans de Goede <redacted>
---
Changes in v2:
- Rewrite to fix a bunch of other error-handling issues too
---
drivers/hid/hid-lenovo.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:31
The HID lenovo probe function only attaches drvdata to one of the
USB interfaces, but lenovo_event() will get called for all USB interfaces
to which hid-lenovo is bound.
This allows a malicious device to fake being a device handled by
hid-lenovo, which generates events for which lenovo_event() has
special handling (and thus dereferences hid_get_drvdata()) on another
interface triggering a NULL pointer exception.
Add a check for hid_get_drvdata() returning NULL, avoiding this
possible NULL pointer exception.
Fixes: bc04b37ea0ec ("HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support")
Signed-off-by: Hans de Goede <redacted>
---
drivers/hid/hid-lenovo.c | 3 +++
1 file changed, 3 insertions(+)
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:31
The led_classdev already contains a cached value of the last set
brightness, the brightness_get callback is only meant for LED drivers
which can read back the actual / current brightness from the hardware.
Since lenovo_led_brightness_get() just returns the last set value
it does not add any functionality, so we can just remove it.
Signed-off-by: Hans de Goede <redacted>
---
Changes in v2:
- New patch in v2 of this patch-set
---
drivers/hid/hid-lenovo.c | 18 ------------------
1 file changed, 18 deletions(-)
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:31
The LEDs can only by turned on/off, so max_brightness should be set to 1
(aka LED_ON). Without this the max_brightness sysfs-attribute will report
255 which is wrong.
Signed-off-by: Hans de Goede <redacted>
---
Changes in v2:
- New patch in v2 of this patch-set
---
drivers/hid/hid-lenovo.c | 2 ++
1 file changed, 2 insertions(+)
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:31
Mapping the mic-mute button to KEY_MICMUTE is technically correct but
KEY_MICMUTE translates to a scancode of 256 (248 + 8) under X,
which does not fit in 8 bits, so it does not work.
Because of this userspace is expecting KEY_F20 instead,
theoretically KEY_MICMUTE should work under Wayland but even
there it does not work, because the desktop-environment is
listening only for KEY_F20 and not for KEY_MICMUTE.
Fixes: bc04b37ea0ec ("HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support")
Signed-off-by: Hans de Goede <redacted>
---
drivers/hid/hid-lenovo.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
@@ -33,6 +33,9 @@#include"hid-ids.h"+/* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */+#define LENOVO_KEY_MICMUTE KEY_F20+structlenovo_drvdata{u8led_report[3];/* Must be first for proper alignment */intled_state;
@@ -128,7 +131,7 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,if(usage->hid==(HID_UP_BUTTON|0x0010)){/* This sub-device contains trackpoint, mark it */hid_set_drvdata(hdev,(void*)1);-map_key_clear(KEY_MICMUTE);+map_key_clear(LENOVO_KEY_MICMUTE);return1;}return0;
@@ -143,7 +146,7 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,(usage->hid&HID_USAGE_PAGE)==HID_UP_LNVENDOR){switch(usage->hid&HID_USAGE){case0x00f1:/* Fn-F4: Mic mute */-map_key_clear(KEY_MICMUTE);+map_key_clear(LENOVO_KEY_MICMUTE);return1;case0x00f2:/* Fn-F5: Brightness down */map_key_clear(KEY_BRIGHTNESSDOWN);
@@ -233,7 +236,7 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,map_key_clear(KEY_FN_ESC);return1;case9:/* Fn-F4: Mic mute */-map_key_clear(KEY_MICMUTE);+map_key_clear(LENOVO_KEY_MICMUTE);return1;case10:/* Fn-F7: Control panel */map_key_clear(KEY_CONFIG);
From: Hans de Goede <hidden> Date: 2021-02-20 12:26:31
The mute and mic-mute LEDs should be automatically turned on/off based
on the audio-cards mixer settings.
Add the standardized default-trigger names for this, so that the alsa
code can turn the LEDs on/off as appropriate (on supported audio cards).
This brings the mute/mic-mute LED support inline with the thinkpad_acpi
support for the same LEDs in keyboards directly connected to the
laptop's embedded-controller.
Signed-off-by: Hans de Goede <redacted>
---
drivers/hid/hid-lenovo.c | 2 ++
1 file changed, 2 insertions(+)
From: Marek Behun <hidden> Date: 2021-02-21 01:43:10
On Sat, 20 Feb 2021 13:24:37 +0100
Hans de Goede [off-list ref] wrote:
Mapping the mic-mute button to KEY_MICMUTE is technically correct but
KEY_MICMUTE translates to a scancode of 256 (248 + 8) under X,
which does not fit in 8 bits, so it does not work.
Why does it need to fit 8 bits? Where is the problem?
Marek
From: Hans de Goede <hidden> Date: 2021-02-21 10:44:05
Hi,
On 2/21/21 2:42 AM, Marek Behun wrote:
On Sat, 20 Feb 2021 13:24:37 +0100
Hans de Goede [off-list ref] wrote:
quoted
Mapping the mic-mute button to KEY_MICMUTE is technically correct but
KEY_MICMUTE translates to a scancode of 256 (248 + 8) under X,
which does not fit in 8 bits, so it does not work.
Why does it need to fit 8 bits? Where is the problem?
As the commit message says, "under X" aka X11 / Xorg. This is a well known
limitation of the X11 input stack / of XKB *as implemented in X11*
the Wayland input stack does not have this limitations and does allow
using raw key-codes >= 248.
If you look at e.g. :
https://github.com/systemd/systemd/blob/main/hwdb.d/60-keyboard.hwdb
Which (mostly) maps custom PS/2 scancodes used for some "media" keys
on laptops to linux evdev KEY_FOO codes, then you will see that there
are no lines there which end with "=micmute" instead there are quite
a few lines like this:
KEYBOARD_KEY_8a=f20 # Microphone mute button; should be micmute
Arguably it would be more correct to have the kernel still send
KEY_MICMUTE and do the remapping to KEY_F20 in userspace in e.g. hwdb.
But that will not work here, the remapping is done based on mapping
the HID usage-code to a new evdev KEY_FOO code, basically overriding
lenovo_input_mapping_tp10_ultrabook_kbd() mapping.
But the "Lenovo ThinkPad 10 Ultrabook Keyboard" uses the same 0x000c0001
usage code for all of its custom Fn+F# media keys, so instead of doing
the mapping purely on usage-code it is done on a combination of usage-code +
the index of the key in the input-report (since the usage-code is not unique
for a single key):
/*
* The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
* a bunch of keys which have no standard consumer page code.
*/
if (usage->hid == 0x000c0001) {
switch (usage->usage_index) {
case 8: /* Fn-Esc: Fn-lock toggle */
map_key_clear(KEY_FN_ESC);
return 1;
case 9: /* Fn-F4: Mic mute */
map_key_clear(LENOVO_KEY_MICMUTE);
return 1;
...
So in this case we cannot fixup the mapping from userspace, as userspace
remapping is purely done based on the "scancode" which in case of HID devices
is the HID usage-code.
I don't even know what will happen if we were to try. I guess that either the
first key with a matching usage-code is remapped, or all of them are remapped,
both of which are wrong.
Regards,
Hans
From: Marek Behún <kabel@kernel.org> Date: 2021-02-21 11:38:07
On Sun, 21 Feb 2021 11:42:16 +0100
Hans de Goede [off-list ref] wrote:
Hi,
On 2/21/21 2:42 AM, Marek Behun wrote:
quoted
On Sat, 20 Feb 2021 13:24:37 +0100
Hans de Goede [off-list ref] wrote:
quoted
Mapping the mic-mute button to KEY_MICMUTE is technically correct but
KEY_MICMUTE translates to a scancode of 256 (248 + 8) under X,
which does not fit in 8 bits, so it does not work.
Why does it need to fit 8 bits? Where is the problem?
As the commit message says, "under X" aka X11 / Xorg. This is a well known
limitation of the X11 input stack / of XKB *as implemented in X11*
the Wayland input stack does not have this limitations and does allow
using raw key-codes >= 248.
If you look at e.g. :
https://github.com/systemd/systemd/blob/main/hwdb.d/60-keyboard.hwdb
Which (mostly) maps custom PS/2 scancodes used for some "media" keys
on laptops to linux evdev KEY_FOO codes, then you will see that there
are no lines there which end with "=micmute" instead there are quite
a few lines like this:
KEYBOARD_KEY_8a=f20 # Microphone mute button; should be micmute
Arguably it would be more correct to have the kernel still send
KEY_MICMUTE and do the remapping to KEY_F20 in userspace in e.g. hwdb.
But that will not work here, the remapping is done based on mapping
the HID usage-code to a new evdev KEY_FOO code, basically overriding
lenovo_input_mapping_tp10_ultrabook_kbd() mapping.
But the "Lenovo ThinkPad 10 Ultrabook Keyboard" uses the same 0x000c0001
usage code for all of its custom Fn+F# media keys, so instead of doing
the mapping purely on usage-code it is done on a combination of usage-code +
the index of the key in the input-report (since the usage-code is not unique
for a single key):
/*
* The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
* a bunch of keys which have no standard consumer page code.
*/
if (usage->hid == 0x000c0001) {
switch (usage->usage_index) {
case 8: /* Fn-Esc: Fn-lock toggle */
map_key_clear(KEY_FN_ESC);
return 1;
case 9: /* Fn-F4: Mic mute */
map_key_clear(LENOVO_KEY_MICMUTE);
return 1;
...
So in this case we cannot fixup the mapping from userspace, as userspace
remapping is purely done based on the "scancode" which in case of HID devices
is the HID usage-code.
I don't even know what will happen if we were to try. I guess that either the
first key with a matching usage-code is remapped, or all of them are remapped,
both of which are wrong.
Regards,
Hans
And no one ever solved this for X? OMFG :(
Very well then.
From: Hans de Goede <hidden> Date: 2021-02-21 11:52:25
Hi,
On 2/21/21 12:37 PM, Marek Behún wrote:
On Sun, 21 Feb 2021 11:42:16 +0100
Hans de Goede [off-list ref] wrote:
quoted
Hi,
On 2/21/21 2:42 AM, Marek Behun wrote:
quoted
On Sat, 20 Feb 2021 13:24:37 +0100
Hans de Goede [off-list ref] wrote:
quoted
Mapping the mic-mute button to KEY_MICMUTE is technically correct but
KEY_MICMUTE translates to a scancode of 256 (248 + 8) under X,
which does not fit in 8 bits, so it does not work.
Why does it need to fit 8 bits? Where is the problem?
As the commit message says, "under X" aka X11 / Xorg. This is a well known
limitation of the X11 input stack / of XKB *as implemented in X11*
the Wayland input stack does not have this limitations and does allow
using raw key-codes >= 248.
If you look at e.g. :
https://github.com/systemd/systemd/blob/main/hwdb.d/60-keyboard.hwdb
Which (mostly) maps custom PS/2 scancodes used for some "media" keys
on laptops to linux evdev KEY_FOO codes, then you will see that there
are no lines there which end with "=micmute" instead there are quite
a few lines like this:
KEYBOARD_KEY_8a=f20 # Microphone mute button; should be micmute
Arguably it would be more correct to have the kernel still send
KEY_MICMUTE and do the remapping to KEY_F20 in userspace in e.g. hwdb.
But that will not work here, the remapping is done based on mapping
the HID usage-code to a new evdev KEY_FOO code, basically overriding
lenovo_input_mapping_tp10_ultrabook_kbd() mapping.
But the "Lenovo ThinkPad 10 Ultrabook Keyboard" uses the same 0x000c0001
usage code for all of its custom Fn+F# media keys, so instead of doing
the mapping purely on usage-code it is done on a combination of usage-code +
the index of the key in the input-report (since the usage-code is not unique
for a single key):
/*
* The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
* a bunch of keys which have no standard consumer page code.
*/
if (usage->hid == 0x000c0001) {
switch (usage->usage_index) {
case 8: /* Fn-Esc: Fn-lock toggle */
map_key_clear(KEY_FN_ESC);
return 1;
case 9: /* Fn-F4: Mic mute */
map_key_clear(LENOVO_KEY_MICMUTE);
return 1;
...
So in this case we cannot fixup the mapping from userspace, as userspace
remapping is purely done based on the "scancode" which in case of HID devices
is the HID usage-code.
I don't even know what will happen if we were to try. I guess that either the
first key with a matching usage-code is remapped, or all of them are remapped,
both of which are wrong.
Regards,
Hans
And no one ever solved this for X? OMFG :(
Many people have looked into fixing this, but X11 is a network protocol, and
the other side could be a many many years old X-terminal (one of those devices
which don't have their own OS but connect over xdmcp to show a desktop
running on some big machine somewhere else on the LAN).
XKB in X is layered on top of the original X input protocol, and the data
gets passed around multiple times in multiple different structs and it is
limited to a 8 bit wide int everywhere.
Note it is not just micmute. The F13 - F24 F-key range has been used to
work around this for a while now.
I'm aware of the following "mappings" being used for this:
evdev -> interpreted by userspace as
KEY_F20 -> mic-mute toggle
KEY_F21 -> touchpad on/off toggle
KEY_F22 -> touchpad on
KEY_F23 -> touchpad off
This is not pretty, I know.
Regards,
Hans
From: Pavel Machek <hidden> Date: 2021-02-23 09:00:46
On Sat 2021-02-20 13:24:32, Hans de Goede wrote:
The lenovo_led_brightness_set function may sleep, so we should have the
the led_class_dev's brightness_set_blocking callback point to it, rather
then the regular brightness_set callback.
When toggle through sysfs this is not a problem, but the brightness_set
callback may be called from atomic context when using LED-triggers.
Fixes: bc04b37ea0ec ("HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support")
Signed-off-by: Hans de Goede <redacted>