console控制台

一.结构体

1.console

[cpp]  view plain copy
  1. struct console {  
  2.     char    name[16];       //console名  
  3.     void    (*write)(struct console *, const char *, unsigned); //写方法  
  4.     int (*read)(struct console *, char *, unsigned);    //读方法  
  5.     struct tty_driver *(*device)(struct console *, int *);  //tty驱动  
  6.     void    (*unblank)(void);  
  7.     int (*setup)(struct console *, char *); //setup方法  
  8.     int (*early_setup)(void);   //early_setup方法  
  9.     short   flags;  
  10.     short   index;  
  11.     int cflag;  
  12.     void    *data;  
  13.     struct   console *next;  
  14. };  

2.标志

[cpp]  view plain copy
  1. #define CON_PRINTBUFFER (1)  
  2. #define CON_CONSDEV (2) /* Last on the command line */  
  3. #define CON_ENABLED (4) //使能标志位  
  4. #define CON_BOOT        (8) //内核引导使用的console  
  5. #define CON_ANYTIME (16) /* Safe to call when cpu is offline */  
  6. #define CON_BRL     (32) /* Used for a braille device */  


 二.初始化

在Vmlinux.lds.h中定义

[cpp]  view plain copy
  1. #define CON_INITCALL                    \  
  2.         VMLINUX_SYMBOL(__con_initcall_start) = .;   \  
  3.         *(.con_initcall.init)           \  
  4.         VMLINUX_SYMBOL(__con_initcall_end) = .;  

在init.h中定义

[cpp]  view plain copy
  1. #define console_initcall(fn) \  
  2.     static initcall_t __initcall_##fn \  
  3.     __used __section(.con_initcall.init) = fn  

在console_init初始化(start_kernel中调用了console_init函数)

[cpp]  view plain copy
  1. void __init console_init(void)  
  2. {  
  3.     initcall_t *call;  
  4.     tty_ldisc_begin();  
  5.     call = __con_initcall_start;  
  6.     while (call < __con_initcall_end) {  //遍历__con_initcall_end段的函数  
  7.         (*call)();  //调用该函数  
  8.         call++;  
  9.     }  
  10. }  

tty线路规程开始

[cpp]  view plain copy
  1. void tty_ldisc_begin(void)  
  2. {  
  3.     (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); //N_TTY=0  
  4. }  

tty注册默认的线路规程

[cpp]  view plain copy
  1. int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)  
  2. {  
  3.     unsigned long flags;  
  4.     int ret = 0;  
  5.     if (disc < N_TTY || disc >= NR_LDISCS)  
  6.         return -EINVAL;  
  7.     spin_lock_irqsave(&tty_ldisc_lock, flags);  
  8.     tty_ldiscs[disc] = new_ldisc;   //设置全局tty_ldiscs[0]=tty_ldisc_N_TTY  
  9.     new_ldisc->num = disc;   //设置num域  
  10.     new_ldisc->refcount = 0; //参考计数  
  11.     spin_unlock_irqrestore(&tty_ldisc_lock, flags);  
  12.     return ret;  
  13. }  
  14. EXPORT_SYMBOL(tty_register_ldisc);  

 该全局数组在tty_ldisc_init函数中使用

三.console的注册和注销

1.注册console

