1 概念

总线是设备模型当中的基础组件,简化了驱动的编写和维护,总线可以是物理总线(如PCI,USB)或虚拟总线.

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
struct bus_type {
const char *name; // 总线类型名称
const char *dev_name;
// 老版本内核这里可能不一样
const struct attribute_group **bus_groups; // 总线属性
const struct attribute_group **dev_groups; // 设备属性
const struct attribute_group **drv_groups; // 驱动属性

int (*match)(struct device *dev, const struct device_driver *drv); // 匹配检查
int (*uevent)(const struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
void (*sync_state)(struct device *dev);
void (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
const struct cpumask *(*irq_get_affinity)(struct device *dev,
unsigned int irq_vec);

int (*online)(struct device *dev);
int (*offline)(struct device *dev);

int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);

int (*num_vf)(struct device *dev);

int (*dma_configure)(struct device *dev);
void (*dma_cleanup)(struct device *dev);

const struct dev_pm_ops *pm;
// 这里之前存在 struct subsys_private *p
// p 属于 bus 的实现细节,不应该暴露在公共的 bus_type 结构里.
// 把它从 bus_type 里移走,放进 bus.c 的实现文件中,用 私有封装管理.

bool need_parent_lock;
};

struct subsys_private {
struct kset subsys; // 总线在内核的表示
struct kset *devices_kset; // 属于总线的 device 的 kset
struct list_head interfaces;
struct mutex mutex;

struct kset *drivers_kset; // 属于总线的 driver 的 kset
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
const struct bus_type *bus;
struct device *dev_root;

struct kset glue_dirs;
const struct class *class;

struct lock_class_key lock_key;
};

我们可以看看每个 /sys/bus 的结构.

1
2
$ ls /sys/bus/gpio/
devices drivers drivers_autoprobe drivers_probe uevent

2 bus 的注册

我们看看 bus 注册的过程, bus_register.

1
2
3
4
5
6
7
8
9
bus_register
|-kzalloc => subsys_private 空间
|-kobject_set_name => 设置 bus 名到 kobj
|-kset_register => 在 /sys/bus/ 下创建 kobj 目录及其 attribute 文件
|-bus_create_file => 创建 uevent 文件
|-kset_create_and_add => 创建 /sys/bus/xxx/devices 文件
|-kset_create_and_add => 创建 /sys/bus/xxx/drivers 文件
|-add_probe_files => 创建 drivers_probe 和 drivers_autoprobe 文件
|-sysfs_create_groups => 创建 bus->bus_group 属性文件
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
int bus_register(const struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
struct kobject *bus_kobj;
struct lock_class_key *key;

priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); // kzalloc
if (!priv)
return -ENOMEM;

priv->bus = bus;

BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

bus_kobj = &priv->subsys.kobj;
retval = kobject_set_name(bus_kobj, "%s", bus->name); // kobject_set_name
if (retval)
goto out;

bus_kobj->kset = bus_kset;
bus_kobj->ktype = &bus_ktype;
priv->drivers_autoprobe = 1;

retval = kset_register(&priv->subsys); // kset_register
if (retval)
goto out;

retval = bus_create_file(bus, &bus_attr_uevent); // bus_create_file
if (retval)
goto bus_uevent_fail;

priv->devices_kset = kset_create_and_add("devices", NULL, bus_kobj); // kset_create_and_add 1
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}

priv->drivers_kset = kset_create_and_add("drivers", NULL, bus_kobj); // kset_create_and_add 2
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}

INIT_LIST_HEAD(&priv->interfaces);
key = &priv->lock_key;
lockdep_register_key(key);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);

retval = add_probe_files(bus); // add_probe_files
if (retval)
goto bus_probe_files_fail;

retval = sysfs_create_groups(bus_kobj, bus->bus_groups); // sysfs_create_groups
if (retval)
goto bus_groups_fail;

pr_debug("bus: '%s': registered\n", bus->name);
return 0;

bus_groups_fail:
remove_probe_files(bus);
bus_probe_files_fail:
kset_unregister(priv->drivers_kset);
bus_drivers_fail:
kset_unregister(priv->devices_kset);
bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
kset_unregister(&priv->subsys);
/* Above kset_unregister() will kfree @priv */
priv = NULL;
out:
kfree(priv);
return retval;
}

之后观察如何在 /sys/bus/xxx 下创建一个文件, 创建路径为:

1
/sys/bus/<bus_name>/<attr->attr.name>