Re: [PATCH] platform/x86: huawei-wmi: add ACPI fallback for Fn-lock on newer models

From: Superstes

Date: Mon May 25 2026 - 15:22:26 EST


>> Thank you for working on this. Could you open an issue and/or send a PR to https://github.com/aymanbagabas/Huawei-WMI ?
Yes, I can send PR in the next two-three days.
>> This is very specific to the FLMH-XX model. Can you confirm this is the case for other newer models?
No, it is the latest model in the Matebook 14 series, I've just bought
it recently and faced multiple issues, which I try to resolve. I can't
found any information about that issues from another users, but i
think that it can be related with other recent laptop based on Intel
Core Ultra processors, it will be good to have someone with following
models:
MateBook Fold (2025)
MateBook X Pro (2024)
MateBook GT 14 (2024)
MateBook D 14 (2024)
>> Wouldn't it be better to put this behavior behind a quirk instead of enforcing it on the whole module?
I haven't found a better place to make such changes. But you can
suggest something. But I think that my workaround is safe because it
calls very specific ACPI objects and uses default fallbacks.

By the way, maybe You, or Ilpo knows a good place to implement board
specific i2c acpi fixes? It Looks like there is a race condition
situation which leads to arbitration loss when kernel tries to
initialize multiple devices on the i2c bus. To fix this I've disabled
light sensor and made systemd service to remove and enable the
i2c_hid_acpi module, but I haven't found a place where to implement a
quirk that fixes that issue.


