Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1176570
  • 博文数量: 93
  • 博客积分: 7185
  • 博客等级: 准将
  • 技术积分: 3560
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-02 13:54
文章分类
文章存档

2011年(43)

2010年(11)

2009年(27)

2008年(12)

分类: 嵌入式

2009-09-07 23:31:44

18 .Uart devices register and driver select

1.machine
cpu的检测与uart设备名的设置
CPU S3C2440A (id 0x32440001) [setup_arch->paging_init->devicemaps_init->mdesc->smdk2410_map_io->s3c24xx_init_io]
   mdesc
SMDK2410,smdk2410_map_io->s3c24xx_init_io根据cpuid设置arm/plat-s3c24xx的全局变量cpu.然后mdk2410_map_io
调用s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));通过(cpu->init_uarts)(cfg, no);注册cpu特的定的uart资源. cpu_idsarch/arm/plat-s3c24xx/cpu.c,其中2440auart初始化函数是:

void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
    s3c24xx_init_uartdevs("
s3c2440-uart", s3c2410_uart_resources, cfg, no);
}
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;  /*uartplatform设备*/

        platdev->name = name;   /*platform 设备名称初始化为 "s3c2440-uart" */
        platdev->resource = resp->resources;
        platdev->num_resources = resp->nr_resources;

        platdev->dev.platform_data = cfgptr;
    }

    nr_uarts = no;
}
然后arch_initcall(s3c_arch_init);-> platform_add_devices(s3c24xx_uart_devs, nr_uarts);注册设备到
platform_bus_type.

2.console 设备初始化

selected clock c0239b70 (pclk) quot 26, calc 115740 [console_initcall(s3c24xx_serial_initconsole)->register_console->console.setup->s3c24xx_serial_console.setup(s3c24xx_serial_console_setup)->uart_set_options->s3c24xx_serial_set_termios->s3c24xx_serial_getclk]console [ttySAC1] enabled                             [console_initcall(s3c24xx_serial_initconsole)->register_console]
先是根据内核命令行选择并配置一个uart的驱动:static int s3c24xx_serial_initconsole(void){
    struct s3c24xx_uart_info *info;
    struct platform_device *dev =
s3c24xx_uart_devs[0]; /*上面已经初始化了*/
    ......
    } else if (strcmp(dev->name, "s3c2440-uart") == 0) {
        info = s3c2440_uart_inf_at;  /*
据设备名称(通过cpu设这的,见上面第一节分析*/
    }
    ........
    s3c24xx_serial_console.data = &
s3c24xx_uart_drv; /*选择uart驱动: ttySACx, 204,64-66*/
    s3c24xx_serial_init_ports(info);

    register_console(&s3c24xx_serial_console);
    return 0;
}
然后再根据命令行参数选择uart端口和波特率:
void
register_console(struct console *console) /*s3c24xx_serial_console*/
{
    ......
    for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
            i++) {
        if (strcmp(console_cmdline[i].name, console->name) != 0)
            continue;
        if (console->index >= 0 &&
            console->index != console_cmdline[i].index)
            continue;
        if (console->index < 0)
            console->index = console_cmdline[i].index;
        if (console->setup &&
            console->setup(console, console_cmdline[i].options) != 0) /*options
中存的是波特率*/
            break;
        console->flags |= CON_ENABLED;
        console->index = console_cmdline[i].index; /*
我们的选择是ttySAC1*/
        if (i == selected_console) {
            console->flags |= CON_CONSDEV;
            preferred_console = selected_console;
        }
        break;
    }
.............
}

3.uart设备驱动初始化

Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled [ module_init(serial8250_init)]
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440

