1,内核调试打印用串口2,共4个串口,id 为0, 1, 2, 3
2,init.rc cmdline= init=/init console=ttyS2,115200
3,各个串口的定义
Devices.c (arch/arm/mach-pxa/generic)
static struct resource pxa_resource_ffuart[] = {
{
.start = 0x40100000,
.end = 0x40100023,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_FFUART,
.end = IRQ_FFUART,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device pxa_device_ffuart= {
.name = "pxa2xx-uart",
.id = 0,
.resource = pxa_resource_ffuart,
.num_resources = ARRAY_SIZE(pxa_resource_ffuart),
};
void __init pxa_set_ffuart_info(struct pxa_uart_mach_info *info)
{
pxa_register_device(&pxa_device_ffuart, info);
}
static struct resource pxa_resource_btuart[] = {
{
.start = 0x40200000,
.end = 0x40200023,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_BTUART,
.end = IRQ_BTUART,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device pxa_device_btuart = {
.name = "pxa2xx-uart",
.id = 1,
.resource = pxa_resource_btuart,
.num_resources = ARRAY_SIZE(pxa_resource_btuart),
};
void __init pxa_set_btuart_info(struct pxa_uart_mach_info *info)
{
pxa_register_device(&pxa_device_btuart, info);
}
static struct resource pxa_resource_stuart[] = {
{
.start = 0x40700000,
.end = 0x40700023,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_STUART,
.end = IRQ_STUART,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device pxa_device_stuart = {
.name = "pxa2xx-uart",
.id = 2,
.resource = pxa_resource_stuart,
.num_resources = ARRAY_SIZE(pxa_resource_stuart),
};
void __init pxa_set_stuart_info(struct pxa_uart_mach_info *info)
{
pxa_register_device(&pxa_device_stuart, info);
}
static struct resource pxa_resource_hwuart[] = {
{
.start = 0x41600000,
.end = 0x4160002F,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_HWUART,
.end = IRQ_HWUART,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device pxa_device_hwuart = {
.name = "pxa2xx-uart",
.id = 3,
.resource = pxa_resource_hwuart,
.num_resources = ARRAY_SIZE(pxa_resource_hwuart),
};
void __init pxa_set_hwuart_info(struct pxa_uart_mach_info *info)
{
pxa_register_device(&pxa_device_hwuart, info);
}
4,串口平台驱动数据结构的定义
Pxa.c (drivers/serial)
static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe,
.remove = serial_pxa_remove,
.suspend = serial_pxa_suspend,
.resume = serial_pxa_resume,
.driver = {
.name = "pxa2xx-uart",
.owner = THIS_MODULE,
},
};
int __init serial_pxa_init(void)
{
int ret;
ret = uart_register_driver(&serial_pxa_reg);
if (ret != 0)
goto out;
ret = platform_driver_register(&serial_pxa_driver);
if (ret != 0) {
uart_unregister_driver(&serial_pxa_reg);
goto out;
}
return ret;
out:
return ret;
}
5,
devices 的 .name = "pxa2xx-uart",
driver的name .driver = {
.name = "pxa2xx-uart",
.owner = THIS_MODULE,
},
都是pxa2xx-uart,注册时mach,就调用probe
6,串口驱动数据结构的定义
static struct console serial_pxa_console = {
.name = "ttyS",
.write = serial_pxa_console_write,
.device = uart_console_device,
.setup = serial_pxa_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial_pxa_reg,
};
控制台= .name = "ttyS", + 串口的ID
也就是ttys0, 或者 ttys1 , ttys2 所以在命令行console =ttys2 这个ttys是console的名字name = "ttyS",,不是串口设备的名字dev_name ,console的名字name 可以和串口设备的名字dev_name不一样,这里两者相同是巧合。
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
.driver_name = "PXA serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = 4,
.cons = PXA_CONSOLE,
};
7,
串口的名字为 .dev_name+id
.dev_name = "ttyS",
所以各个串口的名字分别为ttys0 ttys1 ttys2 ttys3
本板为ttys2为调试串口所以console=ttyS2
serial_pxa_init
uart_register_driver(&serial_pxa_reg);
platform_driver_register(&serial_pxa_driver);
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal = NULL;
int i, retval;
BUG_ON(drv->state);
/*
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
drv->tty_driver = normal;
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
/*
* Initialise the UART state(s).
*/
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
mutex_init(&state->mutex);
tty_port_init(&state->info.port);
init_waitqueue_head(&state->info.delta_msr_wait);
tasklet_init(&state->info.tlet, uart_tasklet_action,
(unsigned long)state);
}
retval = tty_register_driver(normal);
out:
if (retval < 0) {
put_tty_driver(normal);
kfree(drv->state);
}
return retval;
}
启动是根据命令行cmdline console =ttys2 讲consle指向串口2
printk调用serial_pxa_console_write,最终往串口2写字符
下面是printk调用过程
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
return r;
}
asmlinkage int vprintk(const char *fmt, va_list args)
{
.........
emit_log_char(*p);
release_console_sem();
............
}
void release_console_sem(void)
{
..............
call_console_drivers(_con_start, _log_end);
.........
}
static void call_console_drivers(unsigned start, unsigned end)
{.............
_call_console_drivers(start_print, cur_index, msg_level);
............
}
static void _call_console_drivers(unsigned start,
unsigned end, int msg_log_level)
{...........
__call_console_drivers(start, end);
}
static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con;
for (con = console_drivers; con; con = con->next) {
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
con->write(con, &LOG_BUF(start), end - start);
}
}
最终调用serial_pxa_console_write