ARM架构处理器MT6572的LK printf 与UART串口打印分析

来源:互联网 发布:网络文明传播 编辑:程序博客网 时间:2024/05/18 02:19

 

 

相关源码文件:

        bootable/bootloader/lk/include/printf.h

        bootable/bootloader/lk/lib/libc/printf.c

 

其他参考文章:

           MT6572的LK(可以理解为UBOOT)uart串口驱动分析【代码注释】      http://blog.csdn.net/duanlove/article/details/16897717

 

 

 

关于printf的如果调到串口发送函数的,以及printf的实现和调用流程如下: 

 

bootable/bootloader/lk/lib/libc/printf.c

        int printf(const char *fmt, ...)
        {
            int err;

            va_list ap;
            va_start(ap, fmt);
            err = _dvprintf(fmt, ap);
            va_end(ap);

            return err;
        }


bootable/bootloader/lk/lib/debug/debug.c


    int _dvprintf(const char *fmt, va_list ap)
    {
        char buf[256];
        int err;

        err = vsnprintf(buf, sizeof(buf), fmt, ap);

        dputs(ALWAYS, buf);

        return err;
    }
   
    bootable/bootloader/lk/include/debug.h:
           #define dputs(level, str) do { if ((level) <= DEBUGLEVEL) { _dputs(str); } } while (0)

    int _dputs(const char *str)
    {
        while(*str != 0) {
            _dputc(*str++);
        }

        return 0;
    }

 

mediatek/platform/mt6572/lk/debug.c

        #include <debug.h>
        #include <kernel/thread.h>
        #include <stdarg.h>
        #include <dev/uart.h>
        #include <platform/mt_uart.h>

        void _dputc(char c)
        {
            if (c == '\n')
                uart_putc('\r');
            uart_putc(c);// 这个函数便是最终发送字符到串口的函数。它位于LK的串口驱动(mediatek/platform/mt6572/lk/uart.c)中。
        }
 
        //    mediatek/platform/mt6572/kernel/drivers/uart/mt_fiq_debugger.c:    .uart_putc = &fiq_uart_putc,
        //    mediatek/platform/mt6572/lk/uart.c:int uart_putc(const char c )

 

 
mediatek/platform/mt6572/lk/uart.c


        int uart_putc(const char c )
        {
            while (!(DRV_Reg32(UART_LSR(g_uart)) & UART_LSR_THRE));// 读取并判断串口当前的状态,如果忙,就一直轮训,如果不忙,就跳到下面的代码执行,把要发送的字符写入到发送的寄存器UART_THR。

            if (c == '\n')
                mt65xx_reg_sync_writel((unsigned int)'\r', UART_THR(g_uart));

            mt65xx_reg_sync_writel((unsigned int)c, UART_THR(g_uart));

            return 0;
        }

 


 

 

 

 

 

/*

FILENAME: bootable/bootloader/lk/lib/libc/printf.c
 * Copyright (c) 2008 Travis Geiselbrecht
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <debug.h>
#include <limits.h>
#include <stdarg.h>
#include <sys/types.h>
#include <printf.h>
#include <string.h>

void putc(char c)
{
 return _dputc(c);
}

int puts(const char *str)
{
 return _dputs(str);
}

int getc(char *c)
{
 return dgetc(c, true);
}

int printf(const char *fmt, ...)
{
 int err;

 va_list ap;
 va_start(ap, fmt);
 err = _dvprintf(fmt, ap);
 va_end(ap);

 return err;
}

int sprintf(char *str, const char *fmt, ...)
{
 int err;

 va_list ap;
 va_start(ap, fmt);
 err = vsprintf(str, fmt, ap);
 va_end(ap);

 return err;
}

int snprintf(char *str, size_t len, const char *fmt, ...)
{
 int err;

 va_list ap;
 va_start(ap, fmt);
 err = vsnprintf(str, len, fmt, ap);
 va_end(ap);

 return err;
}


#define LONGFLAG     0x00000001
#define LONGLONGFLAG 0x00000002
#define HALFFLAG     0x00000004
#define HALFHALFFLAG 0x00000008
#define SIZETFLAG    0x00000010
#define ALTFLAG      0x00000020
#define CAPSFLAG     0x00000040
#define SHOWSIGNFLAG 0x00000080
#define SIGNEDFLAG   0x00000100
#define LEFTFORMATFLAG 0x00000200
#define LEADZEROFLAG 0x00000400

static char *longlong_to_string(char *buf, unsigned long long n, int len, uint flag)
{
 int pos = len;
 int negative = 0;

 if((flag & SIGNEDFLAG) && (long long)n < 0) {
  negative = 1;
  n = -n;
 }

 buf[--pos] = 0;
 
 /* only do the math if the number is >= 10 */
 while(n >= 10) {
  int digit = n % 10;

  n /= 10;

  buf[--pos] = digit + '0';
 }
 buf[--pos] = n + '0';
 
 if(negative)
  buf[--pos] = '-';
 else if((flag & SHOWSIGNFLAG))
  buf[--pos] = '+';

 return &buf[pos];
}

static char *longlong_to_hexstring(char *buf, unsigned long long u, int len, uint flag)
{
 int pos = len;
 static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 const char *table;

 if((flag & CAPSFLAG))
  table = hextable_caps;
 else
  table = hextable;

 buf[--pos] = 0;
 do {
  unsigned int digit = u % 16;
  u /= 16;
 
  buf[--pos] = table[digit];
 } while(u != 0);

 return &buf[pos];
}

