From: Dave Carey <carvsdriver@gmail.com>
To: Armin Wolf <W_Armin@gmx.de>, platform-driver-x86@vger.kernel.org
Cc: ilpo.jarvinen@linux.intel.com
Subject: Re: [PATCH v4] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver
Date: Tue, 26 May 2026 09:38:45 -0400 [thread overview]
Message-ID: <cc1d6a5e-c2f1-43b0-bc7d-c1efb95efa0d@gmail.com> (raw)
In-Reply-To: <871f18d1-beb7-4d29-8e17-43b806ebcbda@gmx.de>
ack. will review your feedback. thank you.
On 5/22/26 5:59 PM, Armin Wolf wrote:
> Am 21.05.26 um 16:40 schrieb Dave Carey:
>
>> 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).
>>
>> The current BKBD state is read via WMI query GUID
>> E7F300FA-21CD-4003-ADAC-2696135982E6 (WQAF method), which returns an
>> 8-byte buffer: bytes [0..3] hold the LFID constant 0x00060000 and bytes
>> [4..7] hold the BKBD value.
>
> Hi,
>
> does the device contain embedded BMOF data? Take a look at
> Documentation/wmi/driver-development-guide.rst
> to find out how to decode said BMOF data.
>
>>
>> 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 as a WMI driver on the event GUID.
>> - Queries BKBD state on probe and on each WMI notification.
>> - Reports SW_TABLET_MODE=1 when detached, SW_TABLET_MODE=0 when
>> docked
>> in either position (a physical keyboard is present in both cases).
>> - Exposes the raw BKBD value via a read-only sysfs attribute
>> "keyboard_position" for use by userspace (e.g. to distinguish
>> between
>> the two docked positions for different UI layouts).
>>
>> Tested on: Lenovo Yoga Book 9 14IAH10 (model 83KJ), kernel 6.19.
>>
>> Signed-off-by: Dave Carey <carvsdriver@gmail.com>
>> ---
>> .../testing/sysfs-driver-lenovo-yb9-kbdock | 21 ++
>> MAINTAINERS | 7 +
>> drivers/platform/x86/lenovo/Kconfig | 14 ++
>> drivers/platform/x86/lenovo/Makefile | 1 +
>> drivers/platform/x86/lenovo/yb9-kbdock.c | 216 ++++++++++++++++++
>> 5 files changed, 259 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..bb57690
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-driver-lenovo-yb9-kbdock
>> @@ -0,0 +1,21 @@
>> +What: /sys/bus/wmi/drivers/lenovo-yb9-kbdock/<guid>/keyboard_position
>> +Date: April 2026
>> +KernelVersion: 6.10
>> +Contact: Dave Carey <carvsdriver@gmail.com>
>> +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 detached — keyboard is not docked to any screen
>> + 1 top-half — keyboard docked on the top half of the
>> bottom screen
>> + 2 bottom-half — keyboard docked on the bottom half of the
>> bottom screen
>> + == ============================================================
>> +
>> + The value is formatted as "<n> (<name>)\n", e.g. "1
>> (top-half)\n"
>
> IMHO a simple number would be much easier to parse.
>
>> +
>> + 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: platform-driver-x86@vger.kernel.org
>> S: Maintained
>> F: drivers/platform/x86/lenovo/wmi-hotkey-utilities.c
>> +LENOVO YOGA BOOK 9 KEYBOARD DOCK DRIVER
>> +M: Dave Carey <carvsdriver@gmail.com>
>> +L: platform-driver-x86@vger.kernel.org
>> +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 <hansg@kernel.org>
>> L: linux-input@vger.kernel.org
>> 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..693e287
>> --- /dev/null
>> +++ b/drivers/platform/x86/lenovo/yb9-kbdock.c
>> @@ -0,0 +1,216 @@
>> +// 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.
>> + *
>> + * 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
>> + *
>> + * This driver registers for the WMI event GUID, queries BKBD on
>> probe and on
>> + * each event, reports SW_TABLET_MODE=0 when the keyboard is docked
>> (either
>> + * position) and SW_TABLET_MODE=1 when detached, and exposes the raw
>> BKBD
>> + * value in sysfs as "keyboard_position".
>> + *
>> + * Copyright (C) 2026 Dave Carey <carvsdriver@gmail.com>
>> + */
>> +
>> +#include <linux/acpi.h>
>> +#include <linux/dmi.h>
>> +#include <linux/input.h>
>> +#include <linux/module.h>
>> +#include <linux/wmi.h>
>> +
>> +/*
>> + * WM10 ACPI device (_UID "GMZN"):
>> + * Event GUID — notify ID 0xEB fires on keyboard attachment change.
>> + * Query GUID — object "AF", maps to WQAF(); returns 8-byte buffer
>> + * {LFID=0x00060000, BKBD[31:0]}.
>> + */
>> +#define YB9_KBDOCK_EVENT_GUID "806BD2A2-177B-481D-BFB5-3BA0BB4A2285"
>> +#define YB9_KBDOCK_QUERY_GUID "E7F300FA-21CD-4003-ADAC-2696135982E6"
>> +
>> +#define YB9_KBDOCK_QUERY_INSTANCE 0
>> +
>> +/* BKBD encoding — keyboard always docks on the bottom screen */
>> +#define BKBD_DETACHED 0
>> +#define BKBD_TOP_HALF 1 /* docked on top half of bottom
>> screen */
>> +#define BKBD_BOTTOM_HALF 2 /* docked on bottom half of bottom
>> screen */
>> +
>> +static const struct dmi_system_id yb9_kbdock_dmi_table[] = {
>> + {
>> + /* Lenovo Yoga Book 9 14IAH10 */
>> + .matches = {
>> + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
>> + DMI_MATCH(DMI_PRODUCT_NAME, "83KJ"),
>> + },
>> + },
>> + { }
>> +};
>> +
>> +struct yb9_kbdock_priv {
>> + struct input_dev *input_dev;
>> + unsigned int bkbd; /* last read BKBD value (0-3) */
>> +};
>> +
>> +/* Read current BKBD state via WQAF. Returns 0-3 or -errno. */
>> +static int yb9_kbdock_query(struct wmi_device *wdev)
>> +{
>> + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
>> + union acpi_object *obj;
>> + acpi_status status;
>> + u32 bkbd;
>> +
>> + status = wmi_query_block(YB9_KBDOCK_QUERY_GUID,
>> + YB9_KBDOCK_QUERY_INSTANCE, &out);
>
> That method is deprecated, please use wmidev_query_block(); I suggest
> you use a notifier
> to connect both the WMI event device and the WMI blockd device. Take a
> look at drivers/platform/
> x86/uniwill/uniwill-wmi.c for example.
>
>> + if (ACPI_FAILURE(status)) {
>> + dev_warn(&wdev->dev, "WQAF query failed: %s\n",
>> + acpi_format_exception(status));
>> + return -EIO;
>> + }
>> +
>> + obj = out.pointer;
>> + if (!obj) {
>> + dev_warn(&wdev->dev, "WQAF returned NULL\n");
>> + return -EIO;
>> + }
>> +
>> + /*
>> + * WQAF returns an 8-byte buffer: bytes [0..3] = LFID (0x00060000),
>> + * bytes [4..7] = BKBD value. Guard against short buffers.
>> + */
>> + if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length >= 8) {
>> + memcpy(&bkbd, obj->buffer.pointer + 4, sizeof(bkbd));
>> + bkbd &= 0x3;
>> + } else if (obj->type == ACPI_TYPE_INTEGER) {
>> + bkbd = obj->integer.value & 0x3;
>> + } else {
>> + dev_warn(&wdev->dev,
>> + "WQAF: unexpected result type %d len %u\n",
>> + obj->type,
>> + obj->type == ACPI_TYPE_BUFFER
>> + ? obj->buffer.length : 0);
>> + kfree(obj);
>> + return -EIO;
>> + }
>> +
>> + kfree(obj);
>> + return (int)bkbd;
>> +}
>> +
>> +static void yb9_kbdock_update(struct wmi_device *wdev)
>> +{
>> + struct yb9_kbdock_priv *priv = dev_get_drvdata(&wdev->dev);
>> + int bkbd;
>> + int tablet_mode;
>> +
>> + bkbd = yb9_kbdock_query(wdev);
>> + if (bkbd < 0)
>> + return;
>> +
>> + priv->bkbd = bkbd;
>> +
>> + /*
>> + * Report tablet mode only when the keyboard is fully detached.
>> + * Both docked positions (top-half and bottom-half of the bottom
>> screen)
>> + * indicate a physical keyboard is present — report laptop mode.
>> + */
>> + tablet_mode = (bkbd == BKBD_DETACHED) ? 1 : 0;
>> +
>> + input_report_switch(priv->input_dev, SW_TABLET_MODE, tablet_mode);
>> + input_sync(priv->input_dev);
>> +
>> + dev_dbg(&wdev->dev, "BKBD=%u tablet_mode=%d\n", bkbd, tablet_mode);
>> +}
>> +
>> +static void yb9_kbdock_notify(struct wmi_device *wdev, union
>> acpi_object *data)
>> +{
>> + yb9_kbdock_update(wdev);
>> +}
>> +
>> +/* sysfs: keyboard_position — exposes raw BKBD value */
>> +static ssize_t keyboard_position_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct yb9_kbdock_priv *priv = dev_get_drvdata(dev);
>> + static const char * const names[] = {
>> + "detached", "top-half", "bottom-half", "unknown"
>> + };
>> + unsigned int bkbd = priv->bkbd;
>> +
>> + if (bkbd > 3)
>> + bkbd = 3;
>
> I think you should protect bkbd with a spinlock. Or you could just
> read the current value
> from the hardware directly.
>
>> + return sysfs_emit(buf, "%u (%s)\n", bkbd, names[bkbd]);
>> +}
>> +static DEVICE_ATTR_RO(keyboard_position);
>> +
>> +static struct attribute *yb9_kbdock_attrs[] = {
>> + &dev_attr_keyboard_position.attr,
>> + NULL,
>> +};
>> +ATTRIBUTE_GROUPS(yb9_kbdock);
>> +
>> +static int yb9_kbdock_probe(struct wmi_device *wdev, const void *ctx)
>> +{
>> + struct yb9_kbdock_priv *priv;
>> + struct input_dev *input_dev;
>> + int err;
>> +
>> + if (!dmi_check_system(yb9_kbdock_dmi_table)) {
>> + dev_dbg(&wdev->dev, "not a Yoga Book 9, skipping\n");
>> + return -ENODEV;
>> + }
>> +
>> + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> +
>> + input_dev = devm_input_allocate_device(&wdev->dev);
>> + if (!input_dev)
>> + return -ENOMEM;
>> +
>> + input_dev->name = "Lenovo Yoga Book 9 keyboard dock switch";
>> + input_dev->phys = YB9_KBDOCK_EVENT_GUID "/input0";
>> + input_dev->id.bustype = BUS_HOST;
>> + input_set_capability(input_dev, EV_SW, SW_TABLET_MODE);
>> +
>> + err = input_register_device(input_dev);
>> + if (err) {
>> + dev_err(&wdev->dev, "failed to register input device: %d\n",
>> err);
>> + return err;
>> + }
>> +
>> + priv->input_dev = input_dev;
>> + dev_set_drvdata(&wdev->dev, priv);
>> +
>> + /* Report initial state */
>> + yb9_kbdock_update(wdev);
>> + return 0;
>> +}
>> +
>> +static const struct wmi_device_id yb9_kbdock_wmi_id_table[] = {
>> + { .guid_string = YB9_KBDOCK_EVENT_GUID },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(wmi, yb9_kbdock_wmi_id_table);
>> +
>> +static struct wmi_driver yb9_kbdock_driver = {
>> + .driver = {
>> + .name = "lenovo-yb9-kbdock",
>> + .dev_groups = yb9_kbdock_groups,
>> + },
>> + .id_table = yb9_kbdock_wmi_id_table,
>> + .probe = yb9_kbdock_probe,
>> + .notify = yb9_kbdock_notify,
>
> Please set .no_singleton = true. Also please update the docking state
> when resuming from suspend or hibernation.
>
> Thanks,
> Armin Wolf
>
>> +};
>> +module_wmi_driver(yb9_kbdock_driver);
>> +
>> +MODULE_AUTHOR("Dave Carey <carvsdriver@gmail.com>");
>> +MODULE_DESCRIPTION("Lenovo Yoga Book 9 keyboard dock detection");
>> +MODULE_LICENSE("GPL");
next prev parent reply other threads:[~2026-05-26 13:38 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-25 13:23 [PATCH] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver Dave Carey
2026-04-28 14:39 ` Ilpo Järvinen
2026-05-17 15:01 ` Dave Carey
2026-05-17 15:02 ` [PATCH v2] platform/x86/lenovo: add Yoga Book 9 keyboard dock driver Dave Carey
2026-05-19 0:02 ` [PATCH v3] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver Dave Carey
2026-05-21 14:40 ` [PATCH v4] " Dave Carey
2026-05-22 21:59 ` Armin Wolf
2026-05-26 13:38 ` Dave Carey [this message]
2026-05-27 12:27 ` [PATCH v5] " Dave Carey
2026-06-08 9:13 ` johannes.goede
2026-06-08 12:52 ` Dave Carey
2026-06-08 15:55 ` johannes.goede
2026-06-08 19:05 ` Dave Carey
2026-06-08 19:23 ` johannes.goede
2026-06-08 21:52 ` [PATCH v6 0/2] " Dave Carey
2026-06-08 21:52 ` [PATCH v6 1/2] platform/x86/lenovo: lenovo-ymc: Suppress probe on Yoga Book 9 14IAH10 Dave Carey
2026-06-09 1:29 ` Mark Pearson
2026-06-09 1:29 ` Mark Pearson
2026-06-09 8:50 ` johannes.goede
2026-06-08 21:52 ` [PATCH v6 2/2] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver Dave Carey
2026-06-09 8:50 ` johannes.goede
2026-06-09 9:47 ` Ilpo Järvinen
2026-06-09 21:26 ` [PATCH v7 0/2] " Dave Carey
2026-06-09 21:26 ` [PATCH v7 1/2] platform/x86/lenovo: lenovo-ymc: Suppress probe on Yoga Book 9 14IAH10 Dave Carey
2026-06-10 8:00 ` johannes.goede
2026-06-09 21:26 ` [PATCH v7 2/2] platform/x86/lenovo: Add Yoga Book 9 keyboard dock detection driver Dave Carey
2026-06-10 8:36 ` johannes.goede
2026-06-10 8:44 ` Ilpo Järvinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cc1d6a5e-c2f1-43b0-bc7d-c1efb95efa0d@gmail.com \
--to=carvsdriver@gmail.com \
--cc=W_Armin@gmx.de \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=platform-driver-x86@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox