The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: "孙 誉铭" <wolf109909@outlook.com>
To: "platform-driver-x86@vger.kernel.org"
	<platform-driver-x86@vger.kernel.org>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"Mingyou Chen" <qby140326@gmail.com>,
	"Armin Wolf" <W_Armin@gmx.de>, "Hans de Goede" <hansg@kernel.org>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"Nabil Danial" <nabildanial.93@gmail.com>,
	"孙 誉铭" <wolf109909@outlook.com>
Subject: [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14
Date: Tue, 28 Jul 2026 18:10:04 +0000	[thread overview]
Message-ID: <20260728180944.51356-5-wolf109909@outlook.com> (raw)
In-Reply-To: <20260728180944.51356-1-wolf109909@outlook.com>

The Xiaomi Book Pro 14 (2026, Panther Lake) ships with broken
firmware: ECON, referenced by \_SB.PC00.LPCB.Q_EC._STA, is not defined
in any of the 34 SSDTs the firmware loads (boot log: "Could not
resolve symbol [\_SB.PC00.LPCB.Q_EC._STA.ECON], AE_NOT_FOUND"). The
ACPI EC driver therefore never binds and none of the EC query handlers
execute - including _Q0C/_Q0D which notify the PNP0C0D lid device. As
a result closing the lid generates no SW_LID event: the screen stays
on and keys depressed by the closed lid keep typing into the visible
lock screen, locking the user account after repeated failed logins.

The EC itself is alive and its shared-memory window at 0xFE0B0300
(DSDT region "ERAM") tracks the lid state bit LSTE (offset 0x14, bit
0). Poll it from a delayed-work item and, on a change, evaluate the
very AML methods the EC query would have run (_Q0C/_Q0D), which update
the GFX CLID field and notify LID0 so the button driver emits SW_LID.

Gate the quirk on both the MIFS v2 firmware variant and DMI matching
so no other machine gets polled. Verified on the affected machine: lid
close/open now produce proper switch events handled by systemd-logind
(Lid closed -> suspend -> Lid opened -> resume).

Signed-off-by: Yuming Sun <wolf109909@outlook.com>
---
 drivers/platform/x86/bitland-mifs-wmi.c | 94 ++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 5f7c85a8..550ee981 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -14,6 +14,7 @@
 #include <linux/dev_printk.h>
 #include <linux/device.h>
 #include <linux/device/devres.h>
+#include <linux/dmi.h>
 #include <linux/err.h>
 #include <linux/hwmon.h>
 #include <linux/init.h>
@@ -34,6 +35,7 @@
 #include <linux/unaligned.h>
 #include <linux/units.h>
 #include <linux/wmi.h>
+#include <linux/workqueue.h>
 
 #define DRV_NAME		"bitland-mifs-wmi"
 #define BITLAND_MIFS_GUID	"B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B"
@@ -161,6 +163,11 @@ struct bitland_mifs_output {
 #define MIFS_V2_EC_MEM_SIZE	0x100
 #define MIFS_V2_EC_REG_FAN1	0x69
 #define MIFS_V2_EC_REG_FAN2	0x6B
+#define MIFS_V2_EC_REG_LID	0x14	/* bit 0: LSTE, 1 = lid open */
+#define MIFS_V2_EC_LID_OPEN	BIT(0)
+
+/* Interval for the lid-state poll; see bitland_mifs_lid_poll() */
+#define MIFS_V2_LID_POLL_MS	250
 
 static u16 mifs_status(const struct bitland_mifs_output *out)
 {
@@ -200,6 +207,9 @@ struct bitland_mifs_wmi_data {
 	bool profile_valid;
 	bool is_v2;	/* MIFS v2 firmware: QFAN perf-mode codes */
 	u8 __iomem *ec_mem;	/* v2 EC shared-memory window */
+	struct delayed_work lid_work;
+	u8 last_lid;
+	bool lid_quirk;
 };
 
 static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
@@ -390,6 +400,9 @@ static int bitland_mifs_wmi_suspend(struct device *dev)
 	if (!data->pp_dev)
 		return 0;
 
+	if (data->lid_quirk)
+		cancel_delayed_work_sync(&data->lid_work);
+
 	/*
 	 * Never abort suspend: some firmware revisions answer the perf-mode
 	 * query with values this driver cannot map, or fail the call
@@ -410,6 +423,11 @@ static int bitland_mifs_wmi_resume(struct device *dev)
 	if (!data->pp_dev)
 		return 0;
 
+	if (data->lid_quirk) {
+		data->last_lid = 0xff;
+		schedule_delayed_work(&data->lid_work, 0);
+	}
+
 	if (!data->profile_valid)
 		return 0;
 
@@ -549,6 +567,57 @@ static const struct hwmon_chip_info laptop_chip_info = {
 	.info = laptop_hwmon_info,
 };
 
+/*
+ * Lid switch quirk (Xiaomi Book Pro 14 2026):
+ *
+ * The firmware of this machine never defines ECON, which is referenced
+ * by \_SB.PC00.LPCB.Q_EC._STA, so the ACPI EC driver never binds and
+ * none of the EC query handlers run. This kills the lid events
+ * (_Q0C/_Q0D) as well as every other EC-driven event. Poll the lid
+ * state bit (LSTE) in the EC shared-memory window and, on a change,
+ * evaluate the very AML methods the EC query would have run: they
+ * update the GFX CLID field and notify the PNP0C0D lid device, which
+ * makes the button driver emit the SW_LID event.
+ */
+#define MIFS_LID_CLOSE_METHOD	"\\_SB.PC00.LPCB.Q_EC._Q0C"
+#define MIFS_LID_OPEN_METHOD	"\\_SB.PC00.LPCB.Q_EC._Q0D"
+
+static void bitland_mifs_lid_poll(struct work_struct *work)
+{
+	struct bitland_mifs_wmi_data *data =
+		container_of(to_delayed_work(work), struct bitland_mifs_wmi_data,
+			     lid_work);
+	u8 lid;
+
+	lid = readb(data->ec_mem + MIFS_V2_EC_REG_LID) & MIFS_V2_EC_LID_OPEN;
+	if (lid != data->last_lid && data->last_lid != 0xff) {
+		acpi_status status;
+		acpi_string method = (acpi_string)(lid ? MIFS_LID_OPEN_METHOD :
+						    MIFS_LID_CLOSE_METHOD);
+
+		status = acpi_evaluate_object(NULL, method, NULL, NULL);
+		if (ACPI_FAILURE(status))
+			dev_warn(&data->wdev->dev,
+				 "lid %s AML failed: %s\n",
+				 lid ? "open" : "close",
+				 acpi_format_exception(status));
+	}
+	data->last_lid = lid;
+
+	schedule_delayed_work(&data->lid_work,
+			      msecs_to_jiffies(MIFS_V2_LID_POLL_MS));
+}
+
+static const struct dmi_system_id bitland_mifs_lid_quirk_table[] = {
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14"),
+		},
+	},
+	{ }
+};
+
 static int laptop_kbd_led_set(struct led_classdev *led_cdev,
 			      enum led_brightness value)
 {
@@ -843,6 +912,9 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
 			if (!drv_data->ec_mem)
 				dev_warn(&wdev->dev,
 					 "cannot map EC window, fan tach unavailable\n");
+
+			drv_data->lid_quirk = drv_data->ec_mem &&
+				dmi_check_system(bitland_mifs_lid_quirk_table);
 		}
 	}
 
@@ -897,9 +969,20 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
 	if (ret)
 		return ret;
 
-	return devm_add_action_or_reset(&wdev->dev,
+	ret = devm_add_action_or_reset(&wdev->dev,
 				       bitland_notifier_unregister,
 				       &drv_data->notifier);
+	if (ret)
+		return ret;
+
+	if (drv_data->lid_quirk) {
+		INIT_DELAYED_WORK(&drv_data->lid_work, bitland_mifs_lid_poll);
+		drv_data->last_lid = 0xff;
+		schedule_delayed_work(&drv_data->lid_work,
+				      msecs_to_jiffies(MIFS_V2_LID_POLL_MS));
+	}
+
+	return 0;
 }
 
 static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
@@ -982,6 +1065,14 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
 	}
 }
 
