* [PATCH v12 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver Mingyou Chen
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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 fa0571a5e479..0874713f262b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23042,6 +23042,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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v12 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries Mingyou Chen
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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 | 143 ++++++++++++++++--------
1 file changed, 97 insertions(+), 46 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index dd1648b7de77..e240ab733ff1 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,55 @@ 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_PERFORMANCE_PLAN_ALT, 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 +779,36 @@ static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
&drv_data->notifier);
}
+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 (entry->keycode == KEY_ASSISTANT) {
+ 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)
@@ -761,21 +827,11 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
break;
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 +839,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 +857,14 @@ 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);
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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v12 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 1/6] MAINTAINERS: Add maintainer entry of bitland-mifs-wmi driver Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 2/6] platform/x86: bitland-mifs-wmi: Merge the function of redmi-wmi into the bitland driver Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver Mingyou Chen
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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 e240ab733ff1..38843d389827 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,
};
@@ -637,6 +637,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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v12 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (2 preceding siblings ...)
2026-10-12 13:36 ` [PATCH v12 3/6] platform/x86: bitland-mifs-wmi: Add Redmi mic-mute key entries Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 5/6] platform/x86: bitland-mifs-wmi: Add quirks table Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available Mingyou Chen
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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 | 12 ---
drivers/platform/x86/Makefile | 1 -
drivers/platform/x86/redmi-wmi.c | 154 -------------------------------
4 files changed, 173 deletions(-)
delete mode 100644 drivers/platform/x86/redmi-wmi.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 0874713f262b..00338dd596a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23036,12 +23036,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..f87a8ec95a86 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -78,18 +78,6 @@ config XIAOMI_WMI
To compile this driver as a module, choose M here: the module will
be called xiaomi-wmi.
-config REDMI_WMI
- tristate "Redmibook WMI key driver"
- depends on ACPI_WMI
- depends on INPUT
- select INPUT_SPARSEKMAP
- 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.
-
config GIGABYTE_WMI
tristate "Gigabyte WMI temperature driver"
depends on ACPI_WMI
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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v12 5/6] platform/x86: bitland-mifs-wmi: Add quirks table
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (3 preceding siblings ...)
2026-10-12 13:36 ` [PATCH v12 4/6] platform/x86: redmi-wmi: Drop redmi-wmi driver Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
2026-10-12 13:36 ` [PATCH v12 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available Mingyou Chen
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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.
Signed-off-by: Mingyou Chen <qby140326@gmail.com>
---
drivers/platform/x86/bitland-mifs-wmi.c | 180 ++++++++++++++++--------
1 file changed, 122 insertions(+), 58 deletions(-)
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 38843d389827..fac1cdbbd778 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,41 @@ 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;
+
+ /* Accept return value 0 on SET wmi functions */
+ bool accept_zero_function;
+};
+
+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 +167,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 +214,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;
- switch (le16_to_cpu(result->return_code)) {
+ 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(return_code)) {
case WMI_RETURN_CODE_SUCCESS:
break;
case WMI_RETURN_CODE_UNKNOWN_FUNCTION:
@@ -195,11 +257,16 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
return -EIO;
}
- if (result->function != input->function)
- return -ENOMSG;
+ if (function != input->function) {
+ if (!(data->quirks->accept_zero_function && function == 0))
+ return -ENOMSG;
+ }
- if (output)
- memcpy(output, result, sizeof(*output));
+ 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;
@@ -713,6 +771,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);
@@ -727,6 +786,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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v12 6/6] platform/x86: bitland-mifs-wmi: Fallback to balanced platform profile if last performance profile is not available
2026-10-12 13:36 [PATCH v12 0/6] Merge redmi-wmi into bitland-mifs-wmi Mingyou Chen
` (4 preceding siblings ...)
2026-10-12 13:36 ` [PATCH v12 5/6] platform/x86: bitland-mifs-wmi: Add quirks table Mingyou Chen
@ 2026-10-12 13:36 ` Mingyou Chen
5 siblings, 0 replies; 7+ messages in thread
From: Mingyou Chen @ 2026-10-12 13:36 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,
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 fac1cdbbd778..44b16b7b4034 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.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread