platform总线分析
来源:互联网 发布:脑死亡知乎 编辑:程序博客网 时间:2024/06/04 23:31
推荐阅读
http://www.linuxidc.com/Linux/2011-10/44627.htm 讲的很好
http://blog.csdn.net/qb_2008/article/category/896982
☆ platform总线简介
==>总线的产生的意义是让设备(硬件被抽象成一个结构体来代表一个设备)和驱动分离
==>linux内核中常见的的总线有I2C总线,PCI总线,串口总线,SPI总线,PCI总线,CAN总线,单总线等,所以有些设备和驱动就可以挂在这些总线上,然后通过总线上的match进行设备和驱动的匹配。但是有的设备并不属于这些常见总线,所以我们引入了一种虚拟总线,也就是platform总线的概念,对应的设备叫做platform设备,对应的驱动叫做platform驱动
☆ platform总线分析
==>先从使用方法入手分析,我们的驱动代码如果想用platform总线,主要分两个步骤:
① 抽象硬件为一个设备结构体,struct platform_device ,填充后调用 platform_device_register 将设备注册到总线上去
② 驱动部分定义一个结构体 struct platform_driver,填充后调用 platform_driver_register 将驱动注册到总线上去
注 : 比较常用的几个元素是:
platform_device 结构体的 name 用于去适配驱动
platform_device 结构体的 dev.platform_data 包含设备所使用的资源(io口 中断号等)
platform_driver 结构体的 driver.name 和 platform_device_id 用于去适配设备
platform_driver 结构体的 probe函数 是设备和驱动适配成功后去执行的函数
==>x210的调用逻辑分析举例
① 在mach-x210.c 文件中定义了platform_device *smdkc110_devices[]结构体数组,
包含了板级移植着给封装的各类设备(以后我们添加新设备的时候也推荐在这里添加)
这个数组被 smdkc110_machine_init(前面博客已分析如何被start_kernel调用)中的
platform_add_devices函数调用,将数组中的设备依次调用platform_device_register 添加到platform总线上去
② 我们随便分析一个驱动,以dm9000网卡驱动程序为例
module_init(dm9000_init);
platform_driver_register(&dm9000_driver);
当网卡设备和网卡驱动的名字一致的时候就会调用 dm9000_driver 结构体的 .probe 函数;
☆ 是怎么样能够执行.probe函数的
platform总线的设计思想实现设备和驱动分离,驱动和设备分开之后就会有先后加载的顺序,所以platform总线实现了
无论是先加载设备还是先加载驱动,都会对比name,合适后调用.probe 函数,下面来分析这个过程
==> 其实这个过程就是分析 platform_bus_init , platform_device_register 和 platform_driver_register 函数的实现
==>platform_bus_init 是内核启动后被调用的 被调用的流程是
start_kernel
rest_init();
do_basic_setup();
driver_init()
platform_bus_init();
先定义了两个结构体
struct device platform_bus = {
.init_name = "platform",
};
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
然后分析platform_bus_init()函数
platform_bus_init()
device_register(&platform_bus);
改函数把设备名为platform 的设备platform_bus注册到系统中,其他的platform的设备都会以它为parent(后面会看到)。
它在sysfs中目录下.即 /sys/devices/platform。
bus_register(&platform_bus_type);
注册了platform_bus_type总线,(如果设备要注册到platform总线上,要把设备device结构体的bus赋值为platform_bus_type,
然后调用device_add后,系统就会知道这个设备要挂到platform总线上)
这样platform设备的父设备有了,platform bus总线也有了,后面其他设备和驱动就可以挂在platform bus总线上了
==>分析platform_device_register(pdev) 一般是移植人员提供platform_device结构体,然后在板级文件中这个函数被调用,(新版本内核用了驱动树,这里会不一样)
device_initialize(&pdev->dev) 初始化platform_device 的device 结构体关键内容
platform_device_add(pdev)
pdev->dev.parent = &platform_bus; 这个就是前面说的,把platform_bus作为父节点
个人理解之所以用父节点这个东西,方便sys虚拟文件系统下生成树状的文件结构
pdev->dev.bus = &platform_bus_type; 这个就是告诉内核,我们要把这个设备去挂载到platform总线上面
device_add(&pdev->dev); 这个就是真正的挂载设备(猜测里面肯定依据bus到挂载不同的设备总线上)
.................. 一系列的其他操作
bus_probe_device(dev)
device_attach 设备去挨个匹配驱动
bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
参数__device_attach
driver_match_device(drv, dev) 如果没匹配成功则return
drv->bus->match(dev, drv) 这里真正调用的就是platform_bus_type中的.match(也就是platform_match)函数
driver_probe_device(drv, dev) 调用到这里说明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 这里调用就是驱动提供的probe函数
==>分析platform_driver_register(drv) 一般是由驱动开发者提供platform_driver结构体然后调用的,
drv->driver.bus = &platform_bus_type; 这个就是告诉内核,我们要把这个驱动去挂载到platform总线上面
..................... 然后给probe remove 和 shutdown 函数赋默认值(如果没有提供函数)
driver_register(&drv->driver); 这个就是真正的挂载驱动
bus_add_driver Add a driver to the bus.
driver_attach 驱动去挨个匹配设备
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
参数__driver_attach
driver_match_device 如果没匹配成功则return
drv->bus->match(dev, drv) 这里真正调用的就是platform_bus_type中的.match(也就是platform_match)函数
driver_probe_device 调用到这里说明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 这里调用就是驱动提供的probe函数
注:关于really_probe的代码实现里有个细节
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
也就是如果platform_bus_type结构体如果定义了probe函数 则使用它的probe函数,没有定义的情况下才使用驱动开发者提供的probe函数
http://www.linuxidc.com/Linux/2011-10/44627.htm 讲的很好
http://blog.csdn.net/qb_2008/article/category/896982
☆ platform总线简介
==>总线的产生的意义是让设备(硬件被抽象成一个结构体来代表一个设备)和驱动分离
==>linux内核中常见的的总线有I2C总线,PCI总线,串口总线,SPI总线,PCI总线,CAN总线,单总线等,所以有些设备和驱动就可以挂在这些总线上,然后通过总线上的match进行设备和驱动的匹配。但是有的设备并不属于这些常见总线,所以我们引入了一种虚拟总线,也就是platform总线的概念,对应的设备叫做platform设备,对应的驱动叫做platform驱动
☆ platform总线分析
==>先从使用方法入手分析,我们的驱动代码如果想用platform总线,主要分两个步骤:
① 抽象硬件为一个设备结构体,struct platform_device ,填充后调用 platform_device_register 将设备注册到总线上去
② 驱动部分定义一个结构体 struct platform_driver,填充后调用 platform_driver_register 将驱动注册到总线上去
注 : 比较常用的几个元素是:
platform_device 结构体的 name 用于去适配驱动
platform_device 结构体的 dev.platform_data 包含设备所使用的资源(io口 中断号等)
platform_driver 结构体的 driver.name 和 platform_device_id 用于去适配设备
platform_driver 结构体的 probe函数 是设备和驱动适配成功后去执行的函数
==>x210的调用逻辑分析举例
① 在mach-x210.c 文件中定义了platform_device *smdkc110_devices[]结构体数组,
包含了板级移植着给封装的各类设备(以后我们添加新设备的时候也推荐在这里添加)
这个数组被 smdkc110_machine_init(前面博客已分析如何被start_kernel调用)中的
platform_add_devices函数调用,将数组中的设备依次调用platform_device_register 添加到platform总线上去
② 我们随便分析一个驱动,以dm9000网卡驱动程序为例
module_init(dm9000_init);
platform_driver_register(&dm9000_driver);
当网卡设备和网卡驱动的名字一致的时候就会调用 dm9000_driver 结构体的 .probe 函数;
☆ 是怎么样能够执行.probe函数的
platform总线的设计思想实现设备和驱动分离,驱动和设备分开之后就会有先后加载的顺序,所以platform总线实现了
无论是先加载设备还是先加载驱动,都会对比name,合适后调用.probe 函数,下面来分析这个过程
==> 其实这个过程就是分析 platform_bus_init , platform_device_register 和 platform_driver_register 函数的实现
==>platform_bus_init 是内核启动后被调用的 被调用的流程是
start_kernel
rest_init();
do_basic_setup();
driver_init()
platform_bus_init();
先定义了两个结构体
struct device platform_bus = {
.init_name = "platform",
};
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
然后分析platform_bus_init()函数
platform_bus_init()
device_register(&platform_bus);
改函数把设备名为platform 的设备platform_bus注册到系统中,其他的platform的设备都会以它为parent(后面会看到)。
它在sysfs中目录下.即 /sys/devices/platform。
bus_register(&platform_bus_type);
注册了platform_bus_type总线,(如果设备要注册到platform总线上,要把设备device结构体的bus赋值为platform_bus_type,
然后调用device_add后,系统就会知道这个设备要挂到platform总线上)
这样platform设备的父设备有了,platform bus总线也有了,后面其他设备和驱动就可以挂在platform bus总线上了
==>分析platform_device_register(pdev) 一般是移植人员提供platform_device结构体,然后在板级文件中这个函数被调用,(新版本内核用了驱动树,这里会不一样)
device_initialize(&pdev->dev) 初始化platform_device 的device 结构体关键内容
platform_device_add(pdev)
pdev->dev.parent = &platform_bus; 这个就是前面说的,把platform_bus作为父节点
个人理解之所以用父节点这个东西,方便sys虚拟文件系统下生成树状的文件结构
pdev->dev.bus = &platform_bus_type; 这个就是告诉内核,我们要把这个设备去挂载到platform总线上面
device_add(&pdev->dev); 这个就是真正的挂载设备(猜测里面肯定依据bus到挂载不同的设备总线上)
.................. 一系列的其他操作
bus_probe_device(dev)
device_attach 设备去挨个匹配驱动
bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
参数__device_attach
driver_match_device(drv, dev) 如果没匹配成功则return
drv->bus->match(dev, drv) 这里真正调用的就是platform_bus_type中的.match(也就是platform_match)函数
driver_probe_device(drv, dev) 调用到这里说明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 这里调用就是驱动提供的probe函数
==>分析platform_driver_register(drv) 一般是由驱动开发者提供platform_driver结构体然后调用的,
drv->driver.bus = &platform_bus_type; 这个就是告诉内核,我们要把这个驱动去挂载到platform总线上面
..................... 然后给probe remove 和 shutdown 函数赋默认值(如果没有提供函数)
driver_register(&drv->driver); 这个就是真正的挂载驱动
bus_add_driver Add a driver to the bus.
driver_attach 驱动去挨个匹配设备
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
参数__driver_attach
driver_match_device 如果没匹配成功则return
drv->bus->match(dev, drv) 这里真正调用的就是platform_bus_type中的.match(也就是platform_match)函数
driver_probe_device 调用到这里说明匹配成功了
really_probe(dev, drv);
drv->probe(dev) 这里调用就是驱动提供的probe函数
注:关于really_probe的代码实现里有个细节
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
也就是如果platform_bus_type结构体如果定义了probe函数 则使用它的probe函数,没有定义的情况下才使用驱动开发者提供的probe函数
0 0
- platform总线分析
- Linux Platform总线+SPI总线分析
- Linux Platform总线+SPI总线分析
- platform总线按键驱动分析
- sysfs之platform总线初始化简单分析
- platform总线上iic probe分析笔记
- 基于platform总线的驱动分析
- Platform总线按键驱动分析(精华版)
- Linux驱动中的platform总线分析
- platform总线按键驱动分析(精华版)
- Linux Platform总线+SPI总线分析-SPI驱动
- Platform总线
- platform总线
- platform总线
- platform总线
- Platform总线
- Platform总线
- platform总线
- 【Linux】用gcc生成静态库和动态库
- 素数筛法系列
- javaweb的servlet使用指南
- Web安全与防御措施
- 每周总结
- platform总线分析
- eclipse提交项目到git
- Crackme 2
- C语言字符串函数
- C primer plus 第三章编程练习(个人练习答案)
- LightOJ 1060nth Permutation(组合数--k大字典序)
- 《经久不衰的Spring框架:SpringMVC 统括》
- 从C到C++的升级之内存分配与释放
- ios中的Cookie