Linux内核---17.platform_device的添加过程

一、平台设备platform_device的添加过程
内核: Linux 2.6.25
硬件: TQ2440
函数调用过程如下:
start_kernel 
    -->rest_init 
        -->  开启一个线程: kernel_init 
            --> do_basic_setup 
                -->  do_initcalls();          //for循环将所有的__initcall都调用一遍包括smdk2440_machine_init
                    --> customize_machine    // 即 . initcall3 . init在do_initcalls中被调用
                        --> init_machine即smdk2440_machine_init
                            --> platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));      //终于找到了
1. 1 下面从do_initcalls开始分析, 在init/main.c中
  1. 664 static void __init do_initcalls(void)
  2. 665 {
  3. 669     for (call = __initcall_start; call < __initcall_end; call++) {        //查找在__initcall_start 与__initcall_end之间的所有函数,并逐个调用(initcall0.init -- initcall7.init)
  4. ... 
  5. 683          result = (*call)();
  6. 718     }
  7. 719 
  8. 720     /* Make sure there is no pending stuff from the initcall sequence */
  9. 721     flush_scheduled_work();
  10. 722 }
其中, 在 arch/arm/kernel/vmlinux.lds.S 中定义了__initcall_start 与 __init_call_end
  51 __initcall_start  =  . ;
  1.  52     INITCALLS
  2.  53 __initcall_end = .;
include/asm-generic/vmlinux.lds.h 其中INITCALLS的定义如下:
 328 #define INITCALLS  \
  1. 329 *(.initcall0.init) \
  2. 330 *(.initcall0s.init) \
  3. 331 *(.initcall1.init) \
  4. 332 *(.initcall1s.init) \
  5. 333 *(.initcall2.init) \
  6. 334 *(.initcall2s.init) \
  7. 335 *(.initcall3.init) \
  8. 336 *(.initcall3s.init) \
  9. 337 *(.initcall4.init) \
  10. 338 *(.initcall4s.init) \
  11. 339 *(.initcall5.init) \
  12. 340 *(.initcall5s.init) \
  13. 341 *(.initcallrootfs.init) \
  14. 342 *(.initcall6.init) \
  15. 343 *(.initcall6s.init) \
  16. 344 *(.initcall7.init) \
  17. 345 *(.initcall7s.init)
1.2 其中与平台TQ2440相关的函数smdk2440_machine_init,则是在上述的initcall3.init中调用的.
initcall3.init的定义如下:
  1.  779 static int __init customize_machine(void)
     780 {
     781     /* customizes platform devices, or adds new ones */
     782     if (init_machine)                                //如果init_machine不为空指针,则调用init_machine()函数
     783         init_machine();                              //init_machine函数是在arch/arm/mach-s3c440/mach-smdk2440.c中定义了的
     784     return 0;
     785 }
     786 arch_initcall(customize_machine);         //这个宏很重要,下面是分析

  2. include/linux/init.h中
  3. #define arch_initcall(fn)        __define_initcall("3",fn,3)     //宏的定义如下

  4. #define __define_initcall(level,fn,id) \
  5.     static initcall_t __initcall_##fn##id __used \
  6.     __attribute__((__section__(".initcall" level ".init"))) = fn

  7. 即:
  8.    static initcall_t __initcall_customize_machine_3 __used \
  9.     __attribute__((__section__(.initcall3.init))) = customize_machine          //initcall3.init的调用函数是customize_machine
1.3 在 arch/arm/mach-s3c440/mach-smdk2440.c中定义了,函数指针init_machine为smdk2440_machine_init
  1. 166 static void __init smdk2440_machine_init(void)
    167 {
    168     s3c24xx_fb_set_platdata(&smdk2440_fb_info);
    169 
    170     platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
    171     smdk_machine_init();
    172 }
    173 
    174 MACHINE_START(S3C2440, "SMDK2440")
    175     /* Maintainer: Ben Dooks */
    176     .phys_io    = S3C2410_PA_UART,
    177     .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    178     .boot_params    = S3C2410_SDRAM_PA + 0x100,
    179 
    180     .init_irq   = s3c24xx_init_irq,
    181     .map_io     = smdk2440_map_io,
    182     .init_machine   = smdk2440_machine_init,
    183     .timer      = &s3c24xx_timer,
    184 MACHINE_END
所以此时就调用smdk2440_machine_init函数: platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
1.4 在 arch/arm/mach-s3c440/mach-smdk2440.c中定义了所有的smdk2440_devices
  1. 151 static struct platform_device *smdk2440_devices[] __initdata = {
    152     &s3c_device_usb,   // s
    153     &s3c_device_lcd,
    154     &s3c_device_wdt,
    155     &s3c_device_i2c,
    156     &s3c_device_iis,
    157 };

smdk2440_devices[] 是一个struct platform_device数组
                        ├─  s3c_device_usb                         //每一个platform_device又包含了一个struct resource
                        ├─  s3c_lcd          └── struct resource
                        └─ s3c_device_iis

在 arch/arm/plat-s3c24xx/devs.c中定义了s3c_device
  1. 119 static struct resource s3c_usb_resource[] = {
    120     [0] = {
    121         .start = S3C24XX_PA_USBHOST,
    122         .end   = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
    123         .flags = IORESOURCE_MEM,
    124     },
    125     [1] = {
    126         .start = IRQ_USBH,
    127         .end   = IRQ_USBH,
    128         .flags = IORESOURCE_IRQ,
    129     }
    130 };
    131 
    132 static u64 s3c_device_usb_dmamask = 0xffffffffUL;
    133 
    134 struct platform_device s3c_device_usb = {
    135     .name         = "s3c2410-ohci",
    136     .id       = -1,
    137     .num_resources    = ARRAY_SIZE(s3c_usb_resource),
    138     .resource     = s3c_usb_resource,
    139     .dev              = {
    140         .dma_mask = &s3c_device_usb_dmamask,
    141         .coherent_dma_mask = 0xffffffffUL
    142     }
    143 };


二、platform_driver的添加过程

你可能感兴趣的:(linux内核)