+static void bitland_mifs_wmi_remove(struct wmi_device *wdev)
+{
+	struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
+
+	if (data->lid_quirk)
+		cancel_delayed_work_sync(&data->lid_work);
+}
+
 static const struct wmi_device_id bitland_mifs_wmi_id_table[] = {
 	{ BITLAND_MIFS_GUID, (void *)BITLAND_WMI_CONTROL },
 	{ BITLAND_EVENT_GUID, (void *)BITLAND_WMI_EVENT },
@@ -999,6 +1090,7 @@ static struct wmi_driver bitland_mifs_wmi_driver = {
 	.id_table = bitland_mifs_wmi_id_table,
 	.min_event_size = sizeof(struct bitland_mifs_event),
 	.probe = bitland_mifs_wmi_probe,
+	.remove = bitland_mifs_wmi_remove,
 	.notify_new = bitland_mifs_wmi_notify,
 };
 
-- 
2.55.0


  parent reply	other threads:[~2026-07-28 18:10 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28 18:09 [RESEND PATCH 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026) 孙 誉铭
2026-07-28 18:09 ` [RESEND PATCH 1/5] platform/x86: bitland-mifs-wmi: validate WMAA status, never abort suspend 孙 誉铭
2026-08-24 15:42   ` Ilpo Järvinen
2026-07-28 18:09 ` [RESEND PATCH 2/5] platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping 孙 誉铭
2026-07-30 10:56   ` Mingyou Chen
2026-08-16 22:18   ` kento
2026-07-28 18:10 ` [RESEND PATCH 3/5] platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS v2 孙 誉铭
2026-08-24 15:48   ` Ilpo Järvinen
2026-07-28 18:10 ` 孙 誉铭 [this message]
2026-08-24 16:00   ` [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14 Ilpo Järvinen
2026-07-28 18:10 ` [RESEND PATCH 5/5] Documentation: wmi: bitland-mifs-wmi: document MIFS v2 firmware variant 孙 誉铭
2026-07-30  9:24 ` [RESEND PATCH 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026) Armin Wolf

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=20260728180944.51356-5-wolf109909@outlook.com \
    --to=wolf109909@outlook.com \
    --cc=W_Armin@gmx.de \
    --cc=hansg@kernel.org \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nabildanial.93@gmail.com \
    --cc=platform-driver-x86@vger.kernel.org \
    --cc=qby140326@gmail.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox