asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
#ifdef CONFIG_KGDB_KDB
if (unlikely(kdb_trap_printk)) {
va_start(args, fmt);
r = vkdb_printf(fmt, args);
va_end(args);
return r;
}
#endif
va_start(args, fmt);
r = vprintk(fmt, args); -》》跟踪vprintk
va_end(args);
return r;
}
vprintk->console_unlock->call_console_drivers->_call_console_drivers->con->write
con是注册的各个终端
con->write是调用console的写方法
static struct console ram_console = {
.name = "ram",
.write = ram_console_write,
.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
.index = -1,
};
对于 ram_console就是ram_console_write
对于串口控制台为 mux_console_write
static struct console mux_console = {
.name = "ttyB",
.write = mux_console_write,
.device = mux_console_device,
.setup = mux_console_setup,
.flags = CON_ENABLED | CON_PRINTBUFFER,
.index = 0,
};
mux_console_write 直接操作到硬件
static void mux_console_write(struct console *co, const char *s, unsigned count)
{
/* Wait until the FIFO drains. */
while(UART_GET_FIFO_CNT(&mux_ports[0].port))
udelay(1);
while(count--) {
if(*s == '\n') {
UART_PUT_CHAR(&mux_ports[0].port, '\r');
}
UART_PUT_CHAR(&mux_ports[0].port, *s++);
}
}
#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
可见,如果要自定义一个控制台,就得自定义一个console结构体,和它的方法,设置好标志位,对于每个console来说,如果设置了CON_ENABLE,提供write方法,则printk被调用时将把数据通过console输出。
static void __call_console_drivers(unsigned start, unsigned end)
{
struct console *con;
for_each_console(con) {
if (exclusive_console && con != exclusive_console)
continue;
if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME)))
con->write(con, &LOG_BUF(start), end - start);
}
}