当前位置: 首页 > news >正文

linux中sysfs创建设备节点的方法和DEVICE_ATTR

使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,使用函数sysfs_create_group或sysfs_create_file便可以在设备目录下创建具有show和store方法的节点。能方便的进行调试。

一、使用DEVICE_ATTR构建device attribute

下面将顺着我们直接使用的DEVICE_ATTR来分析一下,这个宏究竟都做了哪些事情。

 DEVICE_ATTR的定义:

1

2

#define DEVICE_ATTR(_name, _mode, _show, _store) \

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

 而__ATTR宏的定义在include/linux/sysfs.h文件中,如下:

1

2

3

4

5

6

#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,其定义如下:

1

2

3

4

5

6

7

8

/* 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/device.h中,如下:

1

2

3

4

5

6

7

8

9

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

};

 总结一下:

DEVICE_ATTR(_name, _mode, _show, _store)等价于:

1

2

3

4

5

6

struct device_attribute dev_attr_##_name = {

    .attr = {.name = __stringify(_name),

             .mode = VERIFY_OCTAL_PERMISSIONS(_mode)},

    .show = _show,

    .store = _store,

}

 其中:.show和.store的类型定义如下:

 show函数的详细描述:

1

2

ssize_t (*show)(struct device *dev, struct device_attribute *attr,

        char *buf);

  •  入参buf是需要我们填充的string即我们cat属性节点时要显示的内容;
  • 函数的返回值是我们填充buf的长度,且长度应当小于一个页面的大小(4096字节);
  • 其他参数一般不用关心。

例如:

1

2

3

4

5

static ssize_t show_my_device(struct device *dev,

                              struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数

{

    return sprintf(buf, "%s\n", mybuf);

}

store函数的详细描述:

1

2

ssize_t (*store)(struct device *dev, struct device_attribute *attr,

          const char *buf, size_t count);

  •  入参buf是用户传入的字符串,即echo到属性节点的内容;
  • 入参count是buf中字符串的长度。
  • 函数的返回值通常返回count即可。
  • 其他参数一般不用关心。

例如:

1

2

3

4

5

6

7

static ssize_t store_my_device(struct device *dev,

                             struct device_attribute *attr,

                             const char *buf, size_t count) //echo命令时,将会调用该函数

{

    sprintf(mybuf, "%s", buf);

    return count;

}

mode的权限定义在kernel/include/uapi/linux/stat.h中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

#define S_IRWXU 00700 //用户可读写和执行

#define S_IRUSR 00400//用户可读

#define S_IWUSR 00200//用户可写

#define S_IXUSR 00100//用户可执行

#define S_IRWXG 00070//用户组可读写和执行

#define S_IRGRP 00040//用户组可读

#define S_IWGRP 00020//用户组可写

#define S_IXGRP 00010//用户组可执行

#define S_IRWXO 00007//其他可读写和执行

#define S_IROTH 00004//其他可读

#define S_IWOTH 00002//其他可写

#define S_IXOTH 00001//其他可执行

  至此,我们已经定义好了.show和.store函数,那么就可以使用DEVICE_ATTR了。

1

static DEVICE_ATTR(my_device_test, S_IWUSR | S_IRUSR, show_my_device, store_my_device);

二、将device attribute添加到sysfs中

上面我们已经创建好了所需要的device attribute,下面就要将这些attribute添加到sysfs中了,此处可用的函数由sysfs_create_file和sysfs_create_group。

1、只有一个节点的创建sysfs_create_file

此处在驱动的probe或module_init函数调用sysfs_create_file即可,在module_exit或remove函数中调用sysfs_remove_file来移除节点。

1

2

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

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

以下是全部的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

#include <linux/module.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/gpio.h>

#include <linux/delay.h>

static char sysfs_buff[100] = "my_sysfs_test_string";

static ssize_t show_sys_device(struct device *dev,

                              struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数

{

    return sprintf(buf, "%s\n", sysfs_buff);

}

static ssize_t store_sys_device(struct device *dev,

                             struct device_attribute *attr,

                             const char *buf, size_t count) //echo命令时,将会调用该函数

{

    sprintf(sysfs_buff, "%s", buf);

    return count;

}

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

//定义一个名字为sys_device_file的设备属性文件

struct file_operations mytest_ops = {

    .owner = THIS_MODULE,

};

static int major;

static struct class *cls;

struct device *mydev;

static int mytest_init(void)

{

     

    major = register_chrdev(0, "mytest", &mytest_ops);

    cls = class_create(THIS_MODULE, "mytest_class");

    mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //创建mytest_device设备

    if (sysfs_create_file(&(mydev->kobj), &dev_attr_sys_device_file.attr))

    //在mytest_device设备目录下创建一个sys_device_file属性文件

        return -1;

    }

    return 0;

}

static void mytest_exit(void)

{

    device_destroy(cls, MKDEV(major, 0));

    class_destroy(cls);

    unregister_chrdev(major, "mytest");

    sysfs_remove_file(&(mydev->kobj), &dev_attr_sys_device_file.attr);

}

module_init(mytest_init);

module_exit(mytest_exit);

MODULE_LICENSE("GPL");

2、多个节点的创建sysfs_create_group

 定义attribute属性结构体数组到属性组中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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结尾。

};

static const struct attribute_group sys_device_attr_group = {

    .attrs = sys_device_attributes,

};

 下面就可以利用sysfs_create_group和sysfs_create_group来添加、移除属性节点组了。

定义如下:

1

2

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

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

全部代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

#include <linux/module.h>

#include <linux/init.h>

#include <linux/platform_device.h>

#include <linux/gpio.h>

#include <linux/delay.h>

static char sysfs_buff[100] = "my_sysfs_test_string";

static ssize_t show_sys_device(struct device *dev,

                              struct device_attribute *attr, char *buf) //cat命令时,将会调用该函数

{

    return sprintf(buf, "%s\n", sysfs_buff);

}

static ssize_t store_sys_device(struct device *dev,

                             struct device_attribute *attr,

                             const char *buf, size_t count) //echo命令时,将会调用该函数

{

    sprintf(sysfs_buff, "%s", buf);

    return count;

}

//定义多个sys_device_file的设备属性文件

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结尾。

};

static const struct attribute_group sys_device_attr_group = {

    .attrs = sys_device_attributes,

};

struct file_operations mytest_ops = {

    .owner = THIS_MODULE,

};

static int major;

static struct class *cls;

struct device *mydev;

static int mytest_init(void)

{

     

    major = register_chrdev(0, "mytest", &mytest_ops);

    cls = class_create(THIS_MODULE, "mytest_class");

    mydev = device_create(cls, 0, MKDEV(major, 0), NULL, "mytest_device"); //创建mytest_device设备

    if (sysfs_create_group(&(mydev->kobj), &sys_device_attr_group))

    {

        //在mytest_device设备目录下创建多个sys_device_file属性文件

        return -1;

    }

    return 0;

}

static void mytest_exit(void)

{

    device_destroy(cls, MKDEV(major, 0));

    class_destroy(cls);

    unregister_chrdev(major, "mytest");

    sysfs_remove_group(&(mydev->kobj), &sys_device_attr_group);

}

module_init(mytest_init);

module_exit(mytest_exit);

MODULE_LICENSE("GPL");

相关文章:

  • Linux安装刻录软件
  • SpringBoot前置知识01-SPI接口
  • 谓词逻辑(一)
  • Vue3:可以使用.value获取ref()包裹的值,为何还要存在unref()
  • 基于Vue3 + js-tool-big-box工具库实现3个随机数字的小游戏动画,快来挑战你的非凡手气!
  • 列表的创建和删除
  • 别说废话!说话说到点上,项目高效沟通的底层逻辑揭秘
  • 。。。。。
  • 面试八股之MySQL篇2——索引篇
  • 31.@Anonymous
  • 运行Android项目时,提示错误: 程序包javax.annotation.processing不存在
  • PersonalLLM——探索LLM是否能根据五大人格特质重新塑造一个新的角色?
  • 组播协议简介
  • javascript --对象构造器和class的区别
  • maven的tomcat运行不起来的解决方案
  • 《Java编程思想》读书笔记-对象导论
  • 【css3】浏览器内核及其兼容性
  • 【RocksDB】TransactionDB源码分析
  • 【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • JavaScript 基础知识 - 入门篇(一)
  • JavaScript对象详解
  • JavaScript设计模式之工厂模式
  • Logstash 参考指南(目录)
  • PaddlePaddle-GitHub的正确打开姿势
  • Python - 闭包Closure
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • WebSocket使用
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 解析 Webpack中import、require、按需加载的执行过程
  • 如何实现 font-size 的响应式
  • 学习JavaScript数据结构与算法 — 树
  • 关于Android全面屏虚拟导航栏的适配总结
  • 函数计算新功能-----支持C#函数
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • (52)只出现一次的数字III
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (生成器)yield与(迭代器)generator
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)EOS中账户、钱包和密钥的关系
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)Oracle存储过程编写经验和优化措施
  • ../depcomp: line 571: exec: g++: not found
  • .net 8 发布了,试下微软最近强推的MAUI
  • .net web项目 调用webService
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 材料检测系统崩溃分析
  • .NET 分布式技术比较
  • .NET 回调、接口回调、 委托
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .xml 下拉列表_RecyclerView嵌套recyclerview实现二级下拉列表,包含自定义IOS对话框...