android kernel控制台初始化过程

来源:互联网 发布:java 开发平面地图 编辑:程序博客网 时间:2024/06/18 17:18
对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上

对kernel控制台初始化是在挂载文件系统之前,由于没有串口的设备文件,不能通过打开设备文件来访问串口,只能直接访问硬件,更类似与裸机的访问方式。

下面正式来看

板子初始化的过程
android\kernel_imx\arch\arm\mach-mx6\board-mx6q_sabresd.c
[cpp] view plaincopyprint?
  1. MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")  
  2. /* Maintainer: Freescale Semiconductor, Inc. */  
  3. .boot_params = MX6_PHYS_OFFSET + 0x100,  
  4. .fixup = fixup_mxc_board,  
  5. .map_io = mx6_map_io,  
  6. .init_irq = mx6_init_irq,  
  7. .init_machine = mx6_sabresd_board_init,  
  8. .timer = &mx6_sabresd_timer,  
  9. .reserve = mx6q_sabresd_reserve,  
  10. MACHINE_END  




这其中有个时钟初始化mx6_sabresd_timer我们来看它的定义
[cpp] view plaincopyprint?
  1. static struct sys_timer mx6_sabresd_timer = {  
  2. .init   = mx6_sabresd_timer_init,  
  3. };  
  4. static void __init mx6_sabresd_timer_init(void)  
  5. {  
  6. struct clk *uart_clk;  
  7. #ifdef CONFIG_LOCAL_TIMERS   
  8. twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256);  
  9. BUG_ON(!twd_base);  
  10. #endif   
  11. mx6_clocks_init(32768, 24000000, 0, 0);  
  12.   
  13.   
  14. uart_clk = clk_get_sys("imx-uart.0", NULL);  
  15. early_console_setup(UART1_BASE_ADDR, uart_clk);  
  16. }  


可以看到这里调用了early_console_setup(UART1_BASE_ADDR, uart_clk);
这个函数就是文件系统挂载之前控制台的初始化函数。下面我就开始分析这个函数
android\kernel_imx\arch\arm\plat-mxc\cpu.c
[cpp] view plaincopyprint?
  1. /** 
  2.  * early_console_setup - setup debugging console 
  3.  * 
  4.  * Consoles started here require little enough setup that we can start using 
  5.  * them very early in the boot process, either right after the machine 
  6.  * vector initialization, or even before if the drivers can detect their hw. 
  7.  * 
  8.  * Returns non-zero if a console couldn't be setup. 
  9.  * This function is developed based on 
  10.  * early_console_setup function as defined in arch/ia64/kernel/setup.c 
  11.  * 这个注释里写的很清楚,在设备驱动执行之前,为了调试错误的需要我们 
  12.  * 需要在启动的最初就初始化控制台 
  13.  */  
  14. void __init early_console_setup(unsigned long base, struct clk *clk)  
  15. {  
  16. #ifdef CONFIG_SERIAL_IMX_CONSOLE   
  17. mxc_early_serial_console_init(base, clk);  
  18. #endif   
  19. }  
  20. 这里调用mxc_early_serial_console_init(base, clk);  
  21. android\kernel_imx\drivers\tty\serial、mxc_uart_early.c  
  22. int __init mxc_early_serial_console_init(unsigned long base, struct clk *clk)  
  23. {  
  24. mxc_early_device.clk = clk;  
  25. mxc_early_device.port.mapbase = base;  
  26.   
  27.   
  28. register_console(&mxc_early_uart_console);  
  29. return 0;  
  30. }  


这里可以看到register_console(&mxc_early_uart_console);就是注册一个设备到控制台中,
在最开始注册的这个设备肯定是裸机的访问方式的,因此我们重点来看这个设备
[cpp] view plaincopyprint?
  1. static struct console mxc_early_uart_console __initdata = {  
  2. .name = "ttymxc",  
  3. .write = early_mxcuart_console_write,  
  4. .setup = mxc_early_uart_setup,  
  5. .flags = CON_PRINTBUFFER | CON_BOOT,  
  6. .index = -1,  
  7. };  


这个设备提供的设备访问接口
.write = early_mxcuart_console_write,是串口的发送函数
.setup = mxc_early_uart_setup,是串口的初始化函数
.flags = CON_PRINTBUFFER | CON_BOOT,是控制台标志,CON_BOOT表明这事一个boot的控制台设备
也就是说是挂载设备文件之前的控制台设备


下面我们来分析初始化函数和 数据发送函数
初始化函数

