设备驱动与文件系统:02 键盘
操作系统中键盘驱动的讲解
在这一讲中,我将为大家讲解键盘相关内容。从上一讲开始,我们进入了操作系统第四个部分的学习,也就是操作系统对设备的驱动与管理。
上一讲我们探讨的是显示器,并且提到,一个终端设备是由显示器和键盘共同组成的,显示器属于终端设备的输出部分,我们在显示器上看到的内容就是其输出结果。而键盘,是我们进行最基本输入操作的设备 ,所以这一节,我要为大家讲解的就是键盘是如何被驱动的,以及操作系统是怎样使用键盘的。
外设工作基本原理回顾
要讲述键盘的故事,我们仍然需要从回顾上次讲的外设工作的基本原理开始。从上次课到今天的内容,再到下次课要讲的磁盘的使用和管理,都离不开那张外设工作的基本原理图。
上节课我讲过,外设工作的基本原理非常简单。外设的工作流程是:CPU发出一条读或写的指令,当外设工作完成后,会向CPU返回一个中断。无论是终端设备还是其他任何外设,基本思路都是如此。
想要实现外设的驱动,需要做三件事:
- 核心部分:向设备控制器的某些寄存器端口或存储区域发出读写指令,这是计算机使用外设的核心,通常表现为几条指令。但要写出这些指令,必须对硬件有深入了解,清楚硬件的端口、指令格式及含义等,这些细节处理起来很麻烦,虽然原理简单,但实际操作复杂。
- 统一文件视图:操作系统为了隐蔽硬件细节,将所有外设都以文件的形式呈现。根据文件名或文件对应的结构信息,决定最终执行哪一段与硬件交互的代码,将底层与硬件交互的代码通过文件方式进行封装,这是操作系统进行外设管理的第二个重要方面。
- 中断处理:通常在设备完成读写操作后,进行后续相关工作,这是外设驱动的第三个部分。
将这三个部分弄明白,对于任何外设的管理原理也就基本掌握了。简单总结一下,第一部分是通过out
指令向外设发送命令;第二部分是形成统一的文件视图;第三部分是进行中断处理 。掌握了这三个部分,整个外设工作原理就能清晰明了。
键盘驱动与操作系统对键盘的使用
对于键盘而言,它正好对应着中断处理这一部分。因为键盘的操作是由用户发起的,用户按下按键后就会产生中断,然后进行中断处理,最终将信息传递回上层的文件系统。这也再次印证了,只要理解了外设驱动的三个核心部分,学习任何设备的驱动原理都是相通的。
讲完今天关于键盘的内容,我们就能弄清楚计算机的输入输出原理。上一讲的显示器相当于输出设备,今天的键盘则是输入设备,当这两个设备的原理都搞清楚后,一台基本的计算机就能够正常使用了,即便没有驱动磁盘,只要有CPU、内存、键盘和显示器,计算机也可以运行。
那么,关于键盘的故事该从哪里开始讲起呢?用户敲下按键后会产生什么结果,又会触发哪些操作呢?答案是中断,按下按键后就会触发中断,所以整个故事应该从中断处理开始。
从硬件参与计算的角度来看,有两条路径:一条是从CPU发起,通过out
指令向外设发送指令;另一条是从硬件产生中断信号,向CPU进行中断请求 。而这两条路径最终都会回归到文件系统的统一视图上。今天我们要讲的就是第二条路,从中断开始,因为设备(键盘)一旦有操作就会产生中断。当然,从中断开始,首先得了解中断初始化,即键盘中断被初始化成了什么函数,这个函数又负责做什么事情。
通过查阅手册可知,键盘中断对应21号中断。通过设置,将21号中断关联到特定的处理程序,当发生中断时,就会执行这个中断处理函数,键盘的故事也就由此展开。
中断处理函数的工作
接下来,我们看看中断处理函数具体做了哪些事情。中断处理函数的第一句是in
指令,有out
指令用于输出字节,相对应的,in
指令就是读入一个字节。通过这条核心指令,我们可以将键盘控制器中60端口的内容读取到AL
寄存器中。要理解这一步,需要具备一定的硬件知识,因为in
和out
这类与CPU和设备控制器寄存器交互的指令,都需要参考硬件手册,明确端口对应的含义。在这里,60端口存放的是扫描码,通过in
指令,扫描码就被存储到了AL
(在AX
寄存器中)。
获取扫描码后,根据不同的扫描码,需要调用相应的table
来执行对应的操作。这很好理解,不同的按键对应不同的扫描码,也就需要执行不同的操作。比如,如果扫描码对应的是字母“a”,那就产生字符“a”的ASCII码,然后向上传递;如果是其他按键,如大小写切换键,就执行相应的功能操作。
现在,我们已经有了扫描码,接下来就要根据扫描码获取对应的ASCII码,这就需要用到keymap
。keymap
其实就是一个存储着各种可显示字符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_q
和read_q
队列 。这再次印证了操作系统进行设备处理的三个核心部分:通过out
指令与硬件交互、形成统一的文件视图、进行中断处理。无论是输入设备还是输出设备,其驱动原理都围绕这三个方面展开。
最后,我再给大家留下一个思考和实践的小任务。在上次的内容中,我们提到按下F12键要输出星号。从今天讲解的键盘驱动原理出发,实现这个功能其实并不难。当前按下F12键时,是由func
函数进行处理的,我们只需要将其修改为自定义的函数(如my_func
)。在my_func
函数中,我们可以设置一个标志位flag
,按下一次F12键,将flag
置为1,此时输出全为星号;再按一次F12键,将flag
置为0,恢复正常输出。同时,在tty_write
函数中,根据flag
的值判断是否将输出字符替换为星号 。大家可以在实验中尝试实现这个功能,通过实践,对操作系统设备驱动的理解将会上升到一个新的层次。
相关文章:

