16、在总线目录下创建属性文件 *
在总线目录中创建属性文件可以扩展其功能。通过这些文件,我们能为总线添加额外信息和控制选项,方便设备和驱动使用。例如,可以读取总线状态、设置参数或完成其他操作。
一、总线下创建属性 API 函数
bus_create_file() 函数用于在总线的 sysfs 目录下创建一个属性文件。
C
int bus_create_file(struct bus_type *bus, struct kobject *kobj, const struct attribute *attr);
1
函数参数说明:
- bus:指向总线类型的指针(struct bus_type),表示要操作的总线类型
- kobj:指向内核对象的指针(struct kobject),表示要创建属性文件的位置
- attr:指向属性描述的指针(struct attribute),定义属性文件的元数据信息
返回值: 成功返回0,失败返回负数的错误码
使用前提: 在调用该函数前,必须先做好以下准备:
定义好属性结构体(struct attribute)
必须填写两个关键字段:
- 名称(name):属性文件的显示名称
- 权限(mode):设置文件的读写权限(如0644代表可读可写)
简单来说,这个函数的作用就是在指定的内核对象下,为特定总线类型创建一个属性文件。就像在文件系统里创建一个特殊文件一样,需要先定义好这个文件的名字和访问权限。
C
struct bus_attribute mybus_attr = {
.attr = {
.name = "value",
.mode = 0664,
},
.show = mybus_show,
};
ret = bus_create_file(&mybus, &mydevice.kobj, &mybus_attr.attr);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
上述示例代码创建了一个名为 "value" 的属性文件, 并指定了访问权限为 0664。 在创建属性文件时, 还可以指定其他属性的回调函数, 如 .show、 .store 等, 以实现对属性值的读取和写入操作。
请注意, 在使用 bus_create_file() 函数之前, 需要确保总线对象和内核对象已正确初始化和注册。
二、实验
定义了一个名为 "mybus" 的总线, 并实现了总线的匹配回调函数mybus_match 和设备探测回调函数 mybus_probe。 同时, 还定义了一个名为 "value" 的属性文件, 并实现了属性的显示回调函数 mybus_show。 编写完成的 bus.c 代码如下所示:
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/device.h>
#include <linux/sysfs.h>
int mybus_match(struct device *dev, struct device_driver *drv)
{
// 检查设备名称和驱动程序名称是否匹配
return (strcmp(dev_name(dev), drv->name) == 0);
};
int mybus_probe(struct device *dev)
{
struct device_driver *drv = dev->driver;
if (drv->probe)
drv->probe(dev);
return 0;
};
struct bus_type mybus = {
.name = "mybus", // 总线的名称
.match = mybus_match, // 设备和驱动程序匹配的回调函数
.probe = mybus_probe, // 设备探测的回调函数
};
EXPORT_SYMBOL_GPL(mybus); // 导出总线符号
ssize_t mybus_show(struct bus_type *bus, char *buf)
{
// 在 sysfs 中显示总线的值
return sprintf(buf, "%s\n", "mybus_show");
};
struct bus_attribute mybus_attr = {
.attr = {
.name = "value", // 属性的名称
.mode = 0664, // 属性的访问权限
},
.show = mybus_show, // 属性的 show 回调函数
};
// 模块的初始化函数
static int bus_init(void)
{
int ret;
ret = bus_register(&mybus); // 注册总线
ret = bus_create_file(&mybus, &mybus_attr); // 在 sysfs 中创建属性文件
return 0;
}
// 模块退出函数
static void bus_exit(void)
{
bus_remove_file(&mybus, &mybus_attr); // 从 sysfs 中移除属性文件
bus_unregister(&mybus); // 取消注册总线
}
module_init(bus_init); // 指定模块的初始化函数
module_exit(bus_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
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