看下printk的实现
asmlinkage __visible int printk(const char *fmt, ...)
{
r = vprintk_func(fmt, args);
}
__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{
return vprintk_default(fmt, args);
}
int vprintk_default(const char *fmt, va_list args)
{
r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
}
asmlinkage int vprintk_emit(int facility, int level,const char *dict, size_t dictlen,const char *fmt, va_list args)
{
console_unlock();
}
void console_unlock(void)
{
call_console_drivers(level, text, len);
}
static void call_console_drivers(int level, const char *text, size_t len)
{
struct console *con;
for_each_console(con) {
con->write(con, text, len);
}
}
也就是调用con->write的写接口,把log输出到串口上。
那控制台什么时候注册,以sprd的为例
#define SPRD_TTY_NAME "ttyS"
static struct console sprd_console = {
.name = SPRD_TTY_NAME,
.write = sprd_console_write,
.device = uart_console_device,
.setup = sprd_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &sprd_uart_driver,
};
static int __init sprd_serial_console_init(void)
{
register_console(&sprd_console);
return 0;
}
console_initcall(sprd_serial_console_init);
控制台注册
struct console *console_drivers;
EXPORT_SYMBOL_GPL(console_drivers);
void register_console(struct console *newcon)
{
for (i = 0, c = console_cmdline;i < MAX_CMDLINECONSOLES && c->name[0];i++, c++) {
if (newcon->index < 0)
newcon->index = c->index;
if (newcon->setup &&
newcon->setup(newcon, c->options) != 0)
break;
}
}
if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
newcon->next = console_drivers;
console_drivers = newcon;
} else {
}
}
EXPORT_SYMBOL(register_console);
从命令行中获取控制台信息
console=ttyS1,115200n8
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
static int __add_preferred_console(char *name, int idx, char *options,char *brl_options)
{
struct console_cmdline *c;
int i;
for (i = 0, c = console_cmdline;i < MAX_CMDLINECONSOLES && c->name[0];i++, c++) {
...
}
strlcpy(c->name, name, sizeof(c->name));
c->options = options;
c->index = idx;
return 0;
}
static int __init console_setup(char *str)
{
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */
strncpy(buf, str, sizeof(buf) - 1);
options = strchr(str, ',');
for (s = buf; *s; s++)
if (isdigit(*s) || *s == ',')
break;
idx = simple_strtoul(s, NULL, 10);
__add_preferred_console(buf, idx, options, brl_options);
}
__setup("console=", console_setup);
//看下写串口的实现 write = sprd_console_write
static void sprd_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = &sprd_port[co->index]->port;
uart_console_write(port, s, count, sprd_console_putchar);
}
void uart_console_write(struct uart_port *port, const char *s,unsigned int count,void (*putchar)(struct uart_port *, int))
{
unsigned int i;
for (i = 0; i < count; i++, s++) {
if (*s == '\n')
putchar(port, '\r');
putchar(port, *s);
}
}
static void sprd_console_putchar(struct uart_port *port, int ch)
{
wait_for_xmitr(port);
serial_out(port, SPRD_TXD, ch);
}