uclinux内核的console(4):通过console输出信息

rev 0.2

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADI bf561 DSP

优视BF561EVB开发板

uclinux-2008r1.5-rc3 (smp patch)

Visual DSP++ 5.0 (update 5)

欢迎转载,但请保留作者信息

在内核中,向console输出信息是通过release_console_sem函数来完成的:

/**

* release_console_sem - unlock the console system

*

* Releases the semaphore which the caller holds on the console system

* and the console driver list.

*

* While the semaphore was held, console output may have been buffered

* by printk(). If this is the case, release_console_sem() emits

* the output prior to releasing the semaphore.

*

* If there is output waiting for klogd, we wake it up.

*

* release_console_sem() may be called from any context.

*/

void release_console_sem(void)

{

unsigned long flags;

unsigned long _con_start, _log_end;

unsigned long wake_klogd = 0;

if (console_suspended) {

up(&secondary_console_sem);

return;

}

console_may_schedule = 0;

for ( ; ; ) {

spin_lock_irqsave(&logbuf_lock, flags);

wake_klogd |= log_start - log_end;

if (con_start == log_end)

break; /* Nothing to print */

_con_start = con_start;

_log_end = log_end;

con_start = log_end; /* Flush */

spin_unlock(&logbuf_lock);

call_console_drivers(_con_start, _log_end);

local_irq_restore(flags);

}

console_locked = 0;

up(&console_sem);

spin_unlock_irqrestore(&logbuf_lock, flags);

if (wake_klogd)

wake_up_klogd();

}

在这里,实际输出通过call_console_drivers函数完成:

/*

* Call the console drivers, asking them to write out

* log_buf[start] to log_buf[end - 1].

* The console_sem must be held.

*/

static void call_console_drivers(unsigned long start, unsigned long end)

{

unsigned long cur_index, start_print;

static int msg_level = -1;

BUG_ON(((long)(start - end)) > 0);

cur_index = start;

start_print = start;

while (cur_index != end) {

if (msg_level < 0 && ((end - cur_index) > 2) &&

LOG_BUF(cur_index + 0) == '<' &&

LOG_BUF(cur_index + 1) >= '0' &&

LOG_BUF(cur_index + 1) <= '7' &&

LOG_BUF(cur_index + 2) == '>') {

msg_level = LOG_BUF(cur_index + 1) - '0';

cur_index += 3;

start_print = cur_index;

}

while (cur_index != end) {

char c = LOG_BUF(cur_index);

cur_index++;

if (c == '\n') {

if (msg_level < 0) {

/*

* printk() has already given us loglevel tags in

* the buffer. This code is here in case the

* log buffer has wrapped right round and scribbled

* on those tags

*/

msg_level = default_message_loglevel;

}

_call_console_drivers(start_print, cur_index, msg_level);

msg_level = -1;

start_print = cur_index;

break;

}

}

}

_call_console_drivers(start_print, end, msg_level);

}

继续跟踪_call_console_drivers

/*

* Write out chars from start to end - 1 inclusive

*/

static void _call_console_drivers(unsigned long start,

unsigned long end, int msg_log_level)

{

if ((msg_log_level < console_loglevel || ignore_loglevel) &&

console_drivers && start != end) {

if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {

/* wrapped write */

__call_console_drivers(start & LOG_BUF_MASK,

log_buf_len);

__call_console_drivers(0, end & LOG_BUF_MASK);

} else {

__call_console_drivers(start, end);

}

}

}

继续跟踪__call_console_drivers

/*

* Call the console drivers on a range of log_buf

*/

static void __call_console_drivers(unsigned long start, unsigned long 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);

}

}

嘿嘿,原来是调用console结构体中的write函数!记得我们在内核中是使用了bfin_serial_console做为我们的console,而这个结构体中的write回调函数则初始化为bfin_serial_console_write,这个函数在drivers\serial\bfin_5xx.c

/*

* Interrupts are disabled on entering

*/

static void

bfin_serial_console_write(struct console *co, const char *s, unsigned int count)

{

struct bfin_serial_port *uart = &bfin_serial_ports[co->index];

int flags = 0;

spin_lock_irqsave(&uart->port.lock, flags);

uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);

spin_unlock_irqrestore(&uart->port.lock, flags);

}

再跟踪uart_console_write此函数位于drivers\serial\serial_core.c

/*

* uart_console_write - write a console message to a serial port

* @port: the port to write the message

* @s: array of characters

* @count: number of characters in string to write

* @write: function to write character to port

*/

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);

}

}

因为uart是一个通用的抽象接口,它需要指定与具体硬件相关的函数来进行输出,在我们的调用中使用了bfin_serial_console_putchar做为回调函数,因此实际输出是通过bfin_serial_console_putchar来完成的,此函数在drivers\serial\bfin_5xx.c

static void bfin_serial_console_putchar(struct uart_port *port, int ch)

{

struct bfin_serial_port *uart = (struct bfin_serial_port *)port;

while (!(UART_GET_LSR(uart) & THRE))

barrier();

UART_PUT_CHAR(uart, ch);

SSYNC();

}

1 参考资料

uclinux-2008r1-rc8(bf561)内核的console(1):数据结构2008/5/29

uclinux-2008r1-rc8(bf561)内核的console(2):驱动初始化(2008/5/29)

uclinux-2008r1-rc8(bf561)核的console(3):通过console输出信息(2008/5/29)

uclinux内核的console(1):数据结构(2009-1-31)

uclinux内核的console(2)early console(2009-1-31)

uclinux内核的console(3)console驱动初始化(2009-1-31)

你可能感兴趣的:(数据结构,C++,c,C#,UP)