一.结构体
1.console
- struct console {
- char name[16]; //console名
- void (*write)(struct console *, const char *, unsigned); //写方法
- int (*read)(struct console *, char *, unsigned); //读方法
- struct tty_driver *(*device)(struct console *, int *); //tty驱动
- void (*unblank)(void);
- int (*setup)(struct console *, char *); //setup方法
- int (*early_setup)(void); //early_setup方法
- short flags;
- short index;
- int cflag;
- void *data;
- struct console *next;
- };
2.标志
- #define CON_PRINTBUFFER (1)
- #define CON_CONSDEV (2) /* Last on the command line */
- #define CON_ENABLED (4) //使能标志位
- #define CON_BOOT (8) //内核引导使用的console
- #define CON_ANYTIME (16) /* Safe to call when cpu is offline */
- #define CON_BRL (32) /* Used for a braille device */
二.初始化
在Vmlinux.lds.h中定义
- #define CON_INITCALL \
- VMLINUX_SYMBOL(__con_initcall_start) = .; \
- *(.con_initcall.init) \
- VMLINUX_SYMBOL(__con_initcall_end) = .;
在init.h中定义
- #define console_initcall(fn) \
- static initcall_t __initcall_##fn \
- __used __section(.con_initcall.init) = fn
在console_init初始化(start_kernel中调用了console_init函数)
- void __init console_init(void)
- {
- initcall_t *call;
- tty_ldisc_begin();
- call = __con_initcall_start;
- while (call < __con_initcall_end) { //遍历__con_initcall_end段的函数
- (*call)(); //调用该函数
- call++;
- }
- }
tty线路规程开始
- void tty_ldisc_begin(void)
- {
- (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); //N_TTY=0
- }
tty注册默认的线路规程
- int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
- {
- unsigned long flags;
- int ret = 0;
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- tty_ldiscs[disc] = new_ldisc; //设置全局tty_ldiscs[0]=tty_ldisc_N_TTY
- new_ldisc->num = disc; //设置num域
- new_ldisc->refcount = 0; //参考计数
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return ret;
- }
- EXPORT_SYMBOL(tty_register_ldisc);
该全局数组在tty_ldisc_init函数中使用
三.console的注册和注销
1.注册console
- void register_console(struct console *newcon)
- {
- int i;
- unsigned long flags;
- struct console *bcon = NULL;
- if (console_drivers && newcon->flags & CON_BOOT) { //注册的是引导控制台
- for_each_console(bcon) { //遍历全局console_drivers数组
- if (!(bcon->flags & CON_BOOT)) { //判断是否已经有引导控制台了,有了的话就直接退出
- printk(KERN_INFO "Too late to register bootconsole %s%d\n",newcon->name, newcon->index);
- return;
- }
- }
- }
- if (console_drivers && console_drivers->flags & CON_BOOT) //如果注册的是引导控制台
- bcon = console_drivers; //让bcon指向全局console_drivers
- if (<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> < 0 || bcon || !console_drivers)
- <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = selected_console; //设置<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span>为uboot命令选择的selected_console(索引)
- if (newcon->early_setup) //存在early_setup函数
- newcon->early_setup(); //则调用early_setup函数
- if (<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> < 0) {
- if (newcon->index < 0)
- newcon->index = 0;
- if (newcon->setup == NULL ||newcon->setup(newcon, NULL) == 0) {
- newcon->flags |= CON_ENABLED;
- if (newcon->device) {
- newcon->flags |= CON_CONSDEV;
- <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = 0;
- }
- }
- } //遍历全局console_cmdline找到匹配的
- 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) //若没指定设备号
- newcon->index = console_cmdline[i].index;
- #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
- if (console_cmdline[i].brl_options) {
- newcon->flags |= CON_BRL;
- braille_register_console(newcon,console_cmdline[i].index,console_cmdline[i].options,console_cmdline[i].brl_options);
- return;
- }
- #endif
- if (newcon->setup &&newcon->setup(newcon, console_cmdline[i].options) != 0) //存在setup方法调用setup方法
- break;
- newcon->flags |= CON_ENABLED; //设置标志为CON_ENABLE(这个在printk调用中使用到)
- newcon->index = console_cmdline[i].index; //设置索引号
- if (i == selected_console) { //索引号和uboot指定的console的一样
- newcon->flags |= CON_CONSDEV; //设置标志CON_CONSDEV(全局console_drivers链表中靠前)
- <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = selected_console; //设置preferred
- }
- break;
- } //for循环作用大致是查看注册的console是否是uboot知道的引导console是则设置相关标志和<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span>
- if (!(newcon->flags & CON_ENABLED))
- return;
- if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) //防止重复打印
- newcon->flags &= ~CON_PRINTBUFFER;
- acquire_console_sem();
- if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { //如果是preferred控制台
- newcon->next = console_drivers;
- console_drivers = newcon; //添加进全局console_drivers链表前面位置(printk中会遍历该表调用合适的console的write方法打印信息)
- if (newcon->next)
- newcon->next->flags &= ~CON_CONSDEV;
- } else { //如果不是preferred控制台
- newcon->next = console_drivers->next;
- console_drivers->next = newcon; //添加进全局console_drivers链表后面位置
- }
- if (newcon->flags & CON_PRINTBUFFER) {
- spin_lock_irqsave(&logbuf_lock, flags);
- con_start = log_start;
- spin_unlock_irqrestore(&logbuf_lock, flags);
- }
- release_console_sem();
- if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
- printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n",newcon->name, newcon->index);
- for_each_console(bcon)
- if (bcon->flags & CON_BOOT)
- unregister_console(bcon);
- } else {
- printk(KERN_INFO "%sconsole [%s%d] enabled\n",(newcon->flags & CON_BOOT) ? "boot" : "" ,newcon->name, newcon->index);
- }
- }
- EXPORT_SYMBOL(register_console);
注册console主要是刷选preferred_console放置在全局console_drivers链表前面,剩下的console放置链表靠后的位置,并设置相应的flags,
console_drivers最终会在printk函数的层层调用中遍历到,并调用console的write方法将信息打印出来
2.注销console
- int unregister_console(struct console *console)
- {
- struct console *a, *b;
- int res = 1;
- #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
- if (console->flags & CON_BRL)
- return braille_unregister_console(console);
- #endif
- acquire_console_sem();
- if (console_drivers == console) {
- console_drivers=console->next;
- res = 0;
- } else if (console_drivers) {
- for (a=console_drivers->next, b=console_drivers ;
- a; b=a, a=b->next) {
- if (a == console) {
- b->next = a->next;
- res = 0;
- break;
- }
- }
- }
- /*
- * If this isn't the last console and it has CON_CONSDEV set, we
- * need to set it on the next preferred console.
- */
- if (console_drivers != NULL && console->flags & CON_CONSDEV)
- console_drivers->flags |= CON_CONSDEV;
- release_console_sem();
- return res;
- }
- EXPORT_SYMBOL(unregister_console);
3./dev/console
在tty_init函数中
- int __init tty_init(void)
- {
- cdev_init(&tty_cdev, &tty_fops);
- if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
- register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
- panic("Couldn't register /dev/tty driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,"tty");
- cdev_init(&console_cdev, &console_fops); //初始化字符设备并捆绑console_fops操作函数集合
- if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
- register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) //注册字符设备
- panic("Couldn't register /dev/console driver\n");
- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,"console"); //创建设备文件
- #ifdef CONFIG_VT
- vty_init(&console_fops);
- #endif
- return 0;
- }
当操作/dev/console文件时会调用console_fops操作函数集的方法
- static const struct file_operations console_fops = {
- .llseek = no_llseek,
- .read = tty_read,
- .write = redirected_tty_write,
- .poll = tty_poll,
- .unlocked_ioctl = tty_ioctl,
- .compat_ioctl = tty_compat_ioctl,
- .open = tty_open,
- .release = tty_release,
- .fasync = tty_fasync,
- };
该函数集跟tty_fops基本一样不同的只是写方法
redirected_tty_write函数
- ssize_t redirected_tty_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
- {
- struct file *p = NULL;
- spin_lock(&redirect_lock);
- if (redirect) {
- get_file(redirect);
- p = redirect;
- }
- spin_unlock(&redirect_lock);
- if (p) {
- ssize_t res;
- res = vfs_write(p, buf, count, &p->f_pos); //多了个写文件的方法
- fput(p);
- return res;
- }
- return tty_write(file, buf, count, ppos); //同样也会调用tty_write方法
- }
在tty_open中有个分支专门处理/dev/console
- if (device == MKDEV(TTYAUX_MAJOR, 1)) {
- struct tty_driver *console_driver = console_device(&index);<span style="WHITE-SPACE: pre"> </span>//获取console对应的tty-driver
- if (console_driver) {
- driver = tty_driver_kref_get(console_driver);
- if (driver) {
- filp->f_flags |= O_NONBLOCK;
- noctty = 1;
- goto got_driver;
- }
- }
- tty_unlock();
- mutex_unlock(&tty_mutex);
- return -ENODEV;
- }
- struct tty_driver *console_device(int *index)
- {
- struct console *c;
- struct tty_driver *driver = NULL;
- acquire_console_sem();
- for_each_console(c) {
- if (!c->device)<span style="WHITE-SPACE: pre"> </span>//console存在tty_driver 说明是/dev/console对应的console
- continue;
- driver = c->device(c, index);
- if (driver)
- b