Linux设备驱动模型框架分析(三)——LDDM的实体bus_type、device和device_driver

  在Linux设备模型中,Bus(总线)是一类特殊的设备,它是连接处理器和其它设备之间的通道(channel)。为了方便设备模型的实现,内核规定,系统中的每个设备都要连接在一个Bus上,这个Bus可以是一个内部Bus、虚拟Bus或者Platform Bus

devicedevice driverLinux驱动开发的基本概念。Linux kernel的思路很简单:驱动开发,就是要开发指定的软件(driver)以驱动指定的设备,所以kernel就为设备和驱动它的driver定义了两个数据结构,分别是devicedevice_driver

bus_type

内核通过struct bus_type结构,抽象Bus

                                       

name,该bus的名称,会在sysfs中以目录的形式存在,如platform bussysfs中表现为"/sys/bus/platform”。

dev_name,该名称和下面讲到的struct device结构中的init_name有关。对有些设备而言,允许将设备的名字留空。这样当设备注册到内核后,设备模型的核心逻辑就会用"bus->dev_name+device ID”的形式,为这样的设备生成一个名称。

dev_attrs,被下边的groups取代

bus_groupsdev_groupsdrv_groups,一些默认的attribute,可以在busdevice或者device_driver添加到内核时,自动为它们添加相应的attribute

dev_rootdev_root设备为bus的默认父设备(Default device to use as the parent),但在内核实际实现中,和一个叫sub system的功能有关。

match一个由具体的bus driver实现的回调函数。当任何属于该Busdevice或者device_driver添加到内核时,内核都会调用该接口,如果新加的devicedevice_driver匹配上了彼此的话,该接口要返回非零值,此时Bus模块的核心逻辑就会执行后续的处理

uevent,一个由具体的bus driver实现的回调函数。当任何属于该Busdevice,发生添加、移除或者其它动作时,Bus模块的核心逻辑就会调用该接口,以便bus driver能够修改环境变量。

proberemove,这两个回调函数,和device_driver中的非常类似,但它们的存在是非常有意义的。可以想象一下,如果需要probe(其实就是初始化)指定的device话,需要保证该device所在的bus是被初始化过、确保能正确工作的。这就要就在执行device_driverprobe前,先执行它的busproberemove的过程相反。

并不是所有的bus都需要proberemove接口的,因为对有些bus来说(例如platform bus),它本身就是一个虚拟的总线,无所谓初始化,直接就能使用,因此这些busdriver就可以将这两个回调函数留空。

shutdownsuspendresume,和proberemove的原理类似,电源管理相关的实现。

onlineoffline,和属于这个总线设备的online属性相关。

pm,电源管理相关的逻辑。

iommu_ops,总线的IOMMU相关操作,IOMMUMMU功能类似,可以给设备一个内核空间的地址(或叫总线地址),而不限于可以直接访问的常规内存区域。

p,一个struct subsys_private类型的指针,kobject隐藏在这个结构后面。这个结构也很重要。

device

                                            

device结构很复杂,这里将会选一些对理解设备模型非常关键的字段进行说明。

parent,该设备的父设备,一般是该设备所从属的buscontroller等设备。

p,一个用于设备的私有数据结构指针,保存子设备链表,添加父节点,邻居节点和总线链表等。

kobj,该数据结构对应的struct kobject

init_name,该设备的名称。

在设备模型中,名称是一个非常重要的变量,任何注册到内核中的设备,都必须有一个合法的名称,可以在初始化时给出,也可以由内核根据bus name + device ID”的方式创造。见bus_type.dev_name的说明。

typestruct device_type结构是新版本内核新引入的一个结构,它和struct device关系,非常类似stuct kobj_typestruct kobject之间的关系。

bus,该device属于哪个总线。

driver,该device对应的device driver

platform_data,一个指针,用于保存具体的平台相关的数据。linux经常用来保存一些单板相关的数据,来描述包含哪些设备,以及它们如何互联。以便大幅减少BSP的代码量和驱动中ifdef的使用。

powerpm_domain,电源管理相关的逻辑,后续会由电源管理专题讲解。

pins"PINCTRL”功能。

numa_node"NUMA”功能。

