键盘&鼠标中断实现

本节主要实现键盘中断和鼠标中断,键盘中断实现将键盘数据显示到屏幕;鼠标中断实现鼠标位置的移动。

键盘中断通过主8259A的IRQ1触发,鼠标中断通过从8259A的IRQ4触发

CPU通过中断向量号来寻址待执行的中断代码

中断向量号 = 起始向量号 + 中断请求号

起始向量号通过中断控制字ICW2被初始化  中断请求号即为8259A引脚编号

打开主IRQ1和从IRQ4中断响应引脚

    ;OCW(operation control word);当OCW[i] = 1 时,屏蔽对应的IRQ(i)管线的信号;IRQ1对应的是键盘产生的中断mov al, 11111001bout 021h, alcall io_delay;CPU忽略所有来自从8259A芯片的信号;鼠标是通过从8259A的IRQ4管线向CPU发送信号mov al, 11101111bout 0A1h, alcall io_delay

初始化中断控制字ICW2如下所示:

;向主8259A发送ICW2;20h 对应二进制00100000 ;ICW2[0,1,2] = 0 ;8259A根据被设置的起始向量号(起始向量号通过中断控制字ICW2被初始化)加上中断请求号计算出中断向量号;当主8259A对应的IRQ0管线向CPU发送信号时,CPU根据0x20这个值去查找要执行的代码,;,CPU根据0x21这个值去查找要执行的代码,依次类推。mov al, 020hout 021h, alcall io_delay;向从8259A发送ICW2;28h 对应二进制00100100;8259A根据被设置的起始向量号(起始向量号通过中断控制字ICW2被初始化)加上中断请求号计算出中断向量号;当从8259A对应的IRQ0管线向CPU发送信号时,CPU根据0x28这个值去查找要执行的代码,;IRQ1管线向CPU发送信号时,CPU根据0x29这个值去查找要执行的代码,依次类推。mov al, 028hout 0A1h, alcall io_delay

主控制器起始向量号为0x20 从控制器起始向量号为0x28  因此

键盘中断中断向量号为0x20+0x01=0x21

鼠标中断中断向量号为0x28+0x04=0x2c

因此中断描述符初始化如下:

