lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8FB96079-C8EE-4DD5-AFE0-23F7D66A2332@gmail.com>
Date: Wed, 11 Feb 2026 11:10:36 -0800
From: "Derek J. Clark" <derekjohn.clark@...il.com>
To: Rong Zhang <i@...g.moe>
CC: Kurt Borja <kuurtb@...il.com>, Mark Pearson <mpearson-lenovo@...ebb.ca>,
 Armin Wolf <W_Armin@....de>, Hans de Goede <hansg@...nel.org>,
 Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>,
 platform-driver-x86@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 2/2] platform/x86: lenovo-wmi-capdata: Add debugfs file for dumping capdata

On February 11, 2026 3:47:03 AM PST, Rong Zhang <i@...g.moe> wrote:
>Hi Derek,
>
>On Tue, 2026-02-10 at 12:38 -0800, Derek J. Clark wrote:
>> On February 10, 2026 11:19:37 AM PST, Rong Zhang <i@...g.moe> wrote:
>> > The Lenovo GameZone/Other interfaces have some delicate divergences
>> > among different devices. When making a bug report or adding support for
>> > new devices/interfaces, capdata is the most important information to
>> > cross-check with.
>> > 
>> > Add a debugfs file (lenovo_wmi/<device_name>/capdata), so that users can
>> > dump capdata and include it in their reports.
>> > 
>> > Since `struct capdata01' is just an extension to `struct capdata00',
>> > also converts the former to include the latter anonymously
>> > (-fms-extensions, since v6.19). In this manner type casting won't be
>> > confusing.
>> > 
>> > Signed-off-by: Rong Zhang <i@...g.moe>
>> > ---
>> > drivers/platform/x86/lenovo/Kconfig       |   1 +
>> > drivers/platform/x86/lenovo/wmi-capdata.c | 121 ++++++++++++++++++++++
>> > drivers/platform/x86/lenovo/wmi-capdata.h |   4 +-
>> > 3 files changed, 123 insertions(+), 3 deletions(-)
>> > 
>> > diff --git a/drivers/platform/x86/lenovo/Kconfig b/drivers/platform/x86/lenovo/Kconfig
>> > index f885127b007f1..8357971c76d80 100644
>> > --- a/drivers/platform/x86/lenovo/Kconfig
>> > +++ b/drivers/platform/x86/lenovo/Kconfig
>> > @@ -236,6 +236,7 @@ config YT2_1380
>> > config LENOVO_WMI_CAPDATA
>> > 	tristate
>> > 	depends on ACPI_WMI
>> > +	depends on LENOVO_WMI_HELPERS
>> > 
>> > config LENOVO_WMI_EVENTS
>> > 	tristate
>> > diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c
>> > index ee1fb02d8e31e..ca478b45119bc 100644
>> > --- a/drivers/platform/x86/lenovo/wmi-capdata.c
>> > +++ b/drivers/platform/x86/lenovo/wmi-capdata.c
>> > @@ -32,6 +32,7 @@
>> > #include <linux/cleanup.h>
>> > #include <linux/component.h>
>> > #include <linux/container_of.h>
>> > +#include <linux/debugfs.h>
>> > #include <linux/device.h>
>> > #include <linux/dev_printk.h>
>> > #include <linux/err.h>
>> > @@ -43,11 +44,13 @@
>> > #include <linux/mutex_types.h>
>> > #include <linux/notifier.h>
>> > #include <linux/overflow.h>
>> > +#include <linux/seq_file.h>
>> > #include <linux/stddef.h>
>> > #include <linux/types.h>
>> > #include <linux/wmi.h>
>> > 
>> > #include "wmi-capdata.h"
>> > +#include "wmi-helpers.h"
>> > 
>> > #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"
>> > #define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
>> > @@ -88,6 +91,7 @@ struct lwmi_cd_priv {
>> > 	struct notifier_block acpi_nb; /* ACPI events */
>> > 	struct wmi_device *wdev;
>> > 	struct cd_list *list;
>> > +	struct dentry *debugfs_dir;
>> > 
>> > 	/*
>> > 	 * A capdata device may be a component master of another capdata device.
>> > @@ -118,6 +122,8 @@ struct cd_list {
>> > 
>> > static struct wmi_driver lwmi_cd_driver;
>> > 
>> > +/* ======== Device components ======== */
>> > +
>> > /**
>> >  * lwmi_cd_match() - Match rule for the master driver.
>> >  * @dev: Pointer to the capability data parent device.
>> > @@ -471,6 +477,116 @@ EXPORT_SYMBOL_NS_GPL(lwmi_cd01_get_data, "LENOVO_WMI_CAPDATA");
>> > DEF_LWMI_CDXX_GET_DATA(cd_fan, LENOVO_FAN_TEST_DATA, struct capdata_fan);
>> > EXPORT_SYMBOL_NS_GPL(lwmi_cd_fan_get_data, "LENOVO_WMI_CAPDATA");
>> > 
>> > +/* ======== debugfs ======== */
>> > +
>> > +/**
>> > + * lwmi_cd00_show() - Dump capdata00
>> > + * @s: Pointer to seq_file where the capdata00 is dumped.
>> > + * @cd00: Pointer to a capdata00 struct to be dumped.
>> > + */
>> > +static void lwmi_cd00_show(struct seq_file *s, struct capdata00 *cd00)
>> > +{
>> > +	u8 dev = FIELD_GET(LWMI_ATTR_DEV_ID_MASK, cd00->id);
>> > +	u8 feat = FIELD_GET(LWMI_ATTR_FEAT_ID_MASK, cd00->id);
>> > +	u8 mode = FIELD_GET(LWMI_ATTR_MODE_ID_MASK, cd00->id);
>> > +	u8 type = FIELD_GET(LWMI_ATTR_TYPE_ID_MASK, cd00->id);
>> > +	bool extra = cd00->supported & ~(LWMI_SUPP_GET | LWMI_SUPP_SET | LWMI_SUPP_VALID);
>> > +	bool get = cd00->supported & LWMI_SUPP_GET;
>> > +	bool set = cd00->supported & LWMI_SUPP_SET;
>> > +	bool valid = cd00->supported & LWMI_SUPP_VALID;
>> 
>> Hi Rong,
>> 
>> I have something that will clean this up in the series I'm working on, LWMI_ATTR_ID, that pushes all the FIELD_PREP into a macro. Perhaps it would be worth combining this series into mine that so we can use it here as well. 
>> 
>> My series also addresses some fairly significant bugs, so I'd prefer to not have to wait for this series to get approved to post it as it currently conflicts in other areas.
>
>Feel free to integrate this series into yours :)
>
>I have zero experience in doing so but I guess git-send-email should
>handle the author field well.

Hi Rong,

That sounds good. I should be able to retain authorship and make my edits as needed. I'll add a CDB tag for myself if I make any significant changes beyond rebase edits, and I'll send them back to you before publishing for your verification directly. Thanks.

>> > +	seq_printf(s, "  id:             0x%08x [dev: %2u, feat: %2u, mode: %2u, type: %2u]\n",
>> > +		   cd00->id, dev, feat, mode, type);
>> > +
>> > +	seq_printf(s, "  supported:      0x%08x [%c%c%c%c]\n", cd00->supported,
>> > +		   extra ? '+' : ' ',
>> > +		   get   ? 'R' : ' ',
>> > +		   set   ? 'W' : ' ',
>> > +		   valid ? 'V' : ' ');
>> > +
>> > +	seq_printf(s, "  default_value:  %u\n", cd00->default_value);
>> > +}
>> > +
>> > +/**
>> > + * lwmi_cd01_show() - Dump capdata01
>> > + * @s: Pointer to seq_file where the capdata01 is dumped.
>> > + * @cd01: Pointer to a capdata01 struct to be dumped.
>> > + */
>> > +static void lwmi_cd01_show(struct seq_file *s, struct capdata01 *cd01)
>> > +{
>> > +	/* capdata01 is an extension to capdata00. */
>> > +	lwmi_cd00_show(s, (struct capdata00 *)cd01);
>> > +
>> > +	seq_printf(s, "  step:           %u\n", cd01->step);
>> > +	seq_printf(s, "  min_value:      %u\n", cd01->min_value);
>> > +	seq_printf(s, "  max_value:      %u\n", cd01->max_value);
>> > +}
>> > +
>> > +/**
>> > + * lwmi_cd_fan_show() - Dump capdata_fan
>> > + * @s: Pointer to seq_file where the capdata_fan is dumped.
>> > + * @cd_fan: Pointer to a capdata_fan struct to be dumped.
>> > + */
>> > +static void lwmi_cd_fan_show(struct seq_file *s, struct capdata_fan *cd_fan)
>> > +{
>> > +	seq_printf(s, "  id:             %u\n", cd_fan->id);
>> > +	seq_printf(s, "  min_rpm:        %u\n", cd_fan->min_rpm);
>> > +	seq_printf(s, "  max_rpm:        %u\n", cd_fan->max_rpm);
>> > +}
>> > +
>> > +/**
>> > + * lwmi_cd_debugfs_show() - Dump capability data to debugfs
>> > + * @s: Pointer to seq_file where the capability data is dumped.
>> > + * @data: unused.
>> > + *
>> > + * Return: 0
>> > + */
>> > +static int lwmi_cd_debugfs_show(struct seq_file *s, void *data)
>> > +{
>> > +	struct lwmi_cd_priv *priv = s->private;
>> > +	u8 idx;
>> > +
>> > +	guard(mutex)(&priv->list->list_mutex);
>> > +
>> > +	/* lwmi_cd_alloc() ensured priv->list->type must be a valid type. */
>> > +	for (idx = 0; idx < priv->list->count; idx++) {
>> > +		seq_printf(s, "%s[%u]:\n", lwmi_cd_table[priv->list->type].name, idx);
>> > +
>> > +		if (priv->list->type == LENOVO_CAPABILITY_DATA_00)
>> > +			lwmi_cd00_show(s, &priv->list->cd00[idx]);
>> > +		else if (priv->list->type == LENOVO_CAPABILITY_DATA_01)
>> > +			lwmi_cd01_show(s, &priv->list->cd01[idx]);
>> > +		else if (priv->list->type == LENOVO_FAN_TEST_DATA)
>> > +			lwmi_cd_fan_show(s, &priv->list->cd_fan[idx]);
>> > +	}
>> > +
>> > +	return 0;
>> > +}
>> > +DEFINE_SHOW_ATTRIBUTE(lwmi_cd_debugfs);
>> > +
>> > +/**
>> > + * lwmi_cd_debugfs_add() - Create debugfs directory and files for a device
>> > + * @priv: lenovo-wmi-capdata driver data.
>> > + */
>> > +static void lwmi_cd_debugfs_add(struct lwmi_cd_priv *priv)
>> > +{
>> > +	priv->debugfs_dir = lwmi_debugfs_create_dir(priv->wdev);
>> > +
>> > +	debugfs_create_file("capdata", 0444, priv->debugfs_dir, priv, &lwmi_cd_debugfs_fops);
>> > +}
>> > +
>> > +/**
>> > + * lwmi_cd_debugfs_remove() - Remove debugfs directory for a device
>> > + * @priv: lenovo-wmi-capdata driver data.
>> > + */
>> > +static void lwmi_cd_debugfs_remove(struct lwmi_cd_priv *priv)
>> > +{
>> > +	debugfs_remove_recursive(priv->debugfs_dir);
>> > +	priv->debugfs_dir = NULL;
>> > +}
>> > +
>> > +/* ======== WMI interface ======== */
>> > +
>> > /**
>> >  * lwmi_cd_cache() - Cache all WMI data block information
>> >  * @priv: lenovo-wmi-capdata driver data.
>> > @@ -773,6 +889,8 @@ static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
>> > 		dev_err(&wdev->dev, "failed to register %s: %d\n",
>> > 			info->name, ret);
>> > 	} else {
>> > +		lwmi_cd_debugfs_add(priv);
>> > +
>> > 		dev_dbg(&wdev->dev, "registered %s with %u items\n",
>> > 			info->name, priv->list->count);
>> > 	}
>> > @@ -783,6 +901,8 @@ static void lwmi_cd_remove(struct wmi_device *wdev)
>> > {
>> > 	struct lwmi_cd_priv *priv = dev_get_drvdata(&wdev->dev);
>> > 
>> > +	lwmi_cd_debugfs_remove(priv);
>> > +
>> > 	switch (priv->list->type) {
>> > 	case LENOVO_CAPABILITY_DATA_00:
>> > 		lwmi_cd_sub_master_del(priv);
>> > @@ -822,6 +942,7 @@ static struct wmi_driver lwmi_cd_driver = {
>> > 
>> > module_wmi_driver(lwmi_cd_driver);
>> > 
>> > +MODULE_IMPORT_NS("LENOVO_WMI_HELPERS");
>> > MODULE_DEVICE_TABLE(wmi, lwmi_cd_id_table);
>> > MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@...il.com>");
>> > MODULE_AUTHOR("Rong Zhang <i@...g.moe>");
>> > diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
>> > index 8c1df3efcc553..034a6e48be071 100644
>> > --- a/drivers/platform/x86/lenovo/wmi-capdata.h
>> > +++ b/drivers/platform/x86/lenovo/wmi-capdata.h
>> > @@ -30,9 +30,7 @@ struct capdata00 {
>> > };
>> > 
>> > struct capdata01 {
>> > -	u32 id;
>> > -	u32 supported;
>> > -	u32 default_value;
>> > +	struct capdata00;
>> 
>> Doesn't this also require some significant changes to the usage in wmi-other and in the query function? We're accessing these members directly.
>
>No. As Kurt said, it utilizes a relatively new (since v6.19-rc1) change
>to kbuild. See commit c4781dc3d1cf ("Kbuild: enable -fms-extensions").

That's pretty neat. In that case this makes a lot of sense.

Thanks,
Derek

>Thanks,
>Rong
>
>> Thanks, 
>> Derek
>> 
>> > 	u32 step;
>> > 	u32 min_value;
>> > 	u32 max_value;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