PS/2键盘的数据端口是0x60,直接读取这个端口就能取到数据.但是前提是,键盘必须处于可读状态.在驱动中没有对端口的读取进行限制,直接汇编指令就可以读取.每次只能读取1字节.
在初始化鼠标之前,必须要初始化键盘,先往0x64里写一个0x60,好像是什么写模式,然后向0x60里写入0x47,就完成了。
如何确定键盘可读呢?答案是读取键盘的命令端口.如果读出的值没有0x02标记,则说明可以读取.等待到可以读取的代码如下:
waitkbdout:
IN AL,0x64
AND AL,0x02
JNZ waitkbdout ; AND结果不为0跳转到waitkbdout
RET
它会一直读,直到读到0x02为止,说明可用了。
同样,键盘也并不是随时可以写入数据的.下面的代码可以等待到键盘可写.
waitkbdin:
IN AL,0x64
AND AL,0x01
JNZ waitkbdout ; AND结果不为0跳转到waitkbdout
RET
一般我们不会对键盘进行写操作。
每次对键盘进行端口操作后,都要执行这个函数使端口实际可用。
根据PS/2协议,鼠标是由键盘的控制器(i8042)进行控制的,键盘控制器(i8042)总共有两个通道,一个通道由键盘使用,另一个通道由鼠标使用,我们对鼠标进行操作也是通过i8042芯片来完成的,因此,现在的重点就是了解并熟悉怎样对i8042进行编程,来完成对鼠标的控制。
鼠标的控制电路一开始是不被启用的, 我们需要激活这个控制电路。
i8042支持两种工作模式——AT模式及PS/2模式,现在我们假设我们使用的都是PS/2键盘及鼠标。
0xA8命令:许可i8042的鼠标通道,即允许鼠标操作。
0xD4命令:把发往0x60端口的参数数据发给鼠标。
0x60命令:把发往0x60端口的参数数据写入i8042的控制寄存器。
从上面的分析我们可以基本窥见怎样操作鼠标。首先,我们应向i8042的0x64端口发送0xA8命令,以许可i8042的鼠标通道,以便完成对鼠标的操作。其次我们应向i8042的0x64端口发送0xD4命令,以通知i8042我们需要控制鼠标,并把控制鼠标的命令发到i8042的0x60端口,再从i8042的0x60端口取回鼠标发给我们的数据。
控制鼠标的命令非常之多,比如
0xFF命令可以让鼠标复位;
0xFE命令可以让鼠标重新发送上次的数据包;
0xF3命令可以设置鼠标的采样率,也即鼠标滑动时的灵敏度;
0xF4命令可以允许鼠标向主机发送数据包等。
这里最重要的就是0xF4命令,而其它的设置鼠标的命令我们暂时可以不用理会,因为使用默认值已经能很好的完成本实验了。要理解0xF4命令有什么作用,我们需要先了解一下鼠标的四种工作模式:Reset模式,Stream模式,Remote模式及Wrap模式。
首先是Reset模式,当鼠标初次加电或收到0xFF命令之后,鼠标就处于此模式,然后鼠标将进行一系列的初始化及检测工作,包括设定默认的采样率等,完成初始化极检测之后,鼠标将进入Stream模式。
在Stream模式下,如果鼠标被移动,或者有键被按下,那么鼠标将向主机发送数据包,并提请一个中断请求,主机需要响应此中断,并在中断处理程序中取得鼠标发送的数据包。如果在Stream模式下,我们向鼠标发送0xF0命令,将使鼠标进入Remote模式。
Remote模式同Stream模式差不多,主要工作就是检测鼠标是否被移动及是否有键被按下,不过它与Stream模式的区别在于,它并不会主动的向主机提请中断请求,也即它不会主动的向主机发送数据包,而是被动的等待主机使用0xEB(读数据命令)后,再向主机提请中断请求,发送数据包。换句话说,如果在Remote模式下,你每次欲读数据时,均需要向鼠标发送0xEB命令,而如果是在Stream模式下,鼠标会自动向你发送数据。
Wrap模式主要用于检测鼠标与主机之间的连线是否正常,主机向它发送命令,它一般不会执行此命令,而只是简单的将此命令原封不同的回送给主机,主机可比较它发出的命令及接收到的命令是否一致,并以此来认定鼠标与主机之间的连线是否正常。
从上面的描述中我们可以看出,我们需要关心的只有Reset模式及Stream模式,但对于操作系统编写人员而非BIOS编写人员来说,真正需要关心的只有Stream模式,这是因为当计算机启动的时候,BIOS会自动检测鼠标,与鼠标进行通信,这个时候它会向鼠标发送0xFF(复位)命令,然后鼠标会自检,并通知主机自检是否正常,然后鼠标就将处于Stream模式,此时,鼠标已经开始检测鼠标是否移动及是否有键按下了,但是它不会立即就向主机发送数据,因为有可能主机还没有进入真正的操作系统,主机还正在启动中,因此,鼠标会等待主机的通知,直到主机给它发送0xF4命令后,它才开始向主机发送数据。
中断向量号实际上是地址,0x21就是IDT+0x21,如此。一共256个。
当 I/O 设备把中断信号发送给中断控制器时,与之关联的是一个中断号;而当中断控制器将该中断信号传递给 CPU 时,与之关联的则是一个中断向量。而中断向量表就是IDT,8字节的那个。而中断向量表也不是你随便放入的,放入不同的地址有不同的作用。
现在学学PIC:
寄存器:
中断请求寄存器(IRR):保存中断请求输入引脚上所有请求服务中断级。寄存器8位D7--D0分别对应引脚IR7--IR0.
中断屏蔽寄存器(IMR): 保存被屏蔽中断请求线对应的位。寄存器8位分别对应8个中断级,哪位置位哪表示相应级中断被屏蔽。
正在服务寄存器(ISR):保存正在接受服务的中断请求。
初始化命令字寄存器:保存初始化命令字(ICWS)
操作命令寄存器组:保存操作命令字(OCWS)
8259A在正常工作前须设置初始化命令字(ICW)寄存器组内容,在工作过程中可以写入操作命令字(OCW)寄存器组来随时设置和管理工作方式。8259A采用写端口方式输入命令,逻辑图中的A0用来决定端口地址。A0=0 端口用0x20(主)和0xA0(从),A0=1 端口用0x21(主)和0xA1(从)。
新增加的Slave PIC在原有系统中不存在,所以,设计者从Slave PIC的IRQ中挑出IRQ9,要求软件设计者将原来的IRQ2重定向到IRQ9上,也就是说IRQ9的中断服务程序需要调用IRQ2的中断服务程序。 这样,将原来接在IRQ2上的设备现在接在IRQ9上,在软件上只需要增加IRQ9的中断服务程序,由它调用IRQ2的中断服务程序,就可以和原有系统保 持兼容。而在当时,增加的IRQ9中断服务程序(其实就是仅仅调用了IRQ2)是由PC开发商开发的BIOS提供的,所以就从根本上保证了兼容。
8259A的端口地址是0x20,0x21;Slave 8259A的端口地址是0
xA0,0xA1。既然鼠标在IRQ12上,就必定要开启PIC2.
任 何时候,只要向某一个8259A的第一个端口(0x20 for Master, and 0xA0 for Slave)写入的命令的bit-4(从0算起)为1,那么这个8259A就认为这是一个ICW1;而一旦一个8259A收到一个ICW1,它就认为一个 初始化序列开始了(紧接着写2,3,4,但是它们是后面的端口)。你可以通过对照上边的表和后面的表,第一端口可写的有ICW1,OCW2和OCW3。而ICW1的bit-4要求必须是1,但OCW2 和OCW3的bit-4要求必须是0。
最终可算完成了,出bug的地方是0x21*8和0x2c*8,忘记乘以8了。。。
每日小常识:
据说PS/2接口协议最初是由IBM公司制定的(这个本人没有考究过),现在广泛用于键盘,鼠标和条码扫描仪等设备当中。
PS/2接口一共有6根线,4根有效连接线:2根电源线(+5V电源线和Ground电源地)、1根数据线(DATA)、1根时钟线(CLK)。PS/2键盘鼠标与电脑的物理连接上只要保证上述四根线一一对应就可以了。
PS/2键盘鼠标没有独立电源,靠电脑的PS/2端口提供+5V电源,另外两个脚Clock(时钟脚)和Data数据脚都是集电极开路的,所以必须接大阻值的上拉电阻。
qemu查看大量内存可以用 x/100x 0x26f800什么的,直接显示100个双字。而且每行前面还有地址显示。