Bootstrap

linux bus、driver、device及三者的关系

一、概念
1、bus
    总线是处理器和设备之间的通道。总线有多种类型,每种总线可以挂载多个设备。
2、driver
    驱动程序是在CPU运行时,提供操作的软件接口。所有的设备必须有与之配套驱动程序才能正常工作。一个驱动程序可以驱动多个类似或者完全不同的设备。
3、device
    设备就是连接在总线上的物理实体。设备是有功能之分的。具有相同功能的设备被归到一个类,如输入设备(鼠标,键盘,游戏杆等)。

 

二、三者的关系
   

 总线上有两个重要的链表:

1)设备(device)链表;

2)驱动(driver)链表


    每次出现一个设备就要向总线汇报,每次出现一个驱动,也要向总线注册。系统初始化的时候,会扫描连接了哪些设备,为每一个设备建立起一个struct device的变量,并加入设备链表;每次注册一个驱动,就要准备一个struct device_driver结构的变量,并加入驱动链表。这样所有的设备都挂载到总线上,当加载驱动时,驱动就去总线上找到自己对应的设备,或者先把驱动注册上,来了一个设备就去总线找驱动。如果只有设备却没有对应的驱动,那么设备无法工作,如果只有驱动却没有设备,驱动也起不了任何作用。
    每种总线下面可以挂载许多设备。(通过kset devices)
    每种总线下可以用很多驱动。(通过包含一个kset drivers)
    每个驱动可以处理一个或多个设备。

三、如何注册驱动、添加设备
    1、注册驱动
    注册一个驱动,首先把驱动链入到驱动(driver)链表中,然后从设备(device)链表中逐个寻找,看有没有可以关联的设备。如果找到关联的设备,就执行probe函数
    具体流程如下:
platform_driver_register-》driver_register-》bus_add_driver-》driver_attach-》bus_for_each_dev-》__driver_attach
-》driver_probe_device-》really_probe
    2、添加设备
    添加一个设备,首先把设备链入到设备(device)链表中,然后从驱动(driver)链表中逐个寻找,看有没有可以关联的驱动。如果找到关联的驱动,就执行probe函数
    具体流程如下:
device_add-》bus_add_device-》bus_probe_device-》device_attach-》bus_for_each_drv-》__device_attach
-》driver_probe_device-》really_probe

 

Linux 设备驱动模型中,按照层次的组织结构,抽象成总线(struct bus_type),设备(struct device),驱动(struct device_driver)的层次组织形式,这是最原始的抽象结构,在此基础之上,根据不同类型的总线/设备/驱动,有形成了更高层次的组织结构,如virtio总线(struct bus_type virtio_bus),virtio设备(struct virtio_device),virtio驱动(struct virtio_driver)等。

   不同的抽象层次构成一颗网状的树,linux内核通过驱动模型:kobject,kset来组织树的结构。

上图说明了总线通过两个数据结构:devices_kset和driver_kset来管理注册在此总线上的所有的设备和驱动,为了方便遍历,linux增加了klist_devices和klist_drivers用来实现设备和驱动的遍历

   理解linux驱动模型,最重要的是理解设备与驱动的匹配过程,即在何时,驱动与设备如何实现匹配?

   总结起来,设备的注册时机为调用device_register(),将devices注册到总线的devices_kset上,同理,驱动的注册为调用driver_register将驱动注册到总线的drivers_kset上

   

下图对照说明了Device和Driver的注册过程

 

 

    设备与驱动的匹配主要有以下几个点:

    (1)如果总线的match函数非空,调用总线的match函数

     (2)如果总线的probe函数非空,调用总线的probe函数,然后会在总线的probe函数中调用驱动的probe函数

    (3)如果总线的probe函数为空,则直接调用驱动的probe函数

   另外,bus_for_each_drv()是对BUS上所有的Driver都进行__device_attach()操作;同样的,bus_for_each_dev()是对BUS上所有的Device都进行__driver_attach()操作。

      那么,这些函数的执行时机在哪呢?

     只要有device或device_driver被注册到总线上,都会执行上面的过程。

;