Sysfs属性控制

为驱动创建自定义的 sysfs 属性文件,实现读写回调

什么是Sysfs?

Sysfs是一个虚拟文件系统,它提供了内核对象、设备、驱动和模块的信息。通过Sysfs,用户空间可以与内核空间进行交互,读取或设置驱动参数。

用户空间 应用程序 内核空间 设备驱动 Sysfs交互

为什么需要自定义Sysfs属性?

创建Sysfs属性的基本步骤

  1. 定义属性文件
  2. 实现show和store回调函数
  3. 将属性添加到设备或驱动中
  4. 在适当的时候创建和删除属性文件

属性回调函数示例

下面是一个简单的示例,展示如何创建具有读写功能的sysfs属性:

#include <linux/device.h>
#include <linux/sysfs.h>

static int my_value = 0;

// 读取回调函数
static ssize_t my_value_show(struct device *dev, 
                            struct device_attribute *attr, 
                            char *buf)
{
    return sprintf(buf, "%d\n", my_value);
}

// 写入回调函数
static ssize_t my_value_store(struct device *dev,
                             struct device_attribute *attr,
                             const char *buf, size_t count)
{
    int ret;
    ret = kstrtoint(buf, 10, &my_value);
    if (ret < 0)
        return ret;
    return count;
}

// 定义设备属性
static DEVICE_ATTR_RW(my_value);

属性创建和删除

在驱动探测函数中创建属性文件,在移除函数中删除它:

static int my_driver_probe(struct device *dev)
{
    int err;
    // 创建属性文件
    err = device_create_file(dev, &dev_attr_my_value);
    if (err) {
        dev_err(dev, "无法创建sysfs属性\n");
        return err;
    }
    return 0;
}

static void my_driver_remove(struct device *dev)
{
    // 删除属性文件
    device_remove_file(dev, &dev_attr_my_value);
}

Sysfs属性类型

属性类型 宏定义 描述
只读 DEVICE_ATTR_RO 只能读取的属性
只写 DEVICE_ATTR_WO 只能写入的属性
读写 DEVICE_ATTR_RW 可读可写的属性

Sysfs属性架构

Sysfs属性架构图 设备驱动 属性结构体 回调函数 Sysfs文件系统 用户空间

最佳实践和注意事项

提示: 确保属性操作是线程安全的,特别是在多处理器系统中。

注意: 不要在show和store函数中执行耗时操作,这会阻塞用户空间进程。

完整示例代码

下面是一个完整的驱动示例,展示了如何创建和使用sysfs属性:

#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>

static struct kobject *example_kobj;
static int example_value = 100;

static ssize_t example_show(struct kobject *kobj, 
                           struct kobj_attribute *attr,
                           char *buf)
{
    return sprintf(buf, "%d\n", example_value);
}

static ssize_t example_store(struct kobject *kobj,
                            struct kobj_attribute *attr,
                            const char *buf, size_t count)
{
    int ret;
    ret = kstrtoint(buf, 10, &example_value);
    if (ret < 0)
        return ret;
    return count;
}

static struct kobj_attribute example_attr = 
    __ATTR(example_value, 0664, example_show, example_store);

static int __init example_init(void)
{
    int ret;
    example_kobj = kobject_create_and_add("example", kernel_kobj);
    if (!example_kobj)
        return -ENOMEM;
        
    ret = sysfs_create_file(example_kobj, &example_attr.attr);
    if (ret)
        kobject_put(example_kobj);
        
    return ret;
}

static void __exit example_exit(void)
{
    kobject_put(example_kobj);
}

module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");