[cpp] view plaincopyprint?
  1. static int __init mxc_early_uart_setup(struct console *console, char *options)  
  2. {  
  3.   
  4. struct mxc_early_uart_device *device = &mxc_early_device;  
  5. struct uart_port *port = &device->port;  
  6. int length;  
  7.   
  8. if (device->port.membase || device->port.iobase)    
  9. return -ENODEV;  
  10.   
  11.   
  12. /* Enable Early MXC UART Clock */  
  13. clk_enable(device->clk);//初始化总线时钟   
  14.   
  15.   
  16. port->uartclk = 5600000;  
  17. port->iotype = UPIO_MEM;  
  18. port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器内存映射  
  19.   
  20.   
  21. if (options) {  
  22. device->baud = simple_strtoul(options, NULL, 0);  
  23. length = min(strlen(options), sizeof(device->options));  
  24. strncpy(device->options, options, length);  
  25. else {  
  26. device->baud = probe_baud(port);  
  27. snprintf(device->options, sizeof(device->options), "%u",  
  28. device->baud);  
  29. }  
  30. printk(KERN_INFO  
  31.       "MXC_Early serial console at MMIO 0x%x (options '%s')\n",  
  32.       port->mapbase, device->options);  
  33. return 0;  
  34. }  

其实从这个初始化函数里看出,它做了很多向mxc_early_device结构体中填入数据的工作,而这些数据

找遍所有代码也没有用到,因此这些事没有意义的,官方代码给的这点并不太好。但是由于uboot中我们已经初始化了

串口因此这里就算没有任何初始化其实串口也可以是使用。

这里真正有用的就两句话
clk_enable(device->clk);//初始化总线时钟
port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器内存映射
但是在寄存器映射结束后没有进行任何串口寄存器初始化,这也很奇怪,我们仔细查找发现,
寄存器初始化代码写在了数据发送函数里,具体为什么我们来分析发送函数
early_mxcuart_console_write

[cpp] view plaincopyprint?
  1. /*! 
  2.  * This function is called to write the console messages through the UART port. 
  3.  * 
  4.  * @param   co    the console structure 
  5.  * @param   s     the log message to be written to the UART 
  6.  * @param   count length of the message 
  7.  */  
  8. void __init early_mxcuart_console_write(struct console *co, const char *s,  
  9. u_int count)  
  10. {  
  11. struct uart_port *port = &mxc_early_device.port;  
  12. unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3;  
  13.   
  14.   
  15. /* 
  16. * First save the control registers and then disable the interrupts 
  17. */  
  18. oldcr1 = readl(port->membase + MXC_UARTUCR1);   //读取当前三个串口控制寄存器的值  
  19. oldcr2 = readl(port->membase + MXC_UARTUCR2);  
  20. oldcr3 = readl(port->membase + MXC_UARTUCR3);  
  21. cr2 =  
  22.    oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN | //初始化串口寄存器数值  
  23.       MXC_UARTUCR2_ESCI);  
  24. cr3 =  
  25.    oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI |  
  26.       MXC_UARTUCR3_DTRDEN);  
  27. writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1);  //使能串口  
  28. writel(cr2, port->membase + MXC_UARTUCR2);  //配置寄存器   
  29. writel(cr3, port->membase + MXC_UARTUCR3);  
  30.   
  31.   
  32. /* Transmit string */  
  33. uart_console_write(port, s, count, mxcuart_console_write_char); //发送数据  
  34.   
  35.   
  36. /* 
  37. * Finally, wait for the transmitter to become empty等待发送完成 
  38. */  
  39. do {  
  40. status = readl(port->membase + MXC_UARTUSR2);  
  41. while (!(status & MXC_UARTUSR2_TXDC));  
  42.   
  43.   
  44. /* 
  45. * Restore the control registers 
  46. */  
  47. writel(oldcr1, port->membase + MXC_UARTUCR1);//恢复串口寄存器数值  
  48. writel(oldcr2, port->membase + MXC_UARTUCR2);  
  49. writel(oldcr3, port->membase + MXC_UARTUCR3);  
  50. }  


从这个函数看书,它首先保存了串口控制寄存器的值,然后初始化成符合控制台的,发送完数据后,又恢复了原来的数据
这样做的目的就是,如果我们加载了串口的驱动,那么很有可能打乱了控制台的配置,而系统启动以后
我们还不能动串口驱动的配置,因此最好的办法就是,每次发送数据都重新配置串口,发送完后再恢复以前的配置。
到了这里控制台初始化的第一部分已经完成了。我们可以知道没有文件系统,控制台是怎么工作的
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 异地恋闹矛盾了怎么办 有人威胁要杀我全家怎么办 分手了借我的钱怎么办 脸打架打肿了怎么办 人家不加我qq好友怎么办 一个好友被删了怎么办 dnf脸黑怎么办还有办法 我想登别人微信怎么办 昌硕工资没到怎么办 昌硕离职不批怎么办 昌硕工资不到卡怎么办 上海人去苏州工作社保怎么办 娶个个脾气暴躁的媳妇怎么办 满脸的黑头痘痘怎么办 脚底磨起泡不敢走路怎么办 老婆老是找异性朋友怎么办 喜欢的人有对象怎么办 遇到了更喜欢的怎么办 8岁骨龄11岁怎么办啊 13岁初中生有思想不听话怎么办 交朋友找对象喜欢颜值高的怎么办 儿子找对象不听父母怎么办 缺爱怎么办的搞笑回答 对象说有人追她怎么办 说了一句话媳妇非常生气怎么办 柔顺后头发太臭怎么办 积分兑换手机被骗了怎么办 老板对你的上级不满怎么办 如果老板不给工资怎么办 手机号码被标记为其他公司怎么办? 被标记为骚扰电话怎么办 手机被标记骚扰电话怎么办 360摄像头不支持5g怎么办 摄像头不支持5g网络怎么办 家里的wifi卡了怎么办 办信用卡没有座机号码怎么办 拨打电话时显示号码有误怎么办 个体营业执照怎么办企业支付宝 没满16岁怎么办电话卡 我的电话卡丢了怎么办 公司注销地税没有补齐怎么办