Linux内核中ideapad-laptop.c文件全解析5

本文深入剖析了Linux内核中ideapad-laptop.c文件的debugfs初始化和退出函数,包括debugfs_create_dir和debugfs_create_file的使用,以及debugfs_cfg_fops和debugfs_status_fops的实现。通过这些函数,模块在debugfs中创建了ideapad目录,并提供了cfg和status文件,用于显示设备状态和配置信息。通过对EC(Embedded Controller)的读取操作,实现了对笔记本特性如无线、蓝牙、摄像头等的状态展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接前一篇文章《Linux内核中ideapad-laptop.c文件全解析4》,链接为:

Linux内核中ideapad-laptop.c文件全解析4_蓝天居士的博客-优快云博客

上一回详细分析了ideapad_sysfs_init,这一回详细分析ideapad_debugfs_init。

  • ideapad_debugfs_init

ideapad_debugfs_init在同文件(drivers/platform/x86/ideapad-laptop.c)中实现,代码如下:

static void ideapad_debugfs_init(struct ideapad_private *priv)
{
	struct dentry *dir;

	dir = debugfs_create_dir("ideapad", NULL);
	priv->debug = dir;

	debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
	debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
}

static void ideapad_debugfs_exit(struct ideapad_private *priv)
{
	debugfs_remove_recursive(priv->debug);
	priv->debug = NULL;
}

debugfs_create_dir函数的声明在include/linux/debugfs.h中: 

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);

debugfs_create_dir函数在指定的父目录下创建一个名为name的目录。如果parent为NULL,则将在debugfs根目录中创建该目录。成功时,返回值是一个struct dentry指针,可用于在目录中创建文件(并在最后清理它)。 ERR_PTR(-ERROR) 返回值表示出现问题;如果返回 ERR_PTR(-ENODEV),这表明内核是在没有debugfs支持的情况下构建的,并且任何功能都将不起作用。

debugfs_create_file函数的声明同样在include/linux/debugfs.h中:

struct dentry *debugfs_create_file(const char *name, umode_t mode,
				   struct dentry *parent, void *data,
				   const struct file_operations *fops);

debugfs_create_file函数在debugfs目录中创建文件。参数name是要创建的文件的名称,mode描述文件应具有的访问权限,parent表示应保存文件的目录,数据将存储在生成的inode结构的i_private字段中,fops是一组实现文件行为的文件操作。至少应该提供read()和/或write()操作;其它的可以根据需要加入。同样,返回值将是指向已创建文件的 dentry 指针,错误时为 ERR_PTR(-ERROR),如果缺少debugfs支持,则返回 ERR_PTR(-ENODEV)。

 这里假设按照一般情况,将debugfs挂载到/sys/kernel/debug/路径下,命令如下:

sudo mount -t debugfs none /sys/kernel/debug

则ideapad_debugfs_init函数的实际作用是,在/sys/kernel/debug/下创建了ideapad文件夹,其中包含了cfg文件和status文件。

回到ideapad_debugfs_init函数

static void ideapad_debugfs_init(struct ideapad_private *priv)
{
	struct dentry *dir;

	dir = debugfs_create_dir("ideapad", NULL);
	priv->debug = dir;

	debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
	debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
}

static void ideapad_debugfs_exit(struct ideapad_private *priv)
{
	debugfs_remove_recursive(priv->debug);
	priv->debug = NULL;
}

debugfs_cfg_fops和debugfs_status_fops的定义直接搜索是搜不到的,因为使用了字符串拼接。在include/linux/seq.h中:

#define DEFINE_SHOW_ATTRIBUTE(__name)					\
static int __name ## _open(struct inode *inode, struct file *file)	\
{									\
	return single_open(file, __name ## _show, inode->i_private);	\
}									\
									\
static const struct file_operations __name ## _fops = {			\
	.owner		= THIS_MODULE,					\
	.open		= __name ## _open,				\
	.read		= seq_read,					\
	.llseek		= seq_lseek,					\
	.release	= single_release,				\
}

因此,将DEFINE_SHOW_ATTRIBUTE(debugfs_status)展开来,具体内容为:

static int __debugfs_status_open(struct inode *inode, struct file *file)
{
    rerurn single_open(file, debugfs_status_show, inode->i_private);
}

static const struct file_operations debugfs_status_fops = {
    .owner        = THIS_MODULE,
    .open         = debugfs_status_open,
    .read         = seq_read,
    .llseek       = seq_lseek,
    .release      = single_release,
}

debugfs_status_show函数的代码如下:

static int debugfs_status_show(struct seq_file *s, void *data)
{
	struct ideapad_private *priv = s->private;
	unsigned long value;

	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
		seq_printf(s, "Backlight max:  %lu\n", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
		seq_printf(s, "Backlight now:  %lu\n", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
		seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);

	seq_puts(s, "=====================\n");

	if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
		seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
		seq_printf(s, "Wifi status:  %s (%lu)\n", value ? "on" : "off", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
		seq_printf(s, "BT status:    %s (%lu)\n", value ? "on" : "off", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
		seq_printf(s, "3G status:    %s (%lu)\n", value ? "on" : "off", value);

	seq_puts(s, "=====================\n");

	if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
		seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
	if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
		seq_printf(s, "Camera status:   %s (%lu)\n", value ? "on" : "off", value);

	seq_puts(s, "=====================\n");

	if (!eval_gbmd(priv->adev->handle, &value))
		seq_printf(s, "GBMD: %#010lx\n", value);
	if (!eval_hals(priv->adev->handle, &value))
		seq_printf(s, "HALS: %#010lx\n", value);

	return 0;
}

将DEFINE_SHOW_ATTRIBUTE(debugfs_cfg)展开来,具体内容为: 

static int __debugfs_cfg_open(struct inode *inode, struct file *file)
{
    rerurn single_open(file, debugfs_cfg_show, inode->i_private);
}

static const struct file_operations debugfs_cfg_fops = {
    .owner        = THIS_MODULE,
    .open         = debugfs_cfg_open,
    .read         = seq_read,
    .llseek       = seq_lseek,
    .release      = single_release,
}

 debugfs_cfg_show函数的代码如下:

static int debugfs_cfg_show(struct seq_file *s, void *data)
{
	struct ideapad_private *priv = s->private;

	seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg);

	seq_puts(s, "Capabilities:");
	if (test_bit(CFG_CAP_BT_BIT, &priv->cfg))
		seq_puts(s, " bluetooth");
	if (test_bit(CFG_CAP_3G_BIT, &priv->cfg))
		seq_puts(s, " 3G");
	if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg))
		seq_puts(s, " wifi");
	if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
		seq_puts(s, " camera");
	if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
		seq_puts(s, " touchpad");
	seq_puts(s, "\n");

	seq_puts(s, "Graphics: ");
	switch (priv->cfg & 0x700) {
	case 0x100:
		seq_puts(s, "Intel");
		break;
	case 0x200:
		seq_puts(s, "ATI");
		break;
	case 0x300:
		seq_puts(s, "Nvidia");
		break;
	case 0x400:
		seq_puts(s, "Intel and ATI");
		break;
	case 0x500:
		seq_puts(s, "Intel and Nvidia");
		break;
	}
	seq_puts(s, "\n");

	return 0;
}

和sysfs一样,其中用到的接口函数在单独一个会目中详细分析。

至此,ideapad-laptop.c中debugfs部分的代码就全部分析完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝天居士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值