设备驱动与文件系统:02 键盘

操作系统中键盘驱动的讲解

在这一讲中,我将为大家讲解键盘相关内容 。从上一讲开始,我们进入了操作系统第四个部分的学习,也就是操作系统对设备的驱动与管理。

上一讲我们探讨的是显示器,并且提到,一个终端设备是由显示器和键盘共同组成的,显示器属于终端设备的输出部分,我们在显示器上看到的内容就是其输出结果。而键盘,是我们进行最基本输入操作的设备 ,所以这一节,我要为大家讲解的就是键盘是如何被驱动的,以及操作系统是怎样使用键盘的

外设工作基本原理回顾

要讲述键盘的故事,我们仍然需要从回顾上次讲的外设工作的基本原理开始。从上次课到今天的内容,再到下次课要讲的磁盘的使用和管理,都离不开那张外设工作的基本原理图。

上节课我讲过,外设工作的基本原理非常简单。外设的工作流程是:CPU发出一条读或写的指令,当外设工作完成后,会向CPU返回一个中断。无论是终端设备还是其他任何外设,基本思路都是如此。

想要实现外设的驱动,需要做三件事:

  1. 核心部分:向设备控制器的某些寄存器端口或存储区域发出读写指令,这是计算机使用外设的核心,通常表现为几条指令。但要写出这些指令,必须对硬件有深入了解,清楚硬件的端口、指令格式及含义等,这些细节处理起来很麻烦,虽然原理简单,但实际操作复杂。
  2. 统一文件视图:操作系统为了隐蔽硬件细节,将所有外设都以文件的形式呈现。根据文件名或文件对应的结构信息,决定最终执行哪一段与硬件交互的代码,将底层与硬件交互的代码通过文件方式进行封装,这是操作系统进行外设管理的第二个重要方面。
  3. 中断处理:通常在设备完成读写操作后,进行后续相关工作,这是外设驱动的第三个部分。

将这三个部分弄明白,对于任何外设的管理原理也就基本掌握了 。简单总结一下,第一部分是通过out指令向外设发送命令;第二部分是形成统一的文件视图;第三部分是进行中断处理 。掌握了这三个部分,整个外设工作原理就能清晰明了。

键盘驱动与操作系统对键盘的使用

对于键盘而言,它正好对应着中断处理这一部分。因为键盘的操作是由用户发起的,用户按下按键后就会产生中断,然后进行中断处理,最终将信息传递回上层的文件系统。这也再次印证了,只要理解了外设驱动的三个核心部分,学习任何设备的驱动原理都是相通的。

讲完今天关于键盘的内容,我们就能弄清楚计算机的输入输出原理。上一讲的显示器相当于输出设备,今天的键盘则是输入设备,当这两个设备的原理都搞清楚后,一台基本的计算机就能够正常使用了,即便没有驱动磁盘,只要有CPU、内存、键盘和显示器,计算机也可以运行。

那么,关于键盘的故事该从哪里开始讲起呢?用户敲下按键后会产生什么结果,又会触发哪些操作呢?答案是中断,按下按键后就会触发中断,所以整个故事应该从中断处理开始

从硬件参与计算的角度来看,有两条路径:一条是从CPU发起,通过out指令向外设发送指令;另一条是从硬件产生中断信号,向CPU进行中断请求 。而这两条路径最终都会回归到文件系统的统一视图上。今天我们要讲的就是第二条路,从中断开始,因为设备(键盘)一旦有操作就会产生中断。当然,从中断开始,首先得了解中断初始化,即键盘中断被初始化成了什么函数,这个函数又负责做什么事情。

通过查阅手册可知,键盘中断对应21号中断。通过设置,将21号中断关联到特定的处理程序,当发生中断时,就会执行这个中断处理函数,键盘的故事也就由此展开。

中断处理函数的工作

接下来,我们看看中断处理函数具体做了哪些事情。中断处理函数的第一句是in指令,有out指令用于输出字节,相对应的,in指令就是读入一个字节。通过这条核心指令,我们可以将键盘控制器中60端口的内容读取到AL寄存器中。要理解这一步,需要具备一定的硬件知识,因为inout这类与CPU和设备控制器寄存器交互的指令,都需要参考硬件手册,明确端口对应的含义。在这里,60端口存放的是扫描码,通过in指令,扫描码就被存储到了AL(在AX寄存器中)。

获取扫描码后,根据不同的扫描码,需要调用相应的table来执行对应的操作。这很好理解,不同的按键对应不同的扫描码,也就需要执行不同的操作。比如,如果扫描码对应的是字母"a",那就产生字符"a"的ASCII码,然后向上传递;如果是其他按键,如大小写切换键,就执行相应的功能操作。

现在,我们已经有了扫描码,接下来就要根据扫描码获取对应的ASCII码,这就需要用到keymapkeymap其实就是一个存储着各种可显示字符ASCII码的表,例如数字、字母,以及按下Shift键时对应的特殊字符(如叹号、@、#等)的ASCII码 。将keymap表的起始地址存入EBX寄存器,再结合刚才获取的扫描码(作为表的偏移量),就可以找到按下按键所对应的ASCII码,并将其赋值给AL寄存器。至此,我们就成功得到了按键对应的ASCII码。

ASCII码的处理与存储

得到ASCII码后,下一步就是将其放置到合适的位置。显然,ASCII码需要被放到缓冲队列中,就像上一次讲显示器输出时,数据会被写入缓冲队列等待处理一样。在这里,键盘输入的ASCII码会通过put_queue操作,放入read_q队列中。put_queue的操作过程也很简单,就是获取read_q队列的头部指针,然后将ASCII码存储到队列头部。

到这一步,似乎键盘输入的处理已经完成了,将得到的ASCII码放入队列中,上层程序(如执行scanf的进程)在需要时就可以从队列中获取数据。这部分与显示器输出时数据写入队列,以及上层程序通过printf等函数从队列获取数据的原理是一样的,只是这里是输入操作,将write相关操作替换为read操作即可。

键盘输入的"回显"处理

不过,我们还需要考虑一个环节,那就是"回显"。"回显"其实就是对输入字符进行一些处理后,将其再次进行输出显示等操作 。在将字符放入队列时,对于一些可显示字符,通常需要进行"回显"操作,也就是将其显示在屏幕上。

"回显"的过程和前面将ASCII码放入read_q队列类似,同样是将字符数据写入相关队列(这里仍然是read_q队列),然后在"回显"操作中,通过调用console_write函数,将字符显示在屏幕上。

总结与拓展思考

我们可以总结一下键盘处理的整个流程:从硬件产生中断开始,中断处理程序获取扫描码,并将其转换为ASCII码,然后将ASCII码放入read_q队列中,在这个过程中可能会涉及一些中间处理和"回显"操作,最终上层程序从队列中获取数据进行后续处理 。

将键盘的处理和上次显示器的处理结合起来看,我们会发现它们都通过文件接口进行操作。输出时使用tty_write,输入时使用tty_read,分别操作write_qread_q队列 。这再次印证了操作系统进行设备处理的三个核心部分:通过out指令与硬件交互、形成统一的文件视图、进行中断处理。无论是输入设备还是输出设备,其驱动原理都围绕这三个方面展开。

最后,我再给大家留下一个思考和实践的小任务。在上次的内容中,我们提到按下F12键要输出星号。从今天讲解的键盘驱动原理出发,实现这个功能其实并不难。当前按下F12键时,是由func函数进行处理的,我们只需要将其修改为自定义的函数(如my_func)。在my_func函数中,我们可以设置一个标志位flag,按下一次F12键,将flag置为1,此时输出全为星号;再按一次F12键,将flag置为0,恢复正常输出。同时,在tty_write函数中,根据flag的值判断是否将输出字符替换为星号 。大家可以在实验中尝试实现这个功能,通过实践,对操作系统设备驱动的理解将会上升到一个新的层次。

相关推荐
egoist20234 小时前
【Linux仓库】冯诺依曼体系结构与操作系统【进程·壹】
linux·运维·服务器·开发语言·操作系统·冯诺依曼体系结构
望获linux16 小时前
【Linux基础知识系列】第八篇-基本网络配置
linux·数据库·postgresql·操作系统·php·开源软件·rtos
GoGeekBaird16 小时前
69天探索操作系统-第67天:从恐慌到解决:实施内核调试技术进行崩溃分析
后端·操作系统
shark-chili20 小时前
Java并发编程哲学系列汇总
linux·运维·服务器·操作系统
不爱说话郭德纲20 小时前
你需要来自XXX的权限才能对此文件夹进行更改?看我三步暴删
linux·windows·操作系统
GoGeekBaird2 天前
69天探索操作系统-第65天:为内核操作构建可扩展和线程安全的内存分配器
后端·操作系统
GoGeekBaird2 天前
69天探索操作系统-第66天:为现代操作系统设计高级实时进程间通信机制
后端·操作系统
诸葛悠闲3 天前
内存管理 : 05 内存换入-请求调页
操作系统
奕天者3 天前
操作系统学习(十)——文件系统
学习·操作系统·文件系统