* [PATCH v14 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
@ 2026-10-26 10:20 ` Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver Mingyou Chen
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:20 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen
Add a new maintainer entry for the bitland-mifs-wmi platform driver.
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 508912fb4e54..250c471e674d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23044,6 +23044,13 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/redmi-wmi.c
+BITLAND LAPTOP DRIVER
+M: Mingyou Chen <qby140326@gmail.com>
+M: Ilya Gladyshev <ilya.gladyshev@linux.dev>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: drivers/platform/x86/bitland-mifs-wmi.c
+
REDPINE WIRELESS DRIVER
L: linux-wireless@vger.kernel.org
S: Orphan
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v14 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver Mingyou Chen
@ 2026-10-26 10:20 ` Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries Mingyou Chen
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:20 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen, Nika Krasnova
The bitland-mifs-wmi and legacy redmi-wmi drivers both attempt to bind
to the same WMI GUID (46C93E13-EE9B-4262-8488-563BCA757FEF). This
overlap causes a device registration conflict, preventing one of the
drivers from loading properly depending on the module initialization
order.
Merge the event handling logic from redmi-wmi into bitland-mifs-wmi. By
handling both device layouts within a single driver, we eliminate the
GUID ownership conflict.
Tested-by: Nika Krasnova <nika@nikableh.moe>
Tested-by: Ilya Gladyshev <ilya.gladyshev@linux.dev>
Reviewed-by: Ilya Gladyshev <ilya.gladyshev@linux.dev>
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 153 ++++++++++++++++--------
1 file changed, 106 insertions(+), 47 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index dd1648b7de77..9afa2e2764b0 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -35,6 +35,11 @@
#include <linux/units.h>
#include <linux/wmi.h>
+#define BI_HOTKEY_CODE(id, low, high) \
+ (((u32)(high) << 24) | ((u32)(low) << 16) | ((u32)(id) << 8) | WMI_EVENT_TYPE_HOTKEY)
+
+#define AI_KEY_VALUE_MASK BIT(8)
+
#define DRV_NAME "bitland-mifs-wmi"
#define BITLAND_MIFS_GUID "B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B"
#define BITLAND_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
@@ -80,9 +85,9 @@ enum bitland_mifs_power_profile {
};
enum bitland_mifs_event_id {
- WMI_EVENT_RESERVED_1 = 1,
- WMI_EVENT_RESERVED_2 = 2,
- WMI_EVENT_RESERVED_3 = 3,
+ WMI_EVENT_SWITCHVIDEOMODE = 1,
+ WMI_EVENT_SELECTIVE_SCREENSHOT = 2,
+ WMI_EVENT_ALL_APPLICATIONS = 3,
WMI_EVENT_AIRPLANE_MODE = 4,
WMI_EVENT_KBD_BRIGHTNESS = 5,
WMI_EVENT_TOUCHPAD_STATE = 6,
@@ -100,10 +105,11 @@ enum bitland_mifs_event_id {
WMI_EVENT_FN_1 = 19,
WMI_EVENT_FN_2 = 20,
WMI_EVENT_FN_3 = 21,
- WMI_EVENT_FN_4 = 22,
+ WMI_EVENT_PERFORMANCE_PLAN_ALT = 22,
WMI_EVENT_FN_5 = 24,
WMI_EVENT_REFRESH_RATE = 25,
WMI_EVENT_CPU_FAN_SPEED = 26,
+ WMI_EVENT_CONFIG = 27,
WMI_EVENT_GPU_FAN_SPEED = 32,
WMI_EVENT_WIN_KEY_LOCK = 33,
WMI_EVENT_RESERVED_23 = 34,
@@ -607,18 +613,54 @@ static const struct attribute *const laptop_attrs[] = {
ATTRIBUTE_GROUPS(laptop);
static const struct key_entry bitland_mifs_wmi_keymap[] = {
- { KE_KEY, WMI_EVENT_OPEN_APP, { KEY_PROG1 } },
- { KE_KEY, WMI_EVENT_CALCULATOR_START, { KEY_CALC } },
- { KE_KEY, WMI_EVENT_BROWSER_START, { KEY_WWW } },
- { KE_IGNORE, WMI_EVENT_FN_J, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_F, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_0, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_1, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_2, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_3, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_4, { KEY_RESERVED } },
- { KE_IGNORE, WMI_EVENT_FN_5, { KEY_RESERVED } },
- { KE_END, 0 }
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_OPEN_APP, 1, 0), { KEY_PROG1 } },
+
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_CALCULATOR_START, 1, 0), { KEY_CALC } },
+
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_BROWSER_START, 1, 0), { KEY_WWW } },
+
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_J, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_F, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_0, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_1, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_2, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_3, 0, 0), {} },
+ { KE_IGNORE, BI_HOTKEY_CODE(WMI_EVENT_FN_5, 0, 0), {} },
+
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_SELECTIVE_SCREENSHOT, 0, 0),
+ { KEY_SELECTIVE_SCREENSHOT } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_ALL_APPLICATIONS, 0, 0), { KEY_ALL_APPLICATIONS } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_CONFIG, 0, 0), { KEY_CONFIG } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_CONFIG, 1, 0), { KEY_CONFIG } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_SWITCHVIDEOMODE, 1, 0), { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_SWITCHVIDEOMODE, 0, 0), { KEY_SWITCHVIDEOMODE } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_REFRESH_RATE, 0, 0), { KEY_REFRESH_RATE_TOGGLE } },
+
+ /* AI button has code for each position */
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_5, 1, 0), { KEY_ASSISTANT } },
+
+ { KE_KEY, BI_HOTKEY_CODE(0x19, 1, 0), { KEY_ASSISTANT } },
+
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_KBD_BRIGHTNESS, 0, 0), {KEY_KBDILLUMTOGGLE} },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_KBD_BRIGHTNESS, 0x80, 0), {KEY_KBDILLUMTOGGLE} },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_KBD_BRIGHTNESS, 5, 0), {KEY_KBDILLUMTOGGLE} },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_KBD_BRIGHTNESS, 0x0a, 0), {KEY_KBDILLUMTOGGLE} },
+
+ /* Xiaomi G Command Center */
+ { KE_KEY, BI_HOTKEY_CODE(0x0a, 1, 0), { KEY_VENDOR } },
+
+ /* Fn Lock state */
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FNLOCK_STATE, 0, 0), { KEY_FN_ESC } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FNLOCK_STATE, 1, 0), { KEY_FN_ESC } },
+
+ /* Fn+`/1/2/3/4 */
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_F, 1, 0), { KEY_F13 } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_0, 1, 0), { KEY_F14 } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_1, 1, 0), { KEY_F15 } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_2, 1, 0), { KEY_F16 } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_3, 1, 0), { KEY_F17 } },
+
+ { KE_END }
};
static void bitland_notifier_unregister(void *data)
@@ -736,13 +778,42 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
&drv_data->notifier);
}
+static bool bitland_is_ai_key_scancode(unsigned int code)
+{
+ return code == BI_HOTKEY_CODE(WMI_EVENT_FN_5, 1, 0) ||
+ code == BI_HOTKEY_CODE(0x19, 1, 0);
+}
+
+static void bitland_mifs_wmi_report_key(struct wmi_device *wdev, u32 payload)
+{
+ struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
+ struct key_entry *entry;
+ bool autorelease = true;
+ int value = 1;
+
+ entry = sparse_keymap_entry_from_scancode(data->input_dev, payload);
+ if (!entry) {
+ dev_dbg(&wdev->dev, "Unknown WMI hotkey with payload 0x%08x\n", payload);
+ return;
+ }
+
+ /* AI key quirk */
+ if (bitland_is_ai_key_scancode(entry->code)) {
+ value = !(payload & AI_KEY_VALUE_MASK);
+ autorelease = false;
+ }
+
+ guard(mutex)(&data->lock);
+ sparse_keymap_report_entry(data->input_dev, entry, value, autorelease);
+}
+
static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
const struct wmi_buffer *buffer)
{
- struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
const struct bitland_mifs_event *event = buffer->data;
struct bitland_fan_notify_data fan_data;
u8 brightness;
+ u32 payload;
/* Validate event type */
if (event->event_type != WMI_EVENT_TYPE_HOTKEY)
@@ -758,24 +829,14 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
blocking_notifier_call_chain(&bitland_notifier_list,
BITLAND_NOTIFY_KBD_BRIGHTNESS,
&brightness);
- break;
+ return;
case WMI_EVENT_PERFORMANCE_PLAN:
+ case WMI_EVENT_PERFORMANCE_PLAN_ALT:
blocking_notifier_call_chain(&bitland_notifier_list,
BITLAND_NOTIFY_PLATFORM_PROFILE,
NULL);
- break;
-
- case WMI_EVENT_OPEN_APP:
- case WMI_EVENT_CALCULATOR_START:
- case WMI_EVENT_BROWSER_START: {
- guard(mutex)(&data->lock);
- if (!sparse_keymap_report_event(data->input_dev,
- event->event_id, 1, true))
- dev_warn(&wdev->dev, "Unknown key pressed: 0x%02x\n",
- event->event_id);
- break;
- }
+ return;
/*
* The device has 3 fans (CPU, GPU, SYS),
@@ -783,6 +844,14 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
*/
case WMI_EVENT_CPU_FAN_SPEED:
case WMI_EVENT_GPU_FAN_SPEED:
+ /* Redmi refresh rate toggle quirk */
+ if (event->event_id == WMI_EVENT_CPU_FAN_SPEED &&
+ event->value_low == 0 && event->value_high == 0) {
+ payload = BI_HOTKEY_CODE(WMI_EVENT_REFRESH_RATE, 0, 0);
+ bitland_mifs_wmi_report_key(wdev, payload);
+ return;
+ }
+
if (event->event_id == WMI_EVENT_CPU_FAN_SPEED)
fan_data.channel = 0;
else
@@ -793,27 +862,17 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
blocking_notifier_call_chain(&bitland_notifier_list,
BITLAND_NOTIFY_HWMON,
&fan_data);
- break;
-
- case WMI_EVENT_AIRPLANE_MODE:
- case WMI_EVENT_TOUCHPAD_STATE:
- case WMI_EVENT_FNLOCK_STATE:
- case WMI_EVENT_KBD_MODE:
- case WMI_EVENT_CAPSLOCK_STATE:
- case WMI_EVENT_NUMLOCK_STATE:
- case WMI_EVENT_SCROLLLOCK_STATE:
- case WMI_EVENT_REFRESH_RATE:
- case WMI_EVENT_WIN_KEY_LOCK:
- /* These events are informational or handled by firmware */
- dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n",
- event->event_id, event->value_low);
- break;
+ return;
default:
- dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n",
- event->event_id, event->value_low);
+ dev_dbg(&wdev->dev,
+ "Unknown WMI event: id=0x%02x value_low=0x%02x value_high=0x%02x\n",
+ event->event_id, event->value_low, event->value_high);
break;
}
+
+ payload = get_unaligned_le32(buffer->data);
+ bitland_mifs_wmi_report_key(wdev, payload);
}
static const struct wmi_device_id bitland_mifs_wmi_id_table[] = {
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v14 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver Mingyou Chen
@ 2026-10-26 10:20 ` Mingyou Chen
2026-10-26 10:20 ` [PATCH v14 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver Mingyou Chen
` (3 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:20 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen, Nika Krasnova
Add the missing Redmibook mic-mute hotkey definitions to the shared
sparse keymap table:
- 0x00002101
- 0x00012101
Reported-by: Nika Krasnova <nika@nikableh.moe>
Link:
https://lore.kernel.org/platform-driver-x86/20260531123345.237521-1-nika@nikableh.moe/
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 9afa2e2764b0..0d7815c2faf9 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -111,7 +111,7 @@ enum bitland_mifs_event_id {
WMI_EVENT_CPU_FAN_SPEED = 26,
WMI_EVENT_CONFIG = 27,
WMI_EVENT_GPU_FAN_SPEED = 32,
- WMI_EVENT_WIN_KEY_LOCK = 33,
+ WMI_EVENT_MIC_MUTE = 33,
WMI_EVENT_RESERVED_23 = 34,
WMI_EVENT_OPEN_APP = 35,
};
@@ -636,6 +636,10 @@ static const struct key_entry bitland_mifs_wmi_keymap[] = {
{ KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_SWITCHVIDEOMODE, 0, 0), { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_REFRESH_RATE, 0, 0), { KEY_REFRESH_RATE_TOGGLE } },
+ /* Mic-mute key */
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_MIC_MUTE, 0, 0), { KEY_MICMUTE } },
+ { KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_MIC_MUTE, 1, 0), { KEY_MICMUTE } },
+
/* AI button has code for each position */
{ KE_KEY, BI_HOTKEY_CODE(WMI_EVENT_FN_5, 1, 0), { KEY_ASSISTANT } },
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v14 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (2 preceding siblings ...)
2026-10-26 10:20 ` [PATCH v14 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries Mingyou Chen
@ 2026-10-26 10:20 ` Mingyou Chen
2026-10-26 10:21 ` [PATCH v14 5/6] platform/x86: bitland-mifs-wmi: Add quirks table Mingyou Chen
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:20 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen
The redmi-wmi driver is no longer needed because its functionality
has been superseded by the new generic bitland platform driver.
All supported Redmi laptop models are now handled properly via the
updated WMI interfaces in bitland-mifs-wmi.
Remove the obsolete code, Kconfig entries, and Makefile references
to clean up the platform directory.
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
MAINTAINERS | 6 --
drivers/platform/x86/Kconfig | 15 +--
drivers/platform/x86/Makefile | 1 -
drivers/platform/x86/redmi-wmi.c | 154 -------------------------------
4 files changed, 8 insertions(+), 168 deletions(-)
delete mode 100644 drivers/platform/x86/redmi-wmi.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 250c471e674d..8ca065eb448f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23038,12 +23038,6 @@ S: Maintained
T: git https://github.com/pkshih/rtw.git
F: drivers/net/wireless/realtek/rtw89/
-REDMIBOOK WMI DRIVERS
-M: Gladyshev Ilya <foxido@foxido.dev>
-L: platform-driver-x86@vger.kernel.org
-S: Maintained
-F: drivers/platform/x86/redmi-wmi.c
-
BITLAND LAPTOP DRIVER
M: Mingyou Chen <qby140326@gmail.com>
M: Ilya Gladyshev <ilya.gladyshev@linux.dev>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 7ee9ff3879c9..6e561359a91b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -79,16 +79,17 @@ config XIAOMI_WMI
be called xiaomi-wmi.
config REDMI_WMI
- tristate "Redmibook WMI key driver"
+ tristate "Redmibook WMI key driver (DEPRECATED)"
depends on ACPI_WMI
+ depends on HWMON
depends on INPUT
- select INPUT_SPARSEKMAP
+ depends on LEDS_CLASS
+ depends on POWER_SUPPLY
+ select BITLAND_MIFS_WMI
+ default BITLAND_MIFS_WMI
help
- Say Y here if you want support for WMI-based hotkey events on
- Xiaomi Redmibook devices.
-
- To compile this driver as a module, choose M here: the module will
- be called redmi-wmi.
+ This option is deprecated and will be removed in a future release.
+ Please enable CONFIG_BITLAND_MIFS_WMI directly.
config GIGABYTE_WMI
tristate "Gigabyte WMI temperature driver"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index b90c544387be..3052b92fb5fa 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_HUAWEI_WMI) += huawei-wmi.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
-obj-$(CONFIG_REDMI_WMI) += redmi-wmi.o
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
obj-$(CONFIG_BITLAND_MIFS_WMI) += bitland-mifs-wmi.o
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
deleted file mode 100644
index cc82ef502002..000000000000
--- a/drivers/platform/x86/redmi-wmi.c
+++ /dev/null
@@ -1,154 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* WMI driver for Xiaomi Redmibooks */
-
-#include <linux/acpi.h>
-#include <linux/bits.h>
-#include <linux/device.h>
-#include <linux/input.h>
-#include <linux/input/sparse-keymap.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/unaligned.h>
-#include <linux/wmi.h>
-
-#include <uapi/linux/input-event-codes.h>
-
-#define WMI_REDMIBOOK_KEYBOARD_EVENT_GUID "46C93E13-EE9B-4262-8488-563BCA757FEF"
-
-#define AI_KEY_VALUE_MASK BIT(8)
-
-static const struct key_entry redmi_wmi_keymap[] = {
- {KE_KEY, 0x00000201, {KEY_SELECTIVE_SCREENSHOT}},
- {KE_KEY, 0x00000301, {KEY_ALL_APPLICATIONS}},
- {KE_KEY, 0x00001b01, {KEY_CONFIG}},
- {KE_KEY, 0x00011b01, {KEY_CONFIG}},
- {KE_KEY, 0x00010101, {KEY_SWITCHVIDEOMODE}},
- {KE_KEY, 0x00001a01, {KEY_REFRESH_RATE_TOGGLE}},
-
- /* AI button has code for each position */
- {KE_KEY, 0x00011801, {KEY_ASSISTANT}},
- {KE_KEY, 0x00011901, {KEY_ASSISTANT}},
-
- /* Keyboard backlight: Off / Auto / Low / High (new state in byte 2) */
- {KE_KEY, 0x00000501, {KEY_KBDILLUMTOGGLE}},
- {KE_KEY, 0x00800501, {KEY_KBDILLUMTOGGLE}},
- {KE_KEY, 0x00050501, {KEY_KBDILLUMTOGGLE}},
- {KE_KEY, 0x000a0501, {KEY_KBDILLUMTOGGLE}},
-
- /* Xiaomi G Command Center */
- {KE_KEY, 0x00010a01, {KEY_VENDOR}},
-
- /* OEM preset power mode: 1=Balanced 2=Silent 3=Turbo 4=Full speed */
- {KE_KEY, 0x00011601, {KEY_PERFORMANCE}},
- {KE_KEY, 0x00021601, {KEY_PERFORMANCE}},
- {KE_KEY, 0x00031601, {KEY_PERFORMANCE}},
- {KE_KEY, 0x00041601, {KEY_PERFORMANCE}},
-
- /* Fn Lock state: 1=on 0=off */
- {KE_KEY, 0x00000701, {KEY_FN_ESC}},
- {KE_KEY, 0x00010701, {KEY_FN_ESC}},
-
- /* Fn+`/1/2/3/4 */
- {KE_KEY, 0x00011101, {KEY_F13}},
- {KE_KEY, 0x00011201, {KEY_F14}},
- {KE_KEY, 0x00011301, {KEY_F15}},
- {KE_KEY, 0x00011401, {KEY_F16}},
- {KE_KEY, 0x00011501, {KEY_F17}},
-
- {KE_END}
-};
-
-struct redmi_wmi {
- struct input_dev *input_dev;
- /* Protects the key event sequence */
- struct mutex key_lock;
-};
-
-static int redmi_wmi_probe(struct wmi_device *wdev, const void *context)
-{
- struct redmi_wmi *data;
- int err;
-
- /* Init dev */
- data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- dev_set_drvdata(&wdev->dev, data);
-
- err = devm_mutex_init(&wdev->dev, &data->key_lock);
- if (err)
- return err;
-
- data->input_dev = devm_input_allocate_device(&wdev->dev);
- if (!data->input_dev)
- return -ENOMEM;
-
- data->input_dev->name = "Redmibook WMI keys";
- data->input_dev->phys = "wmi/input0";
-
- err = sparse_keymap_setup(data->input_dev, redmi_wmi_keymap, NULL);
- if (err)
- return err;
-
- return input_register_device(data->input_dev);
-}
-
-static void redmi_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
-{
- struct key_entry *entry;
- struct redmi_wmi *data = dev_get_drvdata(&wdev->dev);
- bool autorelease = true;
- u32 payload;
- int value = 1;
-
- if (obj->type != ACPI_TYPE_BUFFER) {
- dev_err(&wdev->dev, "Bad response type %u\n", obj->type);
- return;
- }
-
- if (obj->buffer.length < 32) {
- dev_err(&wdev->dev, "Invalid buffer length %u\n", obj->buffer.length);
- return;
- }
-
- payload = get_unaligned_le32(obj->buffer.pointer);
- entry = sparse_keymap_entry_from_scancode(data->input_dev, payload);
-
- if (!entry) {
- dev_dbg(&wdev->dev, "Unknown WMI event with payload %u", payload);
- return;
- }
-
- /* AI key quirk */
- if (entry->keycode == KEY_ASSISTANT) {
- value = !(payload & AI_KEY_VALUE_MASK);
- autorelease = false;
- }
-
- guard(mutex)(&data->key_lock);
- sparse_keymap_report_entry(data->input_dev, entry, value, autorelease);
-}
-
-static const struct wmi_device_id redmi_wmi_id_table[] = {
- { WMI_REDMIBOOK_KEYBOARD_EVENT_GUID, NULL },
- { }
-};
-
-static struct wmi_driver redmi_wmi_driver = {
- .driver = {
- .name = "redmi-wmi",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- },
- .id_table = redmi_wmi_id_table,
- .min_event_size = 32,
- .probe = redmi_wmi_probe,
- .notify = redmi_wmi_notify,
- .no_singleton = true,
-};
-module_wmi_driver(redmi_wmi_driver);
-
-MODULE_DEVICE_TABLE(wmi, redmi_wmi_id_table);
-MODULE_AUTHOR("Gladyshev Ilya <foxido@foxido.dev>");
-MODULE_DESCRIPTION("Redmibook WMI driver");
-MODULE_LICENSE("GPL");
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v14 5/6] platform/x86: bitland-mifs-wmi: Add quirks table
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (3 preceding siblings ...)
2026-10-26 10:20 ` [PATCH v14 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver Mingyou Chen
@ 2026-10-26 10:21 ` Mingyou Chen
2026-10-26 10:21 ` [PATCH v14 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available Mingyou Chen
2026-10-26 11:45 ` [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Hans de Goede
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:21 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen
The MIFS WMI interface is shared by several Bitland ODM laptops which
differ in the layout of the performance mode values of
WMI_FN_SYSTEM_PER_MODE and in the capability checks.
Introduce a quirks table to support multiple machine families without
sprinkling model checks over the driver.
Tested-by: Chris Taraszka <chris@miget.com>
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 178 ++++++++++++++++--------
1 file changed, 121 insertions(+), 57 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 0d7815c2faf9..3f8f1ebb10fb 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/container_of.h>
#include <linux/dev_printk.h>
+#include <linux/dmi.h>
#include <linux/device.h>
#include <linux/device/devres.h>
#include <linux/err.h>
@@ -84,6 +85,38 @@ enum bitland_mifs_power_profile {
WMI_PP_FULL_SPEED = 3,
};
+struct bitland_mifs_wmi_data;
+
+struct bitland_profile_entry {
+ enum platform_profile_option profile;
+ u8 wmi_val;
+ bool no_set;
+};
+
+struct bitland_mifs_quirks {
+ const struct bitland_profile_entry *profile_entries;
+ size_t num_profile_entries;
+
+ bool return_code_at_end;
+ bool skip_ac_type_check;
+};
+
+static const struct bitland_profile_entry default_profile_entries[] = {
+ { PLATFORM_PROFILE_LOW_POWER, WMI_PP_QUIET },
+ { PLATFORM_PROFILE_BALANCED, WMI_PP_BALANCED },
+ { PLATFORM_PROFILE_BALANCED_PERFORMANCE, WMI_PP_PERFORMANCE },
+ { PLATFORM_PROFILE_PERFORMANCE, WMI_PP_FULL_SPEED },
+};
+
+static const struct bitland_mifs_quirks default_quirks = {
+ .profile_entries = default_profile_entries,
+ .num_profile_entries = ARRAY_SIZE(default_profile_entries),
+};
+
+static const struct dmi_system_id bitland_mifs_dmi_table[] = {
+ {}
+};
+
enum bitland_mifs_event_id {
WMI_EVENT_SWITCHVIDEOMODE = 1,
WMI_EVENT_SELECTIVE_SCREENSHOT = 2,
@@ -131,12 +164,24 @@ struct bitland_mifs_input {
u8 payload[28];
} __packed;
-struct bitland_mifs_output {
+struct bitland_mifs_output_head_rc {
__le16 return_code;
__le16 function;
u8 data[28];
} __packed;
+struct bitland_mifs_output_tail_rc {
+ __le16 function;
+ u8 data[28];
+ __le16 return_code;
+} __packed;
+
+union bitland_mifs_output_buf {
+ struct bitland_mifs_output_head_rc head;
+ struct bitland_mifs_output_tail_rc tail;
+ u8 raw[32];
+};
+
struct bitland_mifs_event {
u8 event_type;
u8 event_id;
@@ -166,27 +211,41 @@ struct bitland_mifs_wmi_data {
struct input_dev *input_dev;
struct device *hwmon_dev;
struct device *pp_dev;
+ const struct bitland_mifs_quirks *quirks;
enum platform_profile_option saved_profile;
};
static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
const struct bitland_mifs_input *input,
- struct bitland_mifs_output *output)
+ struct bitland_mifs_output_head_rc *output)
{
struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input };
struct wmi_buffer out_buf = { 0 };
+ const u8 *payload_data;
+ __le16 return_code;
+ __le16 function;
int ret;
guard(mutex)(&data->lock);
ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf,
- sizeof(struct bitland_mifs_output));
+ sizeof(union bitland_mifs_output_buf));
if (ret)
return ret;
- struct bitland_mifs_output *result __free(kfree) = out_buf.data;
+ union bitland_mifs_output_buf *result __free(kfree) = out_buf.data;
+
+ if (data->quirks->return_code_at_end) {
+ return_code = result->tail.return_code;
+ function = result->tail.function;
+ payload_data = result->tail.data;
+ } else {
+ return_code = result->head.return_code;
+ function = result->head.function;
+ payload_data = result->head.data;
+ }
- switch (le16_to_cpu(result->return_code)) {
+ switch (le16_to_cpu(return_code)) {
case WMI_RETURN_CODE_SUCCESS:
break;
case WMI_RETURN_CODE_UNKNOWN_FUNCTION:
@@ -195,11 +254,19 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
return -EIO;
}
- if (result->function != input->function)
+ if (function != input->function) {
+ if (function == 0 && input->operation == cpu_to_le16(WMI_METHOD_SET))
+ goto fn_ok;
+
return -ENOMSG;
+ }
- if (output)
- memcpy(output, result, sizeof(*output));
+fn_ok:
+ if (output) {
+ output->return_code = return_code;
+ output->function = function;
+ memcpy(output->data, payload_data, sizeof(output->data));
+ }
return 0;
}
@@ -208,45 +275,41 @@ static int laptop_profile_get(struct device *dev,
enum platform_profile_option *profile)
{
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+ const struct bitland_mifs_quirks *quirks = data->quirks;
struct bitland_mifs_input input = {
.operation = cpu_to_le16(WMI_METHOD_GET),
.function = cpu_to_le16(WMI_FN_SYSTEM_PER_MODE),
};
- struct bitland_mifs_output result;
+ struct bitland_mifs_output_head_rc result;
+ size_t i;
int ret;
ret = bitland_mifs_wmi_call(data, &input, &result);
if (ret)
return ret;
- switch (result.data[0]) {
- case WMI_PP_BALANCED:
- *profile = PLATFORM_PROFILE_BALANCED;
- break;
- case WMI_PP_PERFORMANCE:
- *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
- break;
- case WMI_PP_QUIET:
- *profile = PLATFORM_PROFILE_LOW_POWER;
- break;
- case WMI_PP_FULL_SPEED:
- *profile = PLATFORM_PROFILE_PERFORMANCE;
- break;
- default:
- return -EINVAL;
+ for (i = 0; i < quirks->num_profile_entries; i++) {
+ if (quirks->profile_entries[i].wmi_val == result.data[0]) {
+ *profile = quirks->profile_entries[i].profile;
+ return 0;
+ }
}
- return 0;
+
+ return -EINVAL;
}
-static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *data)
+static int bitland_pp_check_capability(struct bitland_mifs_wmi_data *data)
{
struct bitland_mifs_input input = {
.operation = cpu_to_le16(WMI_METHOD_GET),
.function = cpu_to_le16(WMI_FN_SYSTEM_AC_TYPE),
};
- struct bitland_mifs_output output;
+ struct bitland_mifs_output_head_rc output;
int ret;
+ if (data->quirks->skip_ac_type_check)
+ return power_supply_is_system_supplied() > 0 ? 0 : -EOPNOTSUPP;
+
/* Full-speed/performance mode requires DC power (not USB-C) */
if (!power_supply_is_system_supplied())
return -EOPNOTSUPP;
@@ -269,47 +332,42 @@ static int laptop_profile_set(struct device *dev,
enum platform_profile_option profile)
{
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+ const struct bitland_mifs_quirks *quirks = data->quirks;
struct bitland_mifs_input input = {
.operation = cpu_to_le16(WMI_METHOD_SET),
.function = cpu_to_le16(WMI_FN_SYSTEM_PER_MODE),
};
+ size_t i;
int ret;
- u8 val;
- switch (profile) {
- case PLATFORM_PROFILE_LOW_POWER:
- val = WMI_PP_QUIET;
- break;
- case PLATFORM_PROFILE_BALANCED:
- val = WMI_PP_BALANCED;
- break;
- case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
- ret = bitland_check_performance_capability(data);
- if (ret)
- return ret;
- val = WMI_PP_PERFORMANCE;
- break;
- case PLATFORM_PROFILE_PERFORMANCE:
- ret = bitland_check_performance_capability(data);
+ if (profile == PLATFORM_PROFILE_PERFORMANCE ||
+ profile == PLATFORM_PROFILE_BALANCED_PERFORMANCE) {
+ ret = bitland_pp_check_capability(data);
if (ret)
return ret;
- val = WMI_PP_FULL_SPEED;
- break;
- default:
- return -EOPNOTSUPP;
}
- input.payload[0] = val;
+ for (i = 0; i < quirks->num_profile_entries; i++) {
+ if (quirks->profile_entries[i].profile == profile &&
+ !quirks->profile_entries[i].no_set) {
+ input.payload[0] = quirks->profile_entries[i].wmi_val;
+ return bitland_mifs_wmi_call(data, &input, NULL);
+ }
+ }
- return bitland_mifs_wmi_call(data, &input, NULL);
+ return -EOPNOTSUPP;
}
static int platform_profile_probe(void *drvdata, unsigned long *choices)
{
- set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
- set_bit(PLATFORM_PROFILE_BALANCED, choices);
- set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
- set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
+ struct bitland_mifs_wmi_data *data = drvdata;
+ const struct bitland_mifs_quirks *quirks = data->quirks;
+ size_t i;
+
+ for (i = 0; i < quirks->num_profile_entries; i++) {
+ if (!quirks->profile_entries[i].no_set)
+ set_bit(quirks->profile_entries[i].profile, choices);
+ }
return 0;
}
@@ -366,7 +424,7 @@ static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
struct bitland_mifs_input input = {
.operation = cpu_to_le16(WMI_METHOD_GET),
};
- struct bitland_mifs_output res;
+ struct bitland_mifs_output_head_rc res;
int ret;
switch (type) {
@@ -455,7 +513,7 @@ static enum led_brightness laptop_kbd_led_get(struct led_classdev *led_cdev)
.operation = cpu_to_le16(WMI_METHOD_GET),
.function = cpu_to_le16(WMI_FN_RGB_KB_BRIGHTNESS),
};
- struct bitland_mifs_output res;
+ struct bitland_mifs_output_head_rc res;
int ret;
ret = bitland_mifs_wmi_call(data, &input, &res);
@@ -480,7 +538,7 @@ static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr,
.operation = cpu_to_le16(WMI_METHOD_GET),
.function = cpu_to_le16(WMI_FN_GPU_MODE),
};
- struct bitland_mifs_output res;
+ struct bitland_mifs_output_head_rc res;
u8 mode_val;
int ret;
@@ -534,7 +592,7 @@ static ssize_t kb_mode_show(struct device *dev, struct device_attribute *attr,
.operation = cpu_to_le16(WMI_METHOD_GET),
.function = cpu_to_le16(WMI_FN_RGB_KB_MODE),
};
- struct bitland_mifs_output res;
+ struct bitland_mifs_output_head_rc res;
u8 mode_val;
int ret;
@@ -712,6 +770,7 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
.default_label = ":" LED_FUNCTION_KBD_BACKLIGHT,
.devname_mandatory = true,
};
+ const struct dmi_system_id *dmi_id;
int ret;
drv_data = devm_kzalloc(&wdev->dev, sizeof(*drv_data), GFP_KERNEL);
@@ -726,6 +785,11 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
dev_set_drvdata(&wdev->dev, drv_data);
+ drv_data->quirks = &default_quirks;
+ dmi_id = dmi_first_match(bitland_mifs_dmi_table);
+ if (dmi_id)
+ drv_data->quirks = dmi_id->driver_data;
+
if (dev_type == BITLAND_WMI_EVENT) {
/* Register input device for hotkeys */
drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH v14 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (4 preceding siblings ...)
2026-10-26 10:21 ` [PATCH v14 5/6] platform/x86: bitland-mifs-wmi: Add quirks table Mingyou Chen
@ 2026-10-26 10:21 ` Mingyou Chen
2026-10-26 11:45 ` [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Hans de Goede
6 siblings, 0 replies; 11+ messages in thread
From: Mingyou Chen @ 2026-10-26 10:21 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin, Mingyou Chen
On Bitland laptops, performance profiles require an external power
supply. If the system enters suspend in a performance profile and the AC
adapter is unplugged while the machine is asleep, laptop_profile_set()
fails with -EOPNOTSUPP during resume when attempting to re-apply
saved_profile.
Returning an error from the resume callback simply because the power
cable was removed during sleep is undesirable, as the device is
otherwise
fully functional.
Gracefully handle this condition by falling back to
PLATFORM_PROFILE_BALANCED
whenever restoring the saved profile returns -EOPNOTSUPP. Update
saved_profile accordingly and notify user space via
platform_profile_notify() so daemons such as power-profiles-daemon stay
in sync with the actual hardware state.
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 3f8f1ebb10fb..a431d3fef774 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -392,13 +392,27 @@ static int bitland_mifs_wmi_suspend(struct device *dev)
static int bitland_mifs_wmi_resume(struct device *dev)
{
struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
+ int ret;
/* Skip event device */
if (!data->pp_dev)
return 0;
+ ret = laptop_profile_set(dev, data->saved_profile);
+
+ if (ret == -EOPNOTSUPP && data->saved_profile != PLATFORM_PROFILE_BALANCED) {
+ dev_dbg(dev, "Cannot restore profile %d (likely on battery), falling back to balanced\n",
+ data->saved_profile);
+
+ ret = laptop_profile_set(dev, PLATFORM_PROFILE_BALANCED);
+ if (!ret) {
+ data->saved_profile = PLATFORM_PROFILE_BALANCED;
+ platform_profile_notify(data->pp_dev);
+ }
+ }
+
dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
- return laptop_profile_set(dev, data->saved_profile);
+ return ret;
}
static DEFINE_SIMPLE_DEV_PM_OPS(bitland_mifs_wmi_pm_ops,
--
2.56.0
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi
2026-10-26 10:20 [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (5 preceding siblings ...)
2026-10-26 10:21 ` [PATCH v14 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available Mingyou Chen
@ 2026-10-26 11:45 ` Hans de Goede
2026-10-26 19:56 ` Chris Taraszka
6 siblings, 1 reply; 11+ messages in thread
From: Hans de Goede @ 2026-10-26 11:45 UTC (permalink / raw)
To: Mingyou Chen, Ilpo Järvinen, Ilya Gladyshev
Cc: KentoNion, platform-driver-x86, ted eric, Armin Wolf,
linux-kernel, Chris Taraszka, Matias Civadda,
高 俊文, powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin
Hi,
On 26-Oct-26 11:20 AM, Mingyou Chen wrote:
> This patch series consolidates the standalone 'redmi-wmi' driver into the
> 'bitland-mifs-wmi' driver to eliminate code duplication and centralize
> the maintenance of overlapping ACPI WMI event streams.
<snip>
> And I've got a question, from sashiko's comment in my v12
>
> https://sashiko.dev/#/patchset/20261012133648.132363-1-qby140326%40gmail.com
>
>> Will this result in the loss of KEY_PERFORMANCE events on event-only legacy
>> devices?
>> Looking at bitland_mifs_wmi_probe() in drivers/platform/x86/bitland-mifs-wmi.c,
>> if dev_type == BITLAND_WMI_EVENT, it returns early after registering the input
>> device:
>> if (dev_type == BITLAND_WMI_EVENT) {
>> /* Register input device for hotkeys */
>> drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
>> ...
>> return input_register_device(drv_data->input_dev);
>> }
>> When the performance key is pressed, bitland_mifs_wmi_notify() intercepts it,
>> invokes the bitland_notifier_list, and returns without reporting an input event:
>> case WMI_EVENT_PERFORMANCE_PLAN:
>> case WMI_EVENT_PERFORMANCE_PLAN_ALT:
>> blocking_notifier_call_chain(&bitland_notifier_list,
>> BITLAND_NOTIFY_PLATFORM_PROFILE,
>> NULL);
>> return;
>> Because the platform profile and notifier were not registered during probe
>> for event-only devices, does this mean the events are silently dropped instead
>> of emitting KEY_PERFORMANCE like the old driver did?
>
> I ackknowledged that KEY_PERFORMANCE (WMI_EVENT_PERFORMANCE_PLAN_ALT in
> bitland-mifs-wmi) looks like an event in this LKML thread
>
>> Since the event reports a change that has already happened,
>> platform_profile_notify() is the natural way to pass it on, as
>> suggested in my v6 reply: power-profiles-daemon then re-reads the
>> profile, which is harmless after the driver's own writes too. If
>> KEY_PERFORMANCE should stay for on-screen displays (Ibragim asked to
>> keep these events observable), it may be worth not reporting it for the
>> event that echoes the driver's own write, or at least saying in a
>> comment that it reports a mode change that already happened. On
>> Ibragim's TM2209 the profile SET is reported not to work [3], so there
>> 0x16 can only come from Fn+K and the echo does not exist; Ibragim, can
>> you confirm?
>
> https://lore.kernel.org/all/20261008152647.1510152-1-uselessfire@gmail.com/
>
> So should I follow sashiko's advice?
Copy and pasting my v13 reply about this here to make sure it gets seen:
What I think should happen here is that *if* there is a platform-profile-handler,
then platform_profile_notify() should be used (1). OTOH if there is no
platform-profile-handler (the mentioned event-only mode) then reporting this
to userspace as KEY_PERFORMANCE as was done before makes sense to me.
Does that sound reasonable?
Regards,
Hans
1) This assumes the event indicates a platform-profile-change has happened, if
it is a request for a platform-profile-change then platform_profile_cycle();
should be used instead.
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi
2026-10-26 11:45 ` [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi Hans de Goede
@ 2026-10-26 19:56 ` Chris Taraszka
2026-10-26 20:02 ` Hans de Goede
0 siblings, 1 reply; 11+ messages in thread
From: Chris Taraszka @ 2026-10-26 19:56 UTC (permalink / raw)
To: Hans de Goede
Cc: Mingyou Chen, Ilpo Järvinen, Ilya Gladyshev, KentoNion,
platform-driver-x86, ted eric, Armin Wolf, linux-kernel,
Matias Civadda, 高 俊文,
powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin
On Mon, 26 Oct 2026, Hans de Goede wrote:
> 1) This assumes the event indicates a platform-profile-change has happened, if
> it is a request for a platform-profile-change then platform_profile_cycle();
> should be used instead.
Hi,
Some data for this and for Mingyou's KBD_BRIGHTNESS question, from the
Xiaomi Book Pro 14 (TM2424, BIOS XMAPT4B0P0A0A), traced with a kprobe
on bitland_mifs_wmi_notify() with v13 on v7.3 (v14 has the same event
handling):
- Fn+Space (keyboard backlight) sends no WMI event at all, neither 0x05
nor anything else, and does not change the backlight under Linux. So
this model cannot tell whether the firmware handles KBD_BRIGHTNESS.
- Fn+K sends event 0x28 with value_low 0x01 on every press (01 28 01 00),
not 0x16. The firmware does not change the mode by itself: the
SystemPerMode value (EC 0x68) stays the same across the presses. If
0x28 is the performance mode key on this model, it is a request rather
than a notification, so platform_profile_cycle() would fit. 0x28 is
currently logged as "Unknown WMI event".
- On Windows on the same machine, with Xiaomi PC Manager not running
(it fails to start on this install), neither Fn+K nor Fn+Space does
anything either. So Fn+K looks like a request that Xiaomi's software
normally acts on, not a mode change made by the firmware.
- Mic mute sends 0x21 with value_low 1 and 0 and is reported as
KEY_MICMUTE, as expected.
Thanks,
Chris
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi
2026-10-26 19:56 ` Chris Taraszka
@ 2026-10-26 20:02 ` Hans de Goede
2026-10-26 20:20 ` Chris Taraszka
0 siblings, 1 reply; 11+ messages in thread
From: Hans de Goede @ 2026-10-26 20:02 UTC (permalink / raw)
To: Chris Taraszka
Cc: Mingyou Chen, Ilpo Järvinen, Ilya Gladyshev, KentoNion,
platform-driver-x86, ted eric, Armin Wolf, linux-kernel,
Matias Civadda, 高 俊文,
powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin
Hi,
On 26-Oct-26 20:56, Chris Taraszka wrote:
> On Mon, 26 Oct 2026, Hans de Goede wrote:
>> 1) This assumes the event indicates a platform-profile-change has happened, if
>> it is a request for a platform-profile-change then platform_profile_cycle();
>> should be used instead.
>
> Hi,
>
> Some data for this and for Mingyou's KBD_BRIGHTNESS question, from the
> Xiaomi Book Pro 14 (TM2424, BIOS XMAPT4B0P0A0A), traced with a kprobe
> on bitland_mifs_wmi_notify() with v13 on v7.3 (v14 has the same event
> handling):
Thank you for the info.
> - Fn+Space (keyboard backlight) sends no WMI event at all, neither 0x05
> nor anything else, and does not change the backlight under Linux. So
> this model cannot tell whether the firmware handles KBD_BRIGHTNESS.
Hmm, I wonder if this maybe sends some scan-code on the PS/2 atkbd
interface? Windows must get an event somehow ...
> - Fn+K sends event 0x28 with value_low 0x01 on every press (01 28 01 00),
> not 0x16. The firmware does not change the mode by itself: the
> SystemPerMode value (EC 0x68) stays the same across the presses. If
> 0x28 is the performance mode key on this model, it is a request rather
> than a notification, so platform_profile_cycle() would fit. 0x28 is
> currently logged as "Unknown WMI event".
Ack, this sounds like a case for calling platform_profile_cycle() if
platform-profile support is present.
> - On Windows on the same machine, with Xiaomi PC Manager not running
> (it fails to start on this install), neither Fn+K nor Fn+Space does
> anything either. So Fn+K looks like a request that Xiaomi's software
> normally acts on, not a mode change made by the firmware.
>
> - Mic mute sends 0x21 with value_low 1 and 0 and is reported as
> KEY_MICMUTE, as expected.
Hmm, if the value-low toggles I wonder if the firmware also mutes
the mic itself ? This may need some special handling.
Regards,
Hans
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v14 RESEND 0/6] Merge redmi-wmi into bitland-mifs-wmi
2026-10-26 20:02 ` Hans de Goede
@ 2026-10-26 20:20 ` Chris Taraszka
0 siblings, 0 replies; 11+ messages in thread
From: Chris Taraszka @ 2026-10-26 20:20 UTC (permalink / raw)
To: Hans de Goede
Cc: Mingyou Chen, Ilpo Järvinen, Ilya Gladyshev, KentoNion,
platform-driver-x86, ted eric, Armin Wolf, linux-kernel,
Matias Civadda, 高 俊文,
powerfullz, 孙 誉铭,
Miloš Vlku, Rsplwe, Bozhen Peng, Anton Karasev, Jame Jao,
Serhiy Shliapuhin
On Mon, 26 Oct 2026, Hans de Goede wrote:
> Hmm, I wonder if this maybe sends some scan-code on the PS/2 atkbd
> interface? Windows must get an event somehow ...
Hi Hans,
It does, but only the plain Space scancode: Fn+Space gives scan 0x39 /
KEY_SPACE on the atkbd device, the same as Space alone, and Fn on its
own sends nothing. So there is nothing that tells it apart from Space.
> Ack, this sounds like a case for calling platform_profile_cycle() if
> platform-profile support is present.
I can send a patch for that on top of Mingyou's series and my TM2424
patches.
> Hmm, if the value-low toggles I wonder if the firmware also mutes
> the mic itself ? This may need some special handling.
It does not. I played a 1 kHz tone through the speakers and recorded it
with the internal microphone while pressing mic mute, with the PipeWire
source forced unmuted: the level stayed the same with the key's LED on.
The LED is driven by the firmware and follows its own toggle state,
which is what value_low reports. It does not follow the OS mute: muting
the source from userspace leaves the LED off. So the two can get out of
sync, but nothing in the audio path needs special handling.
Thanks,
Chris
^ permalink raw reply [flat|nested] 11+ messages in thread