platform设备驱动模型理解
platform总线是Linux提供的一种虚拟总线,struct platform_device表示设备,struct platform_driver表示驱动
1> 内核初始化platform总线:
start_kernel()
rest_init()
kernel_init()
do_basic_setup() // init/main.c
driver_init() // drivers/base/init.c
platform_bus_init() // drivers/base/platform.c 初始化platform总线
device_register(&platform_bus);
bus_register(&platform_bus_type);
platform_bus_type ==> platform_match(dev和drv的配对原则)
2> 注册device
设备驱动程序调用platform_device_register(struct platform_device *pdev)向platform总线注册device
如hisfc300_module_init:
platform_device_register(&hisfc300_device_pltdev); // drivers\mtd\devices\hisfc300\hisfc300.c
platform_device_add(pdev) //
device_add(&pdev->dev);
bus_probe_device(struct device *dev)
device_attach(struct device *dev)
bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
__device_attach(struct device_driver *drv, void *data)
driver_match_device(drv, dev) // 匹配drv和dev,匹配成功,往下走
driver_probe_device(drv, dev);
really_probe(dev, drv);
dev->bus->probe(dev);
3> 注册driver
设备驱动程序实现调用platform_driver_register(struct platform_driver *drv)向platform总线注册driver
hisfc300_module_init()
platform_device_register(&hisfc300_device_pltdev);
----------------------------------------------------------------------------------------------------------
device层:
1. 理解两个重要的数据结构:
struct device{} 结构体:(include/linux/device.h)
内核表示设备的基础结构体;每个设备由一个struct device代表();
struct platform_device{}结构体:(include/linux/platform_device.h)
将硬件资源注册进入内核,该结构体中的struct resource(include/linux/ioport.h)结构体关联实际的硬件资源,比如中断号等,
问:谁用platform_device结构体呢?
答:在各个硬件驱动程序中都会有platform_device静态变量定义,在源码中搜索,可以搜索到很多,都是在各个设备的驱动.c文件中。
--------------- 以dm9000网卡驱动为例追踪platform_device怎么样注册platform总线的 ------------------------
问:platform_device定义在哪里?
答:dm9000网卡驱动platform_device在arch/arm/mach-s3c2440/mach-mini2440.c中定义如下:
static struct platform_device mini2440_device_eth = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource, // dm9000的resource
.dev = {
.platform_data = &mini2440_dm9k_pdata,
},
};
上面的定义中.resource定义了dm9k的硬件资源
问:mini2440_device_eth在哪里使用?
答:mini2440_device_eth包含了在了mini2440_devices数组中,该数组包含了mini2440外设的platform_device定义
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_rtc,
&s3c_device_usbgadget,
&mini2440_device_eth,
&mini2440_led1,
&mini2440_led2,
&mini2440_led3,
&mini2440_led4,
&mini2440_button_device,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_iis,
&uda1340_codec,
&mini2440_audio,
&samsung_asoc_dma,
};
问:mini2440_devices[]数组在哪里使用?
答:mini2440_init()函数中作为platform_add_devices函数的参数被使用, platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
platform_add_devices函数中,调用了platform_device_register对mini2440_devices每个元素调用platform_device_add,将设备加入到platform_bus_type中;
platform_device_add函数中继续调用device_add函数,device_add函数 -----
问:mini2440_init()函数在哪里调用?
答:
MACHINE_START(MINI2440, "MINI2440")
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = mini2440_map_io,
.init_machine = mini2440_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
MACHINE_START/MACHINE_END是什么?后面理解,从上面可以看出是赋值给我init_machine字段,搜索init_machine
init_machine在arch/arm/kernel/setup.c中被customize_machine调用;customize_machine放在了arch_initcall中,arch_initcall(customize_machine);
arch_initcall是什么?
arch_initcall是一个宏定义,定义在include/linux/init.h文件中
#define arch_initcall(fn) __define_initcall("3",fn,3)
__define_initcall也是一个宏定义,也定义在include/linux/init.h
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
__define_initcall的作用:将fn放在".initcall" level ".init"
arch_initcall(customize_machine)-> __define_initcall("3",customize_machine,3)->将customize_machine放在".initcall3.init"
.initcall3.init做什么用的?
学习这篇博客:https://blog.csdn.net/ooonebook/article/details/52690132
--------------- 以dm9000网卡驱动为例追踪platform_device怎么样注册platform总线的 ------------------------
总结:不同架构在将device注册进内核的方式不一样,像上面mini2440,内核启动时就会将设备注册到platform总线。还有一些则是在驱动的实现代码中将device加入到platform总线,例如hisfc300驱动
2. platform_device怎么样注册到platform?
驱动程序调用drivers/base/platform.c下的platform_device_register,platform_device_register又调用drivers/base/platform.c文件中的platform_device_add函数
xxx_module_init() //驱动模块入口函数
platform_device_register(struct platform_device *pdev)
platform_device_add(struct platform_device *pdev)
device_add(struct device *dev)
bus_probe_device(struct device *dev)
device_attach(struct device *dev)
bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
__device_attach(struct device_driver *drv, void *data)
driver_match_device(struct device_driver *drv, struct device *dev)
drv->bus->match(dev, drv) // 调用了struct device_driver下的struct bus_type *bus中的match函数,struct bus_type *bus在platform_device_add中被赋值。
driver_probe_device(drv, dev);
really_probe(struct device *dev, struct device_driver *drv)
dev->bus->probe(dev)或者drv->probe(dev); // 优先使用struct device中bus的probe函数,如果struct device中bus的probe为空,则使用struct device_driver中的probe函数
driver层:
struct platform_driver结构体中的probe函数
}
以hisfc300驱动为例理解内核platform驱动总线平台(drivers/mtd/devices/hisfc300/hisfc300.c)
----------------------------------------------------------------------------------------------------------
spi_master: spi_master代表一个主机控制器
spi_device: spi_device代表一个外围spi设备
spi_driver: pi_driver代表一个SPI协议驱动,
基于内核platform总线驱动框架、platform_device, platform_driver, spi_device, spi_driver
struct platform_driver
struct device_driver --->
platform_driver->向总线注册驱动,platform_device向总线挂载设备,总线根据name,选择device对应的driver,找到后执行dirver下的probe函数
drivers\spi\spi_s3c24xx.c
platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe); // drivers/base/platform.c, s3c24xx_spi_probe作用?
drv->probe = probe; // 将s3c24xx_spi_probe赋给s3c24xx_spi_driver的probe
platform_driver_register(drv); // drivers/base/platform.c
driver_register(&drv->driver); // 将s3c24xx_spi_driver注册到platform bus
bus_add_driver()
arch\arm\mach-s3c2440\mach-smdk2440.c
smdk2440_machine_init()
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
platform_device_register
smdk2440_machine_init()在内核启动时调用
Start_kernel() -> setup_arch() -> setup_machine() -> lookup_machine_type()
内核启动的时候, platform_device 是优先于 platform_driver 注册的。 比如 platform_device A , 是在arch/arm/mach-XXXX/mach-XXXX.c 文件里注册的, 而这个文件的代码是 优先于 platform_driver_register 执行的。
所以在你platform_driver_register执行的时候, platform_device A已经被挂在platform_bus总线上了, 而platform_driver_register()有个功能是到platform_bus上去挨个找寻,找寻挂在上面的platform_bus上的platform_device。找到了就执行probe()。
内核初始化platform总线:
start_kernel
rest_init
kernel_init()
do_basic_setup() // init/main.c
driver_init() // drivers/base/init.c
platform_bus_init() // drivers/base/platform.c 初始化platform总线
device_register(&platform_bus);
bus_register(&platform_bus_type);
platform_bus_type ==> platform_match(dev和drv的配对原则)
platform设备驱动模型理解相关推荐
- char添加一个字符_LINUX字符设备驱动模型分析(起始篇)
在前面几个模块的介绍中,我们主要以vfs为起始,完成了sysfs.设备-总线-驱动模型.platform设备驱动模型.i2c设备驱动模型.spi设备驱动模型的分析.在对这些模块进行分析的时候,我们或多 ...
- Linux驱动-platform设备驱动
#1 platform设备驱动模型数据结构 一般总线驱动设备数据结构 驱动 总线 设备 device_driver bus_type device 一般总线驱动设备数据结构 驱动 总线 设备 plat ...
- Linux设备驱动模型之platform(平台)总线详解
/********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...
- Linux Platform平台设备驱动模型
Linux总线设备驱动模型主要包含总线.设备.驱动三个部分. 现实总线:一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI.USB.I2C.SPI等的设备而言,这自然不是问 ...
- linux平台设备驱动模型是什么意思,Linux设备驱动模型之我理解
点击(此处)折叠或打开 /* my_bus.c */ #include #include #include #include #include #include "my_bus.h&qu ...
- Linux SPI总线设备驱动模型详解
随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...
- 设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动
以下内容转载于微信公众号:嵌入式企鹅圈.如有侵权,请告知删除. 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术. 对于初学者来说会非常 ...
- 【Bus】编写一个Demo虚拟的总线-设备-驱动模型
文章目录 1. 前言 2. 总线驱动模型三要素 2.1 总线 2.2 设备 2.3 驱动 3. Demo Code 3.1 virt_bus_core.c 3.2 virt_device.c 3.3 ...
- 嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)
###你好!这里是风筝的博客, ###欢迎和我一起交流. 前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案. Linux早期时候,一个驱 ...
最新文章
- puppet 深入讲解
- 删除与剪切有何区别?
- TFS 路径...已在工作区...
- quartz工程容器启动与 Service注入
- glide 压缩图拍呢_用Glide-图片的压缩-图片压缩原理
- 自学C语言能到达怎样的高度?
- 免费网页模板提供站推荐
- 【光学】基于matlab圆孔菲涅尔衍射【含Matlab源码 522期】
- 基于Rasa_NLU的微信chatbot
- txt文本保存操作(新建文件夹以及保存txt文本)
- 信号、频谱、能量、功率、噪声
- 编译项目时报出已经定义了构造器
- 【无标题】python类报错:takes no arguments
- 逃离x86架构-----CPU体系结构CISC与RISC之争
- mysql脚本修改大量数据问题
- 漂亮的表格样式(使用CSS样式表控制表格样式)
- 草图大师素材是如何快速导入到模型中的呢?草图溜溜来替你解答
- ins的更新带来的一系列问题
- 日常工作,完全无需付费软件(Windows除外)
- githup用户名密码怎么看_最新tplink路由器如何设置密码 tplink路由器设置密码步骤【详解】...