console 设备驱动

一.结构体

1.console

  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.标志

  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中定义

  1. #define CON_INITCALL                    \  
  2.         VMLINUX_SYMBOL(__con_initcall_start) = .;   \  
  3.         *(.con_initcall.init)           \  
  4.         VMLINUX_SYMBOL(__con_initcall_end) = .;  

在init.h中定义

  1. #define console_initcall(fn) \  
  2.     static initcall_t __initcall_##fn \  
  3.     __used __section(.con_initcall.init) = fn  

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

  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线路规程开始

  1. void tty_ldisc_begin(void)  
  2. {  
  3.     (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); //N_TTY=0  
  4. }  

tty注册默认的线路规程

  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

  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

  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函数中

  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操作函数集的方法

  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函数

  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

  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
  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.             break;  
  13.     }  
  14.     release_console_sem();  
  15.     return driver;  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 绿联console线驱动是一款专门为绿联console线设计的驱动程序。绿联console线是一种将电脑连接到电视或者显示器上的设备,通过它可以将计算机的画面投射到大屏幕上进行观看。而绿联console线驱动的作用便是为这种设备提供驱动支持,让电脑可以正确地识别和连接到绿联console线,从而实现电脑画面的投射。在使用绿联console线的时候,用户需要先下载和安装绿联console线驱动程序,然后将设备连接到电脑上,通过选择合适的连接模式就可以将电脑画面投射到大屏幕上了。 绿联console线驱动的使用非常简单方便,只需要按照说明进行安装和设置即可,它可以兼容各种品牌的电视或者显示器,让用户可以随意选择自己喜欢的显示设备。此外,绿联console线驱动还提供了丰富的调节选项,可以帮助用户根据自己的习惯和需求进行优化设置,让使用更加舒适和方便。总之,绿联console线驱动是非常重要和实用的一款程序,对于那些需要将电脑画面投射到大屏幕上的用户来说,它可以让使用变得更加顺畅和高效。 ### 回答2: 绿联console线驱动是一款用于计算机连接控制台设备驱动程序。控制台设备包括键盘、鼠标、显示器等,这些设备通常用于服务器、机房等比较专业的环境,需要可以实现多个计算机共享使用同一套控制台设备。绿联console线驱动的作用就是连接计算机与控制台设备,实现控制台设备在多个计算机间的切换使用。 绿联console线驱动的安装非常简单,只需要将控制台设备与计算机通过一根console线连接,并在计算机端下载安装绿联console线驱动,即可实现多个计算机共享使用同一套控制台设备。同时,绿联console线驱动还支持多种操作系统,包括Windows、Linux等。使用绿联console线驱动可以有效地减少控制台设备的数量,降低成本,同时也可以提高工作效率,方便管理员维护管理多个计算机。 总的来说,绿联console线驱动可以帮助计算机管理员更加便捷地管理多个服务器或机房设备,提高工作效率,减少成本。如果你需要使用控制台设备来管理多台计算机,可以考虑使用绿联console线驱动。 ### 回答3: 绿联console线驱动是指绿联科技为其产品配套开发的驱动程序,通过这个驱动程序,可以实现主机与绿联console线之间的连接和通信,从而保证设备的正常工作。该驱动程序支持多种操作系统,包括Windows、Mac OS、Linux等。用户可以根据需要,在官方网站上下载并安装相应的驱动程序。 相对于其他普通的数据线,绿联console线在设计上考虑了更多的功能和适用性,不仅可以进行数据传输和充电,还支持多种设备的连接,如手机、平板、电脑等。同时,绿联console线还可以实现屏显功能,将设备的屏幕内容直接显示在电脑上,方便用户进行操作和控制。 总之,绿联console线驱动是用户使用绿联console线的必要条件之一,也是保证设备正常工作的重要因素之一。用户在使用绿联console线时,应该根据自己的设备和操作系统的情况,下载并安装相应的驱动程序,以获得更好的使用体验和效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值