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

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值