上面三行信息就是uart初始化的信息,具体是在uart_report_port这个函数内打印的.但是通过什么路径确时费了番周折.串口初始化就是
module_init(s3c24xx_serial_modinit)
static int __init s3c24xx_serial_modinit(void)
{
    int ret;

    ret = uart_register_driver(&s3c24xx_uart_drv); /*选择uart驱动: ttySACx, 204,64-66,设备名称s3c2410_serial*/
    if (ret < 0) {
        printk(KERN_ERR "failed to register UART driver ");
        return -1;
    }
    s3c2400_serial_init();  /*
这里有4cpu的串口初始化函数,到底那个可以成功?*/
    s3c2410_serial_init();  /*
这个在配置里选上了*/
    s3c2412_serial_init();
    s3c2440_serial_init();  /*
这个也在配置里选上了*/
    return 0;
}
只从打印信息看,当然是选择了2440那个,下面从代码里找这个根据:
static inline int s3c2410_serial_init(void)
{
    return
s3c24xx_serial_init(&s3c2410_serial_drv, &s3c2410_uart_inf);
}
static inline int s3c2440_serial_init(void)
{
    return
s3c24xx_serial_init(&s3c2440_serial_drv, &s3c2440_uart_inf);
}
static struct platform_driver s3c2410_serial_drv = {
    .probe        = s3c2410_serial_probe,
    .remove        = s3c24xx_serial_remove,
    .suspend    = s3c24xx_serial_suspend,
    .resume        = s3c24xx_serial_resume,
    .driver        = {
        .name    = "
s3c2410-uart",
        .owner    = THIS_MODULE,
    },
};
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,
    },
};
上面两个初始化函数其实都是调用:
static int s3c24xx_serial_init->
int platform_driver_register(struct platform_driver *drv)
{
    drv->driver.bus = &
platform_bus_type;
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
    ......
    return driver_register(&drv->driver);
}
driver_register->bus_add_driver->
int
bus_add_driver(struct device_driver *drv)

    ......
    if (drv->bus->
drivers_autoprobe) { /*默认是autoprobe*/
        error = driver_attach(drv);
        if (error)
            goto out_unregister;
    }
  ......
}
driver_attach->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);->
static int __driver_attach(struct device * dev, void * data)
{
    struct device_driver * drv = data;
    .......
    if (!dev->driver) /*
这里就能找到在第一节中注册的uart dev*/
       
driver_probe_device(drv, dev);
    }
    .....
}
int
driver_probe_device(struct device_driver * drv, struct device * dev)
{
    int ret = 0;
    if (drv->bus->match && !drv->bus->match(dev, drv))
        goto done;
    ret = really_probe(dev, drv); /*
-> dev->bus->probe(dev)或者drv->probe(dev),这个bus没有probe*/
    ....
}
这里终于找到判定一个设备的驱动的条件:platform_bus_type ->platform_match->就是一个字符创的比较,看设备和驱动的名字是否一致:
strncmp(pdev->name, drv->name, BUS_ID_SIZE)
翻翻上面注册的名字,当然是2440的驱动胜出. 所以probe就调用了:
s3c2440_serial_probe->uart_add_one_port->uart_report_port.

4. uart设备注册后对console设备的影响(register_console只是早期注册给内核printk)
第二节谈到console的注册:
static int s3c24xx_serial_initconsole(void)
{
    struct platform_device *dev =
s3c24xx_uart_devs[0]; /*上面已经初始化了*/
    ......
    s3c24xx_serial_console.data = &
s3c24xx_uart_drv; /*选择uart驱动: ttySACx, 204,64-66*/
    register_console(&
s3c24xx_serial_console);
    return 0;
}
static struct console
s3c24xx_serial_console =
{
    .name        = S3C24XX_SERIAL_NAME,
    .device        = uart_console_device, /*
找到此console对应的tty*/
    .flags        = CON_PRINTBUFFER,
    .index        = -1,
    .write        = s3c24xx_serial_console_write,
    .setup        = s3c24xx_serial_console_setup
    .data =  &
s3c24xx_uart_drv;
};
static struct uart_driver
s3c24xx_uart_drv = {
    .owner        = THIS_MODULE,
    .dev_name    = "s3c2410_serial",
    .nr        = 3,
    .cons        = S3C24XX_SERIAL_CONSOLE,
    .driver_name    = S3C24XX_SERIAL_NAME,
    .major        = S3C24XX_SERIAL_MAJOR,
    .minor        = S3C24XX_SERIAL_MINOR,
};
这个console只提供了最少的接口供printk使用.register_console->release_console_sem.

然后,在第三节谈到的uart设备初始化中:
static int __init s3c24xx_serial_modinit(void)
{
    int ret;
    ret = uart_register_driver(&
s3c24xx_uart_drv); /*初始化s3c24xx_uart_drv->tty_driver*/
     /*
初始化tty_driveruart_console_device就能找到对应tty设备了*/
   ...
}
static inline int s3c2440_serial_init->s3c24xx_serial_init(&
s3c2440_serial_drv, &s3c2440_uart_inf)-> __driver_attach ->...->really_probe,将注册的uart platform_device设备进行进一步初始化:dev->driver = drv;要注意s3c2440_serial_drvplatform_driver,而不是uart_driver:s3c24xx_uart_drv().

阅读(2093) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~