设备驱动与文件系统:02 键盘
操作系统中键盘驱动的讲解 在这一讲中,我将为大家讲解键盘相关内容。从上一讲开始,我们进入了操作系统第四个部分的学习,也就是操作系统对设备的驱动与管理。 上一讲我们探讨的是显示器,并且提到,一个终端设备是由显示…...
matlab分布式电源接入对配电网的影响
MATLAB仿真的分布式电源接入对于配电网的影响,潮流计算加了固定的pq 分布式电源接入对配电网的影响/bustypes.m , 1004 分布式电源接入对配电网的影响/case34.m , 5385 分布式电源接入对配电网的影响/case9.m , 1366 分布式电源接入对配电网的影响/dSbus_dV.m , 14…...
前端ul-image的src接收base64快捷写法
前端ul-image的src接收base64快捷写法 data:image/png;base64,你的base64数据 注意如果是jpg就改成jpg,中间的逗号格式要注意,/注意不要反了 假设后端返回的detail中的url已经是base64格式,下面是示例 <u-image height"120rpx"…...

交通违法拍照数据集,可识别接打电话,不系安全带的行为,支持YOLO,COCO JSON,VOC XML格式的标注数据集 最高正确识别率可达88.6%
交通违法拍照数据集 数据集概述 数据来源:交通监控摄像头、执法记录仪、公开数据集数据类型:图像、视频、元数据(时间、地点、车辆信息)违法类型标注:接打电话、未系安全带 数据采集与标注方法 采集设备࿱…...

Qt OpenGL 3D 编程入门
Qt 提供了强大的 OpenGL 集成功能,使得在 Qt 应用中实现 3D 图形变得更加简单。以下是使用 Qt 进行 OpenGL 3D 编程的基础知识。 1. 环境配置 创建 Qt 项目 新建 Qt Widgets Application 项目 在 .pro 文件中添加 OpenGL 模块: qmake QT co…...

性能优化 - 工具篇:基准测试 JMH
文章目录 Pre引言1. JMH 简介2. JMH 执行流程详解3. 关键注解详解3.1 Warmup3.2 Measurement3.3 BenchmarkMode3.4 OutputTimeUnit3.5 Fork3.6 Threads3.7 Group 与 GroupThreads3.8 State3.9 Setup 与 TearDown3.10 Param3.11 CompilerControl 4. 示例代码与分析4.1 关键点解读…...
Ubuntu 中安装 PostgreSQL 及常规操作指南
目录 一、安装 PostgreSQL 最新版本安装(推荐) 安装特定版本(如 14) 二、基本服务管理 三、连接数据库 四、常规数据库操作 1. 用户与权限管理 2. 数据库管理 3. 表操作 4. 数据操作 五、常用 psql 元命令 六、备份与恢…...

