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设备驱动模型理解相关推荐

  1. char添加一个字符_LINUX字符设备驱动模型分析(起始篇)

    在前面几个模块的介绍中,我们主要以vfs为起始,完成了sysfs.设备-总线-驱动模型.platform设备驱动模型.i2c设备驱动模型.spi设备驱动模型的分析.在对这些模块进行分析的时候,我们或多 ...

  2. Linux驱动-platform设备驱动

    #1 platform设备驱动模型数据结构 一般总线驱动设备数据结构 驱动 总线 设备 device_driver bus_type device 一般总线驱动设备数据结构 驱动 总线 设备 plat ...

  3. Linux设备驱动模型之platform(平台)总线详解

    /********************************************************/ 内核版本:2.6.35.7 运行平台:三星s5pv210 /*********** ...

  4. Linux Platform平台设备驱动模型

    Linux总线设备驱动模型主要包含总线.设备.驱动三个部分. 现实总线:一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI.USB.I2C.SPI等的设备而言,这自然不是问 ...

  5. linux平台设备驱动模型是什么意思,Linux设备驱动模型之我理解

    点击(此处)折叠或打开 /* my_bus.c   */ #include #include #include #include #include #include "my_bus.h&qu ...

  6. Linux SPI总线设备驱动模型详解

    随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...

  7. 设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动

    以下内容转载于微信公众号:嵌入式企鹅圈.如有侵权,请告知删除. 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sysfs等相关概念和技术. 对于初学者来说会非常 ...

  8. 【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 ...

  9. 嵌入式Linux驱动笔记(十六)------设备驱动模型(kobject、kset、ktype)

    ###你好!这里是风筝的博客, ###欢迎和我一起交流. 前几天去面试,被问到Linux设备驱动模型这个问题,没答好,回来后恶补知识,找了些资料,希望下次能答出个满意答案. Linux早期时候,一个驱 ...

最新文章

  1. puppet 深入讲解
  2. 删除与剪切有何区别?
  3. TFS 路径...已在工作区...
  4. quartz工程容器启动与 Service注入
  5. glide 压缩图拍呢_用Glide-图片的压缩-图片压缩原理
  6. 自学C语言能到达怎样的高度?
  7. 免费网页模板提供站推荐
  8. 【光学】基于matlab圆孔菲涅尔衍射【含Matlab源码 522期】
  9. 基于Rasa_NLU的微信chatbot
  10. txt文本保存操作(新建文件夹以及保存txt文本)
  11. 信号、频谱、能量、功率、噪声
  12. 编译项目时报出已经定义了构造器
  13. 【无标题】python类报错:takes no arguments
  14. 逃离x86架构-----CPU体系结构CISC与RISC之争
  15. mysql脚本修改大量数据问题
  16. 漂亮的表格样式(使用CSS样式表控制表格样式)
  17. 草图大师素材是如何快速导入到模型中的呢?草图溜溜来替你解答
  18. ins的更新带来的一系列问题
  19. 日常工作,完全无需付费软件(Windows除外)
  20. githup用户名密码怎么看_最新tplink路由器如何设置密码 tplink路由器设置密码步骤【详解】...

热门文章

  1. 保利威Service+战略发布会「服务+技术」开启私域直播新纪元
  2. python毕业设计选题推荐100例
  3. WIN7装NVME SSD固态硬盘所需的KB2990941 和 KB3087873 补丁微软下载地址
  4. centos E440 安装无线网卡
  5. 【预测模型-DELM分类】基于哈里斯鹰算法改进深度学习极限学习机实现数据分类附matlab代码
  6. python+opencv 打开网络摄像头
  7. RichEdit Ole生命周期
  8. 【JavaScript】JS高频手写汇总
  9. 2019最新《Python网络爬虫数据采集课程完整》
  10. 牛客网 刷题前的准备工作(输入 输出 如何接收?)