;中断描述符表
LABLE_IDT:%rep 0x21Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate%endrep;键盘中断向量(8259A 键盘中断向量0x20,IRQ1 是键盘中断请求,0x20 + IRQ[n] = 0x21.0x21:Gate SelectorCode32, KeyboardHandler, 0, DA_386IGate%rep 10Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate%endrep;从中断控制器8259A 中断向量0x28,IRQ4 是鼠标中断请求,0x28 + IRQ[n] = 0x2c.0x2c:Gate SelectorCode32, MouseHandler, 0, DA_386IGate

相应的键盘和鼠标中断处理函数:

;键盘中断程序
LabelKeyboardHandler:KeyboardHandler EQU LabelKeyboardHandler - $$; 注意中断切换过程push espush dspushadmov eax, esppush eaxcall int_keyboardpop eaxmov esp, eaxpopadpop dspop esiretd;鼠标中断程序
LabelMouseHandler:MouseHandler EQU LabelMouseHandler - $$; 注意中断切换过程push espush dspushadmov eax, esppush eaxcall int_mousepop eaxmov esp, eaxpopadpop dspop esiretd

中断处理函数的处理过程

将当前寄存器值入栈

执行中断响应函数

将栈中寄存器值恢复,继续执行中断前指令

键盘中断响应函数

void int_keyboard(char *index){//0x20是8259A控制端口//0x21对应的是键盘的中断向量。当键盘中断被CPU执行后,下次键盘再向CPU发送信号时,//CPU就不会接收,要想让CPU再次接收信号,必须向主PIC的端口再次发送键盘中断的中断向量号io_out8(0x20, 0x21);unsigned char data = io_in8(PORT_KEYDATA);fifo8_put(&keybufInfo, data);}

将键盘中断产生数据存入队列中,主函数不断检测队列中是否有数据,如果有数据,则将相应数据显示到屏幕中

    for(;;){if (keybufInfo.len > 0) {io_cli();static char keyval[4] = {'0','x'};for(int i=0; i<keybufInfo.len; i++){char data = fifo8_get(&keybufInfo);static int x = 0;char2HexStr(data, keyval);showString(keyval, x%SCREEN_WIDTH, x/SCREEN_WIDTH*20, COL8_FFFFFF);x += 32;}io_seti();} else if (mousebufInfo.len > 0) {io_cli();for(int t=0;t<mousebufInfo.len;t++){mouseCursorMoved(&mouseDes, COL8_008484);}io_seti();} else {io_hlt();}  }

鼠标电路初始化

内核加载完成,初始化中断描述符表,要想响应鼠标中断,需要首先实现鼠标电路的初始化

//初始化键盘控制电路,鼠标控制电路是连接在键盘控制电路上,通过键盘电路实现初始化
void init_mouse(){waitKBCReady();//0x60让键盘电路进入数据接受状态io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);waitKBCReady();//数据0x47要求键盘电路启动鼠标模式,这样鼠标硬件所产生的数据信息,通过键盘电路端口0x60就可读到io_out8(PORT_KEYDATA, KBC_MODE);waitKBCReady();io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);waitKBCReady();//0xf4数据激活鼠标电路,激活后将会给CPU发送中断信号io_out8(PORT_KEYDATA, MOUSECMD_ENABLE);
}

只有当端口0x64端口数据第二个比特为0时,鼠标电路才能接受来自内核命令。

//鼠标电路对应的一个端口是 0x64, 通过读取这个端口的数据来检测鼠标电路的状态,
//内核会从这个端口读入一个字节的数据,如果该字节的第二个比特位为0,那表明鼠标电路可以
//接受来自内核的命令,因此,在给鼠标电路发送数据前,内核需要反复从0x64端口读取数据,
//并检测读到数据的第二个比特位,直到该比特位为0时,才发送控制信息
void waitKBCReady(){for(;;){if((io_in8(PORT_KEYSTA)&0x02)==0){break;}}
}

鼠标中断响应函数

在鼠标中断响应函数中,将鼠标中断产生数据存入队列中

void int_mouse(char *index){//当中断处理后,要想再次接收中断信号,就必须向中断控制器发送一个字节的数据io_out8(0x20, 0x20);io_out8(0xa0, 0x20);//读取鼠标数据unsigned char data = io_in8(PORT_MOUSEDATA);fifo8_put(&mousebufInfo, data);}

主循环不断检测鼠标队列,依次处理每个数据

        for(;;){if (keybufInfo.len > 0) {io_cli();static char keyval[4] = {'0','x'};for(int i=0; i<keybufInfo.len; i++){char data = fifo8_get(&keybufInfo);static int x = 0;char2HexStr(data, keyval);showString(keyval, x%SCREEN_WIDTH, x/SCREEN_WIDTH*20, COL8_FFFFFF);x += 32;}io_seti();} else if (mousebufInfo.len > 0) {io_cli();for(int t=0;t<mousebufInfo.len;t++){mouseCursorMoved(&mouseDes, COL8_008484);}io_seti();} else {io_hlt();}  }

读取队列中的数据,每三个为一组进行解析,每三个数据构建结构体MouseDes来表示当前鼠标的移动信息,然后擦除旧的鼠标信息,计算鼠标新的坐标,绘制新的鼠标。

void mouseCursorMoved(MouseDes *mdec, char bc){unsigned char data = fifo8_get(&mousebufInfo);if(mouse_decode(mdec, data) != 0){//擦除之前鼠标位置fillRect(mdec->x, mdec->y, 16, 16, bc);//计算鼠标新的坐标mdec->x += mdec->offX;mdec->y += mdec->offY;if(mdec->x < 0){mdec->x = 0;}if(mdec->x > SCREEN_WIDTH-16/2){mdec->x = SCREEN_WIDTH-16/2;}if(mdec->y < 0){mdec->y = 0;}if(mdec->y > SCREEN_HEIGHT-16){mdec->y = SCREEN_HEIGHT-16;}//绘制鼠标init_mouse_cursor((char *)VGA_ADDR, mdec->x, mdec->y, COL8_008484);}
}

鼠标移动模型以及处理

//鼠标处理需要连续处理3字节
//phase 表示处理字节阶段
//offX, offY 当前鼠标的偏移
//x,y 鼠标当前所在的坐标位置
typedef struct _MouseDes{char buf[3], phase;int offX, offY;int x, y, btn;
}MouseDes;

每三个数据即可给出鼠标中断的数据信息,主要包括鼠标按键类型(左 滑轮 右)

鼠标上下移动  左右移动数据。第一个字节0xab, a的数值必须在0-3这个范围内,由于a对应的是八比特中的高四位,所以这意味着该字节的第7,8两个比特位必须为0,b对应着八比特位中的低四位,它的值必须在8-F之间,这意味着该字节数据对应的第4个比特位必须为1.把第一个字节转换成二进制,那么它必须满足下面格式(X,*代表0或1):

0 0 X X 1 * \ * * 三个*用来表示鼠标按键,当鼠标的左键,滚轮,右键被按下时,对应的比特位会设置为1.第二个字节用来表示鼠标的左右移动,对该字节进行相应处理后,可以得到鼠标平移的坐标变换。第三个字节的数据表示鼠标的上下移动,对该字节进行相应处理后,可以得到鼠标垂直移动时的坐标数变化。

具体的处理过程如下所示:

int mouse_decode(MouseDes *mdec, unsigned char dat){int flag = -1;if(mdec->phase == 0){if(dat == 0xfa){mdec->phase = 1;}flag = 0;}else if(mdec->phase == 1){if((dat&0xc8) == 0x08){mdec->buf[0] = dat;mdec->phase = 2;}flag = 0;}else if(mdec->phase == 2){mdec->buf[1] = dat;mdec->phase = 3;flag = 0;}else if(mdec->phase == 3){mdec->buf[2] = dat;mdec->phase  =1;mdec->btn = mdec->buf[0]&0x07;mdec->offX = mdec->buf[1];mdec->offY = mdec->buf[2];if((mdec->buf[0]&0x10) != 0){mdec->offX |= 0xffffff00;}if((mdec->buf[0]&0x20) != 0){mdec->offY |= 0xffffff00;}mdec->offY = -mdec->offY;flag = 1;}return flag;
}

代码位置:https://github.com/ChenWenKaiVN/bb_os_core

参考链接:

https://www.jianshu.com/p/5f7244fb71c4

https://blog.csdn.net/Zllvincent/article/details/84099179

动手写操作系统9----键盘鼠标中断实现相关推荐

  1. 自己动手写java虚拟机_自己动手写操作系统(要了解的知识点)

    自己动手写操作系统(开篇) 自己动手写操作系统(字符显示) 说明:Intel 8086 或者不同的处理器,开机寄存器数据可能不一样,但是大致原理差不多 了解过计算机启动的同学肯定知道,当计算机启动的时 ...

  2. 《自己动手写操作系统》读书笔记——初识保护模式

    <自己动手写操作系统>读书笔记--初识保护模式 http://www.cnblogs.com/pang123hui/archive/2010/11/27/2309930.html 书本第三 ...

  3. 全面剖析《自己动手写操作系统》第四章---加载Loader.bin

    全面剖析<自己动手写操作系统>第四章--FAT12文件系统    http://blog.csdn.net/zgh1988/article/details/7284834 1.突破512字 ...

  4. 自己动手写操作系统--个人实践

    近期開始看于渊的<自己动手写操作系统>这本书,刚開始看就发现做系统的引导盘居然是软盘!心里那个汗啊! 如今都是U盘了,谁还用软盘.于是考虑用U盘. 于是開始下面步骤: 1.既然书上说给先要 ...

  5. 「操作系统」《自己动手写操作系统》1.1前期准备工作

    一.软硬件 1.硬件 一台计算机(笔者使用的是Win7 x64操作系统) 2.软件 点击此处下载<自己动手写操作系统>的光盘配套文件以及相应工具 汇编编译器:NASM(资源文件中有) 软盘 ...

  6. 自己动手写操作系统0

    文章目录 自己动手写操作系统0 环境搭建 NASM VirtualBox 添加软盘启动 VMware 开启虚拟机 其他软件 Floppy 自己动手写操作系统0 参考余渊老师写的<自己动手写操作系 ...

  7. 自己动手写操作系统之环境构建篇

    自己动手写操作系统之环境构建篇 最近开始看自己动手写操作系统,但是书中采用软盘启动很是郁闷,于是想是否可以从优盘启动呢?作为一名BIOS工程师,曾经用优盘启动过dos,linux等系统,于是做了如下尝 ...

  8. 自己动手写操作系统——(1)将引导写入U盘

    为什么写博客呢,想了一下,首先是为了给自己留着复习用,因为时间一长,肯定有好多东西会忘记的,在这里留个记录,以后再整理起来就不会太麻烦了:再者是为了分享一下经验,由于在下比较愚笨,说不定在哪个方面就理 ...

  9. 磨刀不误砍柴工 —— 自己动手写操作系统 入门导引

    磨刀不误砍柴工 刺猬@http://blog.csdn.net/littlehedgehog <自己动手写操作系统>其实阅读所需要的前提不过只是C和汇编了,里面涉及到很多操作系统的东西.于 ...

最新文章

  1. 程序员的量化交易之路(35)--Lean之DataFeed数据槽3
  2. SQLAlchemy 常用基本表
  3. mysql cluster自动安装_MySQL Cluster 安装
  4. Go gin静态文件的使用、自定义模板渲染器
  5. 微软腾讯联手开发IM软件MQ QQ和MSN将于2009年停用
  6. 【爱心代码大全】——情人节表白代码送给她属于我们程序员的浪漫
  7. AngularJs ng-repeat限制循环次数
  8. 基于迁移深度学习的雷达信号分选识别
  9. java获取linux下面所有线程,获取Linux中Java线程的线程ID
  10. Python开发【第五篇】迭代器、生成器、递归函数、二分法
  11. 疑似小米11 Pro保护壳曝光:横向矩阵相机设计
  12. JVM :Btrace监控工具
  13. mui toast自定义样式
  14. 【实验技术笔记】基因沉默:siRNA/shRNA
  15. Java第十九天:mysql(二)
  16. 华为云centOS8部署
  17. 手机多控软件使用全面评测,选择更适合自己的那一款!
  18. JAVA求解【乱序整数序列两数之和绝对值最小】
  19. [AHK]设置快捷键快速呼出隐藏XYplorer
  20. linux 系统黑洞简单使用案例

热门文章

  1. iMX6ul开发指导
  2. ElasticJob源码部分解读-Zookeeper建立连接
  3. 19 01 18 dango 模型
  4. 短期怎么学会云计算?新手学习云计算的规划
  5. 滴滴新算法让你应对女友?道翰天琼认知智能机器人平台API接口大脑为您揭秘
  6. 基于最大最小思想优化拉丁超立方采样
  7. 林格斯添加真人语音库
  8. 谐波减速器的结构简图及传动比说明
  9. vue预览excel
  10. 共享单车APP开发文档