linux sysfs的使用

打印 上一主题 下一主题

主题 1729|帖子 1729|积分 5187

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在Linux内核驱动开发中,device_create_file 和 device_remove_file 用于动态创建/删除设备的 sysfs 属性文件,常用于暴露设备信息或控制参数。以下是完整示例及详细阐明:

1. 头文件引入

  1. #include <linux/module.h>
  2. #include <linux/device.h>    // 设备模型相关
  3. #include <linux/slab.h>      // 内存分配
  4. #include <linux/string.h>    // 字符串操作
复制代码

2. 界说设备属性结构

2.1 声明设备属性和读写函数

  1. // 设备结构体
  2. struct my_device {
  3.     struct device *dev;    // 关联的内核设备对象
  4.     int status;            // 示例属性:设备状态(0=关闭,1=开启)
  5. };
  6. // 全局设备实例
  7. static struct my_device *my_dev;
  8. // sysfs属性读函数:显示status值
  9. static ssize_t show_status(struct device *dev,
  10.                           struct device_attribute *attr,
  11.                           char *buf) {
  12.     return scnprintf(buf, PAGE_SIZE, "%d\n", my_dev->status);
  13. }
  14. // sysfs属性写函数:设置status值
  15. static ssize_t store_status(struct device *dev,
  16.                            struct device_attribute *attr,
  17.                            const char *buf, size_t count) {
  18.     int val;
  19.     if (kstrtoint(buf, 10, &val) < 0)
  20.         return -EINVAL;
  21.    
  22.     my_dev->status = (val != 0) ? 1 : 0; // 仅允许0或1
  23.     return count;
  24. }
  25. // 定义设备属性宏(名称: status,权限: root可读写,其他用户只读)
  26. static DEVICE_ATTR(status, 0644, show_status, store_status);
复制代码

3. 模块初始化与退出

3.1 模块初始化(创建立备和属性)

  1. static int __init my_module_init(void) {
  2.     int ret;
  3.     // 1. 分配设备内存
  4.     my_dev = kzalloc(sizeof(*my_dev), GFP_KERNEL);
  5.     if (!my_dev)
  6.         return -ENOMEM;
  7.     // 2. 创建设备类(可选,用于sysfs层级管理)
  8.     static struct class *my_class = NULL;
  9.     my_class = class_create(THIS_MODULE, "my_device_class");
  10.     if (IS_ERR(my_class)) {
  11.         ret = PTR_ERR(my_class);
  12.         goto err_class;
  13.     }
  14.     // 3. 创建设备节点(关联到类)
  15.     my_dev->dev = device_create(my_class, NULL, MKDEV(0, 0), NULL, "mydev");
  16.     if (IS_ERR(my_dev->dev)) {
  17.         ret = PTR_ERR(my_dev->dev);
  18.         goto err_device;
  19.     }
  20.     // 4. 创建sysfs属性文件
  21.     ret = device_create_file(my_dev->dev, &dev_attr_status);
  22.     if (ret < 0)
  23.         goto err_attr;
  24.     // 初始化设备状态
  25.     my_dev->status = 0;
  26.     printk(KERN_INFO "Device and sysfs attribute created.\n");
  27.     return 0;
  28. // 错误处理(逆向释放资源)
  29. err_attr:
  30.     device_destroy(my_class, MKDEV(0, 0));
  31. err_device:
  32.     class_destroy(my_class);
  33. err_class:
  34.     kfree(my_dev);
  35.     return ret;
  36. }
复制代码
3.2 模块退出(删除属性和设备)

  1. static void __exit my_module_exit(void) {
  2.     // 1. 删除sysfs属性文件
  3.     device_remove_file(my_dev->dev, &dev_attr_status);
  4.     // 2. 销毁设备节点
  5.     device_destroy(my_class, MKDEV(0, 0));
  6.     // 3. 销毁设备类
  7.     class_destroy(my_class);
  8.     // 4. 释放设备内存
  9.     kfree(my_dev);
  10.     printk(KERN_INFO "Device and sysfs attribute removed.\n");
  11. }
  12. module_init(my_module_init);
  13. module_exit(my_module_exit);
  14. MODULE_LICENSE("GPL");
复制代码

4. 验证步调

4.1 编译加载模块

  1. make    # 根据Makefile编译模块
  2. insmod my_module.ko
复制代码
4.2 查看sysfs属性

  1. # 属性文件路径(根据设备名和类名)
  2. ls /sys/class/my_device_class/mydev/status
  3. # 读取属性值
  4. cat /sys/class/my_device_class/mydev/status  # 输出 0
  5. # 写入属性值
  6. echo 1 > /sys/class/my_device_class/mydev/status
  7. cat /sys/class/my_device_class/mydev/status  # 输出 1
复制代码
4.3 卸载模块

  1. rmmod my_module
复制代码

5. 关键注意事项


  • 设备注册次序
    确保先调用 device_create 创建立备节点,再调用 device_create_file,否则会因设备未注册而失败。
  • 错误处理
    全部内核资源分配(如 kzalloc, class_create)必须检查返回值,并实现逆向释放逻辑(如示例中的 goto 标签)。
  • 并发控制
    若属性可能被多线程访问,需使用锁(如 mutex)保护共享数据(例如 my_dev->status)。
  • 权限设置
    DEVICE_ATTR 的权限参数(如 0644)需合理设置,制止安全隐患。

6. 扩展场景

动态创建多个属性

  1. // 定义第二个属性(例如"version")
  2. static ssize_t show_version(...) { return scnprintf(buf, "1.0\n"); }
  3. static DEVICE_ATTR(version, 0444, show_version, NULL);
  4. // 在初始化函数中添加
  5. device_create_file(my_dev->dev, &dev_attr_version);
  6. // 在退出函数中删除
  7. device_remove_file(my_dev->dev, &dev_attr_version);
复制代码
使用属性组(简化管理)

  1. static struct attribute *my_attrs[] = {
  2.     &dev_attr_status.attr,
  3.     &dev_attr_version.attr,
  4.     NULL
  5. };
  6. ATTRIBUTE_GROUPS(my); // 定义属性组
  7. // 在class创建时指定默认属性组
  8. my_class = class_create(THIS_MODULE, "my_device_class");
  9. my_class->dev_groups = my_groups;
复制代码

通过上述代码,可以实现在内核驱动中动态管理 sysfs 属性文件,为用户空间提供机动的设备交互接口。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

我爱普洱茶

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表