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");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/633045.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SD-WAN EVPN基本原理

SD-WAN EVPN是一种用于Overlay业务网络和底层传输网络分离以及业务网络路由和传输网络路由分离的VPN技术。SD-WAN EVPN技术采用类似于BGP/MPLS IP VPN的机制&#xff0c;通过扩展BGP协议&#xff0c;使用扩展后的可达性信息&#xff0c;使不同站点的底层传输网络互通&#xff0…

【NumPy】关于numpy.loadtxt()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

微服务如何做好监控

大家好&#xff0c;我是苍何。 在脉脉上看到这条帖子&#xff0c;说阿里 P8 因为上面 P9 斗争失败走人&#xff0c;以超龄 35 被裁&#xff0c;Boss 上找工作半年&#xff0c;到现在还处于失业中。 看了下沟通记录&#xff0c; 沟通了 1000 多次&#xff0c;但没有一个邀请投递…

MySQL-笔记-02.关系模型基本理论

目录 2.1 关系模型 2.1.1 基本概念 2.1.2 关系的完整性 1 实体完整性 2 参照完整性 3 用户定义完整性 2.2 关系代数 2.2.1 传统的集合运算 1 并运算 2 交运算 3 差运算 4 ​​笛卡尔积​编辑 2.2.2 专门的关系运算 1 选择 2 投影 3 连接 &#xff08;1&#xff09;等…

活动预告|来 GIAC 大会听大数据降本利器:AutoMQ 基于云原生重新设计的 Kafka

GIAC大会 2024年5月24日至25日&#xff0c;2024 全球互联网架构大会&#xff08;简称&#xff1a;GIAC大会&#xff09;将于深圳华侨城洲际酒店举行。大会将聚焦互联网架构热门的 AIGC、效能提升、 云原生架构、数据智能、新硬件等领域&#xff0c;甄选前沿的有典型代表性的技…

“手撕”String类+练习题

目录 一、什么是String类 二、String类的使用 三、String类的字符串操作 String对象的比较 字符串的查找 字符串的转换 字符串的替换 字符串的拆分 字符串的截取 大小写和去空格方法 四、字符串的不可变性 五、字符串的修改 六、StringBuilder类和StringBuffer类…

正确可用--Notepad++批量转换文件编码为UTF8

参考了:Notepad批量转换文件编码为UTF8_怎么批量把ansi转成utf8-CSDN博客​​​​​​https://blog.csdn.net/wangmy1988/article/details/118698647我参考了它的教程,但是py脚本写的不对. 只能改一个.不能实现批量更改. 他的操作步骤没问题,就是把脚本代码换成我这个. #-*-…

解锁创意新境界:StartAI插件让Photoshop飞起来!

Photoshop AI插件的革命性突破&#xff1a;StartAI插件的全面体验 作为一名AIGC测评博主&#xff0c;我一直在寻找能够提升设计效率和创意表现的工具。今天&#xff0c;我将带大家深入了解一款令人兴奋的Photoshop AI插件——StartAI&#xff0c;它不仅为设计师带来了前所未有…

新零售数据中台:构建零售业高效率、智能化的数据处理平台_光点科技

随着互联网技术的快速发展和移动支付、大数据等技术的广泛应用&#xff0c;零售行业已经逐渐从传统零售向新零售模式转变。在这个变革的时代背景下&#xff0c;新零售数据中台应运而生&#xff0c;它作为零售行业数据资源的整合与智能分析的核心载体&#xff0c;成为推动零售行…

C语言-----数据存储

# define _CRT_SECURE_NO_WARNINGS # include<stdio.h>int main(void) {char a -1;signed char b -1;unsigned char c -1;printf("a%d,b%d,c%d", a, b, c); //a-1,b-1,c255 }

Google发布的CAT3D,在1分钟内,能够从任意数量的真实或生成的图像创建3D场景。

给定任意数量的输入图像&#xff0c;使用以这些图像为条件的多视图扩散模型来生成场景的新视图。生成的视图被输入到强大的 3D 重建管道&#xff0c;生成可以交互渲染的 3D 表示。总处理时间&#xff08;包括视图生成和 3D 重建&#xff09;仅需一分钟。 相关链接 论文&#x…

Redis主从、哨兵、集群讲解

一、Redis主从 大家在面试中可能经常会被问到Redis的高可用问题。Redis高可用回答包括两个层面&#xff0c;一个就是数据不能丢失&#xff0c;或者说尽量减少丢失 ;另外一个就是保证Redis服务不中断 。 对于尽量减少数据丢失&#xff0c;可以通过AOF和RDB保证。 对于保证服务…

ROS | 用C++和python实现运动控制功能

基础知识&#xff1a; 用C实现&#xff1a; C代码&#xff1a; 用python实现&#xff1a; Python代码&#xff1a;

Git学习和使用指南详细篇

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【源码】二开版发卡自助下单授权DU系统/发卡秒u系统//完整总代理+子代理系统/支付模板全部优化授权

测试环境&#xff1a;宝塔、Linux系统、PHP7.4、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态thinkPHP&#xff0c;开启SSL 和前面发的那一套不一样哈&#xff0c;这套是新的后端&#xff0c;然后用了前面那一套的前端支付授权模板&#xff0c;总之改了很多东西&#…

逻辑漏洞靶场通关

会员中心注册新用户test&#xff0c;密码123123 会员中心注册新用户name&#xff0c;密码abcabc 管理员账号admin&#xff0c;密码123456 1.普通账号间水平越权漏洞测试 一个网站登录普通账号test后修改信息时进行抓包 在重发器中修改普通账号test为普通账号name&#xff0c;并…

Win11系统CMD乱码

1. 背景 在打包前端代码的时候&#xff0c;看到系统控制台中竟然出现了乱码。想到之前就曾经出现过因为影响不大就一直放着没管。今天有空就把问题解决掉吧。 2. 解决过程 2.1 问题定位 在命令行中执行 chcp&#xff0c;看到返回结果如下 Active code page: 936936 代表的…

报名开启!2024 开源之夏丨Serverless Devs 课题已上线!

Serverless 是近年来云计算领域热门话题&#xff0c;凭借极致弹性、按量付费、降本提效等众多优势受到很多人的追捧&#xff0c;各云厂商也在不断地布局 Serverless 领域。 Serverless Devs 是一个由阿里巴巴发起的 Serverless 领域的开源项目&#xff0c;其目的是要和开发者们…

Sketch v100 for Mac 安装教程【支持M芯片】

Sketch v100 for Mac 安装教程【支持M芯片】 原文地址&#xff1a;https://blog.csdn.net/weixin_48311847/article/details/139104315

【技术实操】中标麒麟高级服务器操作系统实例分享,rsync数据同步配置方案

1.rsync介绍 rsync是一款开源的、快速的、多功能的、可实现全量及增量的本地或远程数据同步备份工具。 在守护进程模式&#xff08;daemon mode&#xff09;下&#xff0c;rsync默认监听TCP端口873&#xff0c;以原生rsync传输协议或者通过远程shell如RSH或者SSH提供文件。SS…