Linux的终端设备这一块,涉及的面还是比较多的。经过几天的分析,有点收获,就写出来和大家分享分享,如果有不对的地方,还希望大家提出来。
s3c2440的串口驱动部分,分为platform/tty/console三部分。
既然是分析s3c2440的uart部分,那么第一个该看的就是drivers\serial\s3c2410.c文件。在此文件中,可以找到下面的代码:
-
module_init(s3c24xx_serial_modinit);
-
module_exit(s3c24xx_serial_modexit);
通过上面的两句代码,就很明确的告诉我们,首先需要关注的函数就是:s3c24xx_serial_modinit
-
static int __init s3c24xx_serial_modinit(void)
-
{
-
int ret;
-
-
ret = uart_register_driver(&s3c24xx_uart_drv);
-
if (ret < 0) {
-
printk(KERN_ERR "failed to register UART driver\n");
-
return -1;
-
}
-
-
s3c2400_serial_init(); //不需要关注
-
s3c2410_serial_init(); //不需要关注
-
s3c2412_serial_init(); //不需要关注
-
s3c2440_serial_init();
-
-
return 0;
-
}
既然分为三部分,那么这次就只说一部分,那就是platform这一部分,通过前面博文中对platform的分析,可知,会有platform_driver和platform_device两个结构体会被定义。那么就让我们把他们找出来:
platform_driver部分:
通过分析s3c24xx_serial_modinit函数,会发现如下的调用关系:
-
s3c2410_serial_init
-
s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
-
platform_driver_register(drv);
-
driver_register(&drv->driver);
-
bus_add_driver(drv);
-
driver_attach(drv);
-
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
-
fn(dev, data); ---> __driver_attach(dev, data);
-
driver_probe_device(drv, dev);
-
drv->bus->match(dev, drv) ---> platform_match
-
(strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0)
-
really_probe(dev, drv);
也就是说,s3c24xx_serial_modinit将s3c2410_serial_drv这个实例化的platform_driver结构体注册到了platform总线上。
-
static struct platform_driver s3c2440_serial_drv = {
-
.probe = s3c2440_serial_probe,
-
.remove = s3c24xx_serial_remove,
-
.suspend = s3c24xx_serial_suspend,
-
.resume = s3c24xx_serial_resume,
-
.driver = {
-
.name = "s3c2440-uart",
-
.owner = THIS_MODULE,
-
},
-
};
platform_driver部分:
有platform_driver,自然就有platform_device。我们可以在arch\arm\plat-s3c24xx\Cpu.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);
在查找s3c24xx_uart_devs这个东东时,发现arch\arm\plat-s3c24xx\Devs.c中有如下定义
-
struct platform_device *s3c24xx_uart_devs[3] = {
-
};
也就是它默认定义为指向platform_device的指针数组,那细想,自然会有地方会对其进行赋值。s3c24xx_uart_devs赋值的地方又在什么地方呢??在源码中搜索,会发下函数:
-
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; //给s3c24xx_uart_devs进行赋值
-
-
platdev->name = name;
-
platdev->resource = resp->resources;
-
platdev->num_resources = resp->nr_resources;
-
-
platdev->dev.platform_data = cfgptr;
-
}
-
-
nr_uarts = no; //给nr_uarts进行赋值
-
}
那么s3c24xx_init_uartdevs又是在什么地方被调用的呢?其调用关系如下:
-
smdk2440_map_io
-
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
-
cpu = s3c_lookup_cpu(idcode);
-
tab = cpu_ids;
-
for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
-
if ((idcode & tab->idmask) == tab->idcode)
-
return tab;
-
}
-
(cpu->map_io)(mach_desc, size); ---> s3c244x_map_io
-
s3c24xx_init_clocks(12000000);
-
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
-
(cpu->init_uarts)(cfg, no); ---> s3c244x_init_uarts
-
s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); //初始化struct platform_device *s3c24xx_uart_devs[3]
smdk2440_map_io则是在内核启动的第二阶段被调用的:
-
start_kernel
-
setup_arch(&command_line);
-
mdesc = setup_machine(machine_arch_type);
-
lookup_machine_type(nr);
-
machine_name = mdesc->name;
-
paging_init(&meminfo, mdesc);
-
devicemaps_init(mdesc);
-
mdesc->map_io();
-
init_arch_irq = mdesc->init_irq;
-
system_timer = mdesc->timer;
-
init_machine = mdesc->init_machine;
-
-
-
MACHINE_START(S3C2440, "SMDK2440")
-
/* Maintainer: Ben Dooks <ben@fluff.org> */
-
.phys_io = S3C2410_PA_UART,
-
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
-
.boot_params = S3C2410_SDRAM_PA + 0x100,
-
-
.init_irq = s3c24xx_init_irq,
-
.map_io = smdk2440_map_io,
-
.init_machine = smdk2440_machine_init,
-
.timer = &s3c24xx_timer,
-
MACHINE_END
到此,s3c2440的串口的platform部分就说完了,系统在注册s3c24xx_init_uartdevs后,又注册了s3c2410_serial_drv,之后就会自动调用s3c2440_serial_probe,其作用将在 基于Linux2.6.22和s3c2440的串口驱动简析---(2)中进行分析。
阅读(7278) | 评论(0) | 转发(1) |