Read the fucking source code!
--By 鲁迅A picture is worth a thousand words.
--By 高尔基说明:
《Linux PCI驱动框架分析(一)》
;话不多说,直接开始。
struct pci_host_bridge
描述;struct pci_dev
描述PCI设备,以及PCI-to-PCI桥设备;struct pci_bus
用于描述PCI总线,struct pci_slot
用于描述总线上的物理插槽;来一张更详细的结构体组织图:
pci_host_bridge
,这个结构一般由Host驱动负责来初始化创建;pci_host_bridge
指向root bus,也就是编号为0的总线,在该总线下,可以挂接各种外设或物理slot,也可以通过PCI桥去扩展总线;Linux PCI驱动框架,基于Linux设备驱动模型,因此有必要先简要介绍一下,实际上Linux设备驱动模型也是一个大的topic,先挖个坑,有空再来填。来张图吧:
match
函数),当发现驱动与设备能进行匹配时,就会执行probe函数的操作;bus_type
会维护两个链表,分别用于挂接向其注册的设备和驱动,而match
函数就负责匹配检测;kset/kobject
等内容,建议去看看之前的文章《linux设备模型之kset/kobj/ktype分析》
既然说到了设备驱动模型,那么首先我们要做的事情,就是先在内核里边创建一个PCI总线,用于挂接PCI设备和PCI驱动,我们的实现来到了pci_driver_init()
函数:
pci_driver_init()
来创建一个PCI总线结构(全局变量pci_bus_type
),这里描述的PCI总线结构,是指驱动匹配模型中的概念,PCI的设备和驱动都会挂在该PCI总线上;pci_bus_type
的函数操作接口也能看出来,pci_bus_match
用来检查设备与驱动是否匹配,一旦匹配了就会调用pci_device_probe
函数,下边针对这两个函数稍加介绍;pci_bus_match
函数的调用,实际会去比对vendor
和device
等信息,这个都是厂家固化的,在驱动中设置成PCI_ANY_ID
就能支持所有设备;pci_device_probe
的执行;枚举的入口函数:pci_host_probe
pci_scan_root_bus_bridge
开始,首先需要先向系统注册一个host bridge
,在注册的过程中需要创建一个root bus
,也就是bus 0
,在pci_register_host_bridge
函数中,主要是一系列的初始化和注册工作,此外还为总线分配资源,包括地址空间等;pci_scan_child_bus
开始,从bus 0
向下扫描并添加设备,这个过程由pci_scan_child_bus_extend
来完成;pci_scan_child_bus_extend
的流程可以看出,主要有两大块:
pci_scan_child_bus_extend
的函数来扫描下一级的总线,从这个过程看,就是一个递归过程。Depth First Search
)过程,熟悉数据结构与算法的同学应该清楚,这就类似典型的走迷宫的过程;如果你对上述的流程还不清楚,再来一张图:
暂且写这么多,细节方面不再赘述了,把握大体的框架即可,无法扼住PCI的咽喉,那就扼住它的骨架吧。
欢迎关注个人公众号,不定期分享Linux内核相关技术文章:
原文:https://www.cnblogs.com/LoyenWang/p/14209318.html