找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1757

积分

0

好友

263

主题
发表于 4 天前 | 查看: 2826| 回复: 0

一、sysfs到底是什么?

sysfs是 Linux 内核用于导出“设备对象模型”信息的一种可视化接口。

其本质是一个基于kobject机制、面向设备模型(device model),用于展示内核数据结构、并允许读写设备属性的虚拟文件系统。它的固定挂载点为 /sys。通过操作这个目录下的文件,用户空间程序可以与内核交互,查询或配置设备状态,这是Linux系统编程与驱动开发中的重要组成部分。

二、基于device创建sysfs节点

2.1 定义device_attribute

创建sysfs节点的核心是定义device_attribute结构。内核提供了便捷的宏DEVICE_ATTR

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

__ATTR宏在include/linux/sysfs.h中定义,它将参数组装成一个标准的attribute结构:

#define __ATTR(_name, _mode, _show, _store) {                \
    .attr = {.name = __stringify(_name),                \
    .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },        \
    .show    = _show,                        \
    .store    = _store,                        \
}

最终,struct device_attribute结构体(定义于include/linux/device.h)将attribute与读写函数绑定:

/* interface for exporting device attributes */
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);
};

其中的struct attribute(亦定义于include/linux/sysfs.h)则定义了属性节点的基本元信息:

struct attribute {
    const char        *name;
    umode_t            mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    bool ignore_lockdep:1;
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};

2.2 定义属性读写函数

.show.store成员是两个函数指针,需要驱动开发者实现。

show函数用于响应cat命令,向用户空间返回信息:

ssize_t (*show)(struct device *dev, struct device_attribute *attr,
        char *buf);
//入参buf是内核提供的缓冲区,用于填充要显示的内容。
//返回值应为填充的字节数,且总长度应小于PAGE_SIZE(通常4096字节)。
//dev和attr参数可用于获取特定设备或属性的上下文。

store函数用于响应echo命令,处理从用户空间传入的数据:

ssize_t (*store)(struct device *dev, struct device_attribute *attr,
          const char *buf, size_t count);
//入参buf是用户传入的字符串数据。
//入参count是buf中数据的长度。
//函数通常应返回成功处理的字节数(常直接返回count)。

理解并正确实现这两个回调函数是Linux内核驱动与用户空间进行数据交换的关键。

三、将device attribute添加到sysfs中

定义好属性结构后,需要将其与内核对象(kobject)关联,从而在/sys下创建出可见的文件节点。

3.1 创建单个节点:sysfs_create_file

对于单个属性节点,通常在驱动的probe函数或module_init中调用sysfs_create_file,在退出时调用sysfs_remove_file进行清理。

int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);

这里的kobj通常是&dev->kobj(设备对象的kobject)。

3.2 创建多个节点(推荐):sysfs_create_group

当需要创建多个相关属性时,使用属性组(attribute group)一次注册更为高效和整洁。

首先,定义多个DEVICE_ATTR,并将其指针放入一个数组中(数组必须以NULL结尾):

static DEVICE_ATTR(sys_device_file, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file0, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file1, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);
static DEVICE_ATTR(sys_device_file2, S_IWUSR | S_IRUSR, show_sys_device, store_sys_device);

static struct attribute *sys_device_attributes[] = {
    &dev_attr_sys_device_file.attr,
    &dev_attr_sys_device_file0.attr,
    &dev_attr_sys_device_file1.attr,
    &dev_attr_sys_device_file2.attr,
    NULL // 属性结构体数组最后一项必须以NULL结尾。
};

然后,将这些属性数组包装成一个attribute_group

static const struct attribute_group sys_device_attr_group = {
    .attrs = sys_device_attributes,
};

最后,使用sysfs_create_group一次性注册整个组,使用sysfs_remove_group进行移除:

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)

这种方法逻辑清晰,便于管理,是Linux系统驱动开发中的标准实践。




上一篇:嵌入式硬件工程师成长指南:从单片机、FPGA到SOPC的学习路线与实战经验
下一篇:设计模式核心思想全解:23种模式的通俗比喻与软件工程实战应用
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 19:22 , Processed in 0.270141 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表