对于我们的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);
}

从这个函数看书,它首先保存了串口控制寄存器的值,然后初始化成符合控制台的,发送完数据后,又恢复了原来的数据

这样做的目的就是,如果我们加载了串口的驱动,那么很有可能打乱了控制台的配置,而系统启动以后

我们还不能动串口驱动的配置,因此最好的办法就是,每次发送数据都重新配置串口,发送完后再恢复以前的配置。

到了这里控制台初始化的第一部分已经完成了。我们可以知道没有文件系统,控制台是怎么工作的。

android kernel控制台初始化过程的更多相关文章

  1. Android 8 Wifi 初始化过程

    记录一下wifi初始化过程. packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java public void on ...

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

    Android源代码在编译之前,要先对编译环境进行初始化,其中最主要就是指定编译的类型和目标设备的型号.Android的编译类型主要有eng.userdebug和user三种,而支持的目标设备型号则是 ...

  3. Android(java)学习笔记159:Dalivk虚拟机的初始化过程

    1.初始化下面系统函数(调用dvmStartup函数初始化所有相关的函数) 开始学习虚拟机的初始化过程,先从dvmStartup函数开始,这个函数实现所有开始虚拟机的准备工作: dvmAllocTra ...

  4. Android(java)学习笔记102:Dalivk虚拟机的初始化过程

    1. 初始化下面系统函数(调用dvmStartup函数初始化所有相关的函数) 开始学习虚拟机的初始化过程,先从dvmStartup函数开始,这个函数实现所有开始虚拟机的准备工作:    dvmAllo ...

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

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

  6. [转]在static代码块或static变量的初始化过程中使用ServiceManager提供的api的陷阱

    一. 案例 1.源码: /** @hide */ private TelephonyManager(int slotId) { mContext = null; mSlotId = slotId; i ...

  7. Android 6.0启动过程具体解析

    在之前的一篇文章中.从概念上学习了Andoird系统的启动过程.Android系统启动过程学习 而在这篇文章中,我们将从代码角度细致学习Android系统的启动过程,同一时候,学习Android启动过 ...

  8. 下载 编译 Android源代码 和 Android kernel源代码

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

  9. android绘制view的过程

    1 android绘制view的过程简单描述  简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw):            下面看看每一步的动作到底是 ...

随机推荐

  1. Codeforces Round #287 (Div. 2) A. Amr and Music 水题

    A. Amr and Music time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  2. 小程序swiper 快速滑动闪屏

    bindchange: function(e){ if(e.detail.source == "touch") { this.setData({ current: current ...

  3. Automate Screen or Button Taps via Tasker : Simulating keypress events

    When using Tasker, sometimes we want to do some automation on screen e.g. screen or button taps. At ...

  4. Detecting Underlying Linux Distro

    If you are the owner of the system, then you know which Linux is installed and running. This article ...

  5. 数据是企业的无价財富——爱数备份存储柜server的初体验(图文)

    非常早就像上这样一套数据备份系统,每天採用原来的软件备份加手动备份的方式,总有些不是太方便的地方. 加上企业规模的不断扩大,系统的增多,业务数据也日显重要.容不得半点中断和数据丢失.这不,出于对系统数 ...

  6. ASP.NET浏览器跨域

    转载:http://www.cnblogs.com/alvinwei1024/p/4626054.html 什么是跨域? 访问同源的资源是被浏览器允许的,但是如果访问不同源的资源,浏览器默认是不允许的 ...

  7. 调试查看CLR运行代码

    SOS (Son of Strike)调试扩展可以让我们在调试过程中查看CLR运行代码.SOS.dll随.NET一起安装,对于.NET 4.0来说,SOS.dll的所在位置是:C:\Windows\M ...

  8. Matlab绘图控制命令

    [转载] 图形的控制与表现 (Figure control and representation) MATLAB提供的用于图形控制的函数和命令: axis:  人工选择坐标轴尺寸.     clf: ...

  9. Fine Uploader + Spring3.2.2(Java+html5上传) SpringMVC+jquery-fineuploader 文件上传

    需求:要实现多文件上传,且要支持手机等移动设备... springmvc文件上传真头疼,网上搜了半天没发现都是TMD的用submit按钮提交到后台的,就没有插件的吗?最后发现了fineUploader ...

  10. Struts2 S标签 数目字格式化成金额输出(保留两位小数)

    JSP: <s:property value="%{formatDouble(price)}" /> Action:添加 //格式化数字显示 public String ...