mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
platform/x86: lenovo-wmi-capdata: Add debugfs file for dumping capdata
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 convert the former to include the latter anonymously (-fms-extensions, since v6.19). This is declared as a union in the capdata01 struct, with both the anonymous declaration and as a named member to avoid type casting when passing just the capdata00 struct pointer. Tested-by: Kurt Borja <kuurtb@gmail.com> Signed-off-by: Rong Zhang <i@rong.moe> Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com> Link: https://patch.msgid.link/20260520060740.119554-8-derekjohn.clark@gmail.com Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
parent
229e575451
commit
18a166d29a
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -31,6 +31,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>
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
#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>
|
||||
|
|
@ -87,6 +89,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.
|
||||
|
|
@ -117,6 +120,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.
|
||||
|
|
@ -470,6 +475,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;
|
||||
|
||||
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, &cd01->cd00);
|
||||
|
||||
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.
|
||||
|
|
@ -772,6 +887,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);
|
||||
}
|
||||
|
|
@ -782,6 +899,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);
|
||||
|
|
@ -821,6 +940,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@gmail.com>");
|
||||
MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
|
||||
|
|
|
|||
|
|
@ -38,9 +38,10 @@ struct capdata00 {
|
|||
};
|
||||
|
||||
struct capdata01 {
|
||||
u32 id;
|
||||
u32 supported;
|
||||
u32 default_value;
|
||||
union {
|
||||
struct capdata00;
|
||||
struct capdata00 cd00;
|
||||
};
|
||||
u32 step;
|
||||
u32 min_value;
|
||||
u32 max_value;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user