查找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平台设备变量初始化好了之后才被添加到系统。