printf()函数定义在common/console.c中,是通用函数,除了特殊情况外移植时不需要改动。
void printf(const char *fmt, ...)
{
va_list args;
uint i;
char printbuffer[CONFIG_SYS_PBSIZE];
va_start(args, fmt);
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
i = vsprintf(printbuffer, fmt, args);
va_end(args);
/* Print the string */
puts(printbuffer);
}
1> 函数中形参列表和va_list与c语言变参函数的处理有关,这里不在讨论内容之中,本文讨论uboot关于printf函数输出的内部处理方式,从整体上考虑。
2> vsprintf()为参数格式处理函数,在lib_generic/vsprintf.c中定义。
3> 具体的输出函数为puts()在common/console.c中定义:
void puts(const char *s)
{
#ifdef CONFIG_SILENT_CONSOLE
if (gd->flags & GD_FLG_SILENT)
return;
#endif
#ifdef CONFIG_DISABLE_CONSOLE
if (gd->flags & GD_FLG_DISABLE_CONSOLE)
return;
#endif
if (gd->flags & GD_FLG_DEVINIT) {
/* Send to the standard output */
fputs(stdout, s);
} else {
/* Send directly to the handler */
serial_puts(s);
}
}
两个宏定义是禁止输出的宏定义。从函数的主体可以看到,gd->flags & GD_FLG_DEVINIT,如果设备标准输入输出设备已经初始化,输出时,函数调用的是标准输出设备,如果没有,则使用串口输出函数。当然,标准输出设备也可能是串口,这时调用的是同一个函数,但是也有可能是LCD,主要看自己的设置。
我用的开发板是mini2440,相关串口处理的函数都定义在driver/serial/serial_s3c24x0.c中,对于串口大家还是比较熟悉的,这里不在多数,有兴趣的可以自己到该文件中自己查看。
下面我们来看一下,系统标准设备的处理。
fputs()函数定义在common/console.c中:
void fputs(int file, const char *s)
{
if (file < MAX_FILES)
console_puts(file, s);
}
static inline void console_puts(int file, const char *s)
{
stdio_devices[file]->puts(s);
}
stdio_devices为结构体指针数组:struct stdio_dev *stdio_devices[] = { NULL, NULL, NULL };
结构体定义如下:
struct stdio_dev {
int flags; /* Device flags: input/output/system */
int ext; /* Supported extensions */
char name[16]; /* Device name */
/* GENERAL functions */
int (*start) (void); /* To start the device */
int (*stop) (void);