android kernel控制台初始化过程
来源:互联网 发布:java 开发平面地图 编辑:程序博客网 时间:2024/06/18 17:18
对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上
android\kernel_imx\arch\arm\mach-mx6\board-mx6q_sabresd.c
这其中有个时钟初始化mx6_sabresd_timer我们来看它的定义
可以看到这里调用了early_console_setup(UART1_BASE_ADDR, uart_clk);
这个函数就是文件系统挂载之前控制台的初始化函数。下面我就开始分析这个函数
android\kernel_imx\arch\arm\plat-mxc\cpu.c
这里可以看到register_console(&mxc_early_uart_console);就是注册一个设备到控制台中,
在最开始注册的这个设备肯定是裸机的访问方式的,因此我们重点来看这个设备
这个设备提供的设备访问接口
.write = early_mxcuart_console_write,是串口的发送函数
.setup = mxc_early_uart_setup,是串口的初始化函数
.flags = CON_PRINTBUFFER | CON_BOOT,是控制台标志,CON_BOOT表明这事一个boot的控制台设备
也就是说是挂载设备文件之前的控制台设备
下面我们来分析初始化函数和 数据发送函数
初始化函数
其实从这个初始化函数里看出,它做了很多向mxc_early_device结构体中填入数据的工作,而这些数据
clk_enable(device->clk);//初始化总线时钟
port->membase = ioremap(port->mapbase, SZ_4K);//串口寄存器内存映射
但是在寄存器映射结束后没有进行任何串口寄存器初始化,这也很奇怪,我们仔细查找发现,
寄存器初始化代码写在了数据发送函数里,具体为什么我们来分析发送函数
early_mxcuart_console_write
从这个函数看书,它首先保存了串口控制寄存器的值,然后初始化成符合控制台的,发送完数据后,又恢复了原来的数据
这样做的目的就是,如果我们加载了串口的驱动,那么很有可能打乱了控制台的配置,而系统启动以后
我们还不能动串口驱动的配置,因此最好的办法就是,每次发送数据都重新配置串口,发送完后再恢复以前的配置。
到了这里控制台初始化的第一部分已经完成了。我们可以知道没有文件系统,控制台是怎么工作的
对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
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);
- }
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_TIMERStwd_base = ioremap(LOCAL_TWD_ADDR, SZ_256);BUG_ON(!twd_base);#endifmx6_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;
- }
/** * 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_CONSOLEmxc_early_serial_console_init(base, clk);#endif}这里调用mxc_early_serial_console_init(base, clk);android\kernel_imx\drivers\tty\serial、mxc_uart_early.cint __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,
- };
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;
- }
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);
- }
/*! * 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);}
从这个函数看书,它首先保存了串口控制寄存器的值,然后初始化成符合控制台的,发送完数据后,又恢复了原来的数据
这样做的目的就是,如果我们加载了串口的驱动,那么很有可能打乱了控制台的配置,而系统启动以后
我们还不能动串口驱动的配置,因此最好的办法就是,每次发送数据都重新配置串口,发送完后再恢复以前的配置。
到了这里控制台初始化的第一部分已经完成了。我们可以知道没有文件系统,控制台是怎么工作的
0 0
- android kernel控制台初始化过程
- android kernel控制台初始化过程
- pxa2128 linux kernel console_init 控制台初始化
- android kernel 初始化 1
- android kernel 初始化 2
- Android初始化过程
- android HLS 初始化过程
- Android初始化过程
- kernel 3.0.31 usb_init 子系统初始化过程分析
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程---uboot,kernel,android
- Android系统启动过程-uBoot+Kernel+Android
- Android系统启动过程---uboot,kernel,android
- 转载:Android系统启动过程uboot--kernel--Android
- Android系统启动过程-uBoot+Kernel+Android
- Android系统启动过程-uBoot+Kernel+Android
- Linux kernel起来后Android启动过程
- YUV格式详解
- pow 的使用和常见问题
- 前段学习初始化
- Python程序打包为独立的exe
- hdu 1232 畅通工程 (水题,并查集)
- android kernel控制台初始化过程
- [Android] 字体使用dp单位避免设置系统字体大小对排版的影响
- mac下录屏软件LICEcap
- CSS Position
- UVa 112 - Tree Summing
- JAVA下的归并排序
- 三星确认“有限数量”的Galaxy S5相机有重大缺陷
- sql server08 (mssqlserver)启动不了
- 彩色图像分割技术基础