对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上

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

下面正式来看

板子初始化的过程
android\kernel_imx\arch\arm\mach-mx6\board-mx6q_sabresd.c

MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.boot_params = MX6_PHYS_OFFSET + 0x100,
.fixup = fixup_mxc_board,
.map_io = mx6_map_io,
.init_irq = mx6_init_irq,
.init_machine = mx6_sabresd_board_init,
.timer = &mx6_sabresd_timer,
.reserve = mx6q_sabresd_reserve,
MACHINE_END

这其中有个时钟初始化mx6_sabresd_timer我们来看它的定义

static struct sys_timer mx6_sabresd_timer = {
.init   = mx6_sabresd_timer_init,
};
static void __init mx6_sabresd_timer_init(void)
{
struct clk *uart_clk;
#ifdef CONFIG_LOCAL_TIMERS
twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256);
BUG_ON(!twd_base);
#endif
mx6_clocks_init(32768, 24000000, 0, 0);uart_clk = clk_get_sys("imx-uart.0", NULL);
early_console_setup(UART1_BASE_ADDR, uart_clk);
}

可以看到这里调用了early_console_setup(UART1_BASE_ADDR, uart_clk);
这个函数就是文件系统挂载之前控制台的初始化函数。下面我就开始分析这个函数
android\kernel_imx\arch\arm\plat-mxc\cpu.c

/*** early_console_setup - setup debugging console** Consoles started here require little enough setup that we can start using* them very early in the boot process, either right after the machine* vector initialization, or even before if the drivers can detect their hw.** Returns non-zero if a console couldn't be setup.* This function is developed based on* early_console_setup function as defined in arch/ia64/kernel/setup.c* 这个注释里写的很清楚,在设备驱动执行之前,为了调试错误的需要我们* 需要在启动的最初就初始化控制台*/
void __init early_console_setup(unsigned long base, struct clk *clk)
{
#ifdef CONFIG_SERIAL_IMX_CONSOLE
mxc_early_serial_console_init(base, clk);
#endif
}
这里调用mxc_early_serial_console_init(base, clk);
android\kernel_imx\drivers\tty\serial、mxc_uart_early.c
int __init mxc_early_serial_console_init(unsigned long base, struct clk *clk)
{
mxc_early_device.clk = clk;
mxc_early_device.port.mapbase = base;register_console(&mxc_early_uart_console);
return 0;
}

这里可以看到register_console(&mxc_early_uart_console);就是注册一个设备到控制台中,
在最开始注册的这个设备肯定是裸机的访问方式的,因此我们重点来看这个设备

static struct console mxc_early_uart_console __initdata = {
.name = "ttymxc",
.write = early_mxcuart_console_write,
.setup = mxc_early_uart_setup,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};

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

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

static int __init mxc_early_uart_setup(struct console *console, char *options)
{struct mxc_early_uart_device *device = &mxc_early_device;
struct uart_port *port = &device->port;
int length;if (device->port.membase || device->port.iobase)
return -ENODEV;/* Enable Early MXC UART Clock */
clk_enable(device->clk);//初始化总线时钟port->uartclk = 5600000;
port->iotype = UPIO_MEM;
port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器内存映射if (options) {
device->baud = simple_strtoul(options, NULL, 0);
length = min(strlen(options), sizeof(device->options));
strncpy(device->options, options, length);
} else {
device->baud = probe_baud(port);
snprintf(device->options, sizeof(device->options), "%u",
device->baud);
}
printk(KERN_INFO"MXC_Early serial console at MMIO 0x%x (options '%s')\n",port->mapbase, device->options);
return 0;
}

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

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

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

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

/*!* This function is called to write the console messages through the UART port.** @param   co    the console structure* @param   s     the log message to be written to the UART* @param   count length of the message*/
void __init early_mxcuart_console_write(struct console *co, const char *s,
u_int count)
{
struct uart_port *port = &mxc_early_device.port;
unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3;/*
* First save the control registers and then disable the interrupts
*/
oldcr1 = readl(port->membase + MXC_UARTUCR1);   //读取当前三个串口控制寄存器的值
oldcr2 = readl(port->membase + MXC_UARTUCR2);
oldcr3 = readl(port->membase + MXC_UARTUCR3);
cr2 =oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN | //初始化串口寄存器数值MXC_UARTUCR2_ESCI);
cr3 =oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI |MXC_UARTUCR3_DTRDEN);
writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1);  //使能串口
writel(cr2, port->membase + MXC_UARTUCR2);  //配置寄存器
writel(cr3, port->membase + MXC_UARTUCR3);/* Transmit string */
uart_console_write(port, s, count, mxcuart_console_write_char); //发送数据/*
* Finally, wait for the transmitter to become empty等待发送完成
*/
do {
status = readl(port->membase + MXC_UARTUSR2);
} while (!(status & MXC_UARTUSR2_TXDC));/*
* Restore the control registers
*/
writel(oldcr1, port->membase + MXC_UARTUCR1);//恢复串口寄存器数值
writel(oldcr2, port->membase + MXC_UARTUCR2);
writel(oldcr3, port->membase + MXC_UARTUCR3);
}