Nginx网站服务:从入门到LNMP架构实战
🏡作者主页:点击! Nginx-从零开始的服务器之旅专栏:点击! 🐧Linux高级管理防护和群集专栏:点击! ⏰️创作时间:2025年5月30日14点22分 前言 说起Web服务器,…...

Java面试八股--08-数据结构和算法篇
1、怎么理解时间复杂度和空间复杂度 时间复杂度和空间复杂度一般是针对算法而言,是衡量一个算法是否高效的重要标准。先纠正一个误区,时间复杂度并不是算法执行的时间,在纠正一个误区,算法不单单指冒泡排序之类的,一个…...

Java面试八股--06-Linux篇
目录 一、Git 1、工作中git开发使用流程(命令版本描述) 2.Reset与Rebase,Pull与Fetch的区别 3、git merge和git rebase的区别 4、git如何解决代码冲突 5、项目开发时git分支情况 二、Linux 1、Linux常用的命令 2、如何查看测试项目的…...
Ajax技术分析方法全解:从基础到企业级实践(2025最新版)
引言 Ajax技术自2005年正式命名以来,已支撑全球83%的Web应用实现异步交互。2025年最新数据显示,单页面应用(SPA)的Ajax请求密度已达日均120亿次/应用。本文将系统化解析Ajax分析方法论,涵盖从基础原理到企业级工程实践的完整技术栈。 一、Ajax技术架构解构 1.1 核心组件…...
Unity 性能优化终极指南 — GameObject 篇
🎯 Unity 性能优化终极指南 — GameObject 方法篇 🧩 GameObject 是什么?—— Unity世界的核心实体 GameObject 是 Unity 引擎中最核心、最基础的构建单元。它代表了场景中的一个实体对象,可以是一个角色、一个UI元素、一盏灯光、…...

dvwa7——SQL Injection
LOW: f12打开hackbar 一:判断注入类型 输入id1报错 闭合单引号 ,页面恢复正常 所以为单引号字符型 二:开始攻击 1.判断列数 ?id1 order by 2-- 到3的时候开始报错,所以一共两列 2.爆回显位置 ?id-1 union s…...
Spring AI 项目实战(四):Spring AI + DeepSeek 超参数优化——智能化机器学习平台(附完整源码)
系列文章 序号文章名称1Spring AI 项目实战(一):Spring AI 核心模块入门2Spring AI 项目实战(二):Spring AI + DeepSeek 深度实战(附完整源码)3Spring AI 项目实战(三):Spring AI + DeepSeek 打造智能客服系统(附完整源码)4Spring AI 项目实战(四):Spring AI +…...
Axure疑难杂症:中继器图片替换功能优化(支持修改已有记录-玩转中继器)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!如有帮助请订阅专栏! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 案例视频: 中继器图片替换功能优化 课程主题:中继器图片替换功能优化(支持修改已有记录) 主要内…...

sqlite3 命令行工具详细介绍
一、启动与退出 启动数据库连接 sqlite3 [database_file] # 打开/创建数据库文件(如 test.db) sqlite3 # 启动临时内存数据库 (:memory:) sqlite3 :memory: # 显式启动内存数据库文件不存在时自动创建不指定文件名则使用临时内…...

ubuntu 22.04 编译安装nignx 报错 openssl 问题
前言 Ubuntu 20.04 中安装 Nginx (通过传包编译的方式)、开启关闭防火墙、开放端口号 在ubuntu 22.04.3 服务器上照着上面的文章 通过传包编译的方式安装nginx-1.18.0 的时候报错,报错内容如下: src/event/ngx_event_openssl.c: In function ‘ngx_ssl…...

线程相关面试题
提示:线程相关面试题,持续更新中 文章目录 一、Java线程池1、Java线程池有哪些核心参数,分别有什么的作用?2、线程池有哪些拒绝策略?3、说一说线程池的执行流程?4、线程池核心线程数怎么设置呢?4、Java线程…...

