* [RESEND PATCH 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026)
@ 2026-07-28 18:09 孙 誉铭
2026-07-28 18:09 ` [RESEND PATCH 1/5] platform/x86: bitland-mifs-wmi: validate WMAA status, never abort suspend 孙 誉铭
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:09 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
Resending: the foxmail envelope rewrite (tencent...@qq.com) appears to
have gotten the first attempt filtered. No content changes.
This series makes the Bitland MIFS WMI driver work on the Xiaomi Book
Pro 14 2026 (Intel Panther Lake, Ultra 5 358H) and very likely on the
REDMI Book Pro 14 2025, whose suspend failure was reported earlier [1].
These machines ship a reduced MIFS firmware ("v2"): the WMAA method
implements only function groups 0x0800/0x0a00/0x0c00/0x1000, reports
the performance mode as raw QFAN EC codes {2,3,4,9,10} instead of the
v1 0..3 enumeration, and exposes no WMI fan function. Additionally the
firmware never defines ECON, so \_SB.PC00.LPCB.Q_EC._STA fails and the
ACPI EC driver never binds, which kills all EC query handlers
(including the lid switch notifications _Q0C/_Q0D).
Symptoms fixed by this series, all reproduced and verified on the
affected machine:
* Suspend/hibernate aborted with -EINVAL from the driver's suspend
hook (same failure as [1]: "dpm_run_callback():
bitland_mifs_wmi_suspend returns -22"; 242 failures counted in
suspend_stats). Patch 1 makes the WMI call validate the firmware
status word and the suspend/resume hooks fault-tolerant.
* power-profiles-daemon could not read or set the platform profile
("Failed to get profile for handler bitland-mifs-wmi"; selecting
"performance" failed outright and wedged the daemon). Patch 2
detects the v2 firmware variant at probe and maps the QFAN codes
(2=quiet, 3=balanced, 4=speed, 9/10=extreme).
* The hwmon device reported zero RPM on all channels because the v2
firmware has no WMI fan function. Patch 3 reads the two fan
tachometers (u16 RPM, 0 = stopped) from the EC shared-memory window
at 0xFE0B0300 (DSDT region "ERAM", offsets 0x69/0x6B).
* Closing the lid produced no SW_LID event (screen stayed on, keys
pressed by the closed lid typed into the visible lock screen,
locking the account). Patch 4 polls the LSTE lid bit in the EC
window and, on a change, evaluates the very AML methods the EC
query would have run (_Q0C/_Q0D), restoring proper lid events.
DMI-gated to the affected model.
All values were reverse-engineered from the machine's DSDT/SSDT
(WMID device, _UID "MIFS") and verified live: mode switching changes
the EC QFAN register as expected, fan tachs ramp 0 -> ~2700 RPM under
load, lid close/open emit proper switch events consumed by
systemd-logind, and suspend/resume cycles complete cleanly with the
driver loaded (suspend_stats: fail 0).
Notes for reviewers:
* The v2 variant is detected at runtime (perf-mode query result
outside the v1 enumeration) so other Bitland machines sharing this
firmware generation get support without DMI entries; the lid quirk
additionally requires a DMI match.
* On this platform the firmware perf-mode switch reaches Intel DTT
(\_SB.IETM, INTC10D4) via ODV variables; mainline has no driver for
that device, so the TDP change the firmware intends is currently
not applied on Linux. Programming RAPL directly from this driver
seemed inappropriate; I left it out. Happy to hear preferences.
* Interactions with the in-flight "Merge redmi-wmi into
bitland-mifs-wmi" series [2] are limited to file context; the
control-device paths touched here are disjoint from the event-device
merge.
[1] https://lists.openwall.net/linux-kernel/2026/07/10/72
"[BUG] platform/x86: bitland-mifs-wmi: Hibernation fails with
error -22 on Xiaomi Redmi Book Pro 14 2025"
[2] https://www.spinics.net/lists/kernel/msg6309086.html
"[PATCH v1 0/4] Merge redmi-wmi into bitland-mifs-wmi"
Yuming Sun (5):
platform/x86: bitland-mifs-wmi: validate WMAA status, never abort
suspend
platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping
platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS
v2
platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi
Book Pro 14
Documentation: wmi: bitland-mifs-wmi: document MIFS v2 firmware
variant
.../wmi/devices/bitland-mifs-wmi.rst | 26 ++
drivers/platform/x86/bitland-mifs-wmi.c | 272 +++++++++++++++++-
2 files changed, 290 insertions(+), 8 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [RESEND PATCH 1/5] platform/x86: bitland-mifs-wmi: validate WMAA status, never abort suspend
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 ` 孙 誉铭
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 孙 誉铭
` (4 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:09 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
The WMAA firmware method signals "unknown/unsupported function" with
the status word 0xe000 in the reply. The driver never checked it, so
calls to functions a given firmware revision does not implement
silently returned zero-filled data instead of failing.
Worse, the platform_profile suspend hook propagated such errors: on
firmware whose perf-mode query returns values laptop_profile_get()
cannot map (e.g. MIFS v2 firmware reporting raw QFAN codes, seen on
Xiaomi Book Pro 14 2026 and REDMI Book Pro 14 2025), every suspend
attempt died with:
dpm_run_callback(): bitland_mifs_wmi_suspend returns -22
PM: Some devices failed to suspend, or early wake event detected
Return -EOPNOTSUPP when the firmware reports the error status word,
and make the suspend/resume hooks fault-tolerant: skip saving and
restoring the profile when the query fails instead of aborting the
whole system sleep.
Status word semantics verified against the laptop's SSDT WMAA method
(SGER=0x8000 on success, 0xe000 in the Default branch).
Signed-off-by: Yuming Sun <wolf109909@outlook.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 31 +++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 3a373184..12426d11 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -129,6 +129,18 @@ struct bitland_mifs_output {
u8 data[28];
} __packed;
+/*
+ * The status word of a WMAA reply is formed by the first two bytes
+ * (reserved1 | operation << 8). MIFS firmware signals "unknown or
+ * unsupported function" with 0xe000 and success with 0x8000.
+ */
+#define MIFS_STATUS_ERROR 0xe000
+
+static u16 mifs_status(const struct bitland_mifs_output *out)
+{
+ return out->reserved1 | (out->operation << 8);
+}
+
struct bitland_mifs_event {
u8 event_type;
u8 event_id;
@@ -159,6 +171,7 @@ struct bitland_mifs_wmi_data {
struct device *hwmon_dev;
struct device *pp_dev;
enum platform_profile_option saved_profile;
+ bool profile_valid;
};
static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
@@ -181,6 +194,9 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
memcpy(output, out_buf.data, sizeof(*output));
kfree(out_buf.data);
+ if (mifs_status(output) == MIFS_STATUS_ERROR)
+ return -EOPNOTSUPP;
+
return 0;
}
@@ -298,17 +314,21 @@ static int bitland_mifs_wmi_suspend(struct device *dev)
{
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
enum platform_profile_option profile;
- int ret;
/* Skip event device */
if (!data->pp_dev)
return 0;
- ret = laptop_profile_get(data->pp_dev, &profile);
- if (ret == 0)
+ /*
+ * Never abort suspend: some firmware revisions answer the perf-mode
+ * query with values this driver cannot map, or fail the call
+ * entirely while the system is going down.
+ */
+ data->profile_valid = laptop_profile_get(data->pp_dev, &profile) == 0;
+ if (data->profile_valid)
data->saved_profile = profile;
- return ret;
+ return 0;
}
static int bitland_mifs_wmi_resume(struct device *dev)
@@ -319,6 +339,9 @@ static int bitland_mifs_wmi_resume(struct device *dev)
if (!data->pp_dev)
return 0;
+ if (!data->profile_valid)
+ return 0;
+
dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
return laptop_profile_set(dev, data->saved_profile);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RESEND PATCH 2/5] platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping
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-07-28 18:09 ` 孙 誉铭
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 孙 誉铭
` (3 subsequent siblings)
5 siblings, 2 replies; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:09 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
The MIFS v2 firmware found on e.g. the Xiaomi Book Pro 14 2026 (Intel
Panther Lake, SSDT device "WMID" with _UID "MIFS") implements only a
reduced WMAA command set and reports the performance mode as raw QFAN
embedded-controller codes { 2, 3, 4, 9, 10 } instead of the v1 0..3
enumeration. With the v1 mapping, profile_get() returns -EINVAL for
most firmware states ("platform_profile: Failed to get profile for
handler bitland-mifs-wmi", also reported on REDMI Book Pro 14 2025)
and profile_set() writes values the firmware treats as no-ops, so
power-profiles-daemon can neither read nor switch the profile;
selecting "performance" fails outright and wedges the daemon.
Detect the variant at probe time by querying the current mode: values
outside the v1 enumeration mean v2 firmware. Map the v2 codes to
platform profiles (2=quiet, 3=balanced, 4=speed, 9/10=extreme) and
skip the v1-only AC-type capability probe, which does not exist on v2
and now fails the call after the status-word check.
Values verified against the laptop's SSDT WMAA method and by observing
the EC QFAN register while switching modes.
Signed-off-by: Yuming Sun <wolf109909@outlook.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 79 +++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 12426d11..342dd7e1 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -73,6 +73,21 @@ enum bitland_mifs_power_profile {
WMI_PP_FULL_SPEED = 3,
};
+/*
+ * MIFS v2 firmware (e.g. Xiaomi Book Pro 14 2026, SSDT "WMID" with UID
+ * "MIFS") implements a reduced WMAA command set (only function groups
+ * 0x0800/0x0a00/0x0c00/0x1000) and reports the performance mode as raw
+ * QFAN EC codes instead of the v1 0..3 enumeration. Codes 9 and 10 are
+ * the SMM-backed "extreme" modes.
+ */
+enum bitland_mifs_v2_power_profile {
+ WMI_V2_PP_QUIET = 2,
+ WMI_V2_PP_BALANCED = 3,
+ WMI_V2_PP_SPEED = 4,
+ WMI_V2_PP_EXTREME = 9,
+ WMI_V2_PP_EXTREME2 = 10,
+};
+
enum bitland_mifs_event_id {
WMI_EVENT_RESERVED_1 = 1,
WMI_EVENT_RESERVED_2 = 2,
@@ -172,6 +187,7 @@ struct bitland_mifs_wmi_data {
struct device *pp_dev;
enum platform_profile_option saved_profile;
bool profile_valid;
+ bool is_v2; /* MIFS v2 firmware: QFAN perf-mode codes */
};
static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
@@ -217,6 +233,27 @@ static int laptop_profile_get(struct device *dev,
if (ret)
return ret;
+ if (data->is_v2) {
+ switch (result.data[0]) {
+ case WMI_V2_PP_QUIET:
+ *profile = PLATFORM_PROFILE_LOW_POWER;
+ break;
+ case WMI_V2_PP_BALANCED:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case WMI_V2_PP_SPEED:
+ *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
+ break;
+ case WMI_V2_PP_EXTREME:
+ case WMI_V2_PP_EXTREME2:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
switch (result.data[0]) {
case WMI_PP_BALANCED:
*profile = PLATFORM_PROFILE_BALANCED;
@@ -272,6 +309,28 @@ static int laptop_profile_set(struct device *dev,
int ret;
u8 val;
+ if (data->is_v2) {
+ switch (profile) {
+ case PLATFORM_PROFILE_LOW_POWER:
+ val = WMI_V2_PP_QUIET;
+ break;
+ case PLATFORM_PROFILE_BALANCED:
+ val = WMI_V2_PP_BALANCED;
+ break;
+ case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
+ val = WMI_V2_PP_SPEED;
+ break;
+ case PLATFORM_PROFILE_PERFORMANCE:
+ val = WMI_V2_PP_EXTREME;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ input.payload[0] = val;
+
+ return bitland_mifs_wmi_call(data, &input, NULL);
+ }
+
switch (profile) {
case PLATFORM_PROFILE_LOW_POWER:
val = WMI_PP_QUIET;
@@ -705,6 +764,26 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
dev_set_drvdata(&wdev->dev, drv_data);
+ if (dev_type == BITLAND_WMI_CONTROL) {
+ /*
+ * Firmware variant detection: v1 firmware reports the perf mode
+ * as 0..3 (enum bitland_mifs_power_profile); anything else means
+ * the reduced MIFS v2 command set with raw QFAN codes.
+ */
+ struct bitland_mifs_input probe_in = {
+ .operation = WMI_METHOD_GET,
+ .function = WMI_FN_SYSTEM_PER_MODE,
+ };
+ struct bitland_mifs_output probe_out;
+
+ if (!bitland_mifs_wmi_call(drv_data, &probe_in, &probe_out) &&
+ probe_out.data[0] > WMI_PP_FULL_SPEED) {
+ drv_data->is_v2 = true;
+ dev_info(&wdev->dev,
+ "MIFS v2 firmware detected (QFAN mode codes)\n");
+ }
+ }
+
if (dev_type == BITLAND_WMI_EVENT) {
/* Register input device for hotkeys */
drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RESEND PATCH 3/5] platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS v2
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-07-28 18:09 ` [RESEND PATCH 2/5] platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping 孙 誉铭
@ 2026-07-28 18:10 ` 孙 誉铭
2026-08-24 15:48 ` Ilpo Järvinen
2026-07-28 18:10 ` [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14 孙 誉铭
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:10 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
The MIFS v2 firmware implements no WMI function for fan speeds (nor
for the CPU thermometer), so on these machines the hwmon device
reported zero RPM on every channel.
The fan tachometers instead live in the EC shared-memory window at
0xFE0B0300 (DSDT \_SB.PC00.LPCB.Q_EC region "ERAM") as little-endian
u16 RPM values at offsets 0x69 and 0x6B (0 = fan stopped). Map the
window on v2 systems and expose the two fans with proper labels; hide
the non-existent third fan and temperature channels.
Offsets verified by diffing the window between idle and sustained load
(tach values ramp 0 -> ~2700 RPM and back) on a Xiaomi Book Pro 14.
Signed-off-by: Yuming Sun <wolf109909@outlook.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 68 +++++++++++++++++++++++--
1 file changed, 65 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 342dd7e1..5f7c85a8 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
@@ -151,6 +152,16 @@ struct bitland_mifs_output {
*/
#define MIFS_STATUS_ERROR 0xe000
+/*
+ * MIFS v2 EC shared-memory window (DSDT \_SB.PC00.LPCB.Q_EC region
+ * "ERAM"). The firmware exposes no WMI fan function, but the fan
+ * tachometers live here as little-endian u16 RPM (0 = fan stopped).
+ */
+#define MIFS_V2_EC_MEM_BASE 0xFE0B0300
+#define MIFS_V2_EC_MEM_SIZE 0x100
+#define MIFS_V2_EC_REG_FAN1 0x69
+#define MIFS_V2_EC_REG_FAN2 0x6B
+
static u16 mifs_status(const struct bitland_mifs_output *out)
{
return out->reserved1 | (out->operation << 8);
@@ -188,6 +199,7 @@ struct bitland_mifs_wmi_data {
enum platform_profile_option saved_profile;
bool profile_valid;
bool is_v2; /* MIFS v2 firmware: QFAN perf-mode codes */
+ u8 __iomem *ec_mem; /* v2 EC shared-memory window */
};
static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
@@ -421,6 +433,27 @@ static const char *const fan_labels[] = {
"SYS", /* 2 */
};
+static const char *const fan_labels_v2[] = {
+ "Left Fan", /* 0 */
+ "Right Fan", /* 1 */
+};
+
+static umode_t laptop_hwmon_visible(const void *drvdata,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct bitland_mifs_wmi_data *data = drvdata;
+
+ /* v2 firmware: two fans, no CPU temperature channel */
+ if (data->is_v2) {
+ if (type == hwmon_fan && channel < 2)
+ return 0444;
+ return 0;
+ }
+
+ return 0444;
+}
+
static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
@@ -433,6 +466,22 @@ static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
struct bitland_mifs_output res;
int ret;
+ /* v2: tachometers are u16 RPM in the EC shared-memory window */
+ if (data->is_v2) {
+ if (type != hwmon_fan || !data->ec_mem)
+ return -EINVAL;
+ switch (channel) {
+ case 0:
+ *val = get_unaligned_le16(data->ec_mem + MIFS_V2_EC_REG_FAN1);
+ return 0;
+ case 1:
+ *val = get_unaligned_le16(data->ec_mem + MIFS_V2_EC_REG_FAN2);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ }
+
switch (type) {
case hwmon_temp:
input.function = WMI_FN_CPU_THERMOMETER;
@@ -468,9 +517,13 @@ static int laptop_hwmon_read_string(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, const char **str)
{
+ struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+ const char *const *labels = data->is_v2 ? fan_labels_v2 : fan_labels;
+ int nlabels = data->is_v2 ? ARRAY_SIZE(fan_labels_v2) : ARRAY_SIZE(fan_labels);
+
if (type == hwmon_fan && attr == hwmon_fan_label) {
- if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) {
- *str = fan_labels[channel];
+ if (channel >= 0 && channel < nlabels) {
+ *str = labels[channel];
return 0;
}
}
@@ -486,7 +539,7 @@ static const struct hwmon_channel_info *laptop_hwmon_info[] = {
};
static const struct hwmon_ops laptop_hwmon_ops = {
- .visible = 0444,
+ .is_visible = laptop_hwmon_visible,
.read = laptop_hwmon_read,
.read_string = laptop_hwmon_read_string,
};
@@ -782,6 +835,15 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
dev_info(&wdev->dev,
"MIFS v2 firmware detected (QFAN mode codes)\n");
}
+
+ if (drv_data->is_v2) {
+ drv_data->ec_mem = devm_ioremap(&wdev->dev,
+ MIFS_V2_EC_MEM_BASE,
+ MIFS_V2_EC_MEM_SIZE);
+ if (!drv_data->ec_mem)
+ dev_warn(&wdev->dev,
+ "cannot map EC window, fan tach unavailable\n");
+ }
}
if (dev_type == BITLAND_WMI_EVENT) {
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14
2026-07-28 18:09 [RESEND PATCH 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026) 孙 誉铭
` (2 preceding siblings ...)
2026-07-28 18:10 ` [RESEND PATCH 3/5] platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS v2 孙 誉铭
@ 2026-07-28 18:10 ` 孙 誉铭
2026-08-24 16:00 ` 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
5 siblings, 1 reply; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:10 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RESEND PATCH 5/5] Documentation: wmi: bitland-mifs-wmi: document MIFS v2 firmware variant
2026-07-28 18:09 [RESEND PATCH 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026) 孙 誉铭
` (3 preceding siblings ...)
2026-07-28 18:10 ` [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14 孙 誉铭
@ 2026-07-28 18:10 ` 孙 誉铭
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
5 siblings, 0 replies; 12+ messages in thread
From: 孙 誉铭 @ 2026-07-28 18:10 UTC (permalink / raw)
To: platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Armin Wolf,
Hans de Goede, Ilpo Järvinen, Nabil Danial,
孙 誉铭
Document the reduced MIFS v2 command set found on newer machines:
QFAN performance-mode codes {2,3,4,9,10}, fan tachometer location in
the EC shared-memory window (no WMI fan function), the missing ECON
definition that disables the ACPI EC driver (and how the driver works
around it for the lid switch), and the WMAA reply status word.
Signed-off-by: Yuming Sun <wolf109909@outlook.com>
---
.../wmi/devices/bitland-mifs-wmi.rst | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/Documentation/wmi/devices/bitland-mifs-wmi.rst b/Documentation/wmi/devices/bitland-mifs-wmi.rst
index 9e86ecc2..d019a4c8 100644
--- a/Documentation/wmi/devices/bitland-mifs-wmi.rst
+++ b/Documentation/wmi/devices/bitland-mifs-wmi.rst
@@ -133,6 +133,32 @@ The driver listens for events from the ``HID_EVENT20`` class
(GUID: ``{46c93e13-ee9b-4262-8488-563bca757fef}``). These events are triggered
by hotkeys or system state changes (e.g., plugging in AC power).
+MIFS v2 firmware variant
+========================
+
+Some newer machines (e.g. Xiaomi Book Pro 14 2026, REDMI Book Pro 14 2025)
+ship a reduced MIFS firmware, called "v2" here. Its WMAA method implements
+only function groups 0x0800/0x0a00/0x0c00/0x1000, so of the command table
+above only SystemPerMode (0x08) and a few state toggles exist. Differences:
+
+* SystemPerMode (0x08) reports raw QFAN EC codes instead of the 0..3
+ enumeration: 2 = Quiet, 3 = Balanced, 4 = Speed, 9/10 = Extreme
+ (SMM-backed). The driver maps these to platform profiles and detects the
+ variant at probe time when the reported mode is outside the v1 range.
+* There is no WMI fan-speed or CPU-temperature function. The two fan
+ tachometers live in the EC shared-memory window at 0xFE0B0300 (DSDT
+ \_SB.PC00.LPCB.Q_EC region "ERAM") as little-endian u16 RPM values at
+ offsets 0x69 and 0x6B (0 = fan stopped). The EC controls the fans
+ autonomously; no OS fan-speed override exists on this firmware.
+* The firmware never defines ECON, so \_SB.PC00.LPCB.Q_EC._STA fails, the
+ ACPI EC driver never binds and EC query handlers (lid switch _Q0C/_Q0D,
+ hotkey queries) never run. On DMI-matched models the driver polls the
+ LSTE lid bit (offset 0x14, bit 0) in the EC window and evaluates
+ _Q0C/_Q0D itself so the PNP0C0D lid device keeps emitting SW_LID.
+* The reply status word (bytes 0-1 of OutData, SGER) is 0x8000 on success
+ and 0xe000 for unknown/unsupported functions; the driver turns the
+ latter into -EOPNOTSUPP.
+
Event Structure
---------------
--
2.55.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [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 0/5] platform/x86: bitland-mifs-wmi: MIFS v2 firmware support (Xiaomi Book Pro 14 2026) 孙 誉铭
` (4 preceding siblings ...)
2026-07-28 18:10 ` [RESEND PATCH 5/5] Documentation: wmi: bitland-mifs-wmi: document MIFS v2 firmware variant 孙 誉铭
@ 2026-07-30 9:24 ` Armin Wolf
5 siblings, 0 replies; 12+ messages in thread
From: Armin Wolf @ 2026-07-30 9:24 UTC (permalink / raw)
To: 孙 誉铭, platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Mingyou Chen, Hans de Goede,
Ilpo Järvinen, Nabil Danial
Am 28.07.26 um 20:09 schrieb 孙 誉铭:
> Resending: the foxmail envelope rewrite (tencent...@qq.com) appears to
> have gotten the first attempt filtered. No content changes.
>
> This series makes the Bitland MIFS WMI driver work on the Xiaomi Book
> Pro 14 2026 (Intel Panther Lake, Ultra 5 358H) and very likely on the
> REDMI Book Pro 14 2025, whose suspend failure was reported earlier [1].
>
> These machines ship a reduced MIFS firmware ("v2"): the WMAA method
> implements only function groups 0x0800/0x0a00/0x0c00/0x1000, reports
> the performance mode as raw QFAN EC codes {2,3,4,9,10} instead of the
> v1 0..3 enumeration, and exposes no WMI fan function. Additionally the
> firmware never defines ECON, so \_SB.PC00.LPCB.Q_EC._STA fails and the
> ACPI EC driver never binds, which kills all EC query handlers
> (including the lid switch notifications _Q0C/_Q0D).
>
> Symptoms fixed by this series, all reproduced and verified on the
> affected machine:
>
> * Suspend/hibernate aborted with -EINVAL from the driver's suspend
> hook (same failure as [1]: "dpm_run_callback():
> bitland_mifs_wmi_suspend returns -22"; 242 failures counted in
> suspend_stats). Patch 1 makes the WMI call validate the firmware
> status word and the suspend/resume hooks fault-tolerant.
>
> * power-profiles-daemon could not read or set the platform profile
> ("Failed to get profile for handler bitland-mifs-wmi"; selecting
> "performance" failed outright and wedged the daemon). Patch 2
> detects the v2 firmware variant at probe and maps the QFAN codes
> (2=quiet, 3=balanced, 4=speed, 9/10=extreme).
>
> * The hwmon device reported zero RPM on all channels because the v2
> firmware has no WMI fan function. Patch 3 reads the two fan
> tachometers (u16 RPM, 0 = stopped) from the EC shared-memory window
> at 0xFE0B0300 (DSDT region "ERAM", offsets 0x69/0x6B).
>
> * Closing the lid produced no SW_LID event (screen stayed on, keys
> pressed by the closed lid typed into the visible lock screen,
> locking the account). Patch 4 polls the LSTE lid bit in the EC
> window and, on a change, evaluates the very AML methods the EC
> query would have run (_Q0C/_Q0D), restoring proper lid events.
> DMI-gated to the affected model.
Hi,
can you share the output of "acpidump" on your machine? Missing Lid events
usually indicate a deeper problem with the ACPI handling on a given machine.
Thanks,
Armin Wolf
>
> All values were reverse-engineered from the machine's DSDT/SSDT
> (WMID device, _UID "MIFS") and verified live: mode switching changes
> the EC QFAN register as expected, fan tachs ramp 0 -> ~2700 RPM under
> load, lid close/open emit proper switch events consumed by
> systemd-logind, and suspend/resume cycles complete cleanly with the
> driver loaded (suspend_stats: fail 0).
>
> Notes for reviewers:
>
> * The v2 variant is detected at runtime (perf-mode query result
> outside the v1 enumeration) so other Bitland machines sharing this
> firmware generation get support without DMI entries; the lid quirk
> additionally requires a DMI match.
> * On this platform the firmware perf-mode switch reaches Intel DTT
> (\_SB.IETM, INTC10D4) via ODV variables; mainline has no driver for
> that device, so the TDP change the firmware intends is currently
> not applied on Linux. Programming RAPL directly from this driver
> seemed inappropriate; I left it out. Happy to hear preferences.
> * Interactions with the in-flight "Merge redmi-wmi into
> bitland-mifs-wmi" series [2] are limited to file context; the
> control-device paths touched here are disjoint from the event-device
> merge.
>
> [1] https://lists.openwall.net/linux-kernel/2026/07/10/72
> "[BUG] platform/x86: bitland-mifs-wmi: Hibernation fails with
> error -22 on Xiaomi Redmi Book Pro 14 2025"
> [2] https://www.spinics.net/lists/kernel/msg6309086.html
> "[PATCH v1 0/4] Merge redmi-wmi into bitland-mifs-wmi"
>
>
> Yuming Sun (5):
> platform/x86: bitland-mifs-wmi: validate WMAA status, never abort
> suspend
> platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping
> platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS
> v2
> platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi
> Book Pro 14
> Documentation: wmi: bitland-mifs-wmi: document MIFS v2 firmware
> variant
>
> .../wmi/devices/bitland-mifs-wmi.rst | 26 ++
> drivers/platform/x86/bitland-mifs-wmi.c | 272 +++++++++++++++++-
> 2 files changed, 290 insertions(+), 8 deletions(-)
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RESEND PATCH 2/5] platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping
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
1 sibling, 0 replies; 12+ messages in thread
From: Mingyou Chen @ 2026-07-30 10:56 UTC (permalink / raw)
To: 孙 誉铭, platform-driver-x86@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Armin Wolf, Hans de Goede,
Ilpo Järvinen, Nabil Danial
On 7/29/26 2:09 AM, 孙 誉铭 wrote:
> The MIFS v2 firmware found on e.g. the Xiaomi Book Pro 14 2026 (Intel
> Panther Lake, SSDT device "WMID" with _UID "MIFS") implements only a
> reduced WMAA command set and reports the performance mode as raw QFAN
> embedded-controller codes { 2, 3, 4, 9, 10 } instead of the v1 0..3
> enumeration. With the v1 mapping, profile_get() returns -EINVAL for
> most firmware states ("platform_profile: Failed to get profile for
> handler bitland-mifs-wmi", also reported on REDMI Book Pro 14 2025)
> and profile_set() writes values the firmware treats as no-ops, so
> power-profiles-daemon can neither read nor switch the profile;
> selecting "performance" fails outright and wedges the daemon.
>
> Detect the variant at probe time by querying the current mode: values
> outside the v1 enumeration mean v2 firmware. Map the v2 codes to
> platform profiles (2=quiet, 3=balanced, 4=speed, 9/10=extreme) and
> skip the v1-only AC-type capability probe, which does not exist on v2
> and now fails the call after the status-word check.
>
> Values verified against the laptop's SSDT WMAA method and by observing
> the EC QFAN register while switching modes.
>
> Signed-off-by: Yuming Sun <wolf109909@outlook.com>
> ---
> drivers/platform/x86/bitland-mifs-wmi.c | 79 +++++++++++++++++++++++++
> 1 file changed, 79 insertions(+)
>
> diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
> index 12426d11..342dd7e1 100644
> --- a/drivers/platform/x86/bitland-mifs-wmi.c
> +++ b/drivers/platform/x86/bitland-mifs-wmi.c
> @@ -73,6 +73,21 @@ enum bitland_mifs_power_profile {
> WMI_PP_FULL_SPEED = 3,
> };
>
> +/*
> + * MIFS v2 firmware (e.g. Xiaomi Book Pro 14 2026, SSDT "WMID" with UID
> + * "MIFS") implements a reduced WMAA command set (only function groups
> + * 0x0800/0x0a00/0x0c00/0x1000) and reports the performance mode as raw
> + * QFAN EC codes instead of the v1 0..3 enumeration. Codes 9 and 10 are
> + * the SMM-backed "extreme" modes.
> + */
> +enum bitland_mifs_v2_power_profile {
> + WMI_V2_PP_QUIET = 2,
> + WMI_V2_PP_BALANCED = 3,
> + WMI_V2_PP_SPEED = 4,
> + WMI_V2_PP_EXTREME = 9,
> + WMI_V2_PP_EXTREME2 = 10,
> +};
> +
> enum bitland_mifs_event_id {
> WMI_EVENT_RESERVED_1 = 1,
> WMI_EVENT_RESERVED_2 = 2,
> @@ -172,6 +187,7 @@ struct bitland_mifs_wmi_data {
> struct device *pp_dev;
> enum platform_profile_option saved_profile;
> bool profile_valid;
> + bool is_v2; /* MIFS v2 firmware: QFAN perf-mode codes */
> };
>
> static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
> @@ -217,6 +233,27 @@ static int laptop_profile_get(struct device *dev,
> if (ret)
> return ret;
>
> + if (data->is_v2) {
> + switch (result.data[0]) {
> + case WMI_V2_PP_QUIET:
> + *profile = PLATFORM_PROFILE_LOW_POWER;
> + break;
> + case WMI_V2_PP_BALANCED:
> + *profile = PLATFORM_PROFILE_BALANCED;
> + break;
> + case WMI_V2_PP_SPEED:
> + *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
> + break;
> + case WMI_V2_PP_EXTREME:
> + case WMI_V2_PP_EXTREME2:
> + *profile = PLATFORM_PROFILE_PERFORMANCE;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> + }
> +
> switch (result.data[0]) {
> case WMI_PP_BALANCED:
> *profile = PLATFORM_PROFILE_BALANCED;
> @@ -272,6 +309,28 @@ static int laptop_profile_set(struct device *dev,
> int ret;
> u8 val;
>
> + if (data->is_v2) {
Consider introducing an ops table. Then you can completely remove the
is_v2 conditions.
> + switch (profile) {
> + case PLATFORM_PROFILE_LOW_POWER:
> + val = WMI_V2_PP_QUIET;
> + break;
> + case PLATFORM_PROFILE_BALANCED:
> + val = WMI_V2_PP_BALANCED;
> + break;
> + case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
> + val = WMI_V2_PP_SPEED;
> + break;
> + case PLATFORM_PROFILE_PERFORMANCE:
> + val = WMI_V2_PP_EXTREME;
> + break;
> + default:
> + return -EOPNOTSUPP;
> + }
> + input.payload[0] = val;
> +
> + return bitland_mifs_wmi_call(data, &input, NULL);
> + }
> +
> switch (profile) {
> case PLATFORM_PROFILE_LOW_POWER:
> val = WMI_PP_QUIET;
> @@ -705,6 +764,26 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
>
> dev_set_drvdata(&wdev->dev, drv_data);
>
> + if (dev_type == BITLAND_WMI_CONTROL) {
> + /*
> + * Firmware variant detection: v1 firmware reports the perf mode
> + * as 0..3 (enum bitland_mifs_power_profile); anything else means
> + * the reduced MIFS v2 command set with raw QFAN codes.
> + */
> + struct bitland_mifs_input probe_in = {
> + .operation = WMI_METHOD_GET,
> + .function = WMI_FN_SYSTEM_PER_MODE,
> + };
> + struct bitland_mifs_output probe_out;
> +
> + if (!bitland_mifs_wmi_call(drv_data, &probe_in, &probe_out) &&
> + probe_out.data[0] > WMI_PP_FULL_SPEED) {
If the current profile is WMI_V2_PP_QUIET or WMI_V2_PP_BALANCED,
probe_out.data[0] > WMI_PP_FULL_SPEED would be false.
> + drv_data->is_v2 = true;
> + dev_info(&wdev->dev,
> + "MIFS v2 firmware detected (QFAN mode codes)\n");
This log message doesn't print any useful information, consider remove it.
> + }
> + }
> +
> if (dev_type == BITLAND_WMI_EVENT) {
> /* Register input device for hotkeys */
> drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RESEND PATCH 2/5] platform/x86: bitland-mifs-wmi: support MIFS v2 perf-mode mapping
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
1 sibling, 0 replies; 12+ messages in thread
From: kento @ 2026-08-16 22:18 UTC (permalink / raw)
To: 孙誉铭, platform-driver-x86
Cc: KentoNion, linux-kernel, Mingyou Chen, Armin Wolf, Hans de Goede,
Ilpo Järvinen, Nabil Danial
From: KentoNion <kento@kekto.ru>
Hi Yuming, Mingyou, all,
I sent a TM2424-only quirk today [1] before I had seen this series.
Please treat this series as the right vehicle; I am not proposing a
competing v2. Two things from live testing on the same machine class
(Xiaomi Book Pro 14 2026, DMI board_name=TM2424, SKU TM2424-77080)
disagree with patch 2/5 and with a note in 0/5.
On Tue, Jul 28, 2026 at 06:09:58PM +0000, Yuming Sun wrote:
> Map the v2 codes to platform profiles (2=quiet, 3=balanced, 4=speed,
> 9/10=extreme)
On this SKU those bytes are the Xiaomi thin-ultrabook names from the
Windows OEM stack (MIControl / XiControl [2]), not "extreme":
0x02 Quiet
0x03 Turbo
0x04 Full-speed (firmware rejects this on battery; status != 0x80)
0x09 Auto / Smart
0x0A Eco (dims keyboard backlight and panel; more aggressive
than Quiet)
Confirmed by SET/GET with status byte 0x80, and by UX: Eco really dims
the machine. 0x01 Balance is rejected and does not stick.
That makes the SET path in 2/5 invert the user's intent:
platform_profile 2/5 writes firmware meaning on TM2424
---------------- --------- --------------------------
low-power 0x02 Quiet not the strongest saver (Eco)
balanced 0x03 Turbo a high-power mode
performance 0x09 "extreme" Auto, not Full-speed
So "performance" never programs 0x04. On AC, 0x04 is the mode that
holds ~50 W package power under stress-ng + turbostat here; 0x03 is
noticeably lower. That is also why I disagree with the cover-letter
note that the TDP change "is currently not applied on Linux": a Linux
DTT driver is not required for the firmware preset to move package
power. I did not program RAPL from this driver either.
Suggested mapping (matches power-profiles-daemon's three choices):
SET low-power -> 0x0A Eco
SET balanced -> 0x09 Auto
SET performance -> 0x04 Full-speed; if firmware NACK, 0x03 Turbo
GET 0x0A / 0x02 -> low-power
GET 0x09 -> balanced
GET 0x04 / 0x03 -> performance
Mingyou already pointed out that `probe_out.data[0] > 3` misses v2
when the machine is sitting in Quiet (2) or Turbo (3). A DMI match
(XIAOMI + TM2424, and likely other TM24*) plus the >3 heuristic would
cover both.
Everything else in this series looks strictly better than my quirk:
status-word / suspend -22 (Nabil's TM2411), EC fan tachs, lid poll.
Please keep those. I only ask to retarget patch 2/5's names and SET
values before this lands, otherwise Linux "performance" on these
thin machines will select Auto.
I can test a v3 of 2/5 on TM2424.
[1] https://lore.kernel.org/lkml/20260816215825.289356-1-kento@kekto.ru/
[2] https://github.com/Oksion/XiControl/blob/main/docs/01-wmi-protocol.md
Thanks,
KentoNion
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RESEND PATCH 1/5] platform/x86: bitland-mifs-wmi: validate WMAA status, never abort suspend
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
0 siblings, 0 replies; 12+ messages in thread
From: Ilpo Järvinen @ 2026-08-24 15:42 UTC (permalink / raw)
To: 孙 誉铭
Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org,
Mingyou Chen, Armin Wolf, Hans de Goede, Nabil Danial
[-- Attachment #1: Type: text/plain, Size: 4081 bytes --]
On Tue, 28 Jul 2026, 孙 誉铭 wrote:
> The WMAA firmware method signals "unknown/unsupported function" with
> the status word 0xe000 in the reply. The driver never checked it, so
> calls to functions a given firmware revision does not implement
> silently returned zero-filled data instead of failing.
>
> Worse, the platform_profile suspend hook propagated such errors: on
> firmware whose perf-mode query returns values laptop_profile_get()
> cannot map (e.g. MIFS v2 firmware reporting raw QFAN codes, seen on
> Xiaomi Book Pro 14 2026 and REDMI Book Pro 14 2025), every suspend
> attempt died with:
>
> dpm_run_callback(): bitland_mifs_wmi_suspend returns -22
> PM: Some devices failed to suspend, or early wake event detected
>
> Return -EOPNOTSUPP when the firmware reports the error status word,
> and make the suspend/resume hooks fault-tolerant: skip saving and
> restoring the profile when the query fails instead of aborting the
> whole system sleep.
>
> Status word semantics verified against the laptop's SSDT WMAA method
> (SGER=0x8000 on success, 0xe000 in the Default branch).
>
> Signed-off-by: Yuming Sun <wolf109909@outlook.com>
> ---
> drivers/platform/x86/bitland-mifs-wmi.c | 31 +++++++++++++++++++++----
> 1 file changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
> index 3a373184..12426d11 100644
> --- a/drivers/platform/x86/bitland-mifs-wmi.c
> +++ b/drivers/platform/x86/bitland-mifs-wmi.c
> @@ -129,6 +129,18 @@ struct bitland_mifs_output {
> u8 data[28];
> } __packed;
>
> +/*
> + * The status word of a WMAA reply is formed by the first two bytes
> + * (reserved1 | operation << 8). MIFS firmware signals "unknown or
> + * unsupported function" with 0xe000 and success with 0x8000.
> + */
> +#define MIFS_STATUS_ERROR 0xe000
> +
> +static u16 mifs_status(const struct bitland_mifs_output *out)
> +{
> + return out->reserved1 | (out->operation << 8);
How about using union inside the struct and a type that annotates the
endianness + endianness accessor to read it here?
> +}
> +
> struct bitland_mifs_event {
> u8 event_type;
> u8 event_id;
> @@ -159,6 +171,7 @@ struct bitland_mifs_wmi_data {
> struct device *hwmon_dev;
> struct device *pp_dev;
> enum platform_profile_option saved_profile;
> + bool profile_valid;
> };
>
> static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
> @@ -181,6 +194,9 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
> memcpy(output, out_buf.data, sizeof(*output));
> kfree(out_buf.data);
>
> + if (mifs_status(output) == MIFS_STATUS_ERROR)
> + return -EOPNOTSUPP;
> +
> return 0;
> }
>
> @@ -298,17 +314,21 @@ static int bitland_mifs_wmi_suspend(struct device *dev)
> {
> struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> enum platform_profile_option profile;
> - int ret;
>
> /* Skip event device */
> if (!data->pp_dev)
> return 0;
>
> - ret = laptop_profile_get(data->pp_dev, &profile);
> - if (ret == 0)
> + /*
> + * Never abort suspend: some firmware revisions answer the perf-mode
> + * query with values this driver cannot map, or fail the call
> + * entirely while the system is going down.
> + */
> + data->profile_valid = laptop_profile_get(data->pp_dev, &profile) == 0;
> + if (data->profile_valid)
This code makes no sense to me. laptop_profile_get() can return error
codes so how come can profile be "valid" in that case?
> data->saved_profile = profile;
>
> - return ret;
> + return 0;
> }
>
> static int bitland_mifs_wmi_resume(struct device *dev)
> @@ -319,6 +339,9 @@ static int bitland_mifs_wmi_resume(struct device *dev)
> if (!data->pp_dev)
> return 0;
>
> + if (!data->profile_valid)
> + return 0;
> +
> dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
> return laptop_profile_set(dev, data->saved_profile);
> }
>
--
i.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RESEND PATCH 3/5] platform/x86: bitland-mifs-wmi: read fan tach from EC window on MIFS v2
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
0 siblings, 0 replies; 12+ messages in thread
From: Ilpo Järvinen @ 2026-08-24 15:48 UTC (permalink / raw)
To: 孙 誉铭
Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org,
Mingyou Chen, Armin Wolf, Hans de Goede, Nabil Danial
[-- Attachment #1: Type: text/plain, Size: 5642 bytes --]
On Tue, 28 Jul 2026, 孙 誉铭 wrote:
> The MIFS v2 firmware implements no WMI function for fan speeds (nor
> for the CPU thermometer), so on these machines the hwmon device
> reported zero RPM on every channel.
>
> The fan tachometers instead live in the EC shared-memory window at
> 0xFE0B0300 (DSDT \_SB.PC00.LPCB.Q_EC region "ERAM") as little-endian
> u16 RPM values at offsets 0x69 and 0x6B (0 = fan stopped). Map the
> window on v2 systems and expose the two fans with proper labels; hide
> the non-existent third fan and temperature channels.
>
> Offsets verified by diffing the window between idle and sustained load
> (tach values ramp 0 -> ~2700 RPM and back) on a Xiaomi Book Pro 14.
>
> Signed-off-by: Yuming Sun <wolf109909@outlook.com>
> ---
> drivers/platform/x86/bitland-mifs-wmi.c | 68 +++++++++++++++++++++++--
> 1 file changed, 65 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
> index 342dd7e1..5f7c85a8 100644
> --- a/drivers/platform/x86/bitland-mifs-wmi.c
> +++ b/drivers/platform/x86/bitland-mifs-wmi.c
> @@ -17,6 +17,7 @@
> #include <linux/err.h>
> #include <linux/hwmon.h>
> #include <linux/init.h>
> +#include <linux/io.h>
> #include <linux/input-event-codes.h>
> #include <linux/input.h>
> #include <linux/input/sparse-keymap.h>
> @@ -151,6 +152,16 @@ struct bitland_mifs_output {
> */
> #define MIFS_STATUS_ERROR 0xe000
>
> +/*
> + * MIFS v2 EC shared-memory window (DSDT \_SB.PC00.LPCB.Q_EC region
> + * "ERAM"). The firmware exposes no WMI fan function, but the fan
> + * tachometers live here as little-endian u16 RPM (0 = fan stopped).
> + */
> +#define MIFS_V2_EC_MEM_BASE 0xFE0B0300
> +#define MIFS_V2_EC_MEM_SIZE 0x100
SZ_xx from sizes.h
> +#define MIFS_V2_EC_REG_FAN1 0x69
> +#define MIFS_V2_EC_REG_FAN2 0x6B
> +
> static u16 mifs_status(const struct bitland_mifs_output *out)
> {
> return out->reserved1 | (out->operation << 8);
> @@ -188,6 +199,7 @@ struct bitland_mifs_wmi_data {
> enum platform_profile_option saved_profile;
> bool profile_valid;
> bool is_v2; /* MIFS v2 firmware: QFAN perf-mode codes */
> + u8 __iomem *ec_mem; /* v2 EC shared-memory window */
> };
>
> static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
> @@ -421,6 +433,27 @@ static const char *const fan_labels[] = {
> "SYS", /* 2 */
> };
>
> +static const char *const fan_labels_v2[] = {
> + "Left Fan", /* 0 */
> + "Right Fan", /* 1 */
Please align comments.
> +};
> +
> +static umode_t laptop_hwmon_visible(const void *drvdata,
> + enum hwmon_sensor_types type,
> + u32 attr, int channel)
> +{
> + const struct bitland_mifs_wmi_data *data = drvdata;
> +
> + /* v2 firmware: two fans, no CPU temperature channel */
> + if (data->is_v2) {
> + if (type == hwmon_fan && channel < 2)
> + return 0444;
> + return 0;
> + }
> +
> + return 0444;
> +}
> +
> static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
> u32 attr, int channel, long *val)
> {
> @@ -433,6 +466,22 @@ static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
> struct bitland_mifs_output res;
> int ret;
>
> + /* v2: tachometers are u16 RPM in the EC shared-memory window */
> + if (data->is_v2) {
> + if (type != hwmon_fan || !data->ec_mem)
> + return -EINVAL;
-EINVAL is plain wrong if you failed to initialize ec_mem. There's no
problem in input parameters whatsoever in that case.
> + switch (channel) {
> + case 0:
> + *val = get_unaligned_le16(data->ec_mem + MIFS_V2_EC_REG_FAN1);
> + return 0;
> + case 1:
> + *val = get_unaligned_le16(data->ec_mem + MIFS_V2_EC_REG_FAN2);
> + return 0;
> + default:
> + return -EINVAL;
> + }
> + }
> +
> switch (type) {
> case hwmon_temp:
> input.function = WMI_FN_CPU_THERMOMETER;
> @@ -468,9 +517,13 @@ static int laptop_hwmon_read_string(struct device *dev,
> enum hwmon_sensor_types type, u32 attr,
> int channel, const char **str)
> {
> + struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
> + const char *const *labels = data->is_v2 ? fan_labels_v2 : fan_labels;
> + int nlabels = data->is_v2 ? ARRAY_SIZE(fan_labels_v2) : ARRAY_SIZE(fan_labels);
Looks ugly but I suppose you're going to get rid of is_v2 anyway as per
somebody else's suggestion so it should try to deal with this I guess.
> +
> if (type == hwmon_fan && attr == hwmon_fan_label) {
> - if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) {
> - *str = fan_labels[channel];
> + if (channel >= 0 && channel < nlabels) {
> + *str = labels[channel];
> return 0;
> }
> }
> @@ -486,7 +539,7 @@ static const struct hwmon_channel_info *laptop_hwmon_info[] = {
> };
>
> static const struct hwmon_ops laptop_hwmon_ops = {
> - .visible = 0444,
> + .is_visible = laptop_hwmon_visible,
> .read = laptop_hwmon_read,
> .read_string = laptop_hwmon_read_string,
> };
> @@ -782,6 +835,15 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
> dev_info(&wdev->dev,
> "MIFS v2 firmware detected (QFAN mode codes)\n");
> }
> +
> + if (drv_data->is_v2) {
> + drv_data->ec_mem = devm_ioremap(&wdev->dev,
> + MIFS_V2_EC_MEM_BASE,
> + MIFS_V2_EC_MEM_SIZE);
> + if (!drv_data->ec_mem)
> + dev_warn(&wdev->dev,
> + "cannot map EC window, fan tach unavailable\n");
> + }
> }
>
> if (dev_type == BITLAND_WMI_EVENT) {
>
--
i.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14
2026-07-28 18:10 ` [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14 孙 誉铭
@ 2026-08-24 16:00 ` Ilpo Järvinen
0 siblings, 0 replies; 12+ messages in thread
From: Ilpo Järvinen @ 2026-08-24 16:00 UTC (permalink / raw)
To: 孙 誉铭
Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org,
Mingyou Chen, Armin Wolf, Hans de Goede, Nabil Danial
[-- Attachment #1: Type: text/plain, Size: 8067 bytes --]
On Tue, 28 Jul 2026, 孙 誉铭 wrote:
> 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).
So does this mean it polls it while the machine is supposed to be
suspended?
> 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;
Magic literal.
> + 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) {
Please name the literal properly, you're clearly meaning something with
it.
> + 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));
So if acpi failed, you still write ->last_lid?
> + }
> + 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);
devm_delayed_work_autocancel() ?
> + drv_data->last_lid = 0xff;
The literal here as well.
> + schedule_delayed_work(&drv_data->lid_work,
> + msecs_to_jiffies(MIFS_V2_LID_POLL_MS));
Add include for msecs_to_jiffies().
> + }
> +
> + 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,
> };
>
>
--
i.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-08-24 16:00 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [RESEND PATCH 4/5] platform/x86: bitland-mifs-wmi: drive lid switch via EC poll on Xiaomi Book Pro 14 孙 誉铭
2026-08-24 16:00 ` 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox