当前位置:操作系统 > 安卓/Android >>

android kernel控制台初始化过程


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

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

下面正式来看

板子初始化的过程
android\kernel_imx\arch\arm\mach-mx6\board-mx6q_sabresd.c
[cpp]
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 

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我们来看它的定义
[cpp]
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); 

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
[cpp]
/**
 * 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; 

/**
 * 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);就是注册一个设备到控制台中,
在最开始注册的这个设备肯定是裸机的访问方式的,因此我们重点来看这个设备
[cpp]
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, 
}; 

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的控制台设备
也就是说是挂载设备文件之前的控制台设备


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

[cpp]
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 = 易做图_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; 

static int __init mxc_early_uart_setup(struct console *console, char *options)
{

struct mxc

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,