devt,设备号。在这里,该变量主要用于在sys文件系统中,为每个具有设备号的device,创建/sys/dev/*下的对应目录,如下:

class,该设备属于哪个class。这从侧面说明了classdevice的集合。

groups,该设备的默认attribute集合。将会在设备注册时自动在sysfs中创建对应的文件。


device_driver

                                            

name,该driver的名称。和device结构一样,该名称非常重要,和devicedriver的匹配有关。

bus,该driver所驱动设备的总线设备。内核要保证在driver运行前,设备所依赖的总线能够正确初始化。

ownermod_name,內核module相关的变量。

suppress_bind_attrs,通过sysfs启用bindunbindattribute,如下:

# ls /sys/bus/platform/drivers/switch-gpio/                                                  

    bind   uevent    unbind

kernel中,bind/unbind是从用户空间手动的为driver绑定/解绑定指定的设备的机制。

proberemove,这两个接口函数用于实现driver逻辑的开始和结束。在设备模型的结构下,只有driverdevice同时存在时,才需要开始执行driver的代码逻辑。这也是proberemove两个接口名称的由来:检测到了设备和移除了设备(就是为热拔插起的!)。

shutdownsuspendresumepm,电源管理相关的内容。

groups,和struct device结构中的同名变量类似,driver也可以定义一些默认attribute,这样在将driver注册到内核中时,内核设备模型部分的代码会自动将这些attribute添加到sysfs中。

p,私有数据的指针。

 

subsys_private

旧的linux存在独立的子系统数据结构subsystem2.6.35抛弃了这个数据结构。转而用subsys_private表示。

什么是子系统?无论是bus,还是class,还是一些虚拟的子系统,它都构成了一个“子系统(sub-system)”,该子系统会包含形形色色的devicedevice_driver,就像一个独立的王国一样,存在于内核中。而这些子系统的表现形式,就是/sys/bus(或/sys/class,或其它)目录下面的子目录,每一个子目录,都是一个子系统(如/sys/bus/spi/)。从子系统的角度看bus和后面的class很类似,它们都用subsys_private表示子系统。

                                                 

subsysdevices_ksetdrivers_kset是三个kset。其中subsys,代表了本bus(如/sys/bus/spi),它下面可以包含其它的kset或者其它的kobjectdevices_ksetdrivers_kset则是bus下面的两个kset(如/sys/bus/spi/devices/sys/bus/spi/drivers),分别包括本bus下所有的devicedevice_driverbus_typekobject的关系通过subsys成员体现。通过宏to_subsys_private(obj)可以看出。

interface用于保存该bus下所有的interfaceinterface抽象了此类子系统的专有功能。

klist_devicesklist_drivers,分别保存了本bus下所有的devicedevice_driver的指针,以方便查找。

drivers_autoprobe,用于控制该bus下的drivers或者device是否自动probe

busclass,分别保存上层的bus或者class指针。

 

device_private

klist_childre,包含此设备所有的子设备。

knode_parent,连入父设备的klist_children时所用的节点。

knode_driver,连入驱动的设备链表所用的节点,driver_privateklist_devices节点。

knode_bus,连入总线的设备链表时所用的节点,subsys_privateklist_devices的节点。

deferred_probedeferred_probe_list的入口,deferred_probe_list用来重新绑定那些暂时不能获得device全部资源的驱动,这种情况常常是因为某一个驱动需要另一个驱动首先probe

device,指向包含device_privatedevice

 

driver_private

                                           

kboj,结构对应的kobject

klist_devices,包含此驱动可以驱动的设备。

knode_bus,连入bus的驱动链表的节点,代表subsys_privateklist_drivers的节点。

mkobj,内核module相关变量。

driver,指向包含driver_privatedriver

 

device_type

                                          

name,表示该类型的名称,当该类型的设备添加到内核时,内核会发出"DEVTYPE=name’”类型的uevent,告知用户空间某个类型的设备available了。

groups,该类型设备的公共attribute集合。设备注册时,会同时注册这些attribute。这就是面向对象中“继承”的概念。

uevent,所有相同类型的设备,会有一些共有的uevent需要发送,由该接口实现。

release,如果device结构没有提供release接口,就要查询它所属的type是否提供,用于释放device变量所占的空间。

 

bus_typedevicedevice_driverkobject的关系

devicedevice_driver的角度看

                                                                 

devicedevice_driver直接继承kobjectbus_type通过subsys_privatekobject发生联系。图中ksetkobject的关系是从kset与包含在它里边的kobject的角度看的,与前面ksetkobjcet的关系角度不同。由此可见,总线、设备和驱动是建立在kobject基础上的,借由kobjectkset建立层次关系。

 

bus_typedevicedevice_driver的关系

                                          

一个device_driver可以支持多个devicebus_type通过subsys_privatedevice_driverdevice发生关联。

 

bus_typedevicedevice_driversysfs的关系

总线,设备和设备驱动与sysfs的对应关系相对简单直观



猜你喜欢

转载自blog.csdn.net/chqsy/article/details/80931995