2022-5-10 Linux sysfs使用方法随笔

linux sysfs使用

概述

Linux 2.6以后的内核引入了sysfs文件系统, sysfs被看成是与proc、 devfs和devpty同类别的文件系统,该文件系统是一个虚拟的文件系统, 它可以产生一个包括所有系统硬件的层级视图, 与提供进程和状态信
息的proc文件系统十分类似。
sysfs把连接在系统上的设备和总线组织成为一个分级的文件, 它们可以由用户空间存取, 向用户空间导出内核数据结构以及它们的属性。 sysfs的一个目的就是展示设备驱动模型中各组件的层次关系, 其顶级目录包括block、 bus、 dev、 devices、 class、 fs、 kernel、 power和firmware等。
(出自《Linux设备驱动开发详解:基于最新的Linux4.0内核》)

目录结构

/sys下子目录目录内容
/sys/devices内核对系统中所有设备的分层次表达模型,也是/sys文件系统管理设备的最重要的目录结构;
/sys/dev分为字符设备和块设备,都是以主次设备号的形式链接到/sys/devices的真实设备
/sys/bus按照总线类型将/sys/devices下的真实设备进行分类
/sys/class按照功能分类将/sys/devices下的真实设备进行分类
/sys/block系统中所有的块设备
/sys/firmware路径中是系统使用的devicetree的各个描述符
/sys/module模块中引出来的参数在这个路径下
/sys/power系统中的电源选项,写入控制指令可以suspend/reboot等

创建sysfs节点

device_attribute

创建读写字符串的节点:

#函数原型
int device_create_file(struct device *device, const struct device_attribute *entry);

这里涉及一个结构体:
device_attribute

struct device_attribute {
	struct attribute        attr;
	ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
	ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
};

#define DEVICE_ATTR(_name, _mode, _show, _store) \
	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define DEVICE_ATTR_RW(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_WO(_name)

以一个可以进行字符串读写的AA节点为例:
在代码中需要如下定义:

DEVICE_ATTR_RW(AA) 
#这样就已经定义好了名为 dev_attr_AA 的结构体对象
#同时也定义好了两个方法名称:AA_show()和AA_store()

在probe函数中调用创建函数:

device_create_file(&client->dev, &dev_attr_AA);

然后实现AA_show()和AA_store()实体

static ssize_t vmute_show(struct device *dev,
								struct device_attribute *attr,
								char *buf)
{
	unsigned int value;
	......
	......
	return scnprintf(buf, PAGE_SIZE, "%d\n", value);
}

static ssize_t vmute_store(struct device *dev,
								struct device_attribute *attr,
								const char *buf, size_t count)
{
	......
	......
	return count;
}

有几点注意项:
1.show()方法应该总是使用snprintf 进行返回
2.store()方法应该返回实际使用的字节数
3.show()和store()方法出错时返回相应的错误码
4.show()和store()方法都是同步通信
5.节点的缓冲区总是为1页,为PAGE_SIZE个字节,PAGE_SIZE=4096

bin_attribute

创建读写bin类型的节点:

#函数原型
int __must_check device_create_bin_file(struct device *dev, const struct bin_attribute *attr);
#因为是__must_check,所以该函数的返回值必须进行判定

这里涉及一个结构体:
bin_attribute

struct bin_attribute {
        struct attribute        attr;
		size_t                  size;
		void                    *private;		
		ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t);		
		ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, char *, loff_t, size_t);		
		int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr, struct vm_area_struct *vma);
};	

#define BIN_ATTR(_name, _mode, _read, _write, _size) \
struct bin_attribute bin_attr_##_name = __BIN_ATTR(_name, _mode, _read, \
	_write, _size)
#define BIN_ATTR_RO(_name, _size) \
struct bin_attribute bin_attr_##_name = __BIN_ATTR_RO(_name, _size)
#define BIN_ATTR_WO(_name, _size) \
struct bin_attribute bin_attr_##_name = __BIN_ATTR_WO(_name, _size)
#define BIN_ATTR_RW(_name, _size) \
struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size) 

以一个可以进行二进制读写的BB节点为例:
在代码中需要如下定义:

BIN_ATTR_RW(BB, 0x400) 
#这样就已经定义好了名为 bin_attr_BB 的结构体对象
#同时也定义好了两个方法名称:BB_read()和BB_write()

在probe函数中调用创建函数:

err = device_create_bin_file(&client->dev, &bin_attr_BB);
if (err)
	......

然后实现BB_read()和BB_write()实体

static ssize_t BB_read(struct file *filp,
							struct kobject *kobj, struct bin_attribute *attr,
							char *buf, loff_t offset, size_t count)
{
	......
	......
	return count;
}

static ssize_t BB_write(struct file *filp,
							struct kobject *kobj, struct bin_attribute *attr,
							char *buf, loff_t offset, size_t count)
{
	......
	......
	return count;
}

sysfs_notify

如果内核想主动上报状态,可以使用sysfs_notify方法

#函数原型
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);

直接唤醒该字符串

sysfs_notify(&dev->client->dev.kobj, NULL, "AA");	

/sys/module中的parameter

可以用如下方式向模块中传入参数,例:

static bool xx;
#将模块外传进来的参数yy映射到代码中的xx变量,代码中使用xx进行操作
module_param_named(yy, xx, bool, 0644);		
#这句是对yy参数的描述,在#:modinfo mm.ko时,会打印出来,用来描述参数的作用等
MODULE_PARM_DESC(yy, "Force Off");

用户空间使用sysfs节点

比如:

#第一种
cat  AA			#会调用 AA_show() 方法
echo "xxx" > AA		#会调用 AA_store()方法

#第二种
int fd = open("BB", O_RDWR);
# offset = 1, size = 1
ret = pread(fd, readbuf, 1, 1);		#会调用 BB_read()方法,ret返回读取到的个数,readbuf中是读取到的值
# offset = 1, size = 1
ret = pwrite(fd, writebuf, 1, 1);		#会调用 BB_write()方法,ret返回写入的个数,writebuf中是待写入的值

#第三种
while(1) {
	err = epoll_wait(epfd, pEvent, 1, -1);	#sysfs_notify会唤醒epoll
	if(err) {
		ret = read(fd, read_value, 1);	#会调用 AA_show()
		write(fd, writebuf, sizeof(writebuf)); #会调用 AA_store() 
	}
}

sysfs节点创建原理

在这里插入图片描述

总结

以上只是我在项目中用到的基本内容,还有很多内容有待研究。
如果以上内容有哪些错误,请毫不犹豫的指正。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值