* [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection @ 2026-04-19 10:27 Pit Henrich 2026-06-08 9:09 ` Hans de Goede 2026-06-09 1:19 ` Mark Pearson 0 siblings, 2 replies; 5+ messages in thread From: Pit Henrich @ 2026-04-19 10:27 UTC (permalink / raw) To: hmh Cc: mpearson-lenovo, derekjohn.clark, hansg, ilpo.jarvinen, ibm-acpi-devel, platform-driver-x86, linux-kernel, pithenrich2d ThinkPad X1 Fold 16 Gen 1 firmware reports whether the keyboard is magnetically attached (on the screen), but thinkpad-acpi does not expose this to userspace. The state can be obtained via ACPI methods: GDST (get device state). Add a read-only keyboard_attached_on_screen sysfs attribute, gated by a DMI match. The state is read directly from the EC. Cache the state and emit a sysfs notification on TP_HKEY_EV_TABLET_CHANGED (0x60c0) when it changes. Initialize the cache during hotkey setup and refresh it before the resume notification to keep the state consistent across suspend and resume. Signed-off-by: Pit Henrich <pithenrich2d@gmail.com> --- This replaced the v1 patch in: https://lore.kernel.org/all/20260314142236.74514-1-pithenrich2d@gmail.com/ Changes v1 -> v2: * Use ACPI method instead of using the EC directly (thanks Mark). --- drivers/platform/x86/lenovo/thinkpad_acpi.c | 85 ++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c index 8982d92dfd97..b57ae7eb5548 100644 --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c @@ -218,8 +218,9 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ - TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016): - * enter/leave tablet mode + TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* posture change event: + * X1 Yoga (2016): enter/leave tablet mode + * X1 Fold 16 Gen 1: keyboard attachment state changed */ TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ @@ -375,6 +376,7 @@ static struct { u32 has_adaptive_kbd:1; u32 kbd_lang:1; u32 trackpoint_doubletap:1; + u32 has_keyboard_attached_on_screen:1; struct quirk_entry *quirks; } tp_features; @@ -2928,6 +2930,63 @@ static void hotkey_tablet_mode_notify_change(void) "hotkey_tablet_mode"); } +static bool keyboard_attached_on_screen; +static bool keyboard_attached_on_screen_initialized; + +static int x1_fold_keyboard_attached_on_screen_get(bool *attached) +{ + int state; + + if (!tp_features.has_keyboard_attached_on_screen) + return -ENODEV; + + if (!acpi_evalf(NULL, &state, "\\_SB.DEVD.GDST", "d")) + return -EIO; + + *attached = state != 0; + return 0; +} + +static ssize_t keyboard_attached_on_screen_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + bool attached; + int res; + + res = x1_fold_keyboard_attached_on_screen_get(&attached); + if (res) + return res; + + return sysfs_emit(buf, "%d\n", attached); +} + +static DEVICE_ATTR_RO(keyboard_attached_on_screen); + +static void keyboard_attached_on_screen_notify_change(void) +{ + if (tp_features.has_keyboard_attached_on_screen) + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, + "keyboard_attached_on_screen"); +} + +static bool keyboard_attached_on_screen_update(void) +{ + bool attached; + + if (x1_fold_keyboard_attached_on_screen_get(&attached)) + return false; + + if (keyboard_attached_on_screen_initialized && + keyboard_attached_on_screen == attached) + return false; + + keyboard_attached_on_screen = attached; + keyboard_attached_on_screen_initialized = true; + + return true; +} + /* sysfs wakeup reason (pollable) -------------------------------------- */ static ssize_t hotkey_wakeup_reason_show(struct device *dev, struct device_attribute *attr, @@ -3032,6 +3091,7 @@ static struct attribute *hotkey_attributes[] = { &dev_attr_hotkey_adaptive_all_mask.attr, &dev_attr_hotkey_recommended_mask.attr, &dev_attr_hotkey_tablet_mode.attr, + &dev_attr_keyboard_attached_on_screen.attr, &dev_attr_hotkey_radio_sw.attr, #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL &dev_attr_hotkey_source_mask.attr, @@ -3046,6 +3106,9 @@ static umode_t hotkey_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_hotkey_tablet_mode.attr) { if (!tp_features.hotkey_tablet) return 0; + } else if (attr == &dev_attr_keyboard_attached_on_screen.attr) { + if (!tp_features.has_keyboard_attached_on_screen) + return 0; } else if (attr == &dev_attr_hotkey_radio_sw.attr) { if (!tp_features.hotkey_wlsw) return 0; @@ -3462,6 +3525,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } tabletsw_state = hotkey_init_tablet_mode(); + keyboard_attached_on_screen_update(); /* Set up key map */ keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, @@ -3842,6 +3906,8 @@ static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev) case TP_HKEY_EV_TABLET_CHANGED: tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); + if (keyboard_attached_on_screen_update()) + keyboard_attached_on_screen_notify_change(); *send_acpi_ev = false; return true; @@ -3998,6 +4064,8 @@ static void hotkey_resume(void) tpacpi_send_radiosw_update(); tpacpi_input_send_tabletsw(); hotkey_tablet_mode_notify_change(); + keyboard_attached_on_screen_update(); + keyboard_attached_on_screen_notify_change(); hotkey_wakeup_reason_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change(); hotkey_poll_setup_safe(false); @@ -4296,6 +4364,17 @@ static const struct dmi_system_id fwbug_list[] __initconst = { {} }; +static const struct dmi_system_id keyboard_attached_on_screen_list[] __initconst = { + { + .ident = "ThinkPad X1 Fold 16 Gen 1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"), + }, + }, + {} +}; + static const struct pci_device_id fwbug_cards_ids[] __initconst = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) }, @@ -12230,6 +12309,8 @@ static int __init thinkpad_acpi_module_init(void) dmi_id = dmi_first_match(fwbug_list); if (dmi_id) tp_features.quirks = dmi_id->driver_data; + tp_features.has_keyboard_attached_on_screen = + dmi_check_system(keyboard_attached_on_screen_list); /* Device initialization */ tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE, -- 2.43.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection 2026-04-19 10:27 [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection Pit Henrich @ 2026-06-08 9:09 ` Hans de Goede 2026-06-08 16:00 ` Hans de Goede 2026-06-09 1:19 ` Mark Pearson 1 sibling, 1 reply; 5+ messages in thread From: Hans de Goede @ 2026-06-08 9:09 UTC (permalink / raw) To: Pit Henrich, hmh, Dave Carey, Armin Wolf Cc: mpearson-lenovo, derekjohn.clark, ilpo.jarvinen, ibm-acpi-devel, platform-driver-x86, linux-kernel, pithenrich2d Hi, On 19-Apr-26 12:27 PM, Pit Henrich wrote: > ThinkPad X1 Fold 16 Gen 1 firmware reports whether the keyboard is magnetically > attached (on the screen), but thinkpad-acpi does not expose this to userspace. > The state can be obtained via ACPI methods: GDST (get device state). > > Add a read-only keyboard_attached_on_screen sysfs attribute, gated by > a DMI match. The state is read directly from the EC. > > Cache the state and emit a sysfs notification on > TP_HKEY_EV_TABLET_CHANGED (0x60c0) when it changes. Initialize the cache during > hotkey setup and refresh it before the resume notification to keep the state > consistent across suspend and resume. > > Signed-off-by: Pit Henrich <pithenrich2d@gmail.com> > --- > This replaced the v1 patch in: > https://lore.kernel.org/all/20260314142236.74514-1-pithenrich2d@gmail.com/ > > Changes v1 -> v2: > * Use ACPI method instead of using the EC directly (thanks Mark). Thank you for your patch. It seems that this information is also exposed via WMI and a WMI driver exposing the same information is also being worked on: https://patchwork.kernel.org/project/platform-driver-x86/patch/20260527122701.242907-1-carvsdriver@gmail.com/ +Cc Dave Carey (author of that driver) and Armin (WMI maintainer) Since doing this in thinkpad_acpi requires adding a DMI match and directly calling an APCI method which name may change I believe that the WMI approach may be better. There we can rely on only the Fold exposing the WMI GUID for this functionality. Dave, I see that your "[PATCH v5] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver" patch also uses a DMI match, is that necessary ? If we need the DMI match because the GUID is not unique enough, then we might just as well add this functionality here as this patch is doing ... I do wonder since this seems to emit TP_HKEY_EV_TABLET_CHANGED thinkpad_acpi events if the existing thinkpad_acpi support does not already provide working SW_TABLET_MODE input ? If it does then also having the WMI driver emit SW_TABLET_MODE events seems to be undesirable duplicate functionality. Regards, Hans > > --- > drivers/platform/x86/lenovo/thinkpad_acpi.c | 85 ++++++++++++++++++++- > 1 file changed, 83 insertions(+), 2 deletions(-) > > diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c > index 8982d92dfd97..b57ae7eb5548 100644 > --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c > +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c > @@ -218,8 +218,9 @@ enum tpacpi_hkey_event_t { > TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ > TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ > TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ > - TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016): > - * enter/leave tablet mode > + TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* posture change event: > + * X1 Yoga (2016): enter/leave tablet mode > + * X1 Fold 16 Gen 1: keyboard attachment state changed > */ > TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ > TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ > @@ -375,6 +376,7 @@ static struct { > u32 has_adaptive_kbd:1; > u32 kbd_lang:1; > u32 trackpoint_doubletap:1; > + u32 has_keyboard_attached_on_screen:1; > struct quirk_entry *quirks; > } tp_features; > > @@ -2928,6 +2930,63 @@ static void hotkey_tablet_mode_notify_change(void) > "hotkey_tablet_mode"); > } > > +static bool keyboard_attached_on_screen; > +static bool keyboard_attached_on_screen_initialized; > + > +static int x1_fold_keyboard_attached_on_screen_get(bool *attached) > +{ > + int state; > + > + if (!tp_features.has_keyboard_attached_on_screen) > + return -ENODEV; > + > + if (!acpi_evalf(NULL, &state, "\\_SB.DEVD.GDST", "d")) > + return -EIO; > + > + *attached = state != 0; > + return 0; > +} > + > +static ssize_t keyboard_attached_on_screen_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + bool attached; > + int res; > + > + res = x1_fold_keyboard_attached_on_screen_get(&attached); > + if (res) > + return res; > + > + return sysfs_emit(buf, "%d\n", attached); > +} > + > +static DEVICE_ATTR_RO(keyboard_attached_on_screen); > + > +static void keyboard_attached_on_screen_notify_change(void) > +{ > + if (tp_features.has_keyboard_attached_on_screen) > + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, > + "keyboard_attached_on_screen"); > +} > + > +static bool keyboard_attached_on_screen_update(void) > +{ > + bool attached; > + > + if (x1_fold_keyboard_attached_on_screen_get(&attached)) > + return false; > + > + if (keyboard_attached_on_screen_initialized && > + keyboard_attached_on_screen == attached) > + return false; > + > + keyboard_attached_on_screen = attached; > + keyboard_attached_on_screen_initialized = true; > + > + return true; > +} > + > /* sysfs wakeup reason (pollable) -------------------------------------- */ > static ssize_t hotkey_wakeup_reason_show(struct device *dev, > struct device_attribute *attr, > @@ -3032,6 +3091,7 @@ static struct attribute *hotkey_attributes[] = { > &dev_attr_hotkey_adaptive_all_mask.attr, > &dev_attr_hotkey_recommended_mask.attr, > &dev_attr_hotkey_tablet_mode.attr, > + &dev_attr_keyboard_attached_on_screen.attr, > &dev_attr_hotkey_radio_sw.attr, > #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL > &dev_attr_hotkey_source_mask.attr, > @@ -3046,6 +3106,9 @@ static umode_t hotkey_attr_is_visible(struct kobject *kobj, > if (attr == &dev_attr_hotkey_tablet_mode.attr) { > if (!tp_features.hotkey_tablet) > return 0; > + } else if (attr == &dev_attr_keyboard_attached_on_screen.attr) { > + if (!tp_features.has_keyboard_attached_on_screen) > + return 0; > } else if (attr == &dev_attr_hotkey_radio_sw.attr) { > if (!tp_features.hotkey_wlsw) > return 0; > @@ -3462,6 +3525,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) > } > > tabletsw_state = hotkey_init_tablet_mode(); > + keyboard_attached_on_screen_update(); > > /* Set up key map */ > keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, > @@ -3842,6 +3906,8 @@ static bool hotkey_notify_6xxx(const u32 hkey, bool *send_acpi_ev) > case TP_HKEY_EV_TABLET_CHANGED: > tpacpi_input_send_tabletsw(); > hotkey_tablet_mode_notify_change(); > + if (keyboard_attached_on_screen_update()) > + keyboard_attached_on_screen_notify_change(); > *send_acpi_ev = false; > return true; > > @@ -3998,6 +4064,8 @@ static void hotkey_resume(void) > tpacpi_send_radiosw_update(); > tpacpi_input_send_tabletsw(); > hotkey_tablet_mode_notify_change(); > + keyboard_attached_on_screen_update(); > + keyboard_attached_on_screen_notify_change(); > hotkey_wakeup_reason_notify_change(); > hotkey_wakeup_hotunplug_complete_notify_change(); > hotkey_poll_setup_safe(false); > @@ -4296,6 +4364,17 @@ static const struct dmi_system_id fwbug_list[] __initconst = { > {} > }; > > +static const struct dmi_system_id keyboard_attached_on_screen_list[] __initconst = { > + { > + .ident = "ThinkPad X1 Fold 16 Gen 1", > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), > + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"), > + }, > + }, > + {} > +}; > + > static const struct pci_device_id fwbug_cards_ids[] __initconst = { > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) }, > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) }, > @@ -12230,6 +12309,8 @@ static int __init thinkpad_acpi_module_init(void) > dmi_id = dmi_first_match(fwbug_list); > if (dmi_id) > tp_features.quirks = dmi_id->driver_data; > + tp_features.has_keyboard_attached_on_screen = > + dmi_check_system(keyboard_attached_on_screen_list); > > /* Device initialization */ > tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE, ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection 2026-06-08 9:09 ` Hans de Goede @ 2026-06-08 16:00 ` Hans de Goede 0 siblings, 0 replies; 5+ messages in thread From: Hans de Goede @ 2026-06-08 16:00 UTC (permalink / raw) To: Pit Henrich, hmh, Dave Carey, Armin Wolf Cc: mpearson-lenovo, derekjohn.clark, ilpo.jarvinen, ibm-acpi-devel, platform-driver-x86, linux-kernel, pithenrich2d Hi, On 8-Jun-26 11:09, Hans de Goede wrote: > Hi, > > On 19-Apr-26 12:27 PM, Pit Henrich wrote: >> ThinkPad X1 Fold 16 Gen 1 firmware reports whether the keyboard is magnetically >> attached (on the screen), but thinkpad-acpi does not expose this to userspace. >> The state can be obtained via ACPI methods: GDST (get device state). >> >> Add a read-only keyboard_attached_on_screen sysfs attribute, gated by >> a DMI match. The state is read directly from the EC. >> >> Cache the state and emit a sysfs notification on >> TP_HKEY_EV_TABLET_CHANGED (0x60c0) when it changes. Initialize the cache during >> hotkey setup and refresh it before the resume notification to keep the state >> consistent across suspend and resume. >> >> Signed-off-by: Pit Henrich <pithenrich2d@gmail.com> >> --- >> This replaced the v1 patch in: >> https://lore.kernel.org/all/20260314142236.74514-1-pithenrich2d@gmail.com/ >> >> Changes v1 -> v2: >> * Use ACPI method instead of using the EC directly (thanks Mark). > > Thank you for your patch. It seems that this information is also exposed > via WMI and a WMI driver exposing the same information is also being > worked on: > > https://patchwork.kernel.org/project/platform-driver-x86/patch/20260527122701.242907-1-carvsdriver@gmail.com/ > > +Cc Dave Carey (author of that driver) and Armin (WMI maintainer) Ok, I should have looked closer, this patch is for a "ThinkPad X1 Fold 16 Gen 1" and the driver I linked above is for a "Yoga Book 9" so I was mistaken that these drivers are duplicate, we will need both. Sorry, my bad. Note not a full review, but before we can move forward with this driver, you are going to need to document the new sysfs attribute under: Documentation/admin-guide/laptops/thinkpad-acpi.rst Please add a new "X1 Fold keyboard attachmen" section directly after the "Hardware damage detection capability" section (or iow just above the "Multiple Commands, Module Parameters" section). Regards, Hans ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection 2026-04-19 10:27 [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection Pit Henrich 2026-06-08 9:09 ` Hans de Goede @ 2026-06-09 1:19 ` Mark Pearson 2026-06-09 8:49 ` Hans de Goede 1 sibling, 1 reply; 5+ messages in thread From: Mark Pearson @ 2026-06-09 1:19 UTC (permalink / raw) To: Pit Henrich, Henrique de Moraes Holschuh Cc: Derek J . Clark, Hans de Goede, Ilpo Järvinen, ibm-acpi-devel, platform-driver-x86, linux-kernel, pithenrich2d Hi Pit, On Sun, Apr 19, 2026, at 6:27 AM, Pit Henrich wrote: > ThinkPad X1 Fold 16 Gen 1 firmware reports whether the keyboard is magnetically > attached (on the screen), but thinkpad-acpi does not expose this to userspace. > The state can be obtained via ACPI methods: GDST (get device state). > > Add a read-only keyboard_attached_on_screen sysfs attribute, gated by > a DMI match. The state is read directly from the EC. > > Cache the state and emit a sysfs notification on > TP_HKEY_EV_TABLET_CHANGED (0x60c0) when it changes. Initialize the cache during > hotkey setup and refresh it before the resume notification to keep the state > consistent across suspend and resume. > > Signed-off-by: Pit Henrich <pithenrich2d@gmail.com> > --- > This replaced the v1 patch in: > https://lore.kernel.org/all/20260314142236.74514-1-pithenrich2d@gmail.com/ > > Changes v1 -> v2: > * Use ACPI method instead of using the EC directly (thanks Mark). > > --- > drivers/platform/x86/lenovo/thinkpad_acpi.c | 85 ++++++++++++++++++++- > 1 file changed, 83 insertions(+), 2 deletions(-) > > diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c > b/drivers/platform/x86/lenovo/thinkpad_acpi.c > index 8982d92dfd97..b57ae7eb5548 100644 > --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c > +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c > @@ -218,8 +218,9 @@ enum tpacpi_hkey_event_t { > TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ > TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ > TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ > - TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016): > - * enter/leave tablet mode > + TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* posture change event: > + * X1 Yoga (2016): enter/leave tablet mode > + * X1 Fold 16 Gen 1: keyboard attachment state changed > */ > TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ > TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ > @@ -375,6 +376,7 @@ static struct { > u32 has_adaptive_kbd:1; > u32 kbd_lang:1; > u32 trackpoint_doubletap:1; > + u32 has_keyboard_attached_on_screen:1; > struct quirk_entry *quirks; > } tp_features; > > @@ -2928,6 +2930,63 @@ static void hotkey_tablet_mode_notify_change(void) > "hotkey_tablet_mode"); > } > > +static bool keyboard_attached_on_screen; > +static bool keyboard_attached_on_screen_initialized; > + > +static int x1_fold_keyboard_attached_on_screen_get(bool *attached) > +{ > + int state; > + > + if (!tp_features.has_keyboard_attached_on_screen) > + return -ENODEV; > + > + if (!acpi_evalf(NULL, &state, "\\_SB.DEVD.GDST", "d")) > + return -EIO; I wondered if this should be adding a devd_handle in the same way as hkey_handle etc? (up at the top of the file using define TPACPI_HANDLE Then you would have if (!acpi_evalf(devd_handle, &state, "GDST", "d")) Not sure if this is needed or not - hopefully one of the experts on the mailing list knows. > + > + *attached = state != 0; > + return 0; > +} > + > +static ssize_t keyboard_attached_on_screen_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + bool attached; > + int res; > + > + res = x1_fold_keyboard_attached_on_screen_get(&attached); > + if (res) > + return res; > + > + return sysfs_emit(buf, "%d\n", attached); > +} > + > +static DEVICE_ATTR_RO(keyboard_attached_on_screen); > + > +static void keyboard_attached_on_screen_notify_change(void) > +{ > + if (tp_features.has_keyboard_attached_on_screen) > + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, > + "keyboard_attached_on_screen"); > +} > + > +static bool keyboard_attached_on_screen_update(void) > +{ > + bool attached; > + > + if (x1_fold_keyboard_attached_on_screen_get(&attached)) > + return false; > + > + if (keyboard_attached_on_screen_initialized && > + keyboard_attached_on_screen == attached) > + return false; > + > + keyboard_attached_on_screen = attached; > + keyboard_attached_on_screen_initialized = true; > + > + return true; > +} > + > /* sysfs wakeup reason (pollable) > -------------------------------------- */ > static ssize_t hotkey_wakeup_reason_show(struct device *dev, > struct device_attribute *attr, > @@ -3032,6 +3091,7 @@ static struct attribute *hotkey_attributes[] = { > &dev_attr_hotkey_adaptive_all_mask.attr, > &dev_attr_hotkey_recommended_mask.attr, > &dev_attr_hotkey_tablet_mode.attr, > + &dev_attr_keyboard_attached_on_screen.attr, > &dev_attr_hotkey_radio_sw.attr, > #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL > &dev_attr_hotkey_source_mask.attr, > @@ -3046,6 +3106,9 @@ static umode_t hotkey_attr_is_visible(struct > kobject *kobj, > if (attr == &dev_attr_hotkey_tablet_mode.attr) { > if (!tp_features.hotkey_tablet) > return 0; > + } else if (attr == &dev_attr_keyboard_attached_on_screen.attr) { > + if (!tp_features.has_keyboard_attached_on_screen) > + return 0; > } else if (attr == &dev_attr_hotkey_radio_sw.attr) { > if (!tp_features.hotkey_wlsw) > return 0; > @@ -3462,6 +3525,7 @@ static int __init hotkey_init(struct > ibm_init_struct *iibm) > } > > tabletsw_state = hotkey_init_tablet_mode(); > + keyboard_attached_on_screen_update(); > > /* Set up key map */ > keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, > @@ -3842,6 +3906,8 @@ static bool hotkey_notify_6xxx(const u32 hkey, > bool *send_acpi_ev) > case TP_HKEY_EV_TABLET_CHANGED: > tpacpi_input_send_tabletsw(); > hotkey_tablet_mode_notify_change(); > + if (keyboard_attached_on_screen_update()) > + keyboard_attached_on_screen_notify_change(); > *send_acpi_ev = false; > return true; > > @@ -3998,6 +4064,8 @@ static void hotkey_resume(void) > tpacpi_send_radiosw_update(); > tpacpi_input_send_tabletsw(); > hotkey_tablet_mode_notify_change(); > + keyboard_attached_on_screen_update(); > + keyboard_attached_on_screen_notify_change(); > hotkey_wakeup_reason_notify_change(); > hotkey_wakeup_hotunplug_complete_notify_change(); > hotkey_poll_setup_safe(false); > @@ -4296,6 +4364,17 @@ static const struct dmi_system_id fwbug_list[] > __initconst = { > {} > }; > > +static const struct dmi_system_id keyboard_attached_on_screen_list[] > __initconst = { > + { > + .ident = "ThinkPad X1 Fold 16 Gen 1", > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), > + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"), > + }, Should there also be a matches for the X1 Fold Gen 1 (13" model)? I think doing the DMI match on the product family is OK, but just a note that everywhere else uses the board ID. e.g: DMI_MATCH(DMI_BOARD_NAME, "21ES") I think this way works too, but it's different and I haven't had confirmation from the FW team if it could be different across different SKUs (I'll see if I can find out). If you do want to use board names: - X1 Fold 16 G1 has "21ES' and "21ET" - X1 Fold G1 has "20RK" and "20RL" > + }, > + {} > +}; > + > static const struct pci_device_id fwbug_cards_ids[] __initconst = { > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) }, > { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) }, > @@ -12230,6 +12309,8 @@ static int __init > thinkpad_acpi_module_init(void) > dmi_id = dmi_first_match(fwbug_list); > if (dmi_id) > tp_features.quirks = dmi_id->driver_data; > + tp_features.has_keyboard_attached_on_screen = > + dmi_check_system(keyboard_attached_on_screen_list); > > /* Device initialization */ > tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, > PLATFORM_DEVID_NONE, > -- > 2.43.0 Thanks Mark ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection 2026-06-09 1:19 ` Mark Pearson @ 2026-06-09 8:49 ` Hans de Goede 0 siblings, 0 replies; 5+ messages in thread From: Hans de Goede @ 2026-06-09 8:49 UTC (permalink / raw) To: Mark Pearson, Pit Henrich, Henrique de Moraes Holschuh Cc: Derek J . Clark, Ilpo Järvinen, ibm-acpi-devel, platform-driver-x86, linux-kernel, pithenrich2d Hi, On 9-Jun-26 03:19, Mark Pearson wrote: > Hi Pit, > > On Sun, Apr 19, 2026, at 6:27 AM, Pit Henrich wrote: >> ThinkPad X1 Fold 16 Gen 1 firmware reports whether the keyboard is magnetically >> attached (on the screen), but thinkpad-acpi does not expose this to userspace. >> The state can be obtained via ACPI methods: GDST (get device state). >> >> Add a read-only keyboard_attached_on_screen sysfs attribute, gated by >> a DMI match. The state is read directly from the EC. >> >> Cache the state and emit a sysfs notification on >> TP_HKEY_EV_TABLET_CHANGED (0x60c0) when it changes. Initialize the cache during >> hotkey setup and refresh it before the resume notification to keep the state >> consistent across suspend and resume. >> >> Signed-off-by: Pit Henrich <pithenrich2d@gmail.com> >> --- >> This replaced the v1 patch in: >> https://lore.kernel.org/all/20260314142236.74514-1-pithenrich2d@gmail.com/ >> >> Changes v1 -> v2: >> * Use ACPI method instead of using the EC directly (thanks Mark). >> >> --- >> drivers/platform/x86/lenovo/thinkpad_acpi.c | 85 ++++++++++++++++++++- >> 1 file changed, 83 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c >> b/drivers/platform/x86/lenovo/thinkpad_acpi.c >> index 8982d92dfd97..b57ae7eb5548 100644 >> --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c >> +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c >> @@ -218,8 +218,9 @@ enum tpacpi_hkey_event_t { >> TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ >> TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ >> TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ >> - TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016): >> - * enter/leave tablet mode >> + TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* posture change event: >> + * X1 Yoga (2016): enter/leave tablet mode >> + * X1 Fold 16 Gen 1: keyboard attachment state changed >> */ >> TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ >> TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ >> @@ -375,6 +376,7 @@ static struct { >> u32 has_adaptive_kbd:1; >> u32 kbd_lang:1; >> u32 trackpoint_doubletap:1; >> + u32 has_keyboard_attached_on_screen:1; >> struct quirk_entry *quirks; >> } tp_features; >> >> @@ -2928,6 +2930,63 @@ static void hotkey_tablet_mode_notify_change(void) >> "hotkey_tablet_mode"); >> } >> >> +static bool keyboard_attached_on_screen; >> +static bool keyboard_attached_on_screen_initialized; >> + >> +static int x1_fold_keyboard_attached_on_screen_get(bool *attached) >> +{ >> + int state; >> + >> + if (!tp_features.has_keyboard_attached_on_screen) >> + return -ENODEV; >> + >> + if (!acpi_evalf(NULL, &state, "\\_SB.DEVD.GDST", "d")) >> + return -EIO; > > I wondered if this should be adding a devd_handle in the same way as hkey_handle etc? (up at the top of the file using define TPACPI_HANDLE > > Then you would have > if (!acpi_evalf(devd_handle, &state, "GDST", "d")) > > Not sure if this is needed or not - hopefully one of the experts on the mailing list knows. I don't think using a cached ACPI handle for the parent node of the method is necessary in this case. Using the cached handles is mostly an optimization for handles which are used a lot. Regards, Hans > >> + >> + *attached = state != 0; >> + return 0; >> +} >> + >> +static ssize_t keyboard_attached_on_screen_show(struct device *dev, >> + struct device_attribute *attr, >> + char *buf) >> +{ >> + bool attached; >> + int res; >> + >> + res = x1_fold_keyboard_attached_on_screen_get(&attached); >> + if (res) >> + return res; >> + >> + return sysfs_emit(buf, "%d\n", attached); >> +} >> + >> +static DEVICE_ATTR_RO(keyboard_attached_on_screen); >> + >> +static void keyboard_attached_on_screen_notify_change(void) >> +{ >> + if (tp_features.has_keyboard_attached_on_screen) >> + sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, >> + "keyboard_attached_on_screen"); >> +} >> + >> +static bool keyboard_attached_on_screen_update(void) >> +{ >> + bool attached; >> + >> + if (x1_fold_keyboard_attached_on_screen_get(&attached)) >> + return false; >> + >> + if (keyboard_attached_on_screen_initialized && >> + keyboard_attached_on_screen == attached) >> + return false; >> + >> + keyboard_attached_on_screen = attached; >> + keyboard_attached_on_screen_initialized = true; >> + >> + return true; >> +} >> + >> /* sysfs wakeup reason (pollable) >> -------------------------------------- */ >> static ssize_t hotkey_wakeup_reason_show(struct device *dev, >> struct device_attribute *attr, >> @@ -3032,6 +3091,7 @@ static struct attribute *hotkey_attributes[] = { >> &dev_attr_hotkey_adaptive_all_mask.attr, >> &dev_attr_hotkey_recommended_mask.attr, >> &dev_attr_hotkey_tablet_mode.attr, >> + &dev_attr_keyboard_attached_on_screen.attr, >> &dev_attr_hotkey_radio_sw.attr, >> #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL >> &dev_attr_hotkey_source_mask.attr, >> @@ -3046,6 +3106,9 @@ static umode_t hotkey_attr_is_visible(struct >> kobject *kobj, >> if (attr == &dev_attr_hotkey_tablet_mode.attr) { >> if (!tp_features.hotkey_tablet) >> return 0; >> + } else if (attr == &dev_attr_keyboard_attached_on_screen.attr) { >> + if (!tp_features.has_keyboard_attached_on_screen) >> + return 0; >> } else if (attr == &dev_attr_hotkey_radio_sw.attr) { >> if (!tp_features.hotkey_wlsw) >> return 0; >> @@ -3462,6 +3525,7 @@ static int __init hotkey_init(struct >> ibm_init_struct *iibm) >> } >> >> tabletsw_state = hotkey_init_tablet_mode(); >> + keyboard_attached_on_screen_update(); >> >> /* Set up key map */ >> keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, >> @@ -3842,6 +3906,8 @@ static bool hotkey_notify_6xxx(const u32 hkey, >> bool *send_acpi_ev) >> case TP_HKEY_EV_TABLET_CHANGED: >> tpacpi_input_send_tabletsw(); >> hotkey_tablet_mode_notify_change(); >> + if (keyboard_attached_on_screen_update()) >> + keyboard_attached_on_screen_notify_change(); >> *send_acpi_ev = false; >> return true; >> >> @@ -3998,6 +4064,8 @@ static void hotkey_resume(void) >> tpacpi_send_radiosw_update(); >> tpacpi_input_send_tabletsw(); >> hotkey_tablet_mode_notify_change(); >> + keyboard_attached_on_screen_update(); >> + keyboard_attached_on_screen_notify_change(); >> hotkey_wakeup_reason_notify_change(); >> hotkey_wakeup_hotunplug_complete_notify_change(); >> hotkey_poll_setup_safe(false); >> @@ -4296,6 +4364,17 @@ static const struct dmi_system_id fwbug_list[] >> __initconst = { >> {} >> }; >> >> +static const struct dmi_system_id keyboard_attached_on_screen_list[] >> __initconst = { >> + { >> + .ident = "ThinkPad X1 Fold 16 Gen 1", >> + .matches = { >> + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), >> + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"), >> + }, > > Should there also be a matches for the X1 Fold Gen 1 (13" model)? > > I think doing the DMI match on the product family is OK, but just a note that everywhere else uses the board ID. e.g: DMI_MATCH(DMI_BOARD_NAME, "21ES") > I think this way works too, but it's different and I haven't had confirmation from the FW team if it could be different across different SKUs (I'll see if I can find out). > > If you do want to use board names: > - X1 Fold 16 G1 has "21ES' and "21ET" > - X1 Fold G1 has "20RK" and "20RL" > >> + }, >> + {} >> +}; >> + >> static const struct pci_device_id fwbug_cards_ids[] __initconst = { >> { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24F3) }, >> { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x24FD) }, >> @@ -12230,6 +12309,8 @@ static int __init >> thinkpad_acpi_module_init(void) >> dmi_id = dmi_first_match(fwbug_list); >> if (dmi_id) >> tp_features.quirks = dmi_id->driver_data; >> + tp_features.has_keyboard_attached_on_screen = >> + dmi_check_system(keyboard_attached_on_screen_list); >> >> /* Device initialization */ >> tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, >> PLATFORM_DEVID_NONE, >> -- >> 2.43.0 > > Thanks > Mark ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-09 8:49 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-04-19 10:27 [PATCH v2] platform/x86: thinkpad-acpi: Add X1 Fold keyboard attachment detection Pit Henrich 2026-06-08 9:09 ` Hans de Goede 2026-06-08 16:00 ` Hans de Goede 2026-06-09 1:19 ` Mark Pearson 2026-06-09 8:49 ` Hans de Goede
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
Powered by JetHome