Linux驱动调试:增加文件节点属性

在调试linux驱动的时候,经常需要用户层和内核态进行交互,比较常用的方法是ioctl和文件节点,这里介绍一下在设备驱动增加文件节点的常见方法。

(1)module_param方式

可以在驱动使用函数module_param来设置参数,本意就是设置加载驱动的时候可以传入哪些参数,代码示例如下:

static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-3)");

设置上述参数之后,会在对应的module下面生成文件节点,例如lt6911uxc:

/sys/module/lt6911uxc/parameters/debug

(2)proc文件节点

可以在/proc/目录下生成对应的文件节点,示例如下:

void lt7911uxc_init_procfs(struct lt7911uxc *lt7911uxc)
{
	struct proc_dir_entry *parent;
	struct device *dev = &lt7911uxc->i2c_client->dev;

	g_lt7911uxc = lt7911uxc;
	g_lt7911uxc->crc = LT7911UXC_CRC;

	parent = proc_mkdir("lt7911uxc", NULL);
	if (!parent) {
		dev_err(dev, "lt7911uxc init procfs mkdir fail!");
		return;
	}

	proc_create("crc-set", S_IWUSR | S_IWGRP, parent, &set_crc_fops);
	dev_info(dev, "-- lt7911uxc_init_procfs --");
}

static ssize_t lt7911uxc_crc_write(struct file *file, const char __user *buffer,
		size_t count, loff_t *pos)
{
	u8 data[3]= { 0xff };
	const size_t size = sizeof(data);
	struct device *dev = &g_lt7911uxc->i2c_client->dev;
	unsigned long val;
	dev_info(dev, "-- lt7911uxc crc write start --\n");

	if (count > size)
		return -EINVAL;

	if (copy_from_user(data, buffer, count))
		return -EFAULT;

	val = simple_strtoul(data, NULL, 16);
	g_lt7911uxc->crc = val;

	dev_info(dev, "-- lt7911uxc_crc_write: %x --", g_lt7911uxc->crc);

	return count;
}

static ssize_t lt7911uxc_crc_read(struct file *fd,
			char __user *buf_, size_t size, loff_t *offset)
{
	u16 ver = 0;
	u8 out[7] = {0};// one byte max value in hex is "255".
	ssize_t len = 0;

	ver = g_lt7911uxc->crc;

	len = sizeof(out) - *offset;
	if (len < 0)
		len = 0;

	snprintf(out, sizeof(out), "%x\n", ver);
	if (copy_to_user(buf_, out, len) ) {
		pr_err("copy to user failed");
		return -EFAULT;
	}
	*offset += len;
	pr_info("-- fw_version_read --, len: %zd\n", len);
	return len;
}

static const struct proc_ops set_crc_fops = {
	.proc_write     = lt7911uxc_crc_write,
	.proc_read	= lt7911uxc_crc_read,
};

通过函数proc_mkdir在/proc/目录下创建一个目录,通过proc_create函数创建文件节点,再实现对应的节点的读写函数即可。

例如上述例子,可以通过如下命令操作:

cat /proc/lt7911uxc/crc-set
echo 1 > /proc/lt7911uxc/crc-set

(3)class文件节点

创建class文件节点。如下示例,在sys/class的目录下创建max96714的目录,在max96714目录下再创建max96714_state目录,后面生成的属性都会在这个目录下。

static int max96714_create_class_attr(struct max96714 *max96714)
{
	int ret = 0;
	struct device *dev = &max96714->client->dev;

	max96714->class = class_create(THIS_MODULE, "max96714");
	if (IS_ERR(max96714->class)) {
		ret = -ENOMEM;
		dev_err(dev, "failed to create max96714 class!\n");
		return ret;
	}

	max96714->classdev = device_create_with_groups(max96714->class, dev,
					MKDEV(0, 0), max96714,
					max96714_groups, "max96714_state");
	if (IS_ERR(max96714->classdev)) {
		ret = PTR_ERR(max96714->classdev);
		dev_err(dev, "Failed to create device\n");
		goto err;
	}

	ret = devm_add_action_or_reset(dev, max96714_unregister_class_device, max96714);
	if (ret)
		dev_err(dev, "device unregister max96714 class failed!\n");

	return ret;

err:
	class_destroy(max96714->class);
	return ret;
}

static void max96714_remove_class_attr(struct max96714 *max96714)
{
	class_destroy(max96714->class);
}
static void max96714_unregister_class_device(void *data)
{
	struct max96714 *max96714 = data;
	struct device *dev = max96714->classdev;

	device_unregister(dev);
}

static ssize_t mcu_rise_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
{
	struct max96714 *max96714 = dev_get_drvdata(dev);
	u8 checksum = 0;
	int ret;
	u8 rise_val = 0;

...

	return snprintf(buf, PAGE_SIZE, "%x\n", rise_val);
}

static ssize_t mcu_rise_store(struct device *dev,
			    struct device_attribute *attr,
			    const char *buf, size_t count)
{
	struct max96714 *max96714 = dev_get_drvdata(dev);
	uint8_t value, value_l;
	u8 checksum = 0;
	int ret;

	if (!max96714)
		return -EINVAL;

	sscanf(buf, "%d %d", &value, &value_l);
...

	return count;
}

static DEVICE_ATTR_RW(mcu_rise);
static struct attribute *max96714_attrs[] = {
	&dev_attr_mcu_rise.attr,
	NULL
};
ATTRIBUTE_GROUPS(max96714);

(4)其他方式

其他的创建方式还有sysfs_create_files,device_create_file等方式,这里不再赘述。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

人生苦短,菜的抠脚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值