DSP

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

2019-07-13 15:49发布

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)