printk的定义
可变参数 参考va_list,va_start,va_arg,va_end可变参数
- asmlinkage int printk(const char *fmt, ...)
- {
- va_list args; //可变参数链表
- int r;
- #ifdef CONFIG_KGDB_KDB
- if (unlikely(kdb_trap_printk)) {
- va_start(args, fmt);
- r = vkdb_printf(fmt, args);
- va_end(args);
- return r;
- }
- #endif
- va_start(args, fmt); //获取第一个可变参数
- r = vprintk(fmt, args); //调用vprintk函数
- va_end(args); //释放可变参数链表指针
- return r;
- }
vprintk函数
- asmlinkage int vprintk(const char *fmt, va_list args)
- {
- int printed_len = 0;
- int current_log_level = default_message_loglevel;
- unsigned long flags;
- int this_cpu;
- char *p;
- boot_delay_msec();
- printk_delay();
- preempt_disable();
- raw_local_irq_save(flags);
- this_cpu = smp_processor_id();
- if (unlikely(printk_cpu == this_cpu)) {
- if (!oops_in_progress) {
- recursion_bug = 1;
- goto out_restore_irqs;
- }
- zap_locks();
- }
- lockdep_off();
- spin_lock(&logbuf_lock);
- printk_cpu = this_cpu;
- if (recursion_bug) {
- recursion_bug = 0;
- strcpy(printk_buf, recursion_bug_msg);
- printed_len = strlen(recursion_bug_msg);
- }
- printed_len += vscnprintf(printk_buf + printed_len,sizeof(printk_buf) - printed_len, fmt, args);
- p = printk_buf;
- if (p[0] == '<') { //处理打印级别字段
- unsigned char c = p[1];
- if (c && p[2] == '>') {
- switch (c) {
- case '0' ... '7': /* loglevel */
- current_log_level = c - '0';
- case 'd': /* KERN_DEFAULT */
- if (!new_text_line) {
- emit_log_char('\n');
- new_text_line = 1;
- }
- case 'c': /* KERN_CONT */
- p += 3;
- break;
- }
- }
- }
- for ( ; *p; p++) {
- if (new_text_line) {
- /* Always output the token */
- emit_log_char('<');
- emit_log_char(current_log_level + '0');
- emit_log_char('>');
- printed_len += 3;
- new_text_line = 0;
- if (printk_time) { //打印时间信息
- /* Follow the token with the time */
- char tbuf[50], *tp;
- unsigned tlen;
- unsigned long long t;
- unsigned long nanosec_rem;
- t = cpu_clock(printk_cpu);
- nanosec_rem = do_div(t, 1000000000);
- tlen = sprintf(tbuf, "[%5lu.%06lu] ",(unsigned long) t,nanosec_rem / 1000);
- for (tp = tbuf; tp < tbuf + tlen; tp++)
- emit_log_char(*tp);
- printed_len += tlen;
- }
- if (!*p)
- break;
- }
- emit_log_char(*p);
- if (*p == '\n')
- new_text_line = 1;
- }
- if (acquire_console_semaphore_for_printk(this_cpu))
- release_console_sem();
- lockdep_on();
- out_restore_irqs:
- raw_local_irq_restore(flags);
- preempt_enable();
- return printed_len;
- }
接着调用release_console_sem函数
- void release_console_sem(void)
- {
- unsigned long flags;
- unsigned _con_start, _log_end;
- unsigned wake_klogd = 0;
- if (console_suspended) {
- up(&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);
- stop_critical_timings(); /* don't trace print latency */
- call_console_drivers(_con_start, _log_end);
- start_critical_timings();
- local_irq_restore(flags);
- }
- console_locked = 0;
- up(&console_sem);
- spin_unlock_irqrestore(&logbuf_lock, flags);
- if (wake_klogd)
- wake_up_klogd();
- }
- EXPORT_SYMBOL(release_console_sem);
调用call_console_drivers函数
- static void call_console_drivers(unsigned start, unsigned end)
- {
- unsigned cur_index, start_print;
- static int msg_level = -1;
- BUG_ON(((int)(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) {
- 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函数
- static void _call_console_drivers(unsigned start,unsigned 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函数
遍历console_drivers数组
- #define for_each_console(con) \
- for (con = console_drivers; con != NULL; con = con->next)
调用console的写方法
- static void __call_console_drivers(unsigned start, unsigned end)
- {
- struct console *con;
- for_each_console(con) {
- 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的写方法
- }
- }
二 console 设备驱动