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

From: Superstes

Date: Tue May 26 2026 - 05:11:58 EST


>> Do you mean you'd want to serialize .probe()s of those devices?
I don't really know how to fix this by now, I think serializing i2c
devices initialization can help.
It should be well tested(booting, waking from sleep\hibernation) to
confirm that just serializing works, maybe other workarounds should be
used.

вт, 26 мая 2026 г. в 13:58, Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>:
>
> On Tue, 26 May 2026, Superstes wrote:
>
> > >> 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.
>
> Do you mean you'd want to serialize .probe()s of those devices?
>
> --
> i.
>
> > пн, 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
> > >
> >
> >
> >