[cpp]  view plain copy
  1. void register_console(struct console *newcon)  
  2. {  
  3.     int i;  
  4.     unsigned long flags;  
  5.     struct console *bcon = NULL;  
  6.     if (console_drivers && newcon->flags & CON_BOOT) {   //注册的是引导控制台  
  7.         for_each_console(bcon) {    //遍历全局console_drivers数组  
  8.             if (!(bcon->flags & CON_BOOT)) { //判断是否已经有引导控制台了,有了的话就直接退出  
  9.                 printk(KERN_INFO "Too late to register bootconsole %s%d\n",newcon->name, newcon->index);  
  10.                 return;  
  11.             }  
  12.         }  
  13.     }  
  14.   
  15.     if (console_drivers && console_drivers->flags & CON_BOOT)    //如果注册的是引导控制台  
  16.         bcon = console_drivers; //让bcon指向全局console_drivers  
  17.     if (<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> < 0 || bcon || !console_drivers)  
  18.         <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = selected_console;    //设置<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span>为uboot命令选择的selected_console(索引)  
  19.     if (newcon->early_setup) //存在early_setup函数  
  20.         newcon->early_setup();   //则调用early_setup函数  
  21.     if (<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> < 0) {  
  22.         if (newcon->index < 0)  
  23.             newcon->index = 0;  
  24.         if (newcon->setup == NULL ||newcon->setup(newcon, NULL) == 0) {  
  25.             newcon->flags |= CON_ENABLED;  
  26.             if (newcon->device) {  
  27.                 newcon->flags |= CON_CONSDEV;  
  28.                 <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = 0;  
  29.             }  
  30.         }  
  31.     }   //遍历全局console_cmdline找到匹配的  
  32.     for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];i++) {  
  33.         if (strcmp(console_cmdline[i].name, newcon->name) != 0)  //比较名字  
  34.             continue;  
  35.         if (newcon->index >= 0 &&newcon->index != console_cmdline[i].index)    //比较次设备号  
  36.             continue;  
  37.         if (newcon->index < 0)    //若没指定设备号  
  38.             newcon->index = console_cmdline[i].index;  
  39. #ifdef CONFIG_A11Y_BRAILLE_CONSOLE  
  40.         if (console_cmdline[i].brl_options) {  
  41.             newcon->flags |= CON_BRL;  
  42.             braille_register_console(newcon,console_cmdline[i].index,console_cmdline[i].options,console_cmdline[i].brl_options);  
  43.             return;  
  44.         }  
  45. #endif  
  46.         if (newcon->setup &&newcon->setup(newcon, console_cmdline[i].options) != 0)   //存在setup方法调用setup方法  
  47.             break;  
  48.         newcon->flags |= CON_ENABLED;    //设置标志为CON_ENABLE(这个在printk调用中使用到)  
  49.         newcon->index = console_cmdline[i].index;    //设置索引号  
  50.         if (i == selected_console) {    //索引号和uboot指定的console的一样  
  51.             newcon->flags |= CON_CONSDEV;    //设置标志CON_CONSDEV(全局console_drivers链表中靠前)  
  52.             <span style="BACKGROUND-COLOR: #ffd700">preferred_console</span> = selected_console;    //设置preferred  
  53.         }  
  54.         break;  
  55.     }   //for循环作用大致是查看注册的console是否是uboot知道的引导console是则设置相关标志和<span style="BACKGROUND-COLOR: #ffd700">preferred_console</span>  
  56.     if (!(newcon->flags & CON_ENABLED))  
  57.         return;  
  58.     if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) //防止重复打印  
  59.         newcon->flags &= ~CON_PRINTBUFFER;  
  60.     acquire_console_sem();  
  61.     if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {  //如果是preferred控制台  
  62.         newcon->next = console_drivers;  
  63.         console_drivers = newcon;   //添加进全局console_drivers链表前面位置(printk中会遍历该表调用合适的console的write方法打印信息)  
  64.         if (newcon->next)  
  65.             newcon->next->flags &= ~CON_CONSDEV;  
  66.     } else {    //如果不是preferred控制台  
  67.         newcon->next = console_drivers->next;  
  68.         console_drivers->next = newcon;  //添加进全局console_drivers链表后面位置  
  69.     }  
  70.     if (newcon->flags & CON_PRINTBUFFER) {  
  71.         spin_lock_irqsave(&logbuf_lock, flags);  
  72.         con_start = log_start;  
  73.         spin_unlock_irqrestore(&logbuf_lock, flags);  
  74.     }  
  75.     release_console_sem();  
  76.     if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {  
  77.         printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n",newcon->name, newcon->index);  
  78.         for_each_console(bcon)  
  79.             if (bcon->flags & CON_BOOT)  
  80.                 unregister_console(bcon);  
  81.     } else {  
  82.         printk(KERN_INFO "%sconsole [%s%d] enabled\n",(newcon->flags & CON_BOOT) ? "boot" : "" ,newcon->name, newcon->index);  
  83.     }  
  84. }  
  85. EXPORT_SYMBOL(register_console);  

注册console主要是刷选preferred_console放置在全局console_drivers链表前面,剩下的console放置链表靠后的位置,并设置相应的flags,

console_drivers最终会在printk函数的层层调用中遍历到,并调用console的write方法将信息打印出来

2.注销console

[cpp]  view plain copy
  1. int unregister_console(struct console *console)  
  2. {  
  3.         struct console *a, *b;  
  4.     int res = 1;  
  5.   
  6. #ifdef CONFIG_A11Y_BRAILLE_CONSOLE  
  7.     if (console->flags & CON_BRL)  
  8.         return braille_unregister_console(console);  
  9. #endif  
  10.   
  11.     acquire_console_sem();  
  12.     if (console_drivers == console) {  
  13.         console_drivers=console->next;  
  14.         res = 0;  
  15.     } else if (console_drivers) {  
  16.         for (a=console_drivers->next, b=console_drivers ;  
  17.              a; b=a, a=b->next) {  
  18.             if (a == console) {  
  19.                 b->next = a->next;  
  20.                 res = 0;  
  21.                 break;  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     /* 
  27.      * If this isn't the last console and it has CON_CONSDEV set, we 
  28.      * need to set it on the next preferred console. 
  29.      */  
  30.     if (console_drivers != NULL && console->flags & CON_CONSDEV)  
  31.         console_drivers->flags |= CON_CONSDEV;  
  32.   
  33.     release_console_sem();  
  34.     return res;  
  35. }  
  36. EXPORT_SYMBOL(unregister_console);  

3./dev/console

在tty_init函数中

[cpp]  view plain copy
  1. int __init tty_init(void)  
  2. {  
  3.     cdev_init(&tty_cdev, &tty_fops);  
  4.     if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||  
  5.         register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)  
  6.         panic("Couldn't register /dev/tty driver\n");  
  7.     device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,"tty");  
  8.     cdev_init(&console_cdev, &console_fops);    //初始化字符设备并捆绑console_fops操作函数集合  
  9.     if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||  
  10.         register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)   //注册字符设备  
  11.         panic("Couldn't register /dev/console driver\n");  
  12.     device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,"console"); //创建设备文件  
  13. #ifdef CONFIG_VT  
  14.     vty_init(&console_fops);  
  15. #endif  
  16.     return 0;  
  17. }  

当操作/dev/console文件时会调用console_fops操作函数集的方法

[cpp]  view plain copy
  1. static const struct file_operations console_fops = {  
  2.     .llseek     = no_llseek,  
  3.     .read       = tty_read,  
  4.     .write      = redirected_tty_write,  
  5.     .poll       = tty_poll,  
  6.     .unlocked_ioctl = tty_ioctl,  
  7.     .compat_ioctl   = tty_compat_ioctl,  
  8.     .open       = tty_open,  
  9.     .release    = tty_release,  
  10.     .fasync     = tty_fasync,  
  11. };  

该函数集跟tty_fops基本一样不同的只是写方法

redirected_tty_write函数

[cpp]  view plain copy
  1. ssize_t redirected_tty_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)  
  2. {  
  3.     struct file *p = NULL;  
  4.     spin_lock(&redirect_lock);  
  5.     if (redirect) {  
  6.         get_file(redirect);  
  7.         p = redirect;  
  8.     }  
  9.     spin_unlock(&redirect_lock);  
  10.   
  11.     if (p) {  
  12.         ssize_t res;  
  13.         res = vfs_write(p, buf, count, &p->f_pos);   //多了个写文件的方法  
  14.         fput(p);  
  15.         return res;  
  16.     }  
  17.     return tty_write(file, buf, count, ppos);   //同样也会调用tty_write方法  
  18. }  

在tty_open中有个分支专门处理/dev/console

[cpp]  view plain copy
  1. if (device == MKDEV(TTYAUX_MAJOR, 1)) {  
  2.     struct tty_driver *console_driver = console_device(&index);<span style="WHITE-SPACE: pre">  </span>//获取console对应的tty-driver  
  3.     if (console_driver) {  
  4.         driver = tty_driver_kref_get(console_driver);  
  5.         if (driver) {  
  6.             filp->f_flags |= O_NONBLOCK;  
  7.             noctty = 1;  
  8.             goto got_driver;  
  9.         }  
  10.     }  
  11.     tty_unlock();  
  12.     mutex_unlock(&tty_mutex);  
  13.     return -ENODEV;  
  14. }  
console_device
[cpp]  view plain copy
  1. struct tty_driver *console_device(int *index)  
  2. {  
  3.     struct console *c;  
  4.     struct tty_driver *driver = NULL;  
  5.   
  6.     acquire_console_sem();  
  7.     for_each_console(c) {  
  8.         if (!c->device)<span style="WHITE-SPACE: pre">   </span>//console存在tty_driver 说明是/dev/console对应的console  
  9.             continue;  
  10.         driver = c->device(c, index);  
  11.         if (driver)  
  12.             b
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值