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

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)

{

     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)

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值