查找mach-xxx.c文件,platform_device數組中並沒有uart設備。但看uart驅動,發現採用的還是platform方式註冊的,那uart設備是在哪裏添加的呢?
看下面代碼,位於文件arch/arm/plat-samsung/init.c
static int __init s3c_arch_init(void)
{
int ret;
// do the correct init for cpu
if (cpu == NULL)
panic("s3c_arch_init: NULL cpu\n");
ret = (cpu->init)();
if (ret != 0)
return ret;
ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
return ret;
}
arch_initcall(s3c_arch_init);
這裏可以發現,在平臺初始化代碼中,有這麼一段arch初始化代碼,裏面單獨調用了platform_add_devices添加uart設備。因此,我們可以知道uart設備實在此處添加的。
但搜索s3c24xx_uart_devs,發現該變量定義爲空。
arch/arm/plat-samsung/dev-uart.c:
static struct platform_device s3c24xx_uart_device0 = {
.id = 0,
};
static struct platform_device s3c24xx_uart_device1 = {
.id = 1,
};
static struct platform_device s3c24xx_uart_device2 = {
.id = 2,
};
static struct platform_device s3c24xx_uart_device3 = {
.id = 3,
};
struct platform_device *s3c24xx_uart_src[4] = {
&s3c24xx_uart_device0,
&s3c24xx_uart_device1,
&s3c24xx_uart_device2,
&s3c24xx_uart_device3,
};
struct platform_device *s3c24xx_uart_devs[4] = {
};
有個src變量、有一個devs變量,再看下一段代碼,
arch/arm/plat-samsung/init.c:
void __init s3c24xx_init_uartdevs(char *name,
struct s3c24xx_uart_resources *res,
struct s3c2410_uartcfg *cfg, int no)
{
struct platform_device *platdev;
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
struct s3c24xx_uart_resources *resp;
int uart;
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
platdev = s3c24xx_uart_src[cfgptr->hwport];
resp = res + cfgptr->hwport;
s3c24xx_uart_devs[uart] = platdev;
platdev->name = name;
platdev->resource = resp->resources;
platdev->num_resources = resp->nr_resources;
platdev->dev.platform_data = cfgptr;
}
nr_uarts = no;
}
該函數完成了從src到devs的搬移,並添加了額外的信息,完善了整個uart平臺設備。那調用在哪裏?
arch/arm/mach-s3c64xx.c:
void __init s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
s3c24xx_init_uartdevs("s3c6400-uart", s3c64xx_uart_resources, cfg, no);
}
static const char name_s3c6400[] = "S3C6400";
static const char name_s3c6410[] = "S3C6410";
static struct cpu_table cpu_ids[] __initdata = {
{
.idcode = 0x36400000,
.idmask = 0xfffff000,
.map_io = s3c6400_map_io,
.init_clocks = s3c6400_init_clocks,
.init_uarts = s3c6400_init_uarts,
.init = s3c6400_init,
.name = name_s3c6400,
}, {
.idcode = 0x36410100,
.idmask = 0xffffff00,
.map_io = s3c6410_map_io,
.init_clocks = s3c6410_init_clocks,
.init_uarts = s3c6410_init_uarts,
.init = s3c6410_init,
.name = name_s3c6410,
},
};
arch/arm/mach-s3c64xx/include/mach/s3c6410.c:
#define s3c6410_init_uarts s3c6400_common_init_uarts
通過宏定義將common_init_uarts定義爲了init_uarts,在賦值給cpu_table成員函數init_uarts。
那init_uarts成員函數是在哪裏被調用的呢?再回到arch/arm/plat-samsung/init.c:
void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
if (cpu == NULL)
return;
if (cpu->init_uarts == NULL) {
printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
} else
(cpu->init_uarts)(cfg, no);
}
arch/arm/mach-s3c64xx/mach-mini6410.c:
static void __init mini6410_map_io(void)
{
u32 tmp;
s3c64xx_init_io(mini6410_iodesc, ARRAY_SIZE(mini6410_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs));
/* set the LCD type */
tmp = __raw_readl(S3C64XX_SPCON);
tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
__raw_writel(tmp, S3C64XX_SPCON);
/* remove the lcd bypass */
tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
tmp &= ~MIFPCON_LCD_BYPASS;
__raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
#ifdef CONFIG_VIDEO_SAMSUNG
s3c64xx_reserve_bootmem();
#endif
}
MACHINE_START(MINI6410, "MINI6410")
/* Maintainer: Ben Dooks <[email protected]> */
.boot_params = S3C64XX_PA_SDRAM + 0x100,
.init_irq = s3c6410_init_irq,
.map_io = mini6410_map_io,
.init_machine = mini6410_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
分析到這裏也就差不多了,map_io成員函數會在start_kernel函數中執行,且在rest_init之前,因此會早於所有initcall函數。這就確保了uart平臺設備變量初始化好了之後才被添加到系統。