我们创建了一个属性文件,但是在情况中,我们可能需要创建 N 个属性文件。
一、sysfs_create_group 函数
sysfs_create_group 函数的作用是:在系统文件系统(sysfs)中创建一个文件组,把相关的配置或状态文件集中到一个目录下,方便统一管理和查看。
文件位置
/include/linux/sysfs.h
c
int __must_check sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);1
2
2
这个函数需要两个参数:
- 第一个参数 kobj:指向你要绑定属性组的内核对象的指针。
- 第二个参数 grp:指向属性组的指针,这个结构体里包含了要创建的所有属性文件列表。
attribute_group 结构体的作用是:它是一个容器,里面列出了所有要生成的属性文件(比如 sysfs 中的文件),方便一次性将这些属性关联到指定的内核对象上。
c
/**
* struct attribute_group - data structure used to declare an attribute group.
* @name: Optional: Attribute group name
* If specified, the attribute group will be created in
* a new subdirectory with this name.
* @is_visible: Optional: Function to return permissions associated with an
* attribute of the group. Will be called repeatedly for each
* non-binary attribute in the group. Only read/write
* permissions as well as SYSFS_PREALLOC are accepted. Must
* return 0 if an attribute is not visible. The returned value
* will replace static permissions defined in struct attribute.
* @is_bin_visible:
* Optional: Function to return permissions associated with a
* binary attribute of the group. Will be called repeatedly
* for each binary attribute in the group. Only read/write
* permissions as well as SYSFS_PREALLOC are accepted. Must
* return 0 if a binary attribute is not visible. The returned
* value will replace static permissions defined in
* struct bin_attribute.
* @attrs: Pointer to NULL terminated list of attributes.
* @bin_attrs: Pointer to NULL terminated list of binary attributes.
* Either attrs or bin_attrs or both must be provided.
*/
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
umode_t (*is_bin_visible)(struct kobject *,
struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};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
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
这个结构体包含三个主要部分:
- 名称(name):组的名字,用来创建对应的 sysfs 文件夹。
- 属性列表(attrs):指向一组属性文件的位置列表。
- 可见性检查(is_visible):可选的判断函数,用来决定是否显示每个属性文件。如果没设置这个函数(设为 NULL),所有属性文件都会默认显示。
attrs 详细说明
属性文件数组就是一串指向属性结构体(struct attribute)的指针列表,最后一个位置放 NULL 表示结束。每个结构体对应一个属性文件。
要将某个属性对象(比如 struct kobject_attribute)的 .attr 成员加入数组,只需要:
- 用
&符号获取该成员的内存地址 - 把这个地址存进数组里
这样数组就按顺序存放了所有属性的指针,最后用 NULL 标记结尾。
案例:
下面展示使用 sysfs_create_group 创建一个组并添加属性文件:
c
struct attribute *attrs[] = {
&attr1.attr,
&attr2.attr,
NULL,
};
const struct attribute_group attr_group = {
.name = "my_group",
.attrs = attrs,
};
sysfs_create_group(kobj, &attr_group);1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在上述示例中,我们创建了一个名叫 "my_group" 的组,并将属性文件 attr1 和 attr2 添加到该组中,然后使用 sysfs_create_group 将该组添加到指定的 kobject kobj 中。接下来我们开始做实验。
二、实验
源代码下载
bash
git clone git@gitee.com:yangxuesong314/linux-driver.git1
- 若之前已 git 拉取代码可以忽略
- 代码位于:
linux-driver/02.Linux设备模型/05.创建多个属性文件
c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 自定义的 kobject 结构体,包含一个 kobject 对象和两个整型值
struct mykobj
{
struct kobject kobj;
int value1;
int value2;
};
// 定义了 mykobj 结构体指针变量 mykobject01
struct mykobj *mykobject01;
// 自定义的 kobject 释放函数
static void dynamic_kobj_release(struct kobject *kobj)
{
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
printk("kobject: (%p): %s\n", kobj, __func__);
kfree(mykobject01);
}
// 自定义的 attribute 对象 value1 和 value2
struct attribute value1 = {
.name = "value1",
.mode = 0666,
};
struct attribute value2 = {
.name = "value2",
.mode = 0666,
};
// 将 attribute 对象放入数组中
struct attribute *myattr[] = {
&value1,
&value2,
NULL,
};
// 自定义的 show 函数,用于读取属性值
ssize_t myshow(struct kobject *kobj, struct attribute *attr, char *buf)
{
ssize_t count;
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
if (strcmp(attr->name, "value1") == 0)
{
count = sprintf(buf, "%d\n", mykobject01->value1);
}
else if (strcmp(attr->name, "value2") == 0)
{
count = sprintf(buf, "%d\n", mykobject01->value2);
}
else
{
count = 0;
}
return count;
}
// 自定义的 store 函数,用于写入属性值
ssize_t mystore(struct kobject *kobj, struct attribute *attr, const char *buf, size_t size)
{
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
if (strcmp(attr->name, "value1") == 0)
{
sscanf(buf, "%d\n", &mykobject01->value1);
}
else if (strcmp(attr->name, "value2") == 0)
{
sscanf(buf, "%d\n", &mykobject01->value2);
}
return size;
}
// 自定义的 sysfs_ops 结构体,包含 show 和 store 函数指针
struct sysfs_ops myops = {
.show = myshow,
.store = mystore,
};
// 自定义的 kobj_type 结构体,包含释放函数、默认属性和 sysfs_ops
static struct kobj_type mytype = {
.release = dynamic_kobj_release,
.default_attrs = myattr,
.sysfs_ops = &myops,
};
// 模块的初始化函数
static int mykobj_init(void)
{
int ret;
// 分配并初始化 mykobject01
mykobject01 = kzalloc(sizeof(struct mykobj), GFP_KERNEL);
mykobject01->value1 = 1;
mykobject01->value2 = 1;
// 初始化并添加 mykobject01 到内核中,名为 "mykobject01"
ret = kobject_init_and_add(&mykobject01->kobj, &mytype, NULL, "%s", "mykobject01");
return 0;
}
// 模块的退出函数
static void mykobj_exit(void)
{
// 释放 mykobject01
kobject_put(&mykobject01->kobj);
}
module_init(mykobj_init); // 指定模块的初始化函数
module_exit(mykobj_exit); // 指定模块的退出函数
MODULE_LICENSE("GPL"); // 模块使用的许可证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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
实验:
bash
insmod attr.ko1
驱动加载成功之后,进入 cd /sys/ 目录下,如果实验成功可以看到创建生成的 mykobject01 以及属性组 myattr 和属性组中的属性 value1、value2:
bash
ls /sys/mykobject01/myattr/1
