linux内核部件分析设备驱动模型之bus.docx
《linux内核部件分析设备驱动模型之bus.docx》由会员分享,可在线阅读,更多相关《linux内核部件分析设备驱动模型之bus.docx(22页珍藏版)》请在冰豆网上搜索。
![linux内核部件分析设备驱动模型之bus.docx](https://file1.bdocx.com/fileroot1/2023-1/29/bacf1cc9-0258-414c-ac5a-4f89045b2499/bacf1cc9-0258-414c-ac5a-4f89045b24991.gif)
linux内核部件分析设备驱动模型之bus
前面我们分析了设备驱动模型中的device和driver,device和driver本来是不相关的东西,只因为bus的存在,才被联系到了一起。
本节就来看看设备驱动模型中起枢纽作用的bus。
本节的头文件在include/linux/device.h和drivers/base/base.h,实现代码主要在bus.c中。
因为在bus中有很多代码时为了device找到driver或者driver找到device而定义的,本节先尽量忽略这部分,专注于bus的注册和注销,属性定义等内容。
剩下的留到讨论device和driver关系时在分析。
先来看看bus的数据结构。
[cpp] viewplaincopyprint?
1.struct bus_type {
2. const char *name;
3. struct bus_attribute *bus_attrs;
4. struct device_attribute *dev_attrs;
5. struct driver_attribute *drv_attrs;
6.
7. int (*match)(struct device *dev, struct device_driver *drv);
8. int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
9. int (*probe)(struct device *dev);
10. int (*remove)(struct device *dev);
11. void (*shutdown)(struct device *dev);
12.
13. int (*suspend)(struct device *dev, pm_message_t state);
14. int (*resume)(struct device *dev);
15.
16. const struct dev_pm_ops *pm;
17.
18. struct bus_type_private *p;
19.};
structbus_type是bus的通用数据结构。
name是bus的名称,注意到这里也是constchar类型的,在sysfs中使用的还是kobj中动态创建的名称,这里的name只是初始名。
bus_attrs是bus为自己定义的一系列属性,dev_attrs是bus为旗下的device定义的一系列属性,drv_attrs是bus为旗下的driver定义的一系列属性。
其中dev_attrs在bus_add_device()->device_add_attrs()中被加入dev目录下,drv_attrs在bus_add_driver()->driver_add_attrs()中被加入driver目录下。
match函数匹配总线中的dev和driver,返回值为1代表匹配成功,为0则失败。
uevent函数用于总线对uevent的环境变量添加,但在总线下设备的dev_uevent处理函数也有对它的调用。
probe函数是总线在匹配成功时调用的函数,bus->probe和drv->probe中只会有一个起效,同时存在时使用bus->probe。
remove函数在总线上设备或者驱动要删除时调用,bus->remove和drv->remove中同样只会有一个起效。
shutdown函数在所有设备都关闭时调用,即在core.c中的device_shutdown()函数中调用,bus->shutdown和drv->shutdown同样只会有一个起效。
suspend函数是在总线上设备休眠时调用。
resume函数是在总线上设备恢复时调用。
pm是structdev_pm_ops类型,其中定义了一系列电源管理的函数。
p是指向bus_type_private的指针,其中定义了将bus同其它组件联系起来的变量。
[cpp] viewplaincopyprint?
1.struct bus_type_private {
2. struct kset subsys;
3. struct kset *drivers_kset;
4. struct kset *devices_kset;
5. struct klist klist_devices;
6. struct klist klist_drivers;
7. struct blocking_notifier_head bus_notifier;
8. unsigned int drivers_autoprobe:
1;
9. struct bus_type *bus;
10.};
11.
12.#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)
structbus_type_private是将bus同device、driver、sysfs联系起来的结构。
subsys是kset类型,代表bus在sysfs中的类型。
drivers_kset代表bus目录下的drivers子目录。
devices_kset代表bus目录下地devices子目录。
klist_devices是bus的设备链表,klist_drivers是bus的驱动链表。
bus_notifier用于在总线上内容发送变化时调用特定的函数,这里略过。
driver_autoprobe标志定义是否允许device和driver自动匹配,如果允许会在device或者driver注册时就进行匹配工作。
bus指针指向structbus_type类型。
使用structbus_type_private可以将structbus_type中的部分细节屏蔽掉,利于外界使用bus_type。
struct driver_private和structdevice_private都有类似的功能。
[cpp] viewplaincopyprint?
1.struct bus_attribute {
2. struct attribute attr;
3. ssize_t (*show)(struct bus_type *bus, char *buf);
4. ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
5.};
6.
7.#define BUS_ATTR(_name, _mode, _show, _store) \
8.struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
9.
10.#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
structbus_attribute是bus对structattribute类型的封装,更方便总线属性的定义。
[cpp] viewplaincopyprint?
1.static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
2. char *buf)
3.{
4. struct bus_attribute *bus_attr = to_bus_attr(attr);
5. struct bus_type_private *bus_priv = to_bus(kobj);
6. ssize_t ret = 0;
7.
8. if (bus_attr->show)
9. ret = bus_attr->show(bus_priv->bus, buf);
10. return ret;
11.}
12.
13.static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
14. const char *buf, size_t count)
15.{
16. struct bus_attribute *bus_attr = to_bus_attr(attr);
17. struct bus_type_private *bus_priv = to_bus(kobj);
18. ssize_t ret = 0;
19.
20. if (bus_attr->store)
21. ret = bus_attr->store(bus_priv->bus, buf, count);
22. return ret;
23.}
24.
25.static struct sysfs_ops bus_sysfs_ops = {
26. .show = bus_attr_show,
27. .store = bus_attr_store,
28.};
29.
30.static struct kobj_type bus_ktype = {
31. .sysfs_ops = &bus_sysfs_ops,
32.};
以上应该是我们最熟悉的部分,bus_ktype中定义了bus对应的kset应该使用的kobj_type实例。
与此类似,driver使用的是自定义的driver_ktype,device使用的是自定义的device_ktype。
只是这里仅仅定义了sysfs_ops,并未定义release函数,不知bus_type_private打算何时释放。
[cpp] viewplaincopyprint?
1.int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
2.{
3. int error;
4. if (bus_get(bus)) {
5. error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
6. bus_put(bus);
7. } else
8. error = -EINVAL;
9. return error;
10.}
11.
12.void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
13.{
14. if (bus_get(bus)) {
15. sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
16. bus_put(bus);
17. }
18.}
bus_create_file()在bus目录下创建属性文件,bus_remove_file()在bus目录下删除属性文件。
类似的函数在driver和device中都有见到。
[cpp] viewplaincopyprint?
1.static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
2.{
3. struct kobj_type *ktype = get_ktype(kobj);
4.
5. if (ktype == &bus_ktype)
6. return 1;
7. return 0;
8.}
9.
10.static struct kset_uevent_ops bus_uevent_ops = {
11. .filter = bus_uevent_filter,
12.};
13.
14.static struct kset *bus_kset;
可以看到这里定义了一个bus_uevent_ops变量,这是kset对uevent事件处理所用的结构,它会用在bus_kset中。
[cpp] viewplaincopyprint?
1.int __init buses_init(void)
2.{
3. bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
4. if (!
bus_kset)
5. return -ENOMEM;
6. return 0;
7.}
在buses_init()中创建了/sys/bus目录,这是一个kset类型,使用了bus_uevent_ops的uevent操作类型。
其实这里的操作不难想象,在devices中我们有一个类似的devices_kset,可以回顾一下。
[cpp] viewplaincopyprint?
1.static struct kset_uevent_ops device_uevent_ops = {
2. .filter = dev_uevent_filter,
3. .name = dev_uevent_name,
4. .uevent = dev_uevent,
5.};
6.
7./* kset to create /sys/devices/ */
8.struct kset *devices_kset;
9.
10.int __init devices_init(void)
11.{
12. devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
13. ...
14.}
15.
16.void device_initialize(struct device *dev)
17.{
18. dev->kobj.kset = devices_kset;
19. ...
20.}
devices_kset在devices_init()中被创建,使用相应的device_uevent_ops进行uevent处理。
而devices_kset又被设为每个device初始化时使用的kset。
这就不难想象每个device都是以devices_kset为所属kset的,并使用device_uevent_ops中的处理函数。
只是这里还不知bus_kset会在哪里用到,或许是每个bus所属的kset吧,下面会有答案。
[cpp] viewplaincopyprint?
1.static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
2.{
3. return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
4.}
5.
6.static ssize_t store_drivers_autoprobe(struct bus_type *bus,
7. const char *buf, size_t count)
8.{
9. if (buf[0] == '0')
10. bus->p->drivers_autoprobe = 0;
11. else
12. bus->p->drivers_autoprobe = 1;
13. return count;
14.}
15.
16.static ssize_t store_drivers_probe(struct bus_type *bus,
17. const char *buf, size_t count)
18.{
19. struct device *dev;
20.
21. dev = bus_find_device_by_name(bus, NULL, buf);
22. if (!
dev)
23. return -ENODEV;
24. if (bus_rescan_devices_helper(dev, NULL) !
= 0)
25. return -EINVAL;
26. return count;
27.}
28.
29.static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
30.static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
31. show_drivers_autoprobe, store_drivers_autoprobe);
这里定义了总线下的两个属性,只写得drivers_probe,和可读写的drivers_autoprobe。
至于其怎么实现的,我们现在还不关心。
[cpp] viewplaincopyprint?
1.static int add_probe_files(struct bus_type *bus)
2.{
3. int retval;
4.
5. retval = bus_create_file(bus, &bus_attr_drivers_probe);
6. if (retval)
7. goto out;
8.
9. retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
10. if (retval)
11. bus_remove_file(bus, &bus_attr_drivers_probe);
12.out:
13. return retval;
14.}
15.
16.static void remove_probe_files(struct bus_type *bus)
17.{
18. bus_remove_file(bus, &bus_attr_drivers_autoprobe);
19. bus_remove_file(bus, &bus_attr_drivers_probe);
20.}
add_probe_files()在bus目录下添加drivers_probe和drivers_autoprobe文件。
remove_probe_files()在bus目录下删除drivers_probe和drivers_autoprobe文件。
这两个函数对bus的probe类型属性进行管理,就像add_bind_files/remove_bind_files对driver的bind类型属性进行管理一样。
[cpp] viewplaincopyprint?
1.static ssize_t bus_uevent_store(struct bus_type *bus,
2. const char *buf, size_t count)
3.{
4. enum kobject_action action;
5.
6. if (kobject_action_type(buf, count, &action) == 0)
7. kobject_uevent(&bus->p->subsys.kobj, action);
8. return count;
9.}
10.static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
上面定义了bus的一个属性uevent,用于bus所在的kset节点主动发起uevent消息。
同样地uevent文件在driver目录中也有见到。
device目录中也有,不过除了store_uevent之外,还增加了show_uevent的功能。
[cpp] viewplaincopyprint?
1.static struct device *next_device(struct klist_iter *i)
2.{
3. struct klist_node *n = klist_next(i);
4. struct device *dev = NULL;
5. struct device_private *dev_prv;
6.
7. if (n) {
8. dev_prv = to_device_private_bus(n);
9. dev = dev_prv->device;
10. }
11. return dev;
12.}
13.
14.int bus_for_each_dev(struct bus_type *bus, struct device *start,
15.