int vsprintf(char *str, const char *fmt, va_list ap)
{
 return vsnprintf(str, INT_MAX, fmt, ap);
}

int vsnprintf(char *str, size_t len, const char *fmt, va_list ap)
{
 char c;
 unsigned char uc;
 const char *s;
 unsigned long long n;
 void *ptr;
 int flags;
 unsigned int format_num;
 size_t chars_written = 0;
 char num_buffer[32];

#define OUTPUT_CHAR(c) do { (*str++ = c); chars_written++; if (chars_written + 1 == len) goto done; } while(0)
#define OUTPUT_CHAR_NOLENCHECK(c) do { (*str++ = c); chars_written++; } while(0)

 for(;;) { 
  /* handle regular chars that aren't format related */
  while((c = *fmt++) != 0) {
   if(c == '%')
    break; /* we saw a '%', break and start parsing format */
   OUTPUT_CHAR(c);
  }

  /* make sure we haven't just hit the end of the string */
  if(c == 0)
   break;

  /* reset the format state */
  flags = 0;
  format_num = 0;

next_format:
  /* grab the next format character */
  c = *fmt++;
  if(c == 0)
   break;
     
  switch(c) {
   case '0'...'9':
    if (c == '0' && format_num == 0)
     flags |= LEADZEROFLAG;
    format_num *= 10;
    format_num += c - '0';
    goto next_format;
   case '.':
    /* XXX for now eat numeric formatting */
    goto next_format;
   case '%':
    OUTPUT_CHAR('%');
    break;
   case 'c':
    uc = va_arg(ap, unsigned int);
    OUTPUT_CHAR(uc);
    break;
   case 's':
    s = va_arg(ap, const char *);
    if(s == 0)
     s = "<null>";
    goto _output_string;
   case '-':
    flags |= LEFTFORMATFLAG;
    goto next_format;
   case '+':
    flags |= SHOWSIGNFLAG;
    goto next_format;
   case '#':
    flags |= ALTFLAG;
    goto next_format;
   case 'l':
    if(flags & LONGFLAG)
     flags |= LONGLONGFLAG;
    flags |= LONGFLAG;
    goto next_format;
   case 'h':
    if(flags & HALFFLAG)
     flags |= HALFHALFFLAG;
    flags |= HALFFLAG;
    goto next_format;
      case 'z':
    flags |= SIZETFLAG;
    goto next_format;
   case 'D':
    flags |= LONGFLAG;
    /* fallthrough */
   case 'i':
   case 'd':
    n = (flags & LONGLONGFLAG) ? va_arg(ap, long long) :
     (flags & LONGFLAG) ? va_arg(ap, long) :
     (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) :
     (flags & HALFFLAG) ? (short)va_arg(ap, int) :
     (flags & SIZETFLAG) ? va_arg(ap, ssize_t) :
     va_arg(ap, int);
    flags |= SIGNEDFLAG;
    s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags);
    goto _output_string;
   case 'U':
    flags |= LONGFLAG;
    /* fallthrough */
   case 'u':
    n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
     (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
     (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
     (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
     (flags & SIZETFLAG) ? va_arg(ap, size_t) :
     va_arg(ap, unsigned int);
    s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags);
    goto _output_string;
   case 'p':
    flags |= LONGFLAG | ALTFLAG;
    goto hex;
   case 'X':
    flags |= CAPSFLAG;
    /* fallthrough */
hex:
   case 'x':
    n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
        (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
     (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
     (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
     (flags & SIZETFLAG) ? va_arg(ap, size_t) :
     va_arg(ap, unsigned int);
    s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags);
    if(flags & ALTFLAG) {
     OUTPUT_CHAR('0');
     OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x');
    }
    goto _output_string;
   case 'n':
    ptr = va_arg(ap, void *);
    if(flags & LONGLONGFLAG)
     *(long long *)ptr = chars_written;
    else if(flags & LONGFLAG)
     *(long *)ptr = chars_written;
    else if(flags & HALFHALFFLAG)
     *(signed char *)ptr = chars_written;
    else if(flags & HALFFLAG)
     *(short *)ptr = chars_written;
    else if(flags & SIZETFLAG)
     *(size_t *)ptr = chars_written;
    else
     *(int *)ptr = chars_written;
    break;
   default:
    OUTPUT_CHAR('%');
    OUTPUT_CHAR(c);
    break;
  }

  /* move on to the next field */
  continue;

  /* shared output code */
_output_string:
  if (flags & LEFTFORMATFLAG) {
   /* left justify the text */
   uint count = 0;
   while(*s != 0) {
    OUTPUT_CHAR(*s++);
    count++;
   }

   /* pad to the right (if necessary) */
   for (; format_num > count; format_num--)
    OUTPUT_CHAR(' ');
  } else {
   /* right justify the text (digits) */
   size_t string_len = strlen(s);
   char outchar = (flags & LEADZEROFLAG) ? '0' : ' ';
   for (; format_num > string_len; format_num--)
    OUTPUT_CHAR(outchar);

   /* output the string */
   while(*s != 0)
    OUTPUT_CHAR(*s++);
  }
  continue;
 }

done:
 /* null terminate */
 OUTPUT_CHAR_NOLENCHECK('\0');
 chars_written--; /* don't count the null */

#undef OUTPUT_CHAR
#undef OUTPUT_CHAR_NOLENCHECK

 return chars_written;
}


 

 

 

 

 

 

原创粉丝点击