作者:蜗蜗 发布于:2014-4-15 19:21 1. 概述在Linux设备模型中,Bus(总线)是一类特殊的设备,它是连接处理器和其它设备之间的通道(channel)。为了方便设备模型的实现,内核规定,系统中的每个设备都要连接在一个Bus上,这个Bus可以是一个内部Bus、虚拟Bus或者Platform Bus。 内核通过struct bus_type结构,抽象Bus,它是在include/linux/device.h中定义的。本文会围绕该结构,描述Linux内核中Bus的功能,以及相关的实现逻辑。最后,会简单的介绍一些标准的Bus(如Platform),介绍它们的用途、它们的使用场景。 2. 功能说明按照老传统,描述功能前,先介绍一下该模块的一些核心数据结构,对bus模块而言,核心数据结构就是struct bus_type,另外,还有一个sub system相关的结构,会一并说明。 2.1 struct bus_type1: /* inlcude/linux/device.h, line 93 */ 2: struct bus_type { 3: const char *name; 4: const char *dev_name; 5: struct device *dev_root; 6: struct bus_attribute *bus_attrs; 7: struct device_attribute *dev_attrs; 8: struct driver_attribute *drv_attrs; 9:
10: int (*match)(struct device *dev, struct device_driver *drv); 11: int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 12: int (*probe)(struct device *dev); 13: int (*remove)(struct device *dev); 14: void (*shutdown)(struct device *dev); 15:
16: int (*suspend)(struct device *dev, pm_message_t state); 17: int (*resume)(struct device *dev); 18:
19: const struct dev_pm_ops *pm; 20:
21: struct iommu_ops *iommu_ops; 22:
23: struct subsys_private *p; 24: struct lock_class_key lock_key; 25: };
2.2 struct subsys_private该结构和device_driver中的struct driver_private类似,在"Linux设备模型(5)_device和device driver”章节中有提到它,但没有详细说明。 要说明subsys_private的功能,让我们先看一下该结构的定义: 1: /* drivers/base/base.h, line 28 */ 2: struct subsys_private { 3: struct kset subsys; 4: struct kset *devices_kset; 5: struct list_head interfaces; 6: struct mutex mutex; 7:
8: struct kset *drivers_kset; 9: struct klist klist_devices; 10: struct klist klist_drivers; 11: struct blocking_notifier_head bus_notifier; 12: unsigned int drivers_autoprobe:1; 13: struct bus_type *bus; 14:
15: struct kset glue_dirs; 16: struct class *class; 17: };
看到结构内部的字段,就清晰多了,没事不要乱起名字嘛!什么subsys啊,看的晕晕的!不过还是试着先理解一下为什么起名为subsys吧: 按理说,这个结构就是集合了一些bus模块需要使用的私有数据,例如kset啦、klist啦等等,命名为bus_private会好点(就像device_driver模块一样)。不过为什么内核没这么做呢?看看include/linux/device.h中的struct class结构(我们会在下一篇文章中介绍class)就知道了,因为class结构中也包含了一个一模一样的struct subsys_private指针,看来class和bus很相似啊。 想到这里,就好理解了,无论是bus,还是class,还是我们会在后面看到的一些虚拟的子系统,它都构成了一个“子系统(sub-system)”,该子系统会包含形形色色的device或device_driver,就像一个独立的王国一样,存在于内核中。而这些子系统的表现形式,就是/sys/bus(或/sys/class,或其它)目录下面的子目录,每一个子目录,都是一个子系统(如/sys/bus/spi/)。 好了,我们回过头来看一下struct subsys_private中各个字段的解释:
2.3 功能总结根据上面的核心数据结构,可以总结出bus模块的功能包括:
3. 内部执行逻辑分析3.1 bus的注册bus的注册是由bus_register接口实现的,该接口的原型是在include/linux/device.h中声明的,并在drivers/base/bus.c中实现,其原型如下: 1: /* include/linux/device.h, line 118 */ 2: extern int __must_check bus_register(struct bus_type *bus);
3.2 device和device_driver的添加我们有在"Linux设备模型(5)_device和device driver”中讲过,内核提供了device_register和driver_register两个接口,供各个driver模块使用。而这两个接口的核心逻辑,是通过bus模块的bus_add_device和bus_add_driver实现的,下面我们看看这两个接口的处理逻辑。 这两个接口都是在drivers/base/base.h中声明,在drivers/base/bus.c中实现,其原型为: 1: /* drivers/base/base.h, line 106 */ 2: extern int bus_add_device(struct device *dev); 3:
4: /* drivers/base/base.h, line 110 */ 5: extern int bus_add_driver(struct device_driver *drv);
3.3 driver的probe我们在"Linux设备模型(5)_device和device driver”中,我们已经介绍过driver的probe时机及过程,其中大部分的逻辑会依赖bus模块的实现,主要为bus_probe_device和driver_attach接口。同样,这两个接口都是在drivers/base/base.h中声明,在drivers/base/bus.c中实现。 这两个结构的行为类似,逻辑也很简单,既:搜索所在的bus,比对是否有同名的device_driver(或device),如果有并且该设备没有绑定Driver(注:这一点很重要,通过它,可以使同一个Driver,驱动相同名称的多个设备,后续在Platform设备的描述中会提及)则调用device_driver的probe接口。 4. 杂项4.1 再谈Subsystem在旧的Linux内核版本中(以蜗蜗使用的linux2.6.23版本的内核为例),sysfs下所有的顶层目录(包括一些二级目录)都是以调用subsystem_register接口,以sub-system的形式注册到内核的,如:
那时的subsystem_register的实现很简单,就是调用kset_register,创建一个kset。我们知道,kset就是一堆kobject的集合,并会在sysfs中以目录的形式呈现出来。 在新版本的内核中(如“Linux内核分析”系列文章所参考的linux3.10.29),subsystem的实现有了很大变化,例如:去掉了subsystem_register接口(但为了兼容/sys/device/system子系统,在drivers/base/bus.c中,增加了一个subsys_register的内部接口,用于实现相应的功能)。根据这些变化,现在注册subsystem有两种方式: 方式一,在各自的初始化函数中,调用kset_create_and_add接口,创建对应的子系统,包括:
其中bus子系统就是本文所讲的Bus模块,而其它的,我们会在后续的文章中陆续讲述。这个方式和旧版本内核使用kset_register接口的方式基本一样。 方式二,在bus模块中,利用subsys_register接口,封装出两个API:subsys_system_register和subsys_virtual_register,分别用于注册system设备(/sys/devices/system/*)和virtual设备(/sys/devices/virtual/*)。 而该方式和方式一的区别是:它不仅仅创建了sysfs中的目录,同时会注册同名的bus和device。 4.2 system/virtual/platform在Linux内核中,有三种比较特殊的bus(或者是子系统),分别是system bus、virtual bus和platform bus。它们并不是一个实际存在的bus(像USB、I2C等),而是为了方便设备模型的抽象,而虚构的。 system bus是旧版内核提出的概念,用于抽象系统设备(如CPU、Timer等等)。而新版内核认为它是个坏点子,因为任何设备都应归属于一个普通的子系统(New subsystems should use plain subsystems, drivers/base/bus.c, line 1264),所以就把它抛弃了(不建议再使用,它的存在只为兼容旧有的实现)。 virtaul bus是一个比较新的bus,主要用来抽象那些虚拟设备,所谓的虚拟设备,是指不是真实的硬件设备,而是用软件模拟出来的设备,例如虚拟机中使用的虚拟的网络设备(有关该bus的描述,可参考该链接处的解释:https:///Articles/326540/)。 platform bus就比较普通,它主要抽象集成在CPU(SOC)中的各种设备。这些设备直接和CPU连接,通过总线寻址和中断的方式,和CPU交互信息。
我们会在后续的文章中,进一步分析这些特殊的bus,这里就暂时不详细描述了。 |
|