пн, 25 мая 2026 г. в 23:38, Ayman Bagabas <ayman.bagabas@xxxxxxxxx>:
>
> >
> > Newer Huawei laptops (e.g. FLMH-XX / MateBook 14 2024) no longer support
> > the legacy WMI interface for Fn-lock control. Instead, they expose direct
> > ACPI methods \GFRS and \SFRS (Get/Set Fn key Reversal Status) which
> > communicate with the EC via registers 0x6B (read) and 0x6C (write).
> >
> > Add huawei_acpi_fn_lock_get() and huawei_acpi_fn_lock_set() helpers that
> > use acpi_evaluate_object() to call these methods. Both
> > huawei_wmi_fn_lock_get() and huawei_wmi_fn_lock_set() now probe for
> > \GFRS/\SFRS via acpi_has_method() first and fall back to the legacy WMI
> > path if not present.
>
> Thank you for working on this. Could you open an issue and/or send a PR
> to https://github.com/aymanbagabas/Huawei-WMI ?
>
> >
> > Tested on: HUAWEI FLMH-XX (MateBook 14 2024),
> > CachyOS (kernel 7.0.9-1-cachyos).
> >
> > Signed-off-by: Shaposhnikov Daniil <2minesweeper2@xxxxxxxxx>
> > ---
> > drivers/platform/x86/huawei-wmi.c | 95 +++++++++++++++++++++++++++++++
> > 1 file changed, 95 insertions(+)
> >
> > diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
> > index 93cca17fdf58..19cd8f1a8e33 100644
> > --- a/drivers/platform/x86/huawei-wmi.c
> > +++ b/drivers/platform/x86/huawei-wmi.c
> > @@ -527,11 +527,101 @@ static void huawei_wmi_battery_exit(struct device *dev)
> >
> > /* Fn lock */
> >
> > +/*
> > + * Newer Huawei models (e.g. HUAWEI FLMH-XX / MateBook 14 2024) use direct
> > + * ACPI methods \GFRS / \SFRS (Get/Set Fn key Reversal Status) to control
> > + * Fn-lock via EC registers 0x6B (read) and 0x6C (write).
> > + *
> > + * GFRS response buffer layout:
> > + * byte[0] = STAT (0 = success)
> > + * byte[1] = 0x01 (fn-lock off) or 0x02 (fn-lock on)
> > + *
> > + * SFRS argument layout (CreateByteField(Arg0, 0x02, FRSR)):
> > + * Value is read from byte[2] of the integer argument, so it must be
> > + * passed as (value << 16):
> > + * (1 << 16) = fn-lock off (writes 0x55 to EC 0x6C)
> > + * (2 << 16) = fn-lock on (writes 0x5A to EC 0x6C)
> > + */
>
> This is very specific to the FLMH-XX model. Can you confirm this is the
> case for other newer models?
>
> > +
> > +static int huawei_acpi_fn_lock_get(int *on)
> > +{
> > + union acpi_object acpi_arg, *obj;
> > + struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg };
> > + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
> > + acpi_status status;
> > + u8 val;
> > +
> > + acpi_arg.type = ACPI_TYPE_INTEGER;
> > + acpi_arg.integer.value = 0;
> > +
> > + status = acpi_evaluate_object(NULL, "\\GFRS", &arg_list, &output);
> > + if (ACPI_FAILURE(status))
> > + return -EIO;
> > +
> > + obj = output.pointer;
> > + if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 2) {
> > + kfree(obj);
> > + return -ENODATA;
> > + }
> > +
> > + /* byte[0] = STAT (0 = success), byte[1] = 1 (off) or 2 (on) */
> > + if (obj->buffer.pointer[0] != 0) {
> > + kfree(obj);
> > + return -EIO;
> > + }
> > +
> > + val = obj->buffer.pointer[1];
> > + if (val != 1 && val != 2) {
> > + kfree(obj);
> > + return -ENODATA;
> > + }
> > +
> > + if (on)
> > + *on = val - 1; /* 1→0 (off), 2→1 (on) */
> > +
> > + kfree(obj);
> > + return 0;
> > +}
> > +
> > +static int huawei_acpi_fn_lock_set(int on)
> > +{
> > + union acpi_object acpi_arg, *obj;
> > + struct acpi_object_list arg_list = { .count = 1, .pointer = &acpi_arg };
> > + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
> > + acpi_status status;
> > + int ret = 0;
> > +
> > + /*
> > + * SFRS reads byte[2] of its argument via CreateByteField(Arg0, 0x02).
> > + * on=0 → FRSR=1 → EC gets 0x55 (fn-lock off)
> > + * on=1 → FRSR=2 → EC gets 0x5A (fn-lock on)
> > + */
> > + acpi_arg.type = ACPI_TYPE_INTEGER;
> > + acpi_arg.integer.value = (u64)(on + 1) << 16;
> > +
> > + status = acpi_evaluate_object(NULL, "\\SFRS", &arg_list, &output);
> > + if (ACPI_FAILURE(status))
> > + return -EIO;
> > +
> > + obj = output.pointer;
> > + if (obj && obj->type == ACPI_TYPE_BUFFER &&
> > + obj->buffer.length >= 1 && obj->buffer.pointer[0] != 0)
> > + ret = -EIO;
> > +
> > + kfree(obj);
> > + return ret;
> > +}
> > +
> > static int huawei_wmi_fn_lock_get(int *on)
> > {
> > u8 ret[0x100] = { 0 };
> > int err, i;
> >
> > + /* Newer models: use direct ACPI \GFRS method */
> > + if (acpi_has_method(NULL, "\\GFRS"))
> > + return huawei_acpi_fn_lock_get(on);
>
> Wouldn't it be better to put this behavior behind a quirk instead
> of enforcing it on the whole module? Keep in mind that this is
> also used by Honor devices that have the same WMI method.
>
> > +
> > + /* Legacy WMI fallback */
> > err = huawei_wmi_cmd(FN_LOCK_GET, ret, 0x100);
> > if (err)
> > return err;
> > @@ -550,6 +640,11 @@ static int huawei_wmi_fn_lock_set(int on)
> > {
> > union hwmi_arg arg;
> >
> > + /* Newer models: use direct ACPI \SFRS method */
> > + if (acpi_has_method(NULL, "\\SFRS"))
> > + return huawei_acpi_fn_lock_set(on);
> > +
> > + /* Legacy WMI fallback */
> > arg.cmd = FN_LOCK_SET;
> > arg.args[2] = on + 1; // 0 undefined, 1 off, 2 on.
> >
> > --
> > 2.54.0
> >