3131#include <linux/cleanup.h>
3232#include <linux/component.h>
3333#include <linux/container_of.h>
34+ #include <linux/debugfs.h>
3435#include <linux/device.h>
3536#include <linux/dev_printk.h>
3637#include <linux/err.h>
4243#include <linux/mutex_types.h>
4344#include <linux/notifier.h>
4445#include <linux/overflow.h>
46+ #include <linux/seq_file.h>
4547#include <linux/stddef.h>
4648#include <linux/types.h>
4749#include <linux/wmi.h>
@@ -88,6 +90,7 @@ struct lwmi_cd_priv {
8890 struct notifier_block acpi_nb ; /* ACPI events */
8991 struct wmi_device * wdev ;
9092 struct cd_list * list ;
93+ struct dentry * debugfs_dir ;
9194
9295 /*
9396 * A capdata device may be a component master of another capdata device.
@@ -118,6 +121,8 @@ struct cd_list {
118121
119122static struct wmi_driver lwmi_cd_driver ;
120123
124+ /* ======== Device components ======== */
125+
121126/**
122127 * lwmi_cd_match() - Match rule for the master driver.
123128 * @dev: Pointer to the capability data parent device.
@@ -471,6 +476,116 @@ EXPORT_SYMBOL_NS_GPL(lwmi_cd01_get_data, "LENOVO_WMI_CAPDATA");
471476DEF_LWMI_CDXX_GET_DATA (cd_fan , LENOVO_FAN_TEST_DATA , struct capdata_fan );
472477EXPORT_SYMBOL_NS_GPL (lwmi_cd_fan_get_data , "LENOVO_WMI_CAPDATA" );
473478
479+ /* ======== debugfs ======== */
480+
481+ /**
482+ * lwmi_cd00_show() - Dump capdata00
483+ * @s: Pointer to seq_file where the capdata00 is dumped.
484+ * @cd00: Pointer to a capdata00 struct to be dumped.
485+ */
486+ static void lwmi_cd00_show (struct seq_file * s , struct capdata00 * cd00 )
487+ {
488+ u8 dev = FIELD_GET (LWMI_ATTR_DEV_ID_MASK , cd00 -> id );
489+ u8 feat = FIELD_GET (LWMI_ATTR_FEAT_ID_MASK , cd00 -> id );
490+ u8 mode = FIELD_GET (LWMI_ATTR_MODE_ID_MASK , cd00 -> id );
491+ u8 type = FIELD_GET (LWMI_ATTR_TYPE_ID_MASK , cd00 -> id );
492+ bool extra = cd00 -> supported & ~(LWMI_SUPP_GET | LWMI_SUPP_SET | LWMI_SUPP_VALID );
493+ bool get = cd00 -> supported & LWMI_SUPP_GET ;
494+ bool set = cd00 -> supported & LWMI_SUPP_SET ;
495+ bool valid = cd00 -> supported & LWMI_SUPP_VALID ;
496+
497+ seq_printf (s , " id: 0x%08x [dev: %2u, feat: %2u, mode: %2u, type: %2u]\n" ,
498+ cd00 -> id , dev , feat , mode , type );
499+
500+ seq_printf (s , " supported: 0x%08x [%c%c%c%c]\n" , cd00 -> supported ,
501+ extra ? '+' : ' ' ,
502+ get ? 'R' : ' ' ,
503+ set ? 'W' : ' ' ,
504+ valid ? 'V' : ' ' );
505+
506+ seq_printf (s , " default_value: %u\n" , cd00 -> default_value );
507+ }
508+
509+ /**
510+ * lwmi_cd01_show() - Dump capdata01
511+ * @s: Pointer to seq_file where the capdata01 is dumped.
512+ * @cd01: Pointer to a capdata01 struct to be dumped.
513+ */
514+ static void lwmi_cd01_show (struct seq_file * s , struct capdata01 * cd01 )
515+ {
516+ /* capdata01 is an extension to capdata00. */
517+ lwmi_cd00_show (s , (struct capdata00 * )cd01 );
518+
519+ seq_printf (s , " step: %u\n" , cd01 -> step );
520+ seq_printf (s , " min_value: %u\n" , cd01 -> min_value );
521+ seq_printf (s , " max_value: %u\n" , cd01 -> max_value );
522+ }
523+
524+ /**
525+ * lwmi_cd_fan_show() - Dump capdata_fan
526+ * @s: Pointer to seq_file where the capdata_fan is dumped.
527+ * @cd_fan: Pointer to a capdata_fan struct to be dumped.
528+ */
529+ static void lwmi_cd_fan_show (struct seq_file * s , struct capdata_fan * cd_fan )
530+ {
531+ seq_printf (s , " id: %u\n" , cd_fan -> id );
532+ seq_printf (s , " min_rpm: %u\n" , cd_fan -> min_rpm );
533+ seq_printf (s , " max_rpm: %u\n" , cd_fan -> max_rpm );
534+ }
535+
536+ /**
537+ * lwmi_cd_debugfs_show() - Dump capability data to debugfs
538+ * @s: Pointer to seq_file where the capability data is dumped.
539+ * @data: unused.
540+ *
541+ * Return: 0
542+ */
543+ static int lwmi_cd_debugfs_show (struct seq_file * s , void * data )
544+ {
545+ struct lwmi_cd_priv * priv = s -> private ;
546+ u8 idx ;
547+
548+ guard (mutex )(& priv -> list -> list_mutex );
549+
550+ /* lwmi_cd_alloc() ensured priv->list->type must be a valid type. */
551+ for (idx = 0 ; idx < priv -> list -> count ; idx ++ ) {
552+ seq_printf (s , "%s[%u]:\n" , lwmi_cd_table [priv -> list -> type ].name , idx );
553+
554+ if (priv -> list -> type == LENOVO_CAPABILITY_DATA_00 )
555+ lwmi_cd00_show (s , & priv -> list -> cd00 [idx ]);
556+ else if (priv -> list -> type == LENOVO_CAPABILITY_DATA_01 )
557+ lwmi_cd01_show (s , & priv -> list -> cd01 [idx ]);
558+ else if (priv -> list -> type == LENOVO_FAN_TEST_DATA )
559+ lwmi_cd_fan_show (s , & priv -> list -> cd_fan [idx ]);
560+ }
561+
562+ return 0 ;
563+ }
564+ DEFINE_SHOW_ATTRIBUTE (lwmi_cd_debugfs );
565+
566+ /**
567+ * lwmi_cd_debugfs_add() - Create debugfs directory and files for a device
568+ * @priv: lenovo-wmi-capdata driver data.
569+ */
570+ static void lwmi_cd_debugfs_add (struct lwmi_cd_priv * priv )
571+ {
572+ priv -> debugfs_dir = lwmi_debugfs_create_dir (priv -> wdev );
573+
574+ debugfs_create_file ("capdata" , 0444 , priv -> debugfs_dir , priv , & lwmi_cd_debugfs_fops );
575+ }
576+
577+ /**
578+ * lwmi_cd_debugfs_remove() - Remove debugfs directory for a device
579+ * @priv: lenovo-wmi-capdata driver data.
580+ */
581+ static void lwmi_cd_debugfs_remove (struct lwmi_cd_priv * priv )
582+ {
583+ debugfs_remove_recursive (priv -> debugfs_dir );
584+ priv -> debugfs_dir = NULL ;
585+ }
586+
587+ /* ======== WMI interface ======== */
588+
474589/**
475590 * lwmi_cd_cache() - Cache all WMI data block information
476591 * @priv: lenovo-wmi-capdata driver data.
@@ -773,6 +888,8 @@ static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
773888 dev_err (& wdev -> dev , "failed to register %s: %d\n" ,
774889 info -> name , ret );
775890 } else {
891+ lwmi_cd_debugfs_add (priv );
892+
776893 dev_dbg (& wdev -> dev , "registered %s with %u items\n" ,
777894 info -> name , priv -> list -> count );
778895 }
@@ -783,6 +900,8 @@ static void lwmi_cd_remove(struct wmi_device *wdev)
783900{
784901 struct lwmi_cd_priv * priv = dev_get_drvdata (& wdev -> dev );
785902
903+ lwmi_cd_debugfs_remove (priv );
904+
786905 switch (priv -> list -> type ) {
787906 case LENOVO_CAPABILITY_DATA_00 :
788907 lwmi_cd_sub_master_del (priv );
@@ -822,6 +941,7 @@ static struct wmi_driver lwmi_cd_driver = {
822941
823942module_wmi_driver (lwmi_cd_driver );
824943
944+ MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" );
825945MODULE_DEVICE_TABLE (wmi , lwmi_cd_id_table );
826946MODULE_AUTHOR ("Derek J. Clark <derekjohn.clark@gmail.com>" );
827947MODULE_AUTHOR ("Rong Zhang <i@rong.moe>" );
0 commit comments