pikachu通关教程-目录遍历漏洞(../../)
目录遍历漏洞也可以叫做信息泄露漏洞、非授权文件包含漏洞等. 原理:目录遍历漏洞的原理比较简单,就是程序在实现上没有充分过滤用户输入的../之类的目录跳转符,导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件。 这里的目录跳转符可以是../…...

Maven-生命周期
目录 1.项目对象模型 2.依赖管理模型 3.仓库:用于存储资源,管理各种jar包 4.本地仓库路径 1.项目对象模型 2.依赖管理模型 3.仓库:用于存储资源,管理各种jar包 4.本地仓库路径...
Hadoop复习(九)
Azkaban工作流管理器 选择 问题 1 判断题 2 / 2 分 工作流是指具有依赖的一组job任务,被依赖的job任务最后执行 正确 错误 问题 2 判断题 2 / 2 分 Azkaban兼容任何版本的Hadoop 正确 错误 问题 3 判断题 2 / 2 分 独立服务器模式下,Azkab…...

Matlab实现LSTM-SVM回归预测,作者:机器学习之心
Matlab实现LSTM-SVM回归预测,作者:机器学习之心 目录 Matlab实现LSTM-SVM回归预测,作者:机器学习之心效果一览基本介绍程序设计参考资料 效果一览 基本介绍 代码主要功能 该代码实现了一个LSTM-SVM回归预测模型,核心流…...

Spring Boot 自动配置原理:从入门到精通
Spring Boot 的自动配置是其核心特性之一,它极大地简化了 Spring 应用的开发,让开发者可以专注于业务逻辑,而无需编写大量的配置代码。 本文将深入探讨 Spring Boot 自动配置的原理,帮助你理解其工作机制,并能灵活运用…...
实践深度学习:构建一个简单的图像分类器
引言 深度学习在图像识别领域取得了巨大的成功。本文将指导你如何使用深度学习框架来构建一个简单的图像分类器,我们将以Python和TensorFlow为例,展示从数据准备到模型训练的完整流程。 环境准备 在开始之前,请确保你的环境中安装了以下工…...

腾讯 ovCompose 开源,Kuikly 鸿蒙和 Compose DSL 开源,腾讯的“双”鸿蒙方案发布
近日,腾讯的 ovCompose 和 Kuikly 都发布了全新开源更新,其中 Kuikly 在之前我们聊过,本次 Kuikly 主要是正式开源鸿蒙支持部分和 Compose DSL 的相关支持,而 ovCompose 是腾讯视频团队基于 Compose Multiplatform 生态推出的跨平…...

PYTHON调用讯飞C/C++动态库实现离线语音合成并且实时播放
语音合成(Text-to-Speech, TTS)技术在现代应用中扮演着越来越重要的角色,从智能客服到有声读物,从导航系统到辅助工具,TTS技术无处不在。本文将详细介绍如何使用Python结合科大讯飞的离线SDK实现一个本地化的语音合成系统。 技术背景 离线语…...

黑马Java面试笔记之 消息中间件篇(RabbitMQ)
一. 消息丢失问题 RabbitMQ如何保证消息不丢失? 使用场景有: 异步发送(验证码、短信、邮件... )MYSQL和Redis,ES之间的数据同步分布式事务削峰填谷...... 消息丢失原因会有三种情况,分别分析一下 1.1 生…...
Vue中安装插件的方式
一. 认识Vue插件 1.1. 通常向Vue全局添加一些功能时,会采用插件的模式,它有两种编写方式: 1.1.1. 对象类型:一个对象,但是必须包含一个install的函数,该函数会在安装插件时执行 // 方式一:传入…...
如何提高工作效率
最近,跟一个同事同时测同一业务,在对比自己与同事的产出过程中,发现,别人工作效率极高,产出也比较大。最重要的是,别人每天晚上走得早,自己就算加班到九点十点,似乎产出都没别人高。…...

Redisson学习专栏(五):源码阅读及Redisson的Netty通信层设计
文章目录 前言一、分布式锁核心实现:RedissonLock源码深度解析1.1 加锁机制:原子性与重入性实现1.2 看门狗机制:锁自动续期设计1.3 解锁机制:安全释放与通知1.4 锁竞争处理:等待队列与公平性1.5 容错机制:异…...