📄 jiurl键盘驱动 5.htm
字号:
to 0xfe3a0b88<BR>KBDCLASS-KeyboardClassServiceCallback: bytes remaining
after move to SystemBuffer 0x0<BR>KBDCLASS-KeyboardClassServiceCallback:
exit<BR>8042: I8042KeyboardIsrDpc: Call callback consumed 1 items, left
0<BR>8042: I8xSetDataQueuePointer: enter<BR>8042: I8xSetDataQueuePointer:
old keyboard DataOut 0xfe4cf60c, InputCount 14<BR>8042:
I8xSetDataQueuePointer: new keyboard DataOut 0xfe4cf618, InputCount
13<BR>8042: I8xSetDataQueuePointer: exit<BR><BR>8042:
I8xDpcVariableOperation: enter<BR>8042: Performing decrement at 0xfe4f529c
(current value 0xd)<BR>8042: I8xDpcVariableOperation: exit with value
0xc<BR>8042: I8xDpcVariableOperation: enter<BR>8042: Performing write at
0xfe4f529c (current value 0xc)<BR>8042: Writing 0x0<BR>8042:
I8xDpcVariableOperation: exit with value 0x0<BR>8042: I8042KeyboardIsrDpc:
loop in DPC<BR>8042: I8xGetDataQueuePointer: enter<BR>8042:
I8xGetDataQueuePointer: keyboard<BR>8042: I8xGetDataQueuePointer: DataIn
0xfe4cf6b4, DataOut 0xfe4cf618<BR>8042: I8xGetDataQueuePointer:
exit<BR>8042: I8042KeyboardIsrDpc: calling class callback<BR>8042:
I8042KeyboardIsrDpc: with Start 0xfe4cf618 and End
0xfe4cf6b4<BR>KBDCLASS-KeyboardClassServiceCallback:
enter<BR>KBDCLASS-KeyboardClassServiceCallback: bytes remaining after move
to SystemBuffer 0x9c<BR>KBDCLASS-KeyboardClassServiceCallback: unused
bytes in class queue 0x4b0, remaining bytes in port queue
0x9c<BR>KBDCLASS-KeyboardClassServiceCallback: total number of bytes to
move to class queue 0x9c<BR>KBDCLASS-KeyboardClassServiceCallback: number
of bytes to end of class buffer
0x12c<BR>KBDCLASS-KeyboardClassServiceCallback: number of bytes in first
move to class 0x9c<BR>KBDCLASS-KeyboardClassServiceCallback: move bytes
from 0xfe4cf618 to 0xfe4f5c8c<BR>KBDCLASS-KeyboardClassServiceCallback:
changed InputCount to 13 entries in the class
queue<BR>KBDCLASS-KeyboardClassServiceCallback: DataIn 0xfe4f5d28, DataOut
0xfe4f5c8c<BR>KBDCLASS-KeyboardClassServiceCallback: Input data items
consumed = 13<BR>KBDCLASS-KeyboardClassServiceCallback: exit<BR>8042:
I8042KeyboardIsrDpc: Call callback consumed 13 items, left 0<BR>8042:
I8xSetDataQueuePointer: enter<BR>8042: I8xSetDataQueuePointer: old
keyboard DataOut 0xfe4cf618, InputCount 13<BR>8042:
I8xSetDataQueuePointer: Okay to log keyboard overflow<BR>8042:
I8xSetDataQueuePointer: new keyboard DataOut 0xfe4cf6b4, InputCount
0<BR>8042: I8xSetDataQueuePointer: exit<BR>8042: I8xDpcVariableOperation:
enter<BR>8042: Performing decrement at 0xfe4f529c (current value
0x0)<BR>8042: I8xDpcVariableOperation: exit with value 0xffffffff<BR>8042:
I8042KeyboardIsrDpc: exit<BR><BR>KBDCLASS-KeyboardClassRead:
enter<BR>KBDCLASS-KeyboardClassStartIo:
enter<BR>KBDCLASS-KeyboardClassStartIo: DataIn 0xfe4f5d28, DataOut
0xfe4f5c8c<BR>KBDCLASS-KeyboardClassStartIo: entries in queue
13<BR>KBDCLASS-KeyboardClassStartIo: queue size 0x9c, read length
0x78<BR>KBDCLASS-KeyboardClassStartIo: bytes to end of queue
0x12c<BR>KBDCLASS-KeyboardClassStartIo: number of bytes in first move
0x78<BR>KBDCLASS-KeyboardClassStartIo: move bytes from 0xfe4f5c8c to
0xfe3a0b88<BR>KBDCLASS-KeyboardClassStartIo: new DataIn 0xfe4f5d28,
DataOut 0xfe4f5d04<BR>KBDCLASS-KeyboardClassStartIo: new InputCount
3<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead:
exit<BR><BR>KBDCLASS-KeyboardClassRead:
enter<BR>KBDCLASS-KeyboardClassStartIo:
enter<BR>KBDCLASS-KeyboardClassStartIo: DataIn 0xfe4f5d28, DataOut
0xfe4f5d04<BR>KBDCLASS-KeyboardClassStartIo: entries in queue
3<BR>KBDCLASS-KeyboardClassStartIo: queue size 0x24, read length
0x78<BR>KBDCLASS-KeyboardClassStartIo: bytes to end of queue
0xb4<BR>KBDCLASS-KeyboardClassStartIo: number of bytes in first move
0x24<BR>KBDCLASS-KeyboardClassStartIo: move bytes from 0xfe4f5d04 to
0xfe3a0b88<BR>KBDCLASS-KeyboardClassStartIo: Okay to log
overflow<BR>KBDCLASS-KeyboardClassStartIo: new DataIn 0xfe4f5d28, DataOut
0xfe4f5d28<BR>KBDCLASS-KeyboardClassStartIo: new InputCount
0<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead:
exit<BR><BR>KBDCLASS-KeyboardClassRead:
enter<BR>KBDCLASS-KeyboardClassStartIo:
enter<BR>KBDCLASS-KeyboardClassStartIo: DataIn 0xfe4f5d28, DataOut
0xfe4f5d28<BR>KBDCLASS-KeyboardClassStartIo: entries in queue
0<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead:
exit<BR><BR>7.7.2
分析<BR><BR>由于按住不放,使得不断的发生中断,让排队的DPC没有机会执行,从而在i8042prt的输入数据队列中累积了大量的数据。导致了在kbdclass层等待的那个
IRP_MJ_READ 的 IRP 不能一次把所有数据读走,于是 KeyboardClassServiceCallback 把剩余的数据放入
kbdclass 的输入数据队列。之后应用层发来的 IRP_MJ_READ 的 IRP 将直接从 kbdclass
的输入数据队列中读数据,直到所有的数据都被读完了,应用层再发来的 IRP_MJ_READ 的 IRP 才会在 kbdclass
上等待数据。<BR><BR>由于第一个 MakeCode 和第二个 MakeCode 之间有一个 Typematic Delay
,之间间隔时间比较长,所以 DPC 有机会被执行。这里就是被执行,不过执行了一半,又被后面的 MakeCode 中断。关于 Typematic
Delay 的详细介绍,请看前面对于 ps/2 键盘硬件的介绍。<BR><BR>7.8 输入数据队列讨论<BR><BR>i8042prt 和
kbdclass 各有自己的一个输入数据队列,循环使用的缓冲区。他们的每个单元是一个 KEYBOARD_INPUT_DATA
结构。<BR><BR>kbclass 和 i8042prt 的输入数据队列是在键盘驱动的初始化过程中分配内存的。<BR><BR>kbdclass
的输入数据队列是在 kbdclass!KeyboardAddDevice
中,分配内存,并初始化设备扩展中的使用输入数据队列的相关域。<BR><BR>i8042prt 的输入数据队列是在
i8042prt!I8xKeyboardStartDevice
中,分配内存,并初始化设备扩展中的使用输入数据队列的相关域。<BR><BR>kbdclass 和 i8042prt
的输入数据队列的单元个数都是读取注册表中的参数决定的,如果注册表中不存在相应的键值,那么使用默认值。默认值为
0x64(十进制100)。<BR><BR>对于这两个输入数据队列,<BR>放入一个数据,这个数据应该被放在 DataIn 处,然后DataIn
后移一格,InputCount 加 1。当 DataIn 移到队列的结尾时,将从队列的开头重新开始。<BR>取出一个数据,这个数据应该从
DataOut 处取出,然后 DataOut 后移一格,InputCount 减 1。当 DataOut
移到队列的结尾时,将从队列的开头重新开始。<BR><BR>对于 i8042prt
的输入数据队列。键盘中断服务例程中,从i8042读出的按键信息,放入i8042prt的输入数据队列。上层处理输入的回调函数中,取出i8042prt的输入数据队列中的数据。由于一次键盘中断只会放入一个数据,所以i8042prt的输入数据队列,只会放入一个一个的放入数据。<BR><BR>对于
kbdclass 的输入数据队列。只有当那个等待的 IRP_MJ_READ IRP
要求读的大小,小于i8042prt的输入队列中放入的数据时,才被使用。也就是说,只有当那个等着读的 IRP 读不完输入数据时,才使用
kbdclass 的输入数据队列。当那个等着读的 IRP
读完要求的数据后,还有剩余时,剩余的数据放入kbdclass的输入数据队列。下一次的应用层发来的 IRP_MJ_READ
IRP,当发现kbdclass的输入数据队列中有数据时,直接从kbdclass的输入数据队列中读出数据。<BR><BR><BR>输入数据队列反转的判断和处理<BR><BR>随着数据的输入,DataIn
不断后移,就会出现下图的情况。
<P align=center><IMG src="JIURL键盘驱动 5.files/Queue1.gif" border=0>
<P>遇到这种情况的话,要想从输入数据队列中复制数据,就需要把数据分为两段来复制,从 DataOut 到 DataEnd 一段,从
InputData 到 DataIn 是另一段。<BR><BR>对于i8042prt的输入数据队列,如果 DataOut >= DataIn
,并且 InputCount > 0,就说明遇到了这种情况。分两段,分别调用
KeyboardClassServiceCallback。<BR><BR>对于kbdclass的输入数据队列,如果要传给 IRP
的数据大小>从DataOut到输入数据队列尾部的大小,说明遇到了这种情况。分两段,分两次复制到IRP的
AssociatedIrp.SystemBuffer
中。<BR><BR><BR>输入数据队列覆盖的判断和处理<BR><BR>随着数据的输入,DataIn
不断后移,最终用完了整个输入数据队列,如下图所示。
<P align=center><IMG src="JIURL键盘驱动 5.files/Queue2.gif" border=0>
<P>如果再有输入数据,DataIn 再后移,就会出现下图的情况。
<P align=center><IMG src="JIURL键盘驱动 5.files/Queue3.gif" border=0>
<P>覆盖会使数据不正确。<BR><BR>i8042prt的输入数据队列,一次只会写入一个数据。写入数据时做判断,如果 DataIn 等于
DataOut ,并且 InputCount
不为0的话,说明如果将当前的输入数据写入输入数据队列会造成覆盖。处理方法就是丢弃当前的输入数据不写入输入数据队列。并且丢弃前一个输入数据,用腾出的单元放一个
MakeCode 为KEYBOARD_OVERRUN_MAKE_CODE
的数据。<BR><BR><BR>DataIn移到队尾时的处理<BR><BR>对于 i8042prt 的输入数据队列,写入数据时判断,如果写入数据后
DataIn 等于 DataEnd,那么说明 DataIn 已经移到了队尾,将 DataIn 设置为队头 InputData。<BR><BR>对于
kbdclass 的输入数据队列,只有当需要移入数据的大小>从当前 DataIn 到队尾的大小时,才会出现 DataIn
移到队尾的情况。遇到这种情况,移入数据将分两次移入,第一次移入到 DataIn 到 队尾,移完之后DataIn就到了队尾,然后把DataIn
设置为队头 InputData。<BR><BR><BR>DataOut移到队尾时的处理<BR><BR>对于 i8042prt
的输入数据队列,只有分两段时,DataOut才会出现移到队尾的情况。分两段取走数据,当第一段(从 DataOut 到
DataEnd)全部取完之后,就把 DataOut 设置为队头 InputData。<BR><BR>对于 kbdclass
的输入数据队列,只有分两段时,DataOut才会出现移到队尾的情况。分两段,分两次复制到IRP的
AssociatedIrp.SystemBuffer 中。DataOut 到队尾不需要特殊处理。<BR><BR><BR><B>8
升华</B><BR><BR>
学会了写驱动,就可以控制硬件了,想想吧,有多好,能干多少有意思的事啊。<BR><BR>
我们以键盘驱动为对象,从硬件直到应用层,这一整套做了一定的研究。对碰到的各种 Windows
驱动的基本问题,比如驱动对象,设备对象,设备栈,IRP机制,等等,也做了一定的研究。对一个的了解,就可以推及其他。对 Windows
驱动建立起了整体的认识。键盘驱动成了一个我们十分熟悉的很好的范例,以后在其他驱动中遇到的很多问题,很可能都可以在键盘驱动中找到值得参考的解决方法。最后我们以键盘驱动为例,来谈一谈
Windows 驱动中的一些概念,认识。<BR><BR>
与所有硬件设备的通信,对所有硬件设备的控制,使用,都是通过读写端口。要给一个硬件写驱动,需要对这个硬件有一定的了解,尤其是通过端口访问的一些寄存器,一些命令。比如键盘驱动中,通过对0x60和0x64这两个端口的读写,完成从键盘上读数据,命令键盘点亮led指示灯,之类的工作。<BR><BR><BR>
FDO, Functional Device Object ,功能设备对象。i8042prt的用于键盘的那个设备对象就是键盘设备栈中的
FDO,而所有与键盘硬件有关的操作都是在 i8042prt 中实现。<BR><BR> PDO,Physical
Device Object ,物理设备对象。acpi的用于键盘的那个设备对象就是键盘设备栈中的
PDO,它是设备栈中最低下的那个设备对象,管一些总线的事,比如处理电源管理之类。对于键盘相关的各种处理不起什么作用。<BR><BR>
port
driver,端口驱动,驱动i8042prt就是键盘驱动中的端口驱动,所有的读写端口的工作都是在这个驱动进行的,这也就是为什么叫做端口驱动。<BR><BR>
class
driver,类驱动,驱动kbdclass就是键盘驱动中的类驱动。ps/2键盘的端口驱动和usb键盘的端口驱动是绝对不同的,而ps/2键盘和usb键盘的类驱动都是kbdclass,kbdclass驱动完成的是硬件无关的,键盘这一类设备共同的工作,这也就是为什么叫做类驱动。<BR><BR>
从这些概念中,我们也可以对驱动为什么要分层,如何分层,有一点感觉。<BR><BR><B>完</B><BR><BR><BR>欢迎访问<BR>主页 <A
href="http://jiurl.yeah.net/" target=_blank>http://jiurl.yeah.net/</A> <A
href="http://jiurl.nease.net/" target=_blank>http://jiurl.nease.net/</A>
论坛 <A href="http://jiurl.cosoft.org.cn/forum"
target=_blank>http://jiurl.cosoft.org.cn/forum</A>
<P>f啊k,不带你们这样的啊,有好事不叫我。
<P>
<P> </P></TD></TR></TBODY></TABLE></DIV>
<SCRIPT src="JIURL键盘驱动 5.files/nnselect.js"></SCRIPT>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -