setup_early_printk()函数分析

关于setup_early_printk()函数,主要用来注册用于启动阶段显示的控制台。内核中声明了一个全局变量early_console,并将定义的全局变量early_console_prom赋值给它,随后开始注册early_console_prom所抽象的终端。上述原型如下:

struct console *early_console;

static void early_console_write(struct console *con, const char *s, unsigned n)
{
	while (n-- && *s) {
		if (*s == '\n')
			prom_putchar('\r');
		prom_putchar(*s);
		s++;
	}
}

static struct console early_console_prom = {
	.name = "early",
	.write = early_console_write,
	.flags = CON_PRINTBUFFER | CON_BOOT,
	.index = -1,
};

void __init setup_early_printk(void)
{
	if (early_console)
		return;
	early_console = &early_console_prom;
	register_console(&early_console_prom);
}

关于控制台注册函数的原型如下:

void register_console(struct console *newcon)
{
	int i;
	unsigned long flags;
	struct console *bcon = NULL;
	struct console_cmdline *c;
	static bool has_preferred;
	
	if (console_drivers)
	//判断是否具有控制台驱动,console_drivers为全局变量,其类型为struct console。
	//如果具有控制台驱动,则检测该控制台驱动是否已注册。
	//假设当前位于内核启动的最初阶段,因此该变量为空。
		for_each_console(bcon)
			if (WARN(bcon == newcon, "console '%s%d' already registered\n", bcon->name, bcon->index))
				return;

	if (console_driver && newcon->flags & CON_BOOT) {
	//如果具有控制台驱动,且所要注册的控制台具有CON_BOOT标识,则检测已有的控制台驱动是否具有CON_BOOT标识,如果没有,则提示所要注册的控制台太迟。
		for_each_console(bcon) {
			if (!(bcon->flags & CON_BOOT)) {
				pr_info("Too late to register bootconsole %s%d\n", newcon->name, newcon->index);
				return;
			}
		}
	}

	if (console_drivers && console_drivers->flags & CON_BOOT)
	//如果具有控制台驱动,且控制台驱动标识为CON_BOOT,则将已存在的控制台赋值给所要注册的控制台。
		bcon = console_drivers;
	
	if (!has_preferred || bcon || !console_drivers)
		has_preferred = preferred_console >= 0;
	
	if (!has_preferred) {
		if (newcon->index < 0)
			newcon->index = 0;
			//更改所要注册的中断的索引号。即将-1更正为0。
		if (newcon->setup == NULL || newcon->setup(newcon, NULL) == 0) {
			//如果所要注册的控制台不存在setup函数,或是setup函数返回为0,则修改其flags标识属性。
			newcon->flags |= CON_ENABLED;
			if (newcon->device) {
			//如果该控制台也具有device函数,则执行下面两步操作。
				newcon->flags |= CON_CONSDEV;
				has_preferred = true;
			}
		}
	}
	
	//在内核启动阶段,console_cmdline数组为空,因此不进入下述的循环结构体中
	for (i = 0, c = console_cmdline; i < MAX_CMDLINECONSOLES && c->name[0]; i++, c++) {	
	//遍历全局数组console_cmdline数组,该数组类型为struct console_cmdline。
		if (!newcon->match || newcon->match(newcon, c->name, c->index, c->options) != 0) {
		//如果所要注册的控制台不存在match函数,或是执行返回值不为0。则执行以下代码。
			BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name));
			//console_cmdline与console结构体中的name变量的长度均为16。
			if (strcmp(c->name, newcon->name) != 0)
				continue;
			if (newcon->index >= 0 && newcon->index != c->index)
				continue;
			if (newcon->index < 0)
				newcon->index = c->index;
			if (_braille_register_console(newcon, c))
				return;
			if (newcon->setup && newcon->setup(newcon, c->options) != 0)
				break;
		}
		newcon->flags |= CON_ENABLED;
		if (i == preferred_console) {
			newcon->flags |= CON_CONSDEV;
			has_preferred = true;
		}
		break;
	}

	if (!(newcon->flags & CON_ENABLED))
	//检查所要注册的控制台是否已使能
		return;

	if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV))
		newcon->flags &= ~CON_PRINTBUFFER;

	console_lock();
	if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
	//如果console_drivers链表为空,且所要注册的设备具有CON_CONSDEV标识,则执行以下操作。
		newcon->next = console_drivers;
		console_drivers = newcon;
	//将所要注册的控制台插入console_drivers链表中
		if (newcon->next)
			newcon->next->flags &= ~CON_CONSDEV;
	} else {
		newcon->next = console_drivers->next;
		console_drivers->next = newcon;
	}	
	...
	if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && !keep_bootcon) {
		for_each_console(bcon)
			if (bcon->flags & CON_BOOT)
				unregister_console(bcon);
				//卸载已注册的控制台驱动
	}
}

综上,便是内核中注册控制台驱动的过程。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值