(由CONSOLE来使用的,既在CONSOLE注册时利用传进来的参数,这个是LINUX内核层的CONSOLE,注意与安桌层及文件系统层的PRINTK的区别。内核层只需要实现输出功能,但前者必须要实现输入输出,以及更复杂的功能)
LINUX内核源码版本:linux-3.0.86
Console控制台:对于输入输出设备一个统一管理组件,可以认为是对计算机输入输出设备的封装。我们对于输入或输出不需要去了解其细节实现原理。只需要调用Console接口。
前一节准备好了参数资源console_cmdline,这一节就是来实用的它了。对于命令行参数的实用是在console的注册函数中。既构建操控台中。
我们代码的console注册流程关系:s5p_serial_init->s3c24xx_serial_init->
platform_driver_register注册平台驱动,然后找到对应的平台设备就会会执行在注册平台驱动中的PROBE函数。s5p_serial_probe->s3c24xx_serial_probe->uart_add_one_port->
uart_configure_port->register_console(port->cons);根据上述流程我们需要得到port->是什么。得到这个代表了什么才能理解register_console函数里面的实现原理。通过查看代码可知
port->cons=s3c24xx_serial_console;
static struct uart_driver s3c24xx_uart_drv = {//注册平台驱动用的串口低层驱动函数
.owner = THIS_MODULE,
.driver_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE_SWITCH
.cons = NULL,
#else
.cons = S3C24XX_SERIAL_CONSOLE,
#endif
.dev_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
static struct console s3c24xx_serial_console = {
.name = S3C24XX_SERIAL_NAME=”ttySAC”,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -1,
.write = s3c24xx_serial_console_write,
.setup = s3c24xx_serial_console_setup,
.data = &s3c24xx_uart_drv,
};
因此register_console(s3c24xx_serial_console)接下来分析这个注册函数的原理。
console_drivers代表已注册了操控台链表。我们可以注册多个操控台。exclusive_console如果定义了打印操控台则这个标记会等于用.flags = CON_PRINTBUFFER,定义了的操控台。在printk函数中会判断这个标记,如果不等于它printk也不会从其它操控台输出数据。
if (preferred_console < 0 || bcon || !console_drivers)
preferred_console = selected_console;第一次注册操控台时,对于我们的串口操控台注册满足selected_console=0。
/*
* See if this console matches one we selected on
* the command line.
*/
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) {
if (strcmp(console_cmdline[i].name, newcon->name) != 0)
continue;
if (newcon->index >= 0 &&
newcon->index != console_cmdline[i].index)
continue;
if (newcon->index < 0)//我们代码会执行这儿,因为index=-1
newcon->index = console_cmdline[i].index=0;
if (newcon->setup &&
newcon->setup(newcon, console_cmdline[i].options) != 0)//根据传入的操控台数据来设置操控台。//newcon=s3c24xx_serial_console console_cmdline[i].options)=115200n8
break;
/*setup=s3c24xx_serial_console_setup(struct console *co, char *options)根据传入的参数来重新初始化串口设备,具体的寄器配置,速率 位数 有无检验等。具体调用函数在s3c24xx_serial_ports中的s3c24xx_serial_ops的.set_termios = s3c24xx_serial_set_termios,来完成上面相关的设置。
*/
newcon->flags |= CON_ENABLED;
newcon->index = console_cmdline[i].index=0;
if (i == selected_console) {
newcon->flags |= CON_CONSDEV;
preferred_console = selected_console=0;
}
上面是对传入的操控台初始化,以及调用
newcon->setup(newcon, console_cmdline[i].options) != 0)函数,这是很核心的代码。
if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
newcon->next = console_drivers;
console_drivers = newcon;
if (newcon->next)
newcon->next->flags &= ~CON_CONSDEV;
} else {
newcon->next = console_drivers->next;
console_drivers->next = newcon;
}
上面代码完成对console_drivers链表的初始化。这个是注册了的操控台的一个链表,其它地方就是用这个变量来查找操控台的。比如PRINTK函数最后也是调用这个链表来查找要输出的串口号的具体硬件设备。
if (newcon->flags & CON_PRINTBUFFER) {
/*
* console_unlock(); will print out the buffered messages
* for us.
*/
spin_lock_irqsave(&logbuf_lock, flags);
con_start = log_start;
spin_unlock_irqrestore(&logbuf_lock, flags);
/*
* We're about to replay the log buffer. Only do this to the
* just-registered console to avoid excessive message spam to
* the already-registered consoles.
*/
exclusive_console = newcon;
}
上面代码说明当如果我们定义了CON_PRINTBUFFER操控台,则exclusive_console就等于它。在printk函数中判断了exclusive_console为真则不会调用console_driver中注册的所有操控来输出信息,而printk只会用exclusive_console定义的操控台。如果没有则会调用console_driver中定义了所有操控来输出信息。最后得出结论。console_driver
代表了所有定义了的操控台。LINUX内核代码中实用操控台都是console_driver链表来操作的。同时printk函数输出信息则会判断我们定义的的操控台CON_PRINTBUFFER类型。通过上面系列处理得到注册操控台链表:console_driver
兴趣交流群抠抠: 461283592