一、platform总线简介
Linux系统支持多种架构CPU,支持的驱动也非常多,内核代码中积累了大量的代码。在驱动中,多个设备使用类似的代码,使内核代码显得很冗余。因此,需要对驱动部分进行处理,这个时候platform总线就被发明出来用于解决驱动中类似的代码如何写驱动的问题。
Linux内核驱动中,分层、分离思想随处可见。platform总线就是这一思想的产物。相对于各种Soc里面的总线(地址总线、数据总线),platform总线是一种虚拟的总线,各种实际总线设备或者未挂载到实际总线上的设备可以挂载到platform总线上,进行驱动开发。
驱动代码中,将易变的部分抽象出来,做成数据的形式,注册到核心层里面,分开设计、编写代码,如图1所示。
图1
各个厂家(A、B、C)只需要编写自己这部分的代码,然后注册到核心层即可,设备驱动开发者也只需要开发自己的那部分代码,对接到核心层即可。这样,实际上形成了三个部分,驱动、核心层、设备三部分,platform总线里面对应到driver、bus、device结构,即驱动-总线-设备模型。
现在的Linux驱动框架,如spi、i2c等等,均是以platform总线为基础开发的,可以看作是platform总线的继承。
二、platform框架组成
platform框架由platform总线、驱动、设备三部分组成。
1. platform driver注册
driver注册使用platform_driver_register函数,
图2
platform_bus_type、platform_drv_probe、platform_drv_remove、platform_drv_shutdown内核已经写好。platform_drv_probe函数里面会最终调用我们注册的drv->probe,这个函数就是我们写的驱动入口函数。platform_driver_register最终调用driver_register注册驱动,分析driver_register函数:
driver_register
->bus_add_driver //添加驱动
->driver_create_file //在文件系统中,创建对应的文件
->driver_attach //匹配驱动
->driver_match_device //匹配成功
->platform_drv_probe //linux内核已经写好
->drv->probe //我们写的probe函数
图3
在driver_attach函数里面,执行bus_for_each_dev,在总线上寻找设备,对每个设备执行__driver_attach函数,若匹配到,则会调用driver_probe_device,driver_probe_device函数会调用
drv->driver.probe即platform_drv_probe,platform_drv_probe调用我们注册的drv->probe,控制权回到了我们手中。
platform总线类型是bus_type类型的常量,bus_type结构体如图4
图4
图5
图5中的match函数,就是用来匹配driver和device的,.pm则是电源管理部分,name字段是总线的名字,在match函数匹配里面会用到。
2. platform匹配过程
进入platform_match函数,可以看到:
platform的match函数一共有四种匹配方式,按照顺序分别是:
a. of_driver_match_device:对应去设备树上的信息
b.acpi_driver_match_device:acpi匹配方式
c. platform_match_id:id_table方式匹配
d.strcmp(pdev->name, drv->name):总线名字,即图3的name字段
常用的是a、c方式,a是支持设备树的Linux内核用到的,会自动根据设备树生成platform_device,在我们写的驱动里面的.driver字段里面会有一个of_match_table,根据这个去匹配数倍书上的compatible字段。若是不支持设备树的Linux内核,需要我们手动写platform_device信息。
分析of_driver_match_device匹配方式
of_driver_match_device
->of_driver_match_device
->of_match_node
->__of_match_node
->__of_device_is_compatible(node, matches->compatible,
matches->type, matches->name) //matches->compatible设备树的compatible
of_driver_match_device最终是在设备树节点上找到对应的compatible。通过上面的分析,可以看到,在Linux内核上,匹配过程最终是我们写的驱动里面的platform_driver.driver字段中的of_match_table,匹配设备树中的compatible字段。
在支持设备树的内核上,内核启动时,会读取设备树信息,根据节点信息自动生成platform_device,与platform_driver进行匹配。
三、总结
现在的驱动开发,已经不需要我们去写一个platform总线模型什么的,分析platform也是为了学习,了解platform总线式如何匹配驱动和设备的。即当我们硬件连接到Linux内核时,驱动如何找到对应的设备,设备如何找到对应的驱动,最终调用probe函数,进入驱动。在驱动-总线-设备模型中,无论是驱动还是设备先进入Linux内核,最后都会调用probe函数,我们可以忽略其中的过程,只需要关注最后的probe函数即可。