从这个函数看书,它首先保存了串口控制寄存器的值,然后初始化成符合控制台的,发送完数据后,又恢复了原来的数据
这样做的目的就是,如果我们加载了串口的驱动,那么很有可能打乱了控制台的配置,而系统启动以后
我们还不能动串口驱动的配置,因此最好的办法就是,每次发送数据都重新配置串口,发送完后再恢复以前的配置。
到了这里控制台初始化的第一部分已经完成了。我们可以知道没有文件系统,控制台是怎么工作的。

转载于:https://www.cnblogs.com/james1207/p/3253853.html

android kernel控制台初始化过程相关推荐

  1. android l camera no panorama,Android Camera从App层到framework层到HAL层的初始化过程

    Android camera 从上到下能够分为四个部分: Application层. framework层. HAL(hardware abstract layer)层. Kernel层 通常面向开发 ...

  2. android 原始编译过程,Android编译系统环境初始化过程分析.doc

    Android编译系统环境初始化过程分析要点 Android编译系统环境初始化过程分析 Android源代码在编译之前,要先对编译环境进行初始化,其中最主要就是指定编译的类型和目标设备的型号.Andr ...

  3. 2021-04-27 Android 理解frameworks services jni hardware kernel 整个控制过程实例包括回调

    Android 理解frameworks services jni hardware kernel 整个控制过程实例包括回调 一.这个例子的实现的功能是,app控制power pin和control ...

  4. linux文件系统启动流程,linux 内核启动过程以及挂载android 根文件系统的过程

    转载 作者:汕头大学-黄珠唐 时间:2009 年10 月29 日 主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源 ...

  5. Android 图形驱动初始化

    从应用程序的角度看 OpenGL 图形系统的接口,主要包括两大部分,一部分是 EGL,它为 OpenGL 渲染准备环境:另一部分是 OpenGL,它执行图形渲染.通过这些接口构造渲染环境,并执行渲染的 ...

  6. Android 图形驱动初始化(二十三)

    从应用程序的角度看 OpenGL 图形系统的接口,主要包括两大部分,一部分是 EGL,它为 OpenGL 渲染准备环境:另一部分是 OpenGL,它执行图形渲染.通过这些接口构造渲染环境,并执行渲染的 ...

  7. 【Android 系统开发】下载 编译 Android源代码 和 Android kernel源代码

    下载Android源码简要流程 : a. 获取repo文件: curl http://commondatastorage.googleapis.com/git-repo-downloads/repo ...

  8. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

  9. Android 图形驱动初始化(二十三),kotlin协程原理

    1 #define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__); 可以看到 struct gl_hooks_t 的 struct gl_t gl 的 ...

最新文章

  1. JS中的7种设计模式
  2. Centos 6 常用服务部署命令说明
  3. GDCM:gdcm::PrivateTag的测试程序
  4. 处理对象的多种状态及其相互转换——状态模式
  5. 华为鸿蒙全能家居,能兑现多少?华为智慧屏十年不过时,用鸿蒙理念做智能家居...
  6. ftp linux 服务器 麒麟_麒麟系统安装ftp
  7. 【T+】T+和天联高级版软件结合使用的时候,运行T+提示网页崩溃了。
  8. 管理定律——管理学中常见的定律集合
  9. 从底层谈webgis原理设计与实现(二)探究本质,WebGIS前端地图显示之地图比例尺换算原理...
  10. oracle 菜单不见了,桌面任务栏不见了 - 电脑任务栏不见了的解决办法 - 安全专题...
  11. HTML超链接引用到地图,HTML超链接
  12. CleanMyMac2023免费版系统清理优化工具
  13. MDK的编译过程及文件类型全解——(二)
  14. ElasticSearch入门-搜索如此简单
  15. 【SIMULINK】simulink实现信号矩阵整合、求逆、转置、分解、向量矩阵相乘(非matlab)
  16. Entity Framework 一对多关系映射
  17. Typora的初步使用及Markdown语法总结
  18. 【计算机毕业设计】外卖点餐系统
  19. fedora dnf 命令
  20. 洛谷P1014题解 [NOIP1999 普及组] Cantor 表

热门文章

  1. yarn资源参数配置
  2. Ansible Playbook企业案例:利用 playbook 安装 nginx、安装和卸载 httpd、安装mysql
  3. 【PyQT5编程】Pycharm结合QtDesigner使用示例:创建登录窗体
  4. Linux shell接收用户的输入
  5. Nginx面试中最常见的18道题及答案
  6. SQLyog连接虚拟机中mysql8.0详解,2003、1130、2058错误码解决
  7. MATLAB中改变默认当前文件夹
  8. spring 5企业级开发实战pdf_SpringBoot实战5-Spring基础-配置与注入
  9. 如何快速解决虚拟机中的CentOS7无法上网的方式
  10. java.sql.SQLException: Before start of result set ---错误笔记