📄 jiurl键盘驱动 5.htm
字号:
I8042KeyboardIsrDpc: enter<BR>8042: I8xDpcVariableOperation:
enter<BR>8042: Performing increment at 0xfe4f529c (current value
0xffffffff)<BR>8042: I8xDpcVariableOperation: exit with value 0x0<BR>8042:
I8xGetDataQueuePointer: enter<BR>8042: I8xGetDataQueuePointer:
keyboard<BR>8042: I8xGetDataQueuePointer: DataIn 0xfe4cf624, DataOut
0xfe4cf60c<BR>8042: I8xGetDataQueuePointer: exit<BR>8042:
I8042KeyboardIsrDpc: calling class callback<BR>8042: I8042KeyboardIsrDpc:
with Start 0xfe4cf60c and End
0xfe4cf624<BR><BR>KBDCLASS-KeyboardClassServiceCallback:
enter<BR>KBDCLASS-KeyboardClassServiceCallback: port queue length 0x18,
read length 0x78<BR>KBDCLASS-KeyboardClassServiceCallback: number of bytes
to move from port to SystemBuffer
0x18<BR>KBDCLASS-KeyboardClassServiceCallback: move bytes from 0xfe4cf60c
to 0xfe426748<BR>KBDCLASS-KeyboardClassServiceCallback: bytes remaining
after move to SystemBuffer 0x0<BR>KBDCLASS-KeyboardClassServiceCallback:
exit<BR><BR>8042: I8042KeyboardIsrDpc: Call callback consumed 2 items,
left 0<BR>8042: I8xSetDataQueuePointer: enter<BR>8042:
I8xSetDataQueuePointer: old keyboard DataOut 0xfe4cf60c, InputCount
2<BR>8042: I8xSetDataQueuePointer: Okay to log keyboard overflow<BR>8042:
I8xSetDataQueuePointer: new keyboard DataOut 0xfe4cf624, 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 0xfe4f5938, DataOut
0xfe4f5938<BR>KBDCLASS-KeyboardClassStartIo: entries in queue
0<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead:
exit<BR><BR>7.5.2 分析<BR><BR>按一个向上箭头键,按下时产生一个 Make Code,引发一个键盘中断,松开时产生一个
Break Code,引发一个键盘中断。向上箭头键的 Scan Code Set 1 的 Make Code 为 0xE0,0x48,Break
Code 为 0xE0,0xC8。这个键的扫描码是扩展码。<BR><BR>对于普通码和扩展码,只在
i8042prt!I8042KeyboardInterruptService 中的处理稍有不同。<BR><BR>首先按下向上箭头键,产生Make
Code,0xE0,0x48。<BR><BR>0xe0 首先引发一个键盘中断,导致
i8042prt!I8042KeyboardInterruptService
被执行。i8042prt!I8042KeyboardInterruptService 中,读取0x60端口,得到的将是 0xe0。此时
deviceExtension->CurrentScanState 为普通状态,当判断发现为读入数据为 0xe0
时,设置CurrentInput 的 Flags 为 KEY_E0,deviceExtension->CurrentScanState 设置为
GotE0。对于 0xe0 的中断处理全部结束,0xe0不会被写入i8042prt的数据队列,也不会排队一个 DPC。<BR><BR>0x48
接着引发一个键盘中断,导致 i8042prt!I8042KeyboardInterruptService
被执行。<BR>i8042prt!I8042KeyboardInterruptService 中,读取0x60端口,得到的将是 0x48。此时
deviceExtension->CurrentScanState 为 GotE0
状态,将不再判断得到的数据是否是e0或者e1,之后判断是否大于 0x7f,也就是判断是 MakeCode 还是
BreakCode,我们这里是MakeCode,于是 CurrentInput 的 MakeCode 被赋值为 0x48。我们要注意一下此时的
CurrentInput 和非扩展键时的 CurrentInput 的不同,他们的 MakeCode
都是按键的扫描码,不过非扩展键时的Flags为0,扩展键时的Flags为KEY_E0。然后将
deviceExtension->CurrentScanState
设置为普通状态,然后将这个CurrentInput放入i8042prt的输入数据队列,然后排队一个DPC。<BR><BR>松开向上箭头键,产生Break
Code,0xE0,0xC8。<BR><BR>0xe0 首先引发一个键盘中断,导致
i8042prt!I8042KeyboardInterruptService
被执行。i8042prt!I8042KeyboardInterruptService 中,读取0x60端口,得到的将是 0xe0。此时
deviceExtension->CurrentScanState 为普通状态,当判断发现为读入数据为 0xe0
时,设置CurrentInput 的 Flags 为 KEY_E0,deviceExtension->CurrentScanState 设置为
GotE0。对于 0xe0 的中断处理全部结束,0xe0不会被写入i8042prt的数据队列,也不会排队一个 DPC。<BR><BR>0x48
接着引发一个键盘中断,导致 i8042prt!I8042KeyboardInterruptService
被执行。<BR>i8042prt!I8042KeyboardInterruptService 中,读取0x60端口,得到的将是 0xC8。此时
deviceExtension->CurrentScanState 为 GotE0
状态,将不再判断得到的数据是否是e0或者e1,之后判断是否大于 0x7f,也就是判断是 MakeCode 还是
BreakCode,我们这里是BreakCode,于是 CurrentInput 的 MakeCode 被赋值为 0xC8。我们要注意一下此时的
CurrentInput 和非扩展键时的 CurrentInput 的不同,他们的 MakeCode
都是按键的扫描码,不过非扩展键时的Flags为KEY_BREAK,扩展键时的Flags为KEY_E0|KEY_BREAK。然后将
deviceExtension->CurrentScanState
设置为普通状态,然后将这个CurrentInput放入i8042prt的输入数据队列,然后排队一个DPC。<BR><BR>之后 DPC
中的处理,和非扩展键没有区别。<BR><BR>我们来讨论一下 扩展键与非扩展键的 KEYBOARD_INPUT_DATA
数据的区别。<BR><BR>KEYBOARD_INPUT_DATA 中的 Flags 的定义在 ntddkbd.h 中<BR><BR>#define
KEY_MAKE 0<BR>#define KEY_BREAK 1<BR>#define KEY_E0 2<BR>#define KEY_E1
4<BR><BR>对于从 i8042 中读到 E0 的情况,E0并不写入输入数据队列 ,而只是设置 KEYBOARD_INPUT_DATA 中的
Flags <BR><BR>对于非扩展键的 MakeCode 的 Flags 为 KEY_MAKE,即 0。<BR>对于非扩展键的
BreakCode 的 Flags 为 KEY_BREAK,即 1。<BR>对于E0扩展键的 MakeCode 的 Flags 为
KEY_MAKE|KEY_E0,即 2。<BR>对于E0扩展键的 BreakCode 的 Flags 为 KEY_BREAK|KEY_E0,即
3。<BR>对于E1扩展键的 MakeCode 的 Flags 为 KEY_MAKE|KEY_E1,即 4。<BR>对于E1扩展键的
BreakCode 的 Flags 为 KEY_BREAK|KEY_E1,即 5。<BR><BR>7.6 按一个设置指示灯的键-Caps
Lock-点亮LED<BR><BR>7.6.1 调试信息<BR><BR>i8042 isr (kb): enter<BR>i8042 isr
(kb): scanCode 0x3a<BR>i8042 isr (kb): real scan code<BR>i8042 isr (kb):
MAKE code<BR>8042: I8xWriteDataToKeyboardQueue: enter<BR>8042:
I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf5c8, DataOut
0xfe4cf5c8<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 0<BR>8042:
I8xWriteDataToKeyboardQueue: new InputCount 1<BR>8042:
I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>i8042 isr
(kb): enter<BR>i8042 isr (kb): scanCode 0xba<BR>i8042 isr (kb): real scan
code<BR>i8042 isr (kb): BREAK code<BR>8042: I8xWriteDataToKeyboardQueue:
enter<BR>8042: I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf5d4, DataOut
0xfe4cf5c8<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 1<BR>8042:
I8xWriteDataToKeyboardQueue: new InputCount 2<BR>8042:
I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>8042:
I8042KeyboardIsrDpc: enter<BR>8042: I8xDpcVariableOperation:
enter<BR>8042: Performing increment at 0xfe4f529c (current value
0xffffffff)<BR>8042: I8xDpcVariableOperation: exit with value 0x0<BR>8042:
I8xGetDataQueuePointer: enter<BR>8042: I8xGetDataQueuePointer:
keyboard<BR>8042: I8xGetDataQueuePointer: DataIn 0xfe4cf5e0, DataOut
0xfe4cf5c8<BR>8042: I8xGetDataQueuePointer: exit<BR>8042:
I8042KeyboardIsrDpc: calling class callback<BR>8042: I8042KeyboardIsrDpc:
with Start 0xfe4cf5c8 and End
0xfe4cf5e0<BR><BR>KBDCLASS-KeyboardClassServiceCallback:
enter<BR>KBDCLASS-KeyboardClassServiceCallback: port queue length 0x18,
read length 0x78<BR>KBDCLASS-KeyboardClassServiceCallback: number of bytes
to move from port to SystemBuffer
0x18<BR>KBDCLASS-KeyboardClassServiceCallback: move bytes from 0xfe4cf5c8
to 0xfe428868<BR>KBDCLASS-KeyboardClassServiceCallback: bytes remaining
after move to SystemBuffer 0x0<BR>KBDCLASS-KeyboardClassServiceCallback:
exit<BR><BR>8042: I8042KeyboardIsrDpc: Call callback consumed 2 items,
left 0<BR>8042: I8xSetDataQueuePointer: enter<BR>8042:
I8xSetDataQueuePointer: old keyboard DataOut 0xfe4cf5c8, InputCount
2<BR>8042: I8xSetDataQueuePointer: Okay to log keyboard overflow<BR>8042:
I8xSetDataQueuePointer: new keyboard DataOut 0xfe4cf5e0, 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><BR>KBDCLASS-KeyboardClassDeviceControl:
enter<BR><BR>8042: IOCTL: enter<BR>8042: IOCTL: keyboard set
indicators<BR>8042: I8042StartIo: enter<BR><BR>8042: I8xControllerRoutine:
keyboard set indicators<BR>8042: I8xInitiateIo: enter<BR>8042:
I8xInitiateIo: sending byte #0 (0xed)<BR>8042: I8xPutByteAsynchronous:
enter<BR>8042: I8xPutByteAsynchronous: sending 0xed to data port<BR>8042:
I8xPutByteAsynchronous: exit<BR>8042: I8xInitiateIo: exit<BR><BR>i8042 isr
(kb): enter<BR>i8042 isr (kb): scanCode 0xfa<BR>i8042 isr (kb): : ACK,
i8042 isr (kb): now initiate send of byte #1<BR><BR>8042: I8xInitiateIo:
enter<BR>8042: I8xInitiateIo: sending byte #1 (0x4)<BR>8042:
I8xPutByteAsynchronous: enter<BR>8042: I8xPutByteAsynchronous: sending 0x4
to data port<BR>8042: I8xPutByteAsynchronous: exit<BR>8042: I8xInitiateIo:
exit<BR><BR>i8042 isr (kb): exit<BR>i8042 isr (kb): enter<BR>i8042 isr
(kb): scanCode 0xfa<BR>i8042 isr (kb): : ACK, i8042 isr (kb): all bytes
have been sent<BR>i8042 isr (kb): exit<BR>8042: I8042StartIo:
exit<BR><BR>8042: I8042CompletionDpc: enter<BR>8042: I8042CompletionDpc:
keyboard set indicators updated<BR>8042: I8042CompletionDpc: new LED flags
0x4<BR>8042: I8042CompletionDpc: exit<BR>8042: IOCTL: exit
(0x103)<BR>KBDCLASS-KeyboardClassDeviceControl:
exit<BR><BR>KBDCLASS-KeyboardClassRead:
enter<BR>KBDCLASS-KeyboardClassStartIo:
enter<BR>KBDCLASS-KeyboardClassStartIo: DataIn 0xfe4f5908, DataOut
0xfe4f5908<BR>KBDCLASS-KeyboardClassStartIo: entries in queue
0<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead:
exit<BR><BR>7.6.2 分析<BR><BR>按一个 Caps Lock 键,按下时产生一个 Make
Code,引发一个键盘中断,松开时产生一个 Break Code,引发一个键盘中断。向上箭头键的 Scan Code Set 1 的 Make
Code 为 0x3A,Break Code 为 0xBA。我们是在 Caps Lock 的 LED
指示灯熄灭的状态下按的。熄灭LED灯和点亮LED灯的处理没有本质区别。<BR><BR>键盘驱动对于按 Caps Lock
键的输入数据的处理,和普通的键没有区别。<BR><BR>而当应用层中处理输入数据时,发现是 Caps Lock,将会调用
DeviceIoControl ,给键盘设备栈发一个 IRP_MJ_DEVICE_CONTROL IOCTL:
IOCTL_KEYBOARD_SET_INDICATORS 的 IRP。这将执行
kbdclass!KeyboardClassDeviceControl。<BR><BR>kbdclass!KeyboardClassDeviceControl
被执行时的 Call Stack<BR><BR># ChildEBP RetAddr Args to Child <BR>00
f90ef800 8041f54b fe4f5df0 fe385368 fe385368
kbdclass!KeyboardClassDeviceControl(struct _DEVICE_OBJECT * DeviceObject =
0xfe4f5df0, struct _IRP * Irp = 0xfe385368) (CONV: stdcall)<BR>01 f90ef814
804ba5e8 fe3b38ec 00000000 fe385368 nt!IopfCallDriver+0x35 (FPO:
[0,0,2])<BR>02 f90ef828 804ac5de fe4f5df0 fe385368 fe426728
nt!IopSynchronousServiceTail+0x60 (FPO: [Non-Fpo])<BR>03 f90ef8f4 804a8f1e
000000d4 00000000 00000000 nt!IopXxxControlFile+0x5e4 (FPO:
[Non-Fpo])<BR>04 f90ef928 80461691 000000d4 00000000 00000000
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -