* [PATCH v2 1/5] platform/x86: uniwill-laptop: Rename FN lock and super key lock attrs
2026-02-12 7:02 [PATCH v2 0/5] uniwill-laptop: Input-related improvements Armin Wolf
@ 2026-02-12 7:02 ` Armin Wolf
2026-02-12 7:02 ` [PATCH v2 2/5] platform/x86: uniwill-laptop: Fix crash on unexpected battery event Armin Wolf
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Armin Wolf @ 2026-02-12 7:02 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
It turns out that both sysfs attributes actually directly control
the FN lock status/super key enable status, rather than the
triggering of the associated events. This behavior was first observed
on a Tuxedo notebook and was belived to be a hardware quirk.
However, it seems that i simply misunderstood the manual of the
OEM software for Intel NUC devices. The correct behavior is:
- fn_lock_toggle_enable enables/disables FN lock mode
- super_key_toggle_enable enables/disables the super key
Rename both sysfs attributes to avoid confusing users.
Fixes: d050479693bb ("platform/x86: Add Uniwill laptop driver")
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
.../ABI/testing/sysfs-driver-uniwill-laptop | 10 ++--
.../admin-guide/laptops/uniwill-laptop.rst | 2 +-
drivers/platform/x86/uniwill/uniwill-acpi.c | 52 +++++++++----------
drivers/platform/x86/uniwill/uniwill-wmi.h | 4 +-
4 files changed, 33 insertions(+), 35 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index eaeb659793d2..2df70792968f 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -1,4 +1,4 @@
-What: /sys/bus/platform/devices/INOU0000:XX/fn_lock_toggle_enable
+What: /sys/bus/platform/devices/INOU0000:XX/fn_lock
Date: November 2025
KernelVersion: 6.19
Contact: Armin Wolf <W_Armin@gmx.de>
@@ -8,15 +8,15 @@ Description:
Reading this file returns the current enable status of the FN lock functionality.
-What: /sys/bus/platform/devices/INOU0000:XX/super_key_toggle_enable
+What: /sys/bus/platform/devices/INOU0000:XX/super_key_enable
Date: November 2025
KernelVersion: 6.19
Contact: Armin Wolf <W_Armin@gmx.de>
Description:
- Allows userspace applications to enable/disable the super key functionality
- of the integrated keyboard by writing "1"/"0" into this file.
+ Allows userspace applications to enable/disable the super key of the integrated
+ keyboard by writing "1"/"0" into this file.
- Reading this file returns the current enable status of the super key functionality.
+ Reading this file returns the current enable status of the super key.
What: /sys/bus/platform/devices/INOU0000:XX/touchpad_toggle_enable
Date: November 2025
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
index a16baf15516b..aff5f57a6bd4 100644
--- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -24,7 +24,7 @@ Keyboard settings
The ``uniwill-laptop`` driver allows the user to enable/disable:
- - the FN and super key lock functionality of the integrated keyboard
+ - the FN lock and super key of the integrated keyboard
- the touchpad toggle functionality of the integrated touchpad
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 3c9af441d133..30acf752adce 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -314,8 +314,8 @@
#define LED_CHANNELS 3
#define LED_MAX_BRIGHTNESS 200
-#define UNIWILL_FEATURE_FN_LOCK_TOGGLE BIT(0)
-#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE BIT(1)
+#define UNIWILL_FEATURE_FN_LOCK BIT(0)
+#define UNIWILL_FEATURE_SUPER_KEY BIT(1)
#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2)
#define UNIWILL_FEATURE_LIGHTBAR BIT(3)
#define UNIWILL_FEATURE_BATTERY BIT(4)
@@ -377,9 +377,9 @@ static const struct key_entry uniwill_keymap[] = {
{ KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }},
{ KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }},
- /* Reported when the user locks/unlocks the super key */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE, { KEY_UNKNOWN }},
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE, { KEY_UNKNOWN }},
+ /* Reported when the user enables/disables the super key */
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_DISABLE, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_ENABLE, { KEY_UNKNOWN }},
/* Optional, might not be reported by all devices */
{ KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }},
@@ -600,8 +600,8 @@ static const struct regmap_config uniwill_ec_config = {
.use_single_write = true,
};
-static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -624,8 +624,7 @@ static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_att
return count;
}
-static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -638,10 +637,10 @@ static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attr
return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(fn_lock_toggle_enable);
+static DEVICE_ATTR_RW(fn_lock);
-static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t super_key_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -673,8 +672,7 @@ static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_a
return count;
}
-static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t super_key_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -687,7 +685,7 @@ static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_at
return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(super_key_toggle_enable);
+static DEVICE_ATTR_RW(super_key_enable);
static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -881,8 +879,8 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
static struct attribute *uniwill_attrs[] = {
/* Keyboard-related */
- &dev_attr_fn_lock_toggle_enable.attr,
- &dev_attr_super_key_toggle_enable.attr,
+ &dev_attr_fn_lock.attr,
+ &dev_attr_super_key_enable.attr,
&dev_attr_touchpad_toggle_enable.attr,
/* Lightbar-related */
&dev_attr_rainbow_animation.attr,
@@ -897,13 +895,13 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
struct device *dev = kobj_to_dev(kobj);
struct uniwill_data *data = dev_get_drvdata(dev);
- if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK_TOGGLE))
+ if (attr == &dev_attr_fn_lock.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
return attr->mode;
}
- if (attr == &dev_attr_super_key_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (attr == &dev_attr_super_key_enable.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return attr->mode;
}
@@ -1505,7 +1503,7 @@ static void uniwill_shutdown(struct platform_device *pdev)
static int uniwill_suspend_keyboard(struct uniwill_data *data)
{
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
/*
@@ -1565,7 +1563,7 @@ static int uniwill_resume_keyboard(struct uniwill_data *data)
unsigned int value;
int ret;
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
@@ -1643,16 +1641,16 @@ static struct platform_driver uniwill_driver = {
};
static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_BATTERY |
UNIWILL_FEATURE_HWMON,
};
static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_LIGHTBAR |
UNIWILL_FEATURE_BATTERY |
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
index 48783b2e9ffb..fb1fd20392a0 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.h
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
@@ -64,8 +64,8 @@
#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E
#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F
-#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40
-#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41
+#define UNIWILL_OSD_SUPER_KEY_DISABLE 0x40
+#define UNIWILL_OSD_SUPER_KEY_ENABLE 0x41
#define UNIWILL_OSD_MENU_JP 0x42
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 3/5] platform/x86: uniwill-laptop: Mark FN lock status as being volatile
2026-02-12 7:02 [PATCH v2 0/5] uniwill-laptop: Input-related improvements Armin Wolf
2026-02-12 7:02 ` [PATCH v2 1/5] platform/x86: uniwill-laptop: Rename FN lock and super key lock attrs Armin Wolf
2026-02-12 7:02 ` [PATCH v2 2/5] platform/x86: uniwill-laptop: Fix crash on unexpected battery event Armin Wolf
@ 2026-02-12 7:02 ` Armin Wolf
2026-02-12 7:02 ` [PATCH v2 4/5] platform/x86: uniwill-laptop: Handle FN lock event Armin Wolf
2026-02-12 7:02 ` [PATCH v2 5/5] platform/x86: uniwill-laptop: Handle super key enable/disable events Armin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Armin Wolf @ 2026-02-12 7:02 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
It turns out that the FN lock status can be changed by the underlying
hardware when the user presses a special key combination. Mark the
associated register as volatile to prevent regmap from caching said
value. Also add the necessary suspend/resume handling.
Fixes: d050479693bb ("platform/x86: Add Uniwill laptop driver")
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 39 ++++++++++++++++++---
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index ca66288e0d5d..5ff8fcec9d9e 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -330,6 +330,7 @@ struct uniwill_data {
struct acpi_battery_hook hook;
unsigned int last_charge_ctrl;
struct mutex battery_lock; /* Protects the list of currently registered batteries */
+ unsigned int last_status;
unsigned int last_switch_status;
struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
struct list_head batteries;
@@ -576,6 +577,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
case EC_ADDR_SECOND_FAN_RPM_1:
case EC_ADDR_SECOND_FAN_RPM_2:
case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_BIOS_OEM:
case EC_ADDR_PWM_1:
case EC_ADDR_PWM_2:
case EC_ADDR_TRIGGER:
@@ -1504,7 +1506,19 @@ static void uniwill_shutdown(struct platform_device *pdev)
regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
}
-static int uniwill_suspend_keyboard(struct uniwill_data *data)
+static int uniwill_suspend_fn_lock(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ /*
+ * The EC_ADDR_BIOS_OEM is marked as volatile, so we have to restore it
+ * ourselves.
+ */
+ return regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &data->last_status);
+}
+
+static int uniwill_suspend_super_key(struct uniwill_data *data)
{
if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
@@ -1543,7 +1557,11 @@ static int uniwill_suspend(struct device *dev)
struct uniwill_data *data = dev_get_drvdata(dev);
int ret;
- ret = uniwill_suspend_keyboard(data);
+ ret = uniwill_suspend_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_suspend_super_key(data);
if (ret < 0)
return ret;
@@ -1561,7 +1579,16 @@ static int uniwill_suspend(struct device *dev)
return 0;
}
-static int uniwill_resume_keyboard(struct uniwill_data *data)
+static int uniwill_resume_fn_lock(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS,
+ data->last_status);
+}
+
+static int uniwill_resume_super_key(struct uniwill_data *data)
{
unsigned int value;
int ret;
@@ -1609,7 +1636,11 @@ static int uniwill_resume(struct device *dev)
if (ret < 0)
return ret;
- ret = uniwill_resume_keyboard(data);
+ ret = uniwill_resume_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_resume_super_key(data);
if (ret < 0)
return ret;
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 4/5] platform/x86: uniwill-laptop: Handle FN lock event
2026-02-12 7:02 [PATCH v2 0/5] uniwill-laptop: Input-related improvements Armin Wolf
` (2 preceding siblings ...)
2026-02-12 7:02 ` [PATCH v2 3/5] platform/x86: uniwill-laptop: Mark FN lock status as being volatile Armin Wolf
@ 2026-02-12 7:02 ` Armin Wolf
2026-02-12 7:02 ` [PATCH v2 5/5] platform/x86: uniwill-laptop: Handle super key enable/disable events Armin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Armin Wolf @ 2026-02-12 7:02 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
On many devices, the user can toggle the Fn lock state by
pressing Fn + Esc. Forward the associated event to the fn_lock
sysfs attribute as a poll notification.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 5ff8fcec9d9e..afa534da6d57 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -402,9 +402,6 @@ static const struct key_entry uniwill_keymap[] = {
/* Reported when the user wants to toggle the mute status */
{ KE_IGNORE, UNIWILL_OSD_MUTE, { KEY_MUTE }},
- /* Reported when the user locks/unlocks the Fn key */
- { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
-
/* Reported when the user wants to toggle the brightness of the keyboard */
{ KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
@@ -1372,6 +1369,13 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
* gets implemented.
*/
+ return NOTIFY_OK;
+ case UNIWILL_OSD_FN_LOCK:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return NOTIFY_DONE;
+
+ sysfs_notify(&data->dev->kobj, NULL, "fn_lock");
+
return NOTIFY_OK;
default:
mutex_lock(&data->input_lock);
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 5/5] platform/x86: uniwill-laptop: Handle super key enable/disable events
2026-02-12 7:02 [PATCH v2 0/5] uniwill-laptop: Input-related improvements Armin Wolf
` (3 preceding siblings ...)
2026-02-12 7:02 ` [PATCH v2 4/5] platform/x86: uniwill-laptop: Handle FN lock event Armin Wolf
@ 2026-02-12 7:02 ` Armin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Armin Wolf @ 2026-02-12 7:02 UTC (permalink / raw)
To: hansg, ilpo.jarvinen; +Cc: wse, platform-driver-x86, linux-kernel
On many devices, the user can enable/disable the super key by
pressing Fn + F9. Forward the associated events to the
super_key_enable sysfs attribute as a poll notification.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/platform/x86/uniwill/uniwill-acpi.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index afa534da6d57..d97a1e050740 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -378,9 +378,6 @@ static const struct key_entry uniwill_keymap[] = {
{ KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }},
{ KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }},
- /* Reported when the user enables/disables the super key */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_DISABLE, { KEY_UNKNOWN }},
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_ENABLE, { KEY_UNKNOWN }},
/* Optional, might not be reported by all devices */
{ KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }},
@@ -1353,6 +1350,14 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
struct uniwill_battery_entry *entry;
switch (action) {
+ case UNIWILL_OSD_SUPER_KEY_DISABLE:
+ case UNIWILL_OSD_SUPER_KEY_ENABLE:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
+ return NOTIFY_DONE;
+
+ sysfs_notify(&data->dev->kobj, NULL, "super_key_enable");
+
+ return NOTIFY_OK;
case UNIWILL_OSD_BATTERY_ALERT:
if (!uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY))
return NOTIFY_DONE;
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread