From nobody Sun May 24 17:48:32 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 693A73932FA for ; Sun, 24 May 2026 12:15:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779624922; cv=none; b=fQnkBR6XjAppkVABA3TynBDucpilXQJEsEn0NKvMfFTlZrwP9ooPmmxZLTroPVCMbt8ol8Oe9PsnLq78195ZfOPge7/StfjK0sAV3GiOTAxtgZrmwJvw5EqgFWYB6NIMdwAF+Ibkyn1k0EgcRzYYMNyyby5VMFcHyqx0sckvHVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779624922; c=relaxed/simple; bh=HPzWupM2ZjUXX0eNWgKt1EEEJD8LJ/Sp25bHL+GC/no=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=bKIvBfmhKtw2trZjAu3obXFfSxrSvCQ842WQd3LBtqsdJil/453WZ3HCigQp5H4Az37u8lO7SuoQHmwS8gUGmgC1dY4pDo4+tA5CZuZAmbCsFIOLJYXOz4goDgbZI1gKQ2DtCgH7THCwn+MPRqbyfNh3OGrP1lilm1o7jNDj3po= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Sf1Skjm2; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Sf1Skjm2" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-4891b0786beso59245555e9.1 for ; Sun, 24 May 2026 05:15:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779624919; x=1780229719; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=CYEgaMhlMyzTUpGDpHyjsYsCWMtgGcpQtucUOR4+Pkg=; b=Sf1Skjm2aOsHmIsmbdU/t9HztzxdNhbb/0NKvSnpkfaUKCz1PylkTwCScJAGrtTWqV NXOOl3paWPbUXFQAKYiXhEMFP8ULsx9G4NeYK7pG98EwOgK6ri568+HUABK3fy5n7TJF 9e1orDT6Svmb2RZoy37LOiEFc65QHZwSm4pv2ekGul7PaQQiIPIEy13LDmduvB3Ax5bx 8xUPnn1fr0y7n2P/5Qdw3Mvz5/xHoF+/LWTQnxNMqD0A2GkF+DzmEGwA0K6oGpJZJQzF 1TWrK9GXefA7pfQ6JgbmyoginxmJIrOs3WnWWl2xtwCgV/YN48K7bor2TMQuZaxKy349 qygQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779624919; x=1780229719; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=CYEgaMhlMyzTUpGDpHyjsYsCWMtgGcpQtucUOR4+Pkg=; b=DdUG/hiNfDl7fwOWMJgvyqXc+gZteQInZa/M2oPrl3lX+pOV9/dxsLMv6YON3d7eJr h1zhBAwj6/WbH1w4NZgcmD0qlkFs5qoYStt5EWz3ZoFJshSAWcAvuok1GZnqb5yffsrB qMTr1Ul6IZGCWf3xH/zxgQUpcdXD1Bz3qKsuSLEDwQO65AzzGbzhIqE1MAlqUUNP1wgo UCE2LbTup8MU8031QrokDw8bEn49qWle4P/Qy6ffeYLiQ98Y+YOWHF7gi7TBAvxzr+mb xoPOdGzpTM2mmDqvma64RIvZKBse8UJz2UHSQNcKFJJE3RVxBpaROa8JhuoQU2dU9WY6 vx/w== X-Forwarded-Encrypted: i=1; AFNElJ8L4+K4PPlWGAvdFCNVkJQlQQvr2ljx7+1UipV5pUzf7dpsxhfHsMUKNU61am0QoeWg4mOtx3sQGcAMhck=@vger.kernel.org X-Gm-Message-State: AOJu0Yyl7/Fi+qP/WreXL+2/J6yBd6Y5DvtsPAwqNv/kfFJeAEnNqteG wzxztm7sJFk2MB3o+K3fdoB7Cyyo9mLj32CdUcnpZ0Ro5oVFoooeQ4L4 X-Gm-Gg: Acq92OFxgAOoLvV9S3LH6eBxZvJHWhIpNaugYtGtxsX1IKktlkFtwTQhm1K5aEHX77C joueJrdjWLWv5hx/GifqznRMO7C24/Z8w2Sxb0eqd3q6ihbuTTWmahaQHaQ7Rs/WlKeUoaosVUj sPl7w+JKIgvdJcl7oAdbFAWLJh7eMMAQ3oh/0pj/S/wgJCKnXLNSnnpy7DNcMh2DegGNvs+HCIY CSchPyh0YjZx4Bg1GuELnigYljz499LW1jyrKf8+60LlldAV5/P/wEG4X1SzNyuhwkuchoTWstZ XVKW9NdLJeDdy5FRkLuqub152wYga4a79VfeQZ1PHVVnEK6vASEQIKjPoKXUIpCmtoTlxtwqXPW dI/kjdnsgULZrWgI88pFgNGHIwje34ykPPhXc7g+h0+V/WgJBbLFuNU1Xeret5ixVqop24RgKje 2P3k6B2RNlXWjOZP46oNlZIlp2Q4Ml63T/+bS8j4WsItMfbrQMeg== X-Received: by 2002:a05:600c:4510:b0:48a:53ea:140b with SMTP id 5b1f17b1804b1-490428ddf15mr159551045e9.28.1779624918271; Sun, 24 May 2026 05:15:18 -0700 (PDT) Received: from localhost ([2a03:32c0:9005:2192:cf9:7a62:a7e9:23f0]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4904526ca21sm172443025e9.3.2026.05.24.05.15.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 24 May 2026 05:15:17 -0700 (PDT) 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 Message-ID: <20260524121510.36961-1-2minesweeper2@gmail.com> X-Mailer: git-send-email 2.54.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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/huawe= i-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 *d= ev) =20 /* Fn lock */ =20 +/* + * 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] =3D STAT (0 =3D success) + * byte[1] =3D 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) =3D fn-lock off (writes 0x55 to EC 0x6C) + * (2 << 16) =3D 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 =3D { .count =3D 1, .pointer =3D &acpi_a= rg }; + struct acpi_buffer output =3D { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + u8 val; + + acpi_arg.type =3D ACPI_TYPE_INTEGER; + acpi_arg.integer.value =3D 0; + + status =3D acpi_evaluate_object(NULL, "\\GFRS", &arg_list, &output); + if (ACPI_FAILURE(status)) + return -EIO; + + obj =3D output.pointer; + if (!obj || obj->type !=3D ACPI_TYPE_BUFFER || obj->buffer.length < 2) { + kfree(obj); + return -ENODATA; + } + + /* byte[0] =3D STAT (0 =3D success), byte[1] =3D 1 (off) or 2 (on) */ + if (obj->buffer.pointer[0] !=3D 0) { + kfree(obj); + return -EIO; + } + + val =3D obj->buffer.pointer[1]; + if (val !=3D 1 && val !=3D 2) { + kfree(obj); + return -ENODATA; + } + + if (on) + *on =3D val - 1; /* 1=E2=86=920 (off), 2=E2=86=921 (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 =3D { .count =3D 1, .pointer =3D &acpi_a= rg }; + struct acpi_buffer output =3D { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + int ret =3D 0; + + /* + * SFRS reads byte[2] of its argument via CreateByteField(Arg0, 0x02). + * on=3D0 =E2=86=92 FRSR=3D1 =E2=86=92 EC gets 0x55 (fn-lock off) + * on=3D1 =E2=86=92 FRSR=3D2 =E2=86=92 EC gets 0x5A (fn-lock on) + */ + acpi_arg.type =3D ACPI_TYPE_INTEGER; + acpi_arg.integer.value =3D (u64)(on + 1) << 16; + + status =3D acpi_evaluate_object(NULL, "\\SFRS", &arg_list, &output); + if (ACPI_FAILURE(status)) + return -EIO; + + obj =3D output.pointer; + if (obj && obj->type =3D=3D ACPI_TYPE_BUFFER && + obj->buffer.length >=3D 1 && obj->buffer.pointer[0] !=3D 0) + ret =3D -EIO; + + kfree(obj); + return ret; +} + static int huawei_wmi_fn_lock_get(int *on) { u8 ret[0x100] =3D { 0 }; int err, i; =20 + /* Newer models: use direct ACPI \GFRS method */ + if (acpi_has_method(NULL, "\\GFRS")) + return huawei_acpi_fn_lock_get(on); + + /* Legacy WMI fallback */ err =3D 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; =20 + /* 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 =3D FN_LOCK_SET; arg.args[2] =3D on + 1; // 0 undefined, 1 off, 2 on. =20 --=20 2.54.0