Cubietruck开发板SPL阶段的printf重定向问题
来源:互联网 发布:信贷员靠谱抢单软件 编辑:程序博客网 时间:2024/05/17 09:36
int printf(const char *fmt, ...){va_list args;uint i;char printbuffer[CONFIG_SYS_PBSIZE];#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)if (!gd->have_console)return 0;#endifva_start(args, fmt);/* For this to work, printbuffer must be larger than * anything we ever want to print. */i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);va_end(args);/* Print the string */puts(printbuffer);return i;}
这里的va_list、va_start、va_end就不用说了,具体参考http://blog.csdn.net/u013691997/article/details/23426619
#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER)
if (!gd->have_console)
return 0;
#endif
意思是加入没有defineCONFIG_SANDBOX和CONFIG_PRE_CONSOLE_BUFFER
那么则检查gd->have_console,也就是检查是否存在串口,如果不存在串口就要退出,
为什么要说CONFIG_PRE_CONSOLE_BUFFER呢?上面的话反过来就是,如果存在缓冲,
就不用检查是否有串口。再往下看,调用了puts()
void puts(const char *s){#ifdef CONFIG_SANDBOXif (!gd) {os_puts(s);return;}#endif#ifdef CONFIG_SILENT_CONSOLEif (gd->flags & GD_FLG_SILENT)return;#endif#ifdef CONFIG_DISABLE_CONSOLEif (gd->flags & GD_FLG_DISABLE_CONSOLE)return;#endifif (!gd->have_console)return pre_console_puts(s);if (gd->flags & GD_FLG_DEVINIT) {/* Send to the standard output */fputs(stdout, s);} else {/* Send directly to the handler */serial_puts(s);}}分析可知puts检查have_console、gd->flags & GD_FLG_DEVINIT,也就是
检查是否有串口、如果有是否初始化,注意这里的初始化不同于一般意义上的初始化
搜索项目可知,gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
是在console_init_r中执行的,而SPL阶段根本不会调用console_init_r
所以puts检查是否有串口,没串口就调用pre_console_puts(s);有串口就调用
serial_puts(s);那么分析一下pre_console_puts
#ifdef CONFIG_PRE_CONSOLE_BUFFER#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)static void pre_console_putc(const char c){char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;}static void pre_console_puts(const char *s){while (*s)pre_console_putc(*s++);}static void print_pre_console_buffer(void){unsigned long i = 0;char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)i = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;while (i < gd->precon_buf_idx)putc(buffer[CIRC_BUF_IDX(i++)]);}#elsestatic inline void pre_console_putc(const char c) {}static inline void pre_console_puts(const char *s) {}static inline void print_pre_console_buffer(void) {}#endif可见,如果定义了缓冲puts将字符串缓冲起来,没有定义缓冲的话什么也不做,
小结一下:
printf执行有三种结果,1.什么都不做只return 0.2.puts字符串到缓冲
3.puts字符串到设备(串口)。
值得注意的是,printf调用puts的话要么输出到缓冲要么输出到设备,而单看puts
时,其有可能什么都不做。如果printf输出到缓冲,然后什么时间处理缓冲呢??
那么回过头来分一下整个preloader_console_init(),只有在get_current()的时候
可能会输出到缓冲(初始化设备失败),而get_current()成功的话,其本身不会
puts错误信息,而之后gd->have_console = 1;所以再调用printf或者puts的话会
直接输出到设备。
/** * serial_puts() - Output string via currently selected serial port * @s:Zero-terminated string to be output from the serial port. * * This function outputs a zero-terminated string via currently * selected serial port. This function behaves as an accelerator * in case the hardware can queue multiple characters for transfer. * The whole string that is to be output is available to the function * implementing the hardware manipulation. Transmitting the whole * string may take some time, thus this function may block for some * amount of time. This function uses the get_current() call to * determine which port is selected. */void serial_puts(const char *s){get_current()->puts(s);}继续一层一层剥开就是
void_serial_putc(const char c,const int port){if (c == '\n')NS16550_putc(PORT, '\r');NS16550_putc(PORT, c);}
NS16550的问题就不说了。
一层一层的这么多,这里只想说,printf是一个中间函数,对于它的重定向其实就是给它一个可用的叶子函数,另外每个printf函数的具体过程都不一样,所以在重定向的
方法也不一样,这里跟stm32(keil使用的arm编译器)比较一下就看出来了
再回忆一下a20的uart串口驱动如何与ns16550挂钩的:
preloader_console_init()——>serial_init()——>get_current——>default_serial_console()
preloader_console_init()——>serial_init():由board.c调用spl.c
serial_init()——>get_current:由spl.c调用drivers/serial/serial.c
get_current——>default_serial_console():
default_serial_console()在serial.h中声明,而serial目录下的很多文件都包含这个serial.h
并且实现了default_serial_console()函数,其他目录下也有此函数的实现,所以与
serial_ns16550.c挂钩是通过makefile实现的,另外还要注意为什么攒在serial_ns16550.c
而不是直接ns16550.c
再次编辑添加:貌似再SPL阶段只有printf,而没有scanf。
- Cubietruck开发板SPL阶段的printf重定向问题
- Cubietruck开发板SPL阶段的s_init分析
- Cubietruck开发板SPL阶段的preloader_console_init()分析
- Cubietruck开发板SPL实验
- Cubietruck开发板SPL阶段加载uboot到SDRAM并启动
- Cubietruck开发板SPL启动分析
- STM32 printf 重定向问题
- STM32 printf的重定向
- stm32的printf重定向
- STM32中printf与scanf的重定向问题
- windows下printf重定向的实现
- windows下printf重定向的实现
- printf的重定向与恢复
- printf 的串口输入重定向
- printf重定向后的Log机制
- STM32的printf函数重定向
- STM32的printf函数重定向
- STM32 printf重定向
- Visual Studio debug 模式和 release 模式
- leetcode:Sort List
- 设计的成长
- java中的断点下载文件
- C++ 将一个文件里面的相同的一个字符串替换成另一个字符串
- Cubietruck开发板SPL阶段的printf重定向问题
- 第五周作业(第四章)
- JS不定长度探究和填充占位符的应用
- 我们还在一起
- hdu3068+hdu3294 最长回文字符串的manacher算法
- IE8下parseInt(8)返回0
- 【Web缓存机制系列】6 – 进击的Hybrid App,量身定做缓存机制
- greenDao
- IOS程序运行时崩溃日志setObjectForKey: object cannot be nil