Re: [PATCH v13 2/2] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver
Dave Carey <[email protected]>
| Newsgroups | org.kernel.vger.platform-driver-x86,org.kernel.vger.linux-input,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Ugh ... let me check, was trying to do a few different things today at
the same time. Appreciate the patience.
-DC
On 7/22/26 10:42 AM, Ilpo Järvinen wrote:
> On Wed, 22 Jul 2026, Dave Carey wrote:
>
>> The Lenovo Yoga Book 9 14IAH10 ships with a detachable Bluetooth keyboard
>> that magnetically attaches to the bottom (secondary) screen in one of two
>> positions. The Embedded Controller tracks the attachment state in a 2-bit
>> field called BKBD and signals changes via WMI event GUID
>> 806BD2A2-177B-481D-BFB5-3BA0BB4A2285 (notify ID 0xEB on the WM10 ACPI
>> device, _UID "GMZN").
>>
>> The device contains embedded BMOF data (WQDD, 20705 bytes) documenting
>> both WMI interfaces used by this driver:
>>
>> LENOVO_BTKBD_EVENT (event GUID): WmiDataId(1) uint32 Status.
>> The ACPI _WED(0xEB) method returns EC.BKBD directly as an integer,
>> so the notify callback receives BKBD without a separate query.
>>
>> LENOVO_FEATURE_STATUS_DATA (block GUID, WQAF method): returns an
>> 8-byte buffer {uint32 IDs=0x00060000, uint32 Status=BKBD}.
>> Used for the initial state read on probe and after resume.
>>
>> BKBD encoding:
>> 0 = keyboard detached
>> 1 = keyboard docked on top half of bottom screen
>> 2 = keyboard docked on bottom half of bottom screen
>> 3 = reserved (not observed in practice)
>>
>> This driver registers two WMI drivers sharing a module-level
>> BLOCKING_NOTIFIER_HEAD:
>>
>> - The event driver (LENOVO_BTKBD_EVENT) uses .notify_new() to receive
>> a pre-parsed wmi_buffer and fires the notifier chain with the BKBD
>> value extracted from the buffer.
>>
>> - The block driver (LENOVO_FEATURE_STATUS_DATA) owns the input_dev in
>> its per-device private struct. At probe time it registers a
>> notifier_block on the chain and reads the initial BKBD state via
>> wmidev_query_block(). The WMI buffer is parsed as
>> struct lenovo_feature_status { __le32 id; __le32 status; }, and the
>> ID field is verified before the status is used.
>>
>> - SW_TABLET_MODE=1 is reported when the keyboard is detached;
>> SW_TABLET_MODE=0 when docked in either position (keyboard present).
>>
>> - The raw BKBD value is exposed via read-only sysfs attribute
>> "keyboard_position".
>>
>> - BKBD state is re-read via wmidev_query_block() on resume from
>> suspend or hibernation.
>>
>> Tested on: Lenovo Yoga Book 9 14IAH10 (model 83KJ), kernel 7.0.
>>
>> Acked-by: Hans de Goede <[email protected]>
>> Reviewed-by: Armin Wolf <[email protected]>
>> Signed-off-by: Dave Carey <[email protected]>
>> ---
>> v13:
>> - Resend of v12: patch was corrupted in transit. git-send-email chose
>> quoted-printable encoding (triggered by non-ASCII in the changelog)
>> which encoded '=' as '=3D', corrupting the RST table separators in
>> the ABI doc and breaking git-am. No content changes from v12.
>>
>> v12:
>> - Add #include <linux/sysfs.h> (for sysfs_emit; Ilpo Järvinen)
>> - Add #include <linux/types.h> (for __le32 and __packed; Ilpo Järvinen)
>>
>> v11 (addressing Armin Wolf's v10 review):
>> - ABI doc: correct Date to "June 2027" and KernelVersion to "7.3"
>>
>> v10 (addressing Armin Wolf's v9 review):
>> - Update ABI doc: Date: June 2026, KernelVersion: 6.16
>> - Add #include <linux/compiler_attributes.h> and <linux/types.h>
>> - yb9_kbdock_query(): change return to pointer-out u32 *bkbd
>> - struct yb9_kbdock_data: add spinlock_t lock
>> - yb9_kbdock_report(): hold lock across input_report_switch + input_sync
>> - yb9_kbdock_sync(): return int, propagate query error to callers
>> - yb9_kbdock_resume(), yb9_kbdock_block_probe(): propagate sync error
>> - struct wmi_buffer out: remove zero-initializer
>> - yb9_kbdock_notify_new(): drop manual length check; use
>> .min_event_size = sizeof(__le32) in struct wmi_driver instead
>>
>> .../testing/sysfs-driver-lenovo-yb9-kbdock | 19 ++
>> MAINTAINERS | 7 +
>> drivers/platform/x86/lenovo/Kconfig | 14 +
>> drivers/platform/x86/lenovo/Makefile | 1 +
>> drivers/platform/x86/lenovo/yb9-kbdock.c | 312 ++++++++++++++++++
>> 5 files changed, 353 insertions(+)
>> create mode 100644 Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock
>> create mode 100644 drivers/platform/x86/lenovo/yb9-kbdock.c
>>
>> diff --git a/Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock b/Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock
>> new file mode 100644
>> index 0000000..ebe713a
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock
>> @@ -0,0 +1,19 @@
>> +What: /sys/bus/wmi/drivers/lenovo-yb9-kbdock/<guid>/keyboard_position
>> +Date: June 2027
>> +KernelVersion: 7.3
>> +Contact: Dave Carey <[email protected]>
>> +Description:
>> + Read-only attribute reporting the current keyboard dock position
>> + as reported by the Embedded Controller on the Lenovo Yoga Book 9
>> + 14IAH10.
>> +
>> + Possible values:
>> +
>> + == =============================================================
>> + 0 keyboard is not docked to any screen (detached)
>> + 1 keyboard docked on the top half of the bottom screen
>> + 2 keyboard docked on the bottom half of the bottom screen
>> + == =============================================================
>> +
>> + SW_TABLET_MODE input events are also emitted: 0 when the keyboard
>> + is docked (either position), 1 when detached.
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index d1cc0e1..00e8275 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -14479,6 +14479,13 @@ L: [email protected]
>> S: Maintained
>> F: drivers/platform/x86/lenovo/wmi-hotkey-utilities.c
>>
>> +LENOVO YOGA BOOK 9 KEYBOARD DOCK DRIVER
>> +M: Dave Carey <[email protected]>
>> +L: [email protected]
>> +S: Maintained
>> +F: Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock
>> +F: drivers/platform/x86/lenovo/yb9-kbdock.c
>> +
>> LETSKETCH HID TABLET DRIVER
>> M: Hans de Goede <[email protected]>
>> L: [email protected]
>> diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/lenovo/Kconfig
>> index 9c48487..938b361 100644
>> --- a/drivers/platform/x86/lenovo/Kconfig
>> +++ b/drivers/platform/x86/lenovo/Kconfig
>> @@ -43,6 +43,20 @@ config LENOVO_WMI_CAMERA
>> To compile this driver as a module, choose M here: the module
>> will be called lenovo-wmi-camera.
>>
>> +config LENOVO_YB9_KBDOCK
>> + tristate "Lenovo Yoga Book 9 keyboard dock detection"
>> + depends on ACPI_WMI
>> + depends on DMI
>> + depends on INPUT
>> + help
>> + Say Y here to enable keyboard dock detection on the Lenovo Yoga Book 9
>> + 14IAH10. The detachable Bluetooth keyboard magnetically attaches to
>> + either screen; this driver reports SW_TABLET_MODE input events based
>> + on the attachment state and exposes the raw position in sysfs.
>> +
>> + To compile this driver as a module, choose M here: the module will be
>> + called lenovo-yb9-kbdock.
>> +
>> config LENOVO_YMC
>> tristate "Lenovo Yoga Tablet Mode Control"
>> depends on ACPI_WMI
>> diff --git a/drivers/platform/x86/lenovo/Makefile b/drivers/platform/x86/lenovo/Makefile
>> index 7b2128e..2842d7d 100644
>> --- a/drivers/platform/x86/lenovo/Makefile
>> +++ b/drivers/platform/x86/lenovo/Makefile
>> @@ -8,6 +8,7 @@ obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o
>> obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
>>
>> lenovo-target-$(CONFIG_LENOVO_WMI_HOTKEY_UTILITIES) += wmi-hotkey-utilities.o
>> +lenovo-target-$(CONFIG_LENOVO_YB9_KBDOCK) += yb9-kbdock.o
>> lenovo-target-$(CONFIG_LENOVO_YMC) += ymc.o
>> lenovo-target-$(CONFIG_YOGABOOK) += yogabook.o
>> lenovo-target-$(CONFIG_YT2_1380) += yoga-tab2-pro-1380-fastcharger.o
>> diff --git a/drivers/platform/x86/lenovo/yb9-kbdock.c b/drivers/platform/x86/lenovo/yb9-kbdock.c
>> new file mode 100644
>> index 0000000..69c68a0
>> --- /dev/null
>> +++ b/drivers/platform/x86/lenovo/yb9-kbdock.c
>> @@ -0,0 +1,312 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Lenovo Yoga Book 9 keyboard-dock detection
>> + *
>> + * The Yoga Book 9 ships with a detachable Bluetooth keyboard that magnetically
>> + * attaches to the bottom screen in one of two positions. The EC tracks
>> + * attachment state in a 2-bit field called BKBD and signals changes via WMI
>> + * event 0xEB on the WM10 ACPI device (_UID "GMZN").
>> + *
>> + * BKBD values:
>> + * 0 = keyboard detached
>> + * 1 = keyboard docked on the top half of the bottom screen
>> + * 2 = keyboard docked on the bottom half of the bottom screen
>> + * 3 = reserved / not observed
>> + *
>> + * Two WMI interfaces are used (documented in embedded BMOF, WQDD, 20705 bytes):
>> + *
>> + * LENOVO_BTKBD_EVENT (event GUID, 806BD2A2-...)
>> + * WmiDataId(1) uint32 Status — _WED(0xEB) returns EC.BKBD directly.
>> + * The notify callback receives BKBD as an integer; no separate query needed.
>> + *
>> + * LENOVO_FEATURE_STATUS_DATA (block GUID, E7F300FA-...)
>> + * WmiDataId(1) uint32 IDs = 0x00060000 (feature selector)
>> + * WmiDataId(2) uint32 Status = BKBD value
>> + * Used on probe and resume to read initial state.
>> + *
>> + * The event driver (LENOVO_BTKBD_EVENT) fires a notifier chain on each WMI
>> + * event. The block driver (LENOVO_FEATURE_STATUS_DATA) owns the input_dev
>> + * and registers a notifier_block to receive those events, eliminating the
>> + * need for shared global state or a mutex.
>> + *
>> + * SW_TABLET_MODE=1 is reported when the keyboard is detached;
>> + * SW_TABLET_MODE=0 when docked in either position (keyboard present).
>> + * The raw BKBD value is exposed via the sysfs attribute "keyboard_position".
>> + *
>> + * Copyright (C) 2026 Dave Carey <[email protected]>
>> + */
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/cleanup.h>
>> +#include <linux/dev_printk.h>
>> +#include <linux/dmi.h>
>> +#include <linux/input.h>
>> +#include <linux/module.h>
>> +#include <linux/notifier.h>
>> +#include <linux/pm.h>
>> +#include <linux/slab.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +#include <linux/wmi.h>
> Hi,
>
> Are you sure you sent the latest version, AFAICT, v12 had this:
>
> +#include <linux/acpi.h>
> +#include <linux/cleanup.h>
> +#include <linux/compiler_attributes.h>
> +#include <linux/dev_printk.h>
> ...
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +#include <linux/wmi.h>
>
> ?
>