原文链接:http://blog.chinaunix.net/uid-20543183-id-1930814.html
前言
platform
总线是kernel中最近加入的一种虚拟总线.在近版的2.6kernel中,很多驱动都用platform
改写了.只有在分析完platform
总线之后,才能继续深入下去分析.在分析完sysfs
和设备驱动模型之后,这部份应该很简单了.闲言少叙.步入正题.GO.GO!以下的源代码分析是基于2.6.25的.
platform概貌
在分析源代码之前,先在内核代码中找一个platform
架构的驱动程序.下面以i8042
芯片的驱动为例进行分析.
在linux-2.6.25/drivers/input/serio/i8042.c
的intel 8042
的初始化入口中,有以下代码分段:
我们在上面的程序片段中看到,驱动程序先注册了一个platform driver
,然后又添加了一个platform device
.这里就涉及到了platform
的两个最主要的操作:一个设备驱动注册,一个设备注册。
要了解platform
总线的来龙去脉.得从它的初始化开始.
platform初始化
platform
总线的初始化是在linux-2.6.25/drivers/base/platform.c
中的platform_bus_init()
完成的,代码如下:
上面代码中调用的子函数在linux设备模型深探中已经分析过了。这段初始化代码创建了一个名为 “platform
”的设备,后续platform
的设备都会以此为parent
。在sysfs
中表示为:所有platform
类型的设备都会添加在platform_bus
所代表的目录下,即 /sys/devices/platform
下面.
接着,这段初始化代码又创建了一个名为“platform
”的总线.platform_bus_type
的定义如下:
我们知道,在bus_type
中包含了诸如设备与驱动匹配,hotplug
事件等很多重要的操作。这些操作在分析platform
设备注册与platform
驱动注册的时候依次分析。
platform device注册
在intel 8042
的驱动代码中,我们看到注册一个platform device
分为了两部分,一部份是创建一个platform device
结构,另一部份是将其注册到总线中.先来看第一个接口.
这段代码主要初始化了封装在struct platform_object
中的struct device
.
struct platform_object
结构定义如下:
在定义中,定义name
长度为1
,所以,才有了platform_device_alloc()
中分配struct platform_object
的时候多加了名称的长度:
struct device
结构如下:
在这个结构里封装了struct device
、struct resource
,struct resource
这个结构在此之前没有接触过,这个结构表示设备所拥有的资源,即I/O端口或者是I/O映射内存。
platform_device_add()
代码分段分析如下:
初始化设备的parent
为platform_bus
, 初始化驱备的总线为platform_bus_type
. 回忆platform
初始化的时候, 这两个东东这里终于派上用场了.
设置设备struct device
的bus_id
成员, 留心这个地方, 在以后还需要用到这个的.
如果设备指定了它所拥有的资源, 将这些资源分配给它. 如果分配失败, 则失败退出. 从代码中可以看出, 如果struct resource
的flags
域被指定为IORESOURCE_MEM
, 则所表示的资源为I/O映射内存; 如果指定为IORESOURCE_IO
, 则所表示的资源为I/O端口.
device_add()
已经很熟悉了吧, 没错, 它就是将设备注册到指定的bus_type
.
在分析linux设备模型的时候, 曾说过, 调用device_add()
会产生一个hotplug
事件. platform device
的hotplug
与一般的device
事件相比, 它还要它所属bus_type
的uevent()
.对这个流程不熟悉的可以参照linux设备模型深探. platform device
所属的bus_type
为platform_bus_type
, 它的uevent()
接口代码如下:
上面的代码很简单,它就是在环境变量中添加一项MODALIAS
.
platform driver的注册
在intel 8024
的驱动代码中看到,platform driver
注册的接口为:
struct platform_driver
主要封装了struct device_driver
结构, 如下:
在这个接口里, 它指定platform driver
的所属总线. 如果在struct platform_driver
指定了各项接口的操作, 就会为struct device_driver
中的相应接口赋值.
不要被上面的platform_drv_XXX
吓倒了, 它们其实很简单, 就是将struct device
转换为struct platform_device
和struct platform_driver
, 然后调用platform_driver
中的相应接口函数.
最后, platform_driver_register()
将驱动注册到总线上.
这样, 总线上有设备, 又有驱动, 就会进行设备与驱动匹配的过程, 调用的相应接口为:bus ->match --- > bus->probe/driver->probe
(如果总线的probe
操作不存在,就会调用设备的probe
接口)。
这样,我们又回到platform_bus_type
中的各项操作了。
对应的match
接口如下:
从代码中看出,如果要匹配成功,那么设备与驱动的名称必须要一致。
platform_bus_type
中没有指定probe
接口,所以,会转至驱动的probe
接口。在platform_driver_register()
中,将其probe
接口指定为了platform_drv_probe
,这个函数又会将操作回溯到struct platform_driver
的probe
接口中。
到这里,platform driver
的注册过程就会析完了。
小结
在本小节里,我们以linux设备模型为基础,分析虚拟总线platform
的架构,对其hotplug
事件,以及设备与驱动的匹配过程做了非常详细的分析,这部份知识是我们深入理解具体设备驱动的基础.