使用DEVICE_ATTR添加device节点

文章介绍了如何在Linux驱动程序中使用DEVICE_ATTR宏创建设备节点,以便在/sys目录下进行读写操作,辅助驱动调试。主要步骤包括定义DEVICE_ATTR,调用device_create_file函数创建节点,以及编写读写函数。此外,文章还提及了不同权限模式和DRIVER_ATTR等其他相关概念。
摘要由CSDN通过智能技术生成


前言

在驱动调试中,有些特定情况需要增加设备节点来协助分析问题。

例如:在调试I2C芯片时,经常需要去实时读写寄存器。通常情况可以在代码运行到某个地方时增加对应的读写函数,但难免需要编译并且烧录固件,如果重复此操作会严重影响任务周期,此时可以增加读写节点方便操作。

记录一下自己增加的节点代码以及自己的个人理解。


一、读写节点是做什么的?

在 /sys 中生成节点,可用于应用层从驱动中获取数据,也可以直接将数据写入驱动中

二、操作步骤

1.DEVICE_ATTR()宏定义

DEVICE_ATTR的功能就是定义一个device_attribute结构体对象。
LINUX中定义位于include/linux/device.h,内容如下:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

_name:你的节点名字,在sys路径下可以直接搜索这个东西
_mode:这个节点的权限

        400 :拥有者能够读,其他任何人不能进行任何操作;
		644 :拥有者都能够读,但只有拥有者可以编辑;
		660 :拥有者和组用户都可读和写,其他人不能进行任何操作;
		664 :所有人都可读,但只有拥有者和组用户可编辑;
		700 :拥有者能够读、写和执行,其他用户不能任何操作;
		744 :所有人都能读,但只有拥有者才能编辑和执行;
		755 :所有人都能读和执行,但只有拥有者才能编辑;
		777 :所有人都能读、写和执行(该设置通常不是好想法)。
        当然也可以用S_IWUSR(用户可写),S_IRUSR(用户可读)等宏代替。

_show: 当cat命令作用于该文件时调用该函数
_store: 当echo数据到该文件时调用该函数

实际用例:

static DEVICE_ATTR(chipID, S_IRUGO, sensor_chipID_show, NULL);//
static DEVICE_ATTR(regRead, S_IRUGO | S_IWUSR, sensor_regRead_show, sensor_regRead_store); 

static struct device_attribute *sensor_attr_list[] = {
	&dev_attr_chipID,
	&dev_attr_regRead,
};

然后在应用层就能通过cat和echo命令来对sys创建出来的文件进行读写驱动设备,实现交互.

2.device_create_file

device_create_file利用创建好的device_attribute 在device下创建文件。
这个方法只能一次创建一个属性文件

实际用例:


//struct device *sensor_dev;
int sensor_platform_probe(struct platform_device *pdev) {
    int i = 0;
    int ret = 0;
	//sensor_dev= &pdev->dev;
	//如果只有一个节点可以直接这么使用,
	//device_create_file(&pdev->dev, &dev_attr_version.attr);
	//多个节点可以这么使用
	for (i = 0; i < ARRAY_SIZE(sensor_attr_list); i++) {
		ret = device_create_file(&pdev->dev, sensor_attr_list[i]);
		if(ret)
			dev_err(&pdev->dev, "sensor>>>%s: call device_create_file fail\n", __func__);
	}
	return 0;
}

这个pdev->dev就是该device。可以在sys/对应的device下搜索节点名字

3.读写函数

函数增加需要用节点实现的功能即可,如下示例为I2C的读写,仅供参考
示例:

static ssize_t sensor_regWrite_store(struct device *cd, struct device_attribute *attr, const char *buf, size_t count)
{
	int num=2;
	uint16_t senosr_regWrite_addr = 0x00000;
	int32_t sensor_regWrite_value = 0x00;
	if ((!count )|| (count > 48)){
		pr_err("sensor>>>%s: wrong count\n", __func__);
		return -EINVAL;
	}
	if (num != sscanf(buf, "0x%04x 0x%02x\n", &senosr_regWrite_addr , &sensor_regWrite_value )){
		pr_err("sensor>>>%s: num = %d !=2,senosr_regWrite_addr= 0x%04x, sensor_regWrite_value =0x%02x\n", __func__, num, senosr_regWrite_addr, sensor_regWrite_value );
		return -1;
	}
	down(&sensor_lock);
	sensor_WriteByte8_4CH(I2C_SLVAE_ADDR, sensor_regWrite_addr, sensor_regWrite_value);
	up(&sensor_lock);
	pr_err("sensor>>>%s: sensor_regWrite_addr=0x%04x, sensor_regWrite_value=0x%02x\n", __func__, sensor_regWrite_addr, sensor_regWrite_value);
	return count;
}
static ssize_t sensor_regRead_show(struct device* cd,struct device_attribute *attr, char* buf)
{
	ssize_t len = 0;
	down(&sensor_lock);
	len += snprintf(buf+len, PAGE_SIZE-len, "0x%04x 0x%02x\n", sensor_regRead_addr, sensor_regRead_value);
	pr_err("sensor>>>%s: sensor_regRead_addr=0x%04x, sensor_regRead_value=0x%02x\n", __func__, sensor_regRead_addr, sensor_regRead_value);
	up(&sensor_lock);
	return len;
}

类似的还有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。
它们的区别就是,DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面。而其他几个分别在driver,bus,class中对应的目录下。


仅是个人学习和记录 , 如有错误也请帮忙及时指证 , 共同学习,进步

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值