U-Boot串口初始化详解

U-Boot串口初始化详解

目录

零、概述
一、init_baudrate
二、serial_init
三、console_init_f
四、devices_init
五、console_init_r
六、打印信息
七、为什么要使用devlist,std_device[]?

零、概述


上面这张图是U-Boot中串口设备驱动的流程,从寄存器级别的设置到最后终端信息的输出。下面我们详细讲解每一个步骤。

一、init_baudrate

该函数设置了gd->bd->bi_baudrate。

  1. static int init_baudrate (void) 
  2.     char tmp[64];   /* long enough for environment variables */ 
  3.     int i = getenv_r ("baudrate", tmp, sizeof (tmp)); 
  4.     gd->bd->bi_baudrate = gd->baudrate = (i > 0) 
  5.             ? (int) simple_strtoul (tmp, NULL, 10) 
  6.             : CONFIG_BAUDRATE; 
  7. //#define CONFIG_BAUDRATE   115200  定义在/include/configs/smdk2410.c中 
  8. //如果环境中没有保存,则使用宏定义的参数 
  9.     return (0); 
static int init_baudrate (void)
{
	char tmp[64];	/* long enough for environment variables */
	int i = getenv_r ("baudrate", tmp, sizeof (tmp));
	gd->bd->bi_baudrate = gd->baudrate = (i > 0)
			? (int) simple_strtoul (tmp, NULL, 10)
			: CONFIG_BAUDRATE;
//#define CONFIG_BAUDRATE	115200  定义在/include/configs/smdk2410.c中
//如果环境中没有保存,则使用宏定义的参数
	return (0);
}

二、serial_init

UART控制器的初始化。

  1. void serial_setbrg (void) 
  2.     S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); 
  3.     int i; 
  4.     unsigned int reg = 0; 
  5.  
  6.     /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ 
  7.     reg = get_PCLK() / (16 * gd->baudrate) - 1; 
  8.  
  9.     /* FIFO enable, Tx/Rx FIFO clear */ 
  10.     uart->UFCON = 0x07; 
  11.     uart->UMCON = 0x0; 
  12.     /* Normal,No parity,1 stop,8 bit */ 
  13.     uart->ULCON = 0x3; 
  14.     /* 
  15.      * tx=level,rx=edge,disable timeout int.,enable rx error int., 
  16.      * normal,interrupt or polling 
  17.      */ 
  18.     uart->UCON = 0x245; 
  19.     uart->UBRDIV = reg; 
  20.  
  21. #ifdef CONFIG_HWFLOW 
  22.     uart->UMCON = 0x1; /* RTS up */ 
  23. #endif 
  24.     for (i = 0; i < 100; i++); 
  25.  
  26. /* 
  27. * Initialise the serial port with the given baudrate. The settings 
  28. * are always 8 data bits, no parity, 1 stop bit, no start bits. 
  29. */ 
  30. int serial_init (void) 
  31.     serial_setbrg ();//UART寄存器设置 
  32.  
  33.     return (0); 
void serial_setbrg (void)
{
	S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
	int i;
	unsigned int reg = 0;

	/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
	reg = get_PCLK() / (16 * gd->baudrate) - 1;

	/* FIFO enable, Tx/Rx FIFO clear */
	uart->UFCON = 0x07;
	uart->UMCON = 0x0;
	/* Normal,No parity,1 stop,8 bit */
	uart->ULCON = 0x3;
	/*
	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
	 * normal,interrupt or polling
	 */
	uart->UCON = 0x245;
	uart->UBRDIV = reg;

#ifdef CONFIG_HWFLOW
	uart->UMCON = 0x1; /* RTS up */
#endif
	for (i = 0; i < 100; i++);
}

/*
 * Initialise the serial port with the given baudrate. The settings
 * are always 8 data bits, no parity, 1 stop bit, no start bits.
 *
 */
int serial_init (void)
{
	serial_setbrg ();//UART寄存器设置

	return (0);
}

三、console_init_f

控制台的前期初始化。

  1. int console_init_f (void) 
  2.     gd->have_console = 1; 
  3.  
  4. #ifdef CONFIG_SILENT_CONSOLE 
  5.     if (getenv("silent") != NULL) 
  6.         gd->flags |= GD_FLG_SILENT; 
  7. #endif 
  8.  
  9.     return (0); 
int console_init_f (void)
{
	gd->have_console = 1;

#ifdef CONFIG_SILENT_CONSOLE
	if (getenv("silent") != NULL)
		gd->flags |= GD_FLG_SILENT;
#endif

	return (0);
}

四、devices_init

这一部分在前面的文章已经分析过了,这里就不在叙述了。

五、console_init_r

控制台后期初始化。查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称,如果没有知道再按照环境指定的名称搜索devlist,将搜到的设备指针赋给标准IO数组stdio_devices[]。

  1. int console_init_r (void) 
  2.     char *stdinname, *stdoutname, *stderrname; 
  3.     device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL; 
  4. #ifdef CFG_CONSOLE_ENV_OVERWRITE 
  5.     int i; 
  6. #endif /* CFG_CONSOLE_ENV_OVERWRITE */ 
  7.  
  8.     /* set default handlers at first 设置跳转表*/ 
  9.     gd->jt[XF_getc] = serial_getc; 
  10.     gd->jt[XF_tstc] = serial_tstc; 
  11.     gd->jt[XF_putc] = serial_putc; 
  12.     gd->jt[XF_puts] = serial_puts; 
  13.     gd->jt[XF_printf] = serial_printf; 
  14.  
  15.     /* stdin stdout and stderr are in environment 查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称*/ 
  16.     /* scan for it */ 
  17.     stdinname  = getenv ("stdin"); 
  18.     stdoutname = getenv ("stdout"); 
  19.     stderrname = getenv ("stderr"); 
  20.  
  21.     if (OVERWRITE_CONSOLE == 0) {   /* if not overwritten by config switch */ 
  22.         inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname); 
  23.         outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname); 
  24.         errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname); 
  25.     } 
  26.     /* if the devices are overwritten or not found, use default device 按指定的名称搜索设备*/ 
  27.     if (inputdev == NULL) { 
  28.         inputdev  = search_device (DEV_FLAGS_INPUT,  "serial"); 
  29.     } 
  30.     if (outputdev == NULL) { 
  31.         outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); 
  32.     } 
  33.     if (errdev == NULL) { 
  34.         errdev    = search_device (DEV_FLAGS_OUTPUT, "serial"); 
  35.     } 
  36.     /* Initializes output console first将搜到的设备指针赋给标准IO数组stdio_devices[],在下面会将为什么要这样做 */ 
  37.     if (outputdev != NULL) { 
  38.         console_setfile (stdout, outputdev); 
  39.     } 
  40.     if (errdev != NULL) { 
  41.         console_setfile (stderr, errdev); 
  42.     } 
  43.     if (inputdev != NULL) { 
  44.         console_setfile (stdin, inputdev); 
  45.     } 
  46.  
  47.     gd->flags |= GD_FLG_DEVINIT; /* device initialization completed,到此串口设备才初始化完成,这个标志会影响getc等函数 */ 
  48.  
  49. #ifndef CFG_CONSOLE_INFO_QUIET 
  50.     /* Print information 打印信息*/ 
  51.     puts ("In:    "); 
  52.     if (stdio_devices[stdin] == NULL) { 
  53.         puts ("No input devices available!\n"); 
  54.     } else { 
  55.         printf ("%s\n", stdio_devices[stdin]->name); 
  56.     } 
  57.  
  58.     puts ("Out:   "); 
  59.     if (stdio_devices[stdout] == NULL) { 
  60.         puts ("No output devices available!\n"); 
  61.     } else { 
  62.         printf ("%s\n", stdio_devices[stdout]->name); 
  63.     } 
  64.  
  65.     puts ("Err:   "); 
  66.     if (stdio_devices[stderr] == NULL) { 
  67.         puts ("No error devices available!\n"); 
  68.     } else { 
  69.         printf ("%s\n", stdio_devices[stderr]->name); 
  70.     } 
  71. #endif /* CFG_CONSOLE_INFO_QUIET */ 
  72.  
  73. #ifdef CFG_CONSOLE_ENV_OVERWRITE 
  74.     /* set the environment variables (will overwrite previous env settings) */ 
  75.     for (i = 0; i < 3; i++) { 
  76.         setenv (stdio_names[i], stdio_devices[i]->name); 
  77.     } 
  78. #endif /* CFG_CONSOLE_ENV_OVERWRITE */ 
  79.  
  80. #if 0 
  81.     /* If nothing usable installed, use only the initial console */ 
  82.     if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) 
  83.         return (0); 
  84. #endif 
  85.     return (0); 
int console_init_r (void)
{
	char *stdinname, *stdoutname, *stderrname;
	device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
#ifdef CFG_CONSOLE_ENV_OVERWRITE
	int i;
#endif /* CFG_CONSOLE_ENV_OVERWRITE */

	/* set default handlers at first 设置跳转表*/
	gd->jt[XF_getc] = serial_getc;
	gd->jt[XF_tstc] = serial_tstc;
	gd->jt[XF_putc] = serial_putc;
	gd->jt[XF_puts] = serial_puts;
	gd->jt[XF_printf] = serial_printf;

	/* stdin stdout and stderr are in environment 查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称*/
	/* scan for it */
	stdinname  = getenv ("stdin");
	stdoutname = getenv ("stdout");
	stderrname = getenv ("stderr");

	if (OVERWRITE_CONSOLE == 0) { 	/* if not overwritten by config switch */
		inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname);
		outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname);
		errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname);
	}
	/* if the devices are overwritten or not found, use default device 按指定的名称搜索设备*/
	if (inputdev == NULL) {
		inputdev  = search_device (DEV_FLAGS_INPUT,  "serial");
	}
	if (outputdev == NULL) {
		outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
	}
	if (errdev == NULL) {
		errdev    = search_device (DEV_FLAGS_OUTPUT, "serial");
	}
	/* Initializes output console first将搜到的设备指针赋给标准IO数组stdio_devices[],在下面会将为什么要这样做 */
	if (outputdev != NULL) {
		console_setfile (stdout, outputdev);
	}
	if (errdev != NULL) {
		console_setfile (stderr, errdev);
	}
	if (inputdev != NULL) {
		console_setfile (stdin, inputdev);
	}

	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed,到此串口设备才初始化完成,这个标志会影响getc等函数 */

#ifndef CFG_CONSOLE_INFO_QUIET
	/* Print information 打印信息*/
	puts ("In:    ");
	if (stdio_devices[stdin] == NULL) {
		puts ("No input devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stdin]->name);
	}

	puts ("Out:   ");
	if (stdio_devices[stdout] == NULL) {
		puts ("No output devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stdout]->name);
	}

	puts ("Err:   ");
	if (stdio_devices[stderr] == NULL) {
		puts ("No error devices available!\n");
	} else {
		printf ("%s\n", stdio_devices[stderr]->name);
	}
#endif /* CFG_CONSOLE_INFO_QUIET */

#ifdef CFG_CONSOLE_ENV_OVERWRITE
	/* set the environment variables (will overwrite previous env settings) */
	for (i = 0; i < 3; i++) {
		setenv (stdio_names[i], stdio_devices[i]->name);
	}
#endif /* CFG_CONSOLE_ENV_OVERWRITE */

#if 0
	/* If nothing usable installed, use only the initial console */
	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
		return (0);
#endif
	return (0);
}

六、打印信息

在最后会打印出如下信息:

In:    serial
Out:   serial
Err:   serial

这说明串口初始化完成。

七、为什么要使用devlist,std_device[]?

为了更灵活地实现标准IO重定向,任何可以作为标准IO的设备,如USB键盘,LCD屏,串口等都可以对应一个device_t的结构体变量,只需要实现getc和putc等函数,就能加入到devlist列表中去,也就可以被assign为标准IO设备stdo_device中去。如函数 int console_assign (int file, char *devname); /* Assign the console 重定向标准输入输出*/这个函数功能就是把名为devname的设备重定向为标准IO文件file(stdin,stdout,stderr)。其执行过程是在devlist中查找devname的设备,返回这个设备的device_t指针,并把指针值赋给stdo_device[file]。

  1. int console_assign (int file, char *devname) 
  2.     int flag, i; 
  3.  
  4.     /* Check for valid file */ 
  5.     switch (file) { 
  6.     case stdin: 
  7.         flag = DEV_FLAGS_INPUT; 
  8.         break; 
  9.     case stdout: 
  10.     case stderr: 
  11.         flag = DEV_FLAGS_OUTPUT; 
  12.         break; 
  13.     default: 
  14.         return -1; 
  15.     } 
  16.  
  17.     /* Check for valid device name */ 
  18.  
  19.     for (i = 1; i <= ListNumItems (devlist); i++) { 
  20.         device_t *dev = ListGetPtrToItem (devlist, i); 
  21.  
  22.         if (strcmp (devname, dev->name) == 0) { 
  23.             if (dev->flags & flag) 
  24.                 return console_setfile (file, dev); 
  25.  
  26.             return -1; 
  27.         } 
  28.     } 
  29.  
  30.     return -1; 
int console_assign (int file, char *devname)
{
	int flag, i;

	/* Check for valid file */
	switch (file) {
	case stdin:
		flag = DEV_FLAGS_INPUT;
		break;
	case stdout:
	case stderr:
		flag = DEV_FLAGS_OUTPUT;
		break;
	default:
		return -1;
	}

	/* Check for valid device name */

	for (i = 1; i <= ListNumItems (devlist); i++) {
		device_t *dev = ListGetPtrToItem (devlist, i);

		if (strcmp (devname, dev->name) == 0) {
			if (dev->flags & flag)
				return console_setfile (file, dev);

			return -1;
		}
	}

	return -1;
}
该函数是调用console_setfile设置stdo_device[]完成重定向输入输出。

  1. static int console_setfile (int file, device_t * dev) 
  2.     int error = 0; 
  3.  
  4.     if (dev == NULL) 
  5.         return -1; 
  6.  
  7.     switch (file) { 
  8.     case stdin: 
  9.     case stdout: 
  10.     case stderr: 
  11.         /* Start new device */ 
  12.         if (dev->start) { 
  13.             error = dev->start (); 
  14.             /* If it's not started dont use it */ 
  15.             if (error < 0) 
  16.                 break; 
  17.         } 
  18.  
  19.         /* Assign the new device (leaving the existing one started) */ 
  20.         stdio_devices[file] = dev;//这里是关键 
  21.  
  22.         /* 
  23.          * Update monitor functions 
  24.          * (to use the console stuff by other applications) 
  25.          */ 
  26.         switch (file) { 
  27.         case stdin: 
  28.             gd->jt[XF_getc] = dev->getc; 
  29.             gd->jt[XF_tstc] = dev->tstc; 
  30.             break; 
  31.         case stdout: 
  32.             gd->jt[XF_putc] = dev->putc; 
  33.             gd->jt[XF_puts] = dev->puts; 
  34.             gd->jt[XF_printf] = printf; 
  35.             break; 
  36.         } 
  37.         break; 
  38.  
  39.     default:        /* Invalid file ID */ 
  40.         error = -1; 
  41.     } 
  42.     return error; 
  43. U-Boot串口初始化详解

    目录

    零、概述
    一、init_baudrate
    二、serial_init
    三、console_init_f
    四、devices_init
    五、console_init_r
    六、打印信息
    七、为什么要使用devlist,std_device[]?

    零、概述


    上面这张图是U-Boot中串口设备驱动的流程,从寄存器级别的设置到最后终端信息的输出。下面我们详细讲解每一个步骤。

    一、init_baudrate

    该函数设置了gd->bd->bi_baudrate。

    1. static int init_baudrate (void) 
    2.     char tmp[64];   /* long enough for environment variables */ 
    3.     int i = getenv_r ("baudrate", tmp, sizeof (tmp)); 
    4.     gd->bd->bi_baudrate = gd->baudrate = (i > 0) 
    5.             ? (int) simple_strtoul (tmp, NULL, 10) 
    6.             : CONFIG_BAUDRATE; 
    7. //#define CONFIG_BAUDRATE   115200  定义在/include/configs/smdk2410.c中 
    8. //如果环境中没有保存,则使用宏定义的参数 
    9.     return (0); 
    static int init_baudrate (void)
    {
    	char tmp[64];	/* long enough for environment variables */
    	int i = getenv_r ("baudrate", tmp, sizeof (tmp));
    	gd->bd->bi_baudrate = gd->baudrate = (i > 0)
    			? (int) simple_strtoul (tmp, NULL, 10)
    			: CONFIG_BAUDRATE;
    //#define CONFIG_BAUDRATE	115200  定义在/include/configs/smdk2410.c中
    //如果环境中没有保存,则使用宏定义的参数
    	return (0);
    }
    

    二、serial_init

    UART控制器的初始化。

    1. void serial_setbrg (void) 
    2.     S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR); 
    3.     int i; 
    4.     unsigned int reg = 0; 
    5.  
    6.     /* value is calculated so : (int)(PCLK/16./baudrate) -1 */ 
    7.     reg = get_PCLK() / (16 * gd->baudrate) - 1; 
    8.  
    9.     /* FIFO enable, Tx/Rx FIFO clear */ 
    10.     uart->UFCON = 0x07; 
    11.     uart->UMCON = 0x0; 
    12.     /* Normal,No parity,1 stop,8 bit */ 
    13.     uart->ULCON = 0x3; 
    14.     /* 
    15.      * tx=level,rx=edge,disable timeout int.,enable rx error int., 
    16.      * normal,interrupt or polling 
    17.      */ 
    18.     uart->UCON = 0x245; 
    19.     uart->UBRDIV = reg; 
    20.  
    21. #ifdef CONFIG_HWFLOW 
    22.     uart->UMCON = 0x1; /* RTS up */ 
    23. #endif 
    24.     for (i = 0; i < 100; i++); 
    25.  
    26. /* 
    27. * Initialise the serial port with the given baudrate. The settings 
    28. * are always 8 data bits, no parity, 1 stop bit, no start bits. 
    29. */ 
    30. int serial_init (void) 
    31.     serial_setbrg ();//UART寄存器设置 
    32.  
    33.     return (0); 
    void serial_setbrg (void)
    {
    	S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
    	int i;
    	unsigned int reg = 0;
    
    	/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
    	reg = get_PCLK() / (16 * gd->baudrate) - 1;
    
    	/* FIFO enable, Tx/Rx FIFO clear */
    	uart->UFCON = 0x07;
    	uart->UMCON = 0x0;
    	/* Normal,No parity,1 stop,8 bit */
    	uart->ULCON = 0x3;
    	/*
    	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
    	 * normal,interrupt or polling
    	 */
    	uart->UCON = 0x245;
    	uart->UBRDIV = reg;
    
    #ifdef CONFIG_HWFLOW
    	uart->UMCON = 0x1; /* RTS up */
    #endif
    	for (i = 0; i < 100; i++);
    }
    
    /*
     * Initialise the serial port with the given baudrate. The settings
     * are always 8 data bits, no parity, 1 stop bit, no start bits.
     *
     */
    int serial_init (void)
    {
    	serial_setbrg ();//UART寄存器设置
    
    	return (0);
    }
    

    三、console_init_f

    控制台的前期初始化。

    1. int console_init_f (void) 
    2.     gd->have_console = 1; 
    3.  
    4. #ifdef CONFIG_SILENT_CONSOLE 
    5.     if (getenv("silent") != NULL) 
    6.         gd->flags |= GD_FLG_SILENT; 
    7. #endif 
    8.  
    9.     return (0); 
    int console_init_f (void)
    {
    	gd->have_console = 1;
    
    #ifdef CONFIG_SILENT_CONSOLE
    	if (getenv("silent") != NULL)
    		gd->flags |= GD_FLG_SILENT;
    #endif
    
    	return (0);
    }
    

    四、devices_init

    这一部分在前面的文章已经分析过了,这里就不在叙述了。

    五、console_init_r

    控制台后期初始化。查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称,如果没有知道再按照环境指定的名称搜索devlist,将搜到的设备指针赋给标准IO数组stdio_devices[]。

    1. int console_init_r (void) 
    2.     char *stdinname, *stdoutname, *stderrname; 
    3.     device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL; 
    4. #ifdef CFG_CONSOLE_ENV_OVERWRITE 
    5.     int i; 
    6. #endif /* CFG_CONSOLE_ENV_OVERWRITE */ 
    7.  
    8.     /* set default handlers at first 设置跳转表*/ 
    9.     gd->jt[XF_getc] = serial_getc; 
    10.     gd->jt[XF_tstc] = serial_tstc; 
    11.     gd->jt[XF_putc] = serial_putc; 
    12.     gd->jt[XF_puts] = serial_puts; 
    13.     gd->jt[XF_printf] = serial_printf; 
    14.  
    15.     /* stdin stdout and stderr are in environment 查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称*/ 
    16.     /* scan for it */ 
    17.     stdinname  = getenv ("stdin"); 
    18.     stdoutname = getenv ("stdout"); 
    19.     stderrname = getenv ("stderr"); 
    20.  
    21.     if (OVERWRITE_CONSOLE == 0) {   /* if not overwritten by config switch */ 
    22.         inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname); 
    23.         outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname); 
    24.         errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname); 
    25.     } 
    26.     /* if the devices are overwritten or not found, use default device 按指定的名称搜索设备*/ 
    27.     if (inputdev == NULL) { 
    28.         inputdev  = search_device (DEV_FLAGS_INPUT,  "serial"); 
    29.     } 
    30.     if (outputdev == NULL) { 
    31.         outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); 
    32.     } 
    33.     if (errdev == NULL) { 
    34.         errdev    = search_device (DEV_FLAGS_OUTPUT, "serial"); 
    35.     } 
    36.     /* Initializes output console first将搜到的设备指针赋给标准IO数组stdio_devices[],在下面会将为什么要这样做 */ 
    37.     if (outputdev != NULL) { 
    38.         console_setfile (stdout, outputdev); 
    39.     } 
    40.     if (errdev != NULL) { 
    41.         console_setfile (stderr, errdev); 
    42.     } 
    43.     if (inputdev != NULL) { 
    44.         console_setfile (stdin, inputdev); 
    45.     } 
    46.  
    47.     gd->flags |= GD_FLG_DEVINIT; /* device initialization completed,到此串口设备才初始化完成,这个标志会影响getc等函数 */ 
    48.  
    49. #ifndef CFG_CONSOLE_INFO_QUIET 
    50.     /* Print information 打印信息*/ 
    51.     puts ("In:    "); 
    52.     if (stdio_devices[stdin] == NULL) { 
    53.         puts ("No input devices available!\n"); 
    54.     } else { 
    55.         printf ("%s\n", stdio_devices[stdin]->name); 
    56.     } 
    57.  
    58.     puts ("Out:   "); 
    59.     if (stdio_devices[stdout] == NULL) { 
    60.         puts ("No output devices available!\n"); 
    61.     } else { 
    62.         printf ("%s\n", stdio_devices[stdout]->name); 
    63.     } 
    64.  
    65.     puts ("Err:   "); 
    66.     if (stdio_devices[stderr] == NULL) { 
    67.         puts ("No error devices available!\n"); 
    68.     } else { 
    69.         printf ("%s\n", stdio_devices[stderr]->name); 
    70.     } 
    71. #endif /* CFG_CONSOLE_INFO_QUIET */ 
    72.  
    73. #ifdef CFG_CONSOLE_ENV_OVERWRITE 
    74.     /* set the environment variables (will overwrite previous env settings) */ 
    75.     for (i = 0; i < 3; i++) { 
    76.         setenv (stdio_names[i], stdio_devices[i]->name); 
    77.     } 
    78. #endif /* CFG_CONSOLE_ENV_OVERWRITE */ 
    79.  
    80. #if 0 
    81.     /* If nothing usable installed, use only the initial console */ 
    82.     if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) 
    83.         return (0); 
    84. #endif 
    85.     return (0); 
    int console_init_r (void)
    {
    	char *stdinname, *stdoutname, *stderrname;
    	device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
    #ifdef CFG_CONSOLE_ENV_OVERWRITE
    	int i;
    #endif /* CFG_CONSOLE_ENV_OVERWRITE */
    
    	/* set default handlers at first 设置跳转表*/
    	gd->jt[XF_getc] = serial_getc;
    	gd->jt[XF_tstc] = serial_tstc;
    	gd->jt[XF_putc] = serial_putc;
    	gd->jt[XF_puts] = serial_puts;
    	gd->jt[XF_printf] = serial_printf;
    
    	/* stdin stdout and stderr are in environment 查看环境参数stdin,stdout,stderr中对标准IO的指定的设备名称*/
    	/* scan for it */
    	stdinname  = getenv ("stdin");
    	stdoutname = getenv ("stdout");
    	stderrname = getenv ("stderr");
    
    	if (OVERWRITE_CONSOLE == 0) { 	/* if not overwritten by config switch */
    		inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname);
    		outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname);
    		errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname);
    	}
    	/* if the devices are overwritten or not found, use default device 按指定的名称搜索设备*/
    	if (inputdev == NULL) {
    		inputdev  = search_device (DEV_FLAGS_INPUT,  "serial");
    	}
    	if (outputdev == NULL) {
    		outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
    	}
    	if (errdev == NULL) {
    		errdev    = search_device (DEV_FLAGS_OUTPUT, "serial");
    	}
    	/* Initializes output console first将搜到的设备指针赋给标准IO数组stdio_devices[],在下面会将为什么要这样做 */
    	if (outputdev != NULL) {
    		console_setfile (stdout, outputdev);
    	}
    	if (errdev != NULL) {
    		console_setfile (stderr, errdev);
    	}
    	if (inputdev != NULL) {
    		console_setfile (stdin, inputdev);
    	}
    
    	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed,到此串口设备才初始化完成,这个标志会影响getc等函数 */
    
    #ifndef CFG_CONSOLE_INFO_QUIET
    	/* Print information 打印信息*/
    	puts ("In:    ");
    	if (stdio_devices[stdin] == NULL) {
    		puts ("No input devices available!\n");
    	} else {
    		printf ("%s\n", stdio_devices[stdin]->name);
    	}
    
    	puts ("Out:   ");
    	if (stdio_devices[stdout] == NULL) {
    		puts ("No output devices available!\n");
    	} else {
    		printf ("%s\n", stdio_devices[stdout]->name);
    	}
    
    	puts ("Err:   ");
    	if (stdio_devices[stderr] == NULL) {
    		puts ("No error devices available!\n");
    	} else {
    		printf ("%s\n", stdio_devices[stderr]->name);
    	}
    #endif /* CFG_CONSOLE_INFO_QUIET */
    
    #ifdef CFG_CONSOLE_ENV_OVERWRITE
    	/* set the environment variables (will overwrite previous env settings) */
    	for (i = 0; i < 3; i++) {
    		setenv (stdio_names[i], stdio_devices[i]->name);
    	}
    #endif /* CFG_CONSOLE_ENV_OVERWRITE */
    
    #if 0
    	/* If nothing usable installed, use only the initial console */
    	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
    		return (0);
    #endif
    	return (0);
    }
    

    六、打印信息

    在最后会打印出如下信息:

    In:    serial
    Out:   serial
    Err:   serial

    这说明串口初始化完成。

    七、为什么要使用devlist,std_device[]?

    为了更灵活地实现标准IO重定向,任何可以作为标准IO的设备,如USB键盘,LCD屏,串口等都可以对应一个device_t的结构体变量,只需要实现getc和putc等函数,就能加入到devlist列表中去,也就可以被assign为标准IO设备stdo_device中去。如函数 int console_assign (int file, char *devname); /* Assign the console 重定向标准输入输出*/这个函数功能就是把名为devname的设备重定向为标准IO文件file(stdin,stdout,stderr)。其执行过程是在devlist中查找devname的设备,返回这个设备的device_t指针,并把指针值赋给stdo_device[file]。

    1. int console_assign (int file, char *devname) 
    2.     int flag, i; 
    3.  
    4.     /* Check for valid file */ 
    5.     switch (file) { 
    6.     case stdin: 
    7.         flag = DEV_FLAGS_INPUT; 
    8.         break; 
    9.     case stdout: 
    10.     case stderr: 
    11.         flag = DEV_FLAGS_OUTPUT; 
    12.         break; 
    13.     default: 
    14.         return -1; 
    15.     } 
    16.  
    17.     /* Check for valid device name */ 
    18.  
    19.     for (i = 1; i <= ListNumItems (devlist); i++) { 
    20.         device_t *dev = ListGetPtrToItem (devlist, i); 
    21.  
    22.         if (strcmp (devname, dev->name) == 0) { 
    23.             if (dev->flags & flag) 
    24.                 return console_setfile (file, dev); 
    25.  
    26.             return -1; 
    27.         } 
    28.     } 
    29.  
    30.     return -1; 
    int console_assign (int file, char *devname)
    {
    	int flag, i;
    
    	/* Check for valid file */
    	switch (file) {
    	case stdin:
    		flag = DEV_FLAGS_INPUT;
    		break;
    	case stdout:
    	case stderr:
    		flag = DEV_FLAGS_OUTPUT;
    		break;
    	default:
    		return -1;
    	}
    
    	/* Check for valid device name */
    
    	for (i = 1; i <= ListNumItems (devlist); i++) {
    		device_t *dev = ListGetPtrToItem (devlist, i);
    
    		if (strcmp (devname, dev->name) == 0) {
    			if (dev->flags & flag)
    				return console_setfile (file, dev);
    
    			return -1;
    		}
    	}
    
    	return -1;
    }
    
    该函数是调用console_setfile设置stdo_device[]完成重定向输入输出。

    1. static int console_setfile (int file, device_t * dev) 
    2.     int error = 0; 
    3.  
    4.     if (dev == NULL) 
    5.         return -1; 
    6.  
    7.     switch (file) { 
    8.     case stdin: 
    9.     case stdout: 
    10.     case stderr: 
    11.         /* Start new device */ 
    12.         if (dev->start) { 
    13.             error = dev->start (); 
    14.             /* If it's not started dont use it */ 
    15.             if (error < 0) 
    16.                 break; 
    17.         } 
    18.  
    19.         /* Assign the new device (leaving the existing one started) */ 
    20.         stdio_devices[file] = dev;//这里是关键 
    21.  
    22.         /* 
    23.          * Update monitor functions 
    24.          * (to use the console stuff by other applications) 
    25.          */ 
    26.         switch (file) { 
    27.         case stdin: 
    28.             gd->jt[XF_getc] = dev->getc; 
    29.             gd->jt[XF_tstc] = dev->tstc; 
    30.             break; 
    31.         case stdout: 
    32.             gd->jt[XF_putc] = dev->putc; 
    33.             gd->jt[XF_puts] = dev->puts; 
    34.             gd->jt[XF_printf] = printf; 
    35.             break; 
    36.         } 
    37.         break; 
    38.  
    39.     default:        /* Invalid file ID */ 
    40.         error = -1; 
    41.     } 
    42.     return error; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值