Linux sysfs接口创建
本文只介绍/sys/class/目录下的节点创建,/sys/下其它目录的节点创建和用法不在本文讨论范围
目录
1. sysfs文件系统介绍
创建/sys节点之前,我们先了解一下sysfs文件系统存在的作用。在Linux内核中,sysfs(System Filesystem)是一个虚拟的文件系统,用于提供对内核和设备信息的动态访问。sysfs节点提供了一种将内核和设备的状态信息以文件和目录的形式呈现给用户空间的机制。简单点讲就是sysfs文件系统是为了方便user space和kernel space之间的一些简单信息交互而存在的,比如我想获取当前硬件的硬件版本,我就cat一下某个节点,这个节点就会返回当前硬件的版本信息(假设这个硬件版本信息是需要读取硬件上的某些状态获取)。
2. /sys/class/节点创建
- 用CLASS_ATTR_RW(…)宏定义节点读写函数的前缀名称
- 实现CLASS_ATTR_RW(…)宏定义节点读写函数的功能
- 用class_create(…)宏创建一个设备类
- 调用class_create_file(…)函数创建/sys/class/节点
2.1 示例代码
tips: 示例代码省去了错误检查,实际中需要加入错误检查。示例代码参照Linux5.15内核提供的api编写
#include <linux/device/class.h> //CLASS_ATTR_RW(...)
#include <linux/device.h> //class_create(...) class_create_file(...)
# define XXX_PATH_NAME "xxx"
/* 2.1 实现CLASS_ATTR_RW(...)宏定义节点读的函数的功能*/
/**
* @class: device class pointer
* @attr: device attribute pointer
* @buf: 返回给user space的内容
*/
static ssize_t sysfs_rw_show(struct class *class,
struct class_attribute *attr, char *buf)
{
...
/* 把想要给user space看到的内容存进buf形参里*/
return sprintf(buf, <返回想给user space读取到的内容>);
}
/* 2.2 实现CLASS_ATTR_RW(...)宏定义节点写的函数的功能*/
/**
* @class: device class pointer
* @attr: device attribute pointer
* @buf: user space传入的内容
* @count: @buf 缓冲区中的字节数
*/
static ssize_t sysfs_rw_store(struct class *class,
struct class_attribute *attr, char *buf)
{
...
/*获取用户空间传入的内容*/
...
return count;
}
/*1. 定义节点读写函数的前缀名称*/
CLASS_ATTR_RW(sysfs_rw);
//传递给宏的内容决定了节点的名字、节点读写函数的前缀名称和定义了
//struct class_attribute的后缀名
static int xxx_probe(struct platform_device *pdev)
{
...
struct class *xxx_class = NULL;
...
/*3. 创建一个设备类*/
xxx_class = class_create(THIS_MODULE, XXX_PATH_NAME);
/*4. 创建/sys/class/节点; 节点路径为/sys/class/xxx/sysfs_rw*/
class_create_file(xxx_class, &class_attr_sysfs_rw);
}
remove只需要做和probe相反的操作即可;如果你看完还有点懵,可能是第一步使用的宏,定义的东西太多了,CLASS_ATTR_RW(…) 宏展开来是这样的
CLASS_ATTR_RW(xxx); <<-- xxx代表你想要的节点名字,可以任意字符内容
||
||
\/
struct class_attribute class_attr_xxx = <<--xxx是宏定义的括号里的内容
{
.attr = {
.name = "xxx", <<--这里就是宏定义的括号里的内容,你想要的节点名字
.mode = VERIFY_OCTAL_PERMISSIONS((S_IWUSR | S_IRUGO))
},
.show = xxx_show, <<--xxx也是宏定义括号里的内容,根据你括号里的内容而变
.store = xxx_store <<--xxx也是宏定义括号里的内容,根据你括号里的内容而变
};
tips: 如果只需要用到只读或者只写的节点,第一步里的宏可以根据需要更换成CLASS_ATTR_RO()/CLASS_ATTR_WO()宏,然后省去对应的读/写函数实现即可