All of lore.kernel.org
 help / color / mirror / Atom feed
From: Shaposhnikov Daniil <2minesweeper2@gmail.com>
To: hansg@kernel.org
Cc: ilpo.jarvinen@linux.intel.com, ayman.bagabas@gmail.com,
	platform-driver-x86@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Shaposhnikov Daniil <2minesweeper2@gmail.com>
Subject: [PATCH] platform/x86: huawei-wmi: add ACPI fallback for Fn-lock on newer models
Date: Sun, 24 May 2026 17:15:09 +0500	[thread overview]
Message-ID: <20260524121510.36961-1-2minesweeper2@gmail.com> (raw)

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.

Tested on: HUAWEI FLMH-XX (MateBook 14 2024),
CachyOS (kernel 7.0.9-1-cachyos).

Signed-off-by: Shaposhnikov Daniil <2minesweeper2@gmail.com>
---
 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)
+ */
+
+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);
+
+	/* 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


             reply	other threads:[~2026-05-24 12:15 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-24 12:15 Shaposhnikov Daniil [this message]
2026-05-25 10:16 ` [PATCH] platform/x86: huawei-wmi: add ACPI fallback for Fn-lock on newer models Ilpo Järvinen
2026-05-25 12:17 ` [PATCH v2 0/1] " Shaposhnikov Daniil
2026-05-25 12:17   ` [PATCH v2 1/1] " Shaposhnikov Daniil
2026-05-25 12:33     ` Ilpo Järvinen
2026-05-25 13:00 ` [PATCH v3 0/1] " Shaposhnikov Daniil
2026-05-25 13:00   ` [PATCH v3 1/1] " Shaposhnikov Daniil
2026-05-25 18:38 ` [PATCH] " Ayman Bagabas
2026-05-25 19:22   ` Superstes
     [not found]   ` <CALOxGBVJzk4GX2xrG3N1Djy1UZhMXMdcYKeJQuBqcf289SO32w@mail.gmail.com>
2026-05-26  8:58     ` Ilpo Järvinen
2026-05-26  9:09       ` Superstes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260524121510.36961-1-2minesweeper2@gmail.com \
    --to=2minesweeper2@gmail.com \
    --cc=ayman.bagabas@gmail.com \
    --cc=hansg@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.