📄 jiurl键盘驱动 4.htm
字号:
[Non-Fpo])<BR>05 f901f764 8048e040 fe4fed68 f901f88c 00000000
nt!IopStartAndEnumerateDevice+0x1c7 (FPO: [Non-Fpo])<BR>06 f901f784
804e504e fe4fed68 f901f88c fe4d6368 nt!IopProcessStartDevicesWorker+0x72
(FPO: [Non-Fpo])<BR>07 f901f794 804a4670 fe4d6368 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>08 f901f7b8 804e504e
fe4d6368 f901f88c fe4e7c28 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>09 f901f7c8 804a4670 fe4e7c28 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0a f901f7ec 804e504e
fe4e7c28 f901f88c fe5181a8 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>0b f901f7fc 804a4670 fe5181a8 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0c f901f820 804e504e
fe5181a8 f901f88c fe51b5e8 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>0d f901f830 804a4670 fe51b5e8 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0e f901f854 804a4607
fe51b5e8 f901f88c 00000003 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>0f f901f870 8054e017 fe51b2c8 f901f88c 80087000
nt!IopProcessStartDevices+0x43 (FPO: [EBP 0xf901f8c0] [2,0,4])<BR>10
f901f8c0 8054c5c9 00000000 00000032 00000000
nt!IopInitializeSystemDrivers+0x5d (FPO: [Non-Fpo])<BR>11 f901fa58
8054b35a 80087000 00000000 00000000 nt!IoInitSystem+0x644 (FPO:
[Non-Fpo])<BR>12 f901fda8 804524f6 80087000 00000000 00000000
nt!Phase1Initialization+0x71b (FPO: [Non-Fpo])<BR>13 f901fddc 80465b62
8054aca6 80087000 00000000 nt!PspSystemThreadStartup+0x69 (FPO:
[Non-Fpo])<BR><BR>kbdclass!KeyboardPnP 和 i8042prt!I8xPnP
中都没有做什么处理。<BR><BR>[启动ps/2鼠标的 IRP_MJ_PNP
IRP_MN_START_DEVICE]<BR><BR>硬件的初始化工作,对于ps/2的鼠标和ps/2的键盘都是向i8042发一些命令。所以驱动
i8042prt 把ps/2键盘鼠标的硬件初始化工作放在了一起进行。<BR>前面已经给键盘设备栈发 IRP_MJ_PNP
IRP_MN_START_DEVICE 的 IRP 将键盘启动了。现在给鼠标设备栈发 IRP_MJ_PNP IRP_MN_START_DEVICE
的 IRP,启动鼠标,将在鼠标启动的最后初始化键盘和鼠标的硬件。<BR><BR># ChildEBP RetAddr Args to
Child <BR>00 f901f5c8 8041f54b fe4d3ba0 fe4fea08 fe4d3b18
i8042prt!I8xPnP(struct _DEVICE_OBJECT * DeviceObject = 0xfe4d3ba0, struct
_IRP * Irp = 0xfe4fea08) (CONV: stdcall)<BR>01 f901f5dc f91ff8c2 fe4d3a60
fe4fea08 fe4fea08 nt!IopfCallDriver+0x35 (FPO: [0,0,2])<BR>WARNING: Stack
unwind information not available. Following frames may be wrong.<BR>02
f901f604 8041f54b fe4d3a60 fe4fea08 00000000 vmmouse+0x8c2<BR>03 f901f618
f8ec26fd fe4fea08 fe4d3928 fe043801 nt!IopfCallDriver+0x35 (FPO:
[0,0,2])<BR>04 f901f638 f8ec12d8 fe4d3a60 fe4fea08 00000001
mouclass!MouseSendIrpSynchronously+0x57 (FPO: [Non-Fpo])<BR>05 f901f6a4
8041f54b fe4feb50 fe4fea08 fe4d3870 mouclass!MousePnP+0x2b2 (FPO:
[Non-Fpo])<BR>06 f901f6b8 8049cb91 00020000 fe4fec88 00000000
nt!IopfCallDriver+0x35 (FPO: [0,0,2])<BR>07 f901f6e4 804289ce fe4d3870
f901f704 f901f72c nt!IopSynchronousCall+0xca (FPO: [Non-Fpo])<BR>08
f901f730 8048e06a fe4dd610 00000000 fe4fec88 nt!IopStartDevice+0x127 (FPO:
[Non-Fpo])<BR>09 f901f764 8048e040 fe4fec88 f901f88c 00000000
nt!IopStartAndEnumerateDevice+0x22 (FPO: [Non-Fpo])<BR>0a f901f784
804e504e fe4fec88 f901f88c fe4d6368 nt!IopProcessStartDevicesWorker+0x72
(FPO: [Non-Fpo])<BR>0b f901f794 804a4670 fe4d6368 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0c f901f7b8 804e504e
fe4d6368 f901f88c fe4e7c28 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>0d f901f7c8 804a4670 fe4e7c28 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0e f901f7ec 804e504e
fe4e7c28 f901f88c fe5181a8 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>0f f901f7fc 804a4670 fe5181a8 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>10 f901f820 804e504e
fe5181a8 f901f88c fe51b5e8 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>11 f901f830 804a4670 fe51b5e8 804a4618 f901f88c
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>12 f901f854 804a4607
fe51b5e8 f901f88c 00000003 nt!IopProcessStartDevicesWorker+0x55 (FPO:
[Non-Fpo])<BR>13 f901f870 8054e017 fe51b2c8 f901f88c 80087000
nt!IopProcessStartDevices+0x43 (FPO: [EBP 0xf901f8c0]
[2,0,4])<BR><BR>我们只讨论键盘部分的内容。<BR><BR>i8042prt!I8xPnP 中,调用
I8xMouseStartDevice。<BR>I8xMouseStartDevice
中都是鼠标相关的内容,我们并不关心,直到最后,判断,如果没有ps/2键盘,或者有ps/2键盘但是已经启动了,那么将调用
i8042prt!I8xMouseInitializeHardware
初始化硬件。我这里有ps/2键盘,并且已经启动了,i8042prt!I8xMouseInitializeHardware
将被调用。<BR><BR>i8042prt!I8xMouseInitializeHardware 中,<BR>调用
I8xInitializeHardwareAtBoot ,初始化硬件。<BR>调用 I8xKeyboardConnectInterrupt
,连接键盘中断。<BR><BR>I8xInitializeHardwareAtBoot 中,<BR>调用
I8xSanityCheckResources ,检查必要的资源是否存在。<BR>调用 I8xToggleInterrupts(FALSE)
,disable 键盘中断。<BR>调用 I8xInitializeHardware ,初始化键盘硬件和鼠标硬件,我们只讨论键盘。<BR>调用
I8xToggleInterrupts(TRUE) ,enable 键盘中断。<BR><BR>I8xSanityCheckResources
中,<BR>将 Globals.ControllerData->DeviceRegisters[i] 设置为
Globals.ControllerData->Configuration.PortList[i].u.Port.Start.LowPart<BR><BR>驱动中把
0x60 叫数据端口。<BR>驱动中把 0x64 叫命令端口。<BR>关于各种命令的详细内容请参考"1 ps/2
键盘的硬件"。<BR><BR>I8xToggleInterrupts(FALSE) 中,<BR>向命令端口发 0x20
,取出i8042的命令字节。我这里取出的命令字节为 0x47,即二进制 01000111,看到Bit0为1,说明 enable
键盘中断。Bit1为1,说明 enable 鼠标中断。使用指定的 ByteMask: ~((UCHAR)
CCB_ENABLE_KEYBOARD_INTERRUPT |(UCHAR) CCB_ENABLE_MOUSE_INTERRUPT)
执行一个指定的操作: AND_OPERATION。于是命令字节变为 0x44,即二进制 01000100。禁止了键盘和鼠标的中断。向命令端口发
0x60
,写入i8042的命令字节,将修改过的命令字节作为参数发送到数据端口,从而禁止了键盘和鼠标的中断。<BR><BR>I8xInitializeHardware
中,调用 I8xInitializeKeyboard 初始化键盘硬件,I8xInitializeKeyboard 中,Reset
Keyboard,关闭键盘的 Translate 模式,设置键盘的 Typematic Rate 和 Typematic
Delay,设置键盘指示灯,重新打开键盘的 Translate 模式。<BR><BR>Reset Keyboard,向数据端口发 0xff ,来
Reset
Keyboard。这个命令将使Keyboard,首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic
Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success,
FCh=Failed),并将键盘的Scan code set设置为2。<BR><BR>关闭键盘的 Translate 模式,首先向命令端口发
0x20 ,取出i8042的命令字节。我这里取出的命令字节为 0x44,即二进制 01000100。使用指定的 ByteMask:
~((UCHAR)CCB_KEYBOARD_TRANSLATE_MODE) 执行一个指定的操作: AND_OPERATION。于是命令字节变为
0x4,即二进制 00000100,Bit6被清0,关闭了 Translate 模式。向命令端口发 0x60
,写入i8042的命令字节,将修改过的命令字写入i8042控制器命令字节,从而关闭了 Translate 模式。<BR><BR>设置
Typematic Rate 和 Typematic Delay,向数据端口发 0xf3,这是设置 Typematic Rate 和
Typematic
Delay的命令,然后将deviceExtension->KeyRepeatCurrent.Rate,deviceExtension->KeyRepeatCurrent.Delay
转换为1个字节的设置命令的参数。deviceExtension->KeyRepeatCurrent.Rate,deviceExtension->KeyRepeatCurrent.Delay
在前面的 I8xKeyboardConfiguration 中,被设置为 KEYBOARD_TYPEMATIC_RATE_DEFAULT 和
KEYBOARD_TYPEMATIC_DELAY_DEFAULT ,KEYBOARD_TYPEMATIC_RATE_DEFAULT 为
30,KEYBOARD_TYPEMATIC_DELAY_DEFAULT 为
250。将转换得到的设置参数,发到数据端口。<BR><BR>设置键盘指示灯,向数据端口发
0xed,这是设置LED命令,然后将deviceExtension->KeyboardIndicators.LedFlags
作为命令的参数,发到数据端口。deviceExtension->KeyboardIndicators.LedFlags 在前面的
I8xKeyboardConfiguration 中,被设置为 KEYBOARD_INDICATORS_DEFAULT,即
0。<BR><BR>重新打开键盘的 Translate 模式,键盘默认发送 scan code set
2,当设置了i8042命令字节中的translate 位时,i8042在把扫描码发送给 CPU 之前,转换为 scan code set
1。首先向命令端口发 0x20 ,取出i8042的命令字节。我这里取出的命令字节为 0x4,即二进制 00000100。使用指定的
ByteMask: CCB_KEYBOARD_TRANSLATE_MODE 执行一个指定的操作: OR_OPERATION。于是命令字节变为
0x44,即二进制 01000100,Bit6被置1,打开了 Translate 模式。向命令端口发 0x60
,写入i8042的命令字节,将修改过的命令字写入i8042控制器命令字节,从而打开了 Translate
模式。<BR><BR>I8xToggleInterrupts(TRUE) 中,<BR>向命令端口发
0xad,禁止键盘接口。向命令端口发0xa7,禁止鼠标接口。向命令端口发 0x20 ,取出i8042的命令字节。我这里取出的命令字节为
0x74,即二进制 01110100,看到Bit0为0,说明 disable 键盘中断。Bit1为0,说明 disable
鼠标中断。Bit4为1,Bit5为1,说明禁止了键盘和鼠标。向命令端口发
0xae,打开键盘接口。向命令端口发0xa8,打开鼠标接口。于是命令字节变为 0x44。使用指定的 ByteMask:
CCB_ENABLE_KEYBOARD_INTERRUPT |CCB_ENABLE_MOUSE_INTERRUPT 执行一个指定的操作:
OR_OPERATION。于是命令字节变为 0x47,即二进制 01000111。enable 了键盘和鼠标的中断。向命令端口发 0x60
,写入i8042的命令字节,将修改过的命令字节作为参数发送到数据端口,从而打开了键盘和鼠标的中断。<BR><BR>I8xKeyboardConnectInterrupt
中,<BR><BR>以i8042prt键盘设备扩展中的一些域为参数,调用 IoConnectInterrupt
连接键盘中断。<BR><BR>IoConnectInterrupt(<BR>&(KeyboardExtension->InterruptObject),<BR>(PKSERVICE_ROUTINE)
I8042KeyboardInterruptService,<BR>self,<BR>&KeyboardExtension->InterruptSpinLock,<BR>KeyboardExtension->InterruptDescriptor.u.Interrupt.Vector, <BR>(KIRQL)
KeyboardExtension->InterruptDescriptor.u.Interrupt.Level,<BR>configuration->InterruptSynchIrql, <BR>KeyboardExtension->InterruptDescriptor.Flags<BR>==
CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive,<BR>(BOOLEAN)
(KeyboardExtension->InterruptDescriptor.ShareDisposition<BR>==
CmResourceShareShared),<BR>KeyboardExtension->InterruptDescriptor.u.Interrupt.Affinity, <BR>configuration->FloatingSave<BR>);<BR><BR>其中
IoConnectInterrupt 的参数 ServiceRoutine 为 I8042KeyboardInterruptService ,参数
Vector 为 KeyboardExtension->InterruptDescriptor.u.Interrupt.Vector ,值为
0xb3。也就是说,键盘中断IRQ1,将引起中断描述符表中 0xb3 中的中断服务例程被执行,最终将执行
i8042!prtI8042KeyboardInterruptService。驱动的中断有一些特殊,详细我们将在以后讨论。<BR><BR>之后会得到键盘设备栈的栈顶设备对象,然后向栈顶发一个
IRP_MJ_INTERNAL_DEVICE_CONTROL
IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION 的
IRP,不过键盘设备栈对此不做什么处理。<BR><BR>[kbdclass!KeyboardClassFindMorePorts]<BR><BR>由于在
kbdclass!DriverEntry 中
IoRegisterDriverReinitialization(DriverObject,KeyboardClassFindMorePorts,NULL);<BR>所以现在
kbdclass!KeyboardClassFindMorePorts 被调用了。<BR><BR># ChildEBP RetAddr Args
to Child <BR>00 f901f614 804d92bc fe4f6330 00000000 00000001
kbdclass!KeyboardClassFindMorePorts(struct _DRIVER_OBJECT * DriverObject =
0xfe4f6330, void * Context = 0x00000000, unsigned long Count = 1) (CONV:
stdcall)<BR>01 f901f638 8052a72f f901f668 f901f6c4 f901f740
nt!IopLoadUnloadDriver+0x7a (FPO: [EBP 0xf901f6b8] [1,1,4])<BR>02 f901f6b8
80461691 f901f760 8000003c 80000040 nt!NtLoadDriver+0x199 (FPO:
[Non-Fpo])<BR>03 f901f6b8 80400d15 f901f760 8000003c 80000040
nt!KiSystemService+0xc4 (FPO: [0,0] TrapFrame @ f901f6c4)<BR>04 f901f734
fe22a8bd f901f760 fe4da470 fe4fea08 nt!ZwLoadDriver+0xb (FPO:
[1,0,0])<BR>05 f901f774 8041f54b fe4da470 fe4fea9c fe4da470
NDIS!ndisPnPDispatch+0x40e (FPO: [Non-Fpo])<BR>06 f901f788 8049cb91
00020000 fe519408 00000000 nt!IopfCallDriver+0x35 (FPO: [0,0,2])<BR>07
f901f7b4 804289ce fe4da470 f901f7d4 f901f7fc nt!IopSynchronousCall+0xca
(FPO: [Non-Fpo])<BR>08 f901f800 8048e06a fe519510 00000000 fe519408
nt!IopStartDevice+0x127 (FPO: [Non-Fpo])<BR>09 f901f834 8048e040 fe519408
f901f88c 00000000 nt!IopStartAndEnumerateDevice+0x22 (FPO:
[Non-Fpo])<BR>0a f901f854 804a4607 fe519408 f901f88c 00000003
nt!IopProcessStartDevicesWorker+0x72 (FPO: [Non-Fpo])<BR>0b f901f870
8054e017 fe519208 f901f88c 80087000 nt!IopProcessStart
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -