rev 0.2快乐虾http://blog.csdn.net/lights_joy/lights@hb165.com本文适用于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){unsignedlong flags;unsignedlong _con_start, _log_end;unsignedlong 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.*/staticvoid call_console_drivers(unsignedlong start, unsignedlong end){unsignedlong cur_index, start_print;staticint 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*/staticvoid _call_console_drivers(unsignedlong start,unsignedlong 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*/staticvoid __call_console_drivers(unsignedlong start, unsignedlong 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*/staticvoidbfin_serial_console_write(struct console *co, constchar *s, unsignedint 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, constchar *s,unsignedint count,void (*putchar)(struct uart_port *, int)){unsignedint 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:staticvoid 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();}