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的配对原则)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值