The event data of the WMI event 0xD0, which is assumed to be the fn_lock, is used to indicate several special keys on newer Yoga 7/9 laptops. Add support for these keys using the wmi_get_event_data_with_guid() function. Signed-off-by: Philipp Jungkamp <p.jungkamp@xxxxxxx> --- I can't really judge how this would affect other devices which depend on the event to toggle their fn-lock light unconditionally. One could check whether the event data on those devices makes it clear when exactly the eval_hals()/exec_sals() path is needed. This should be observable through the dev_dbg() put before the ideapad_input_report(). drivers/platform/x86/ideapad-laptop.c | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 33b3dfdd1b08..2ade423c7813 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1074,6 +1074,7 @@ static void ideapad_sysfs_exit(struct ideapad_private *priv) /* * input device */ +#define IDEAPAD_WMI_KEY 0x100 static const struct key_entry ideapad_keymap[] = { { KE_KEY, 6, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 7, { KEY_CAMERA } }, @@ -1087,6 +1088,26 @@ static const struct key_entry ideapad_keymap[] = { { KE_KEY, 66, { KEY_TOUCHPAD_OFF } }, { KE_KEY, 67, { KEY_TOUCHPAD_ON } }, { KE_KEY, 128, { KEY_ESC } }, + + /* + * WMI keys + */ + + /* FnLock (handled by the firmware) */ + { KE_IGNORE, 0x02 | IDEAPAD_WMI_KEY }, + /* Customizable Lenovo Hotkey ("star" with 'S' inside) */ + { KE_KEY, 0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } }, + /* Dark mode toggle */ + { KE_KEY, 0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } }, + /* Sound profile switch */ + { KE_KEY, 0x12 | IDEAPAD_WMI_KEY, { KEY_PROG2 } }, + /* Lenovo Virtual Background application */ + { KE_KEY, 0x28 | IDEAPAD_WMI_KEY, { KEY_PROG3 } }, + /* Lenovo Support */ + { KE_KEY, 0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } }, + /* Refresh Rate Toggle */ + { KE_KEY, 0x0a | IDEAPAD_WMI_KEY, { KEY_DISPLAYTOGGLE } }, + { KE_END }, }; @@ -1496,6 +1517,10 @@ static void ideapad_wmi_notify(u32 value, void *context) struct ideapad_private *priv = context; unsigned long result; + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *data; + acpi_status status; + switch (value) { case 128: ideapad_input_report(priv, value); @@ -1506,6 +1531,27 @@ static void ideapad_wmi_notify(u32 value, void *context) exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF); } + + status = wmi_get_event_data_with_guid(priv->fnesc_guid, value, &response); + if (ACPI_FAILURE(status)) { + dev_warn(&priv->platform_device->dev, + "Bad WMI event data 0x%x\n", status); + break; + } + + data = (union acpi_object *) response.pointer; + if (data->type != ACPI_TYPE_INTEGER) { + dev_warn(&priv->platform_device->dev, + "WMI event data is not an integer\n"); + } else { + dev_dbg(&priv->platform_device->dev, + "WMI event: notify_id=%d, data=%d\n", + value, + data->integer.value); + ideapad_input_report(priv, data->integer.value | IDEAPAD_WMI_KEY); + } + + kfree(response.pointer); break; default: dev_info(&priv->platform_device->dev, -- 2.38.1