#001 BOOLEAN NTAPI
#002 i8042KbdInterruptService(
#003 IN PKINTERRUPT Interrupt,
#004 PVOID Context)
#005 {
#006 PI8042_KEYBOARD_EXTENSION DeviceExtension;
#007 PPORT_DEVICE_EXTENSION PortDeviceExtension;
#008 PKEYBOARD_INPUT_DATA InputData;
#009 ULONG Counter;
#010 UCHAR PortStatus,Output;
#011 BOOLEAN ToReturn = FALSE;
#012 NTSTATUS Status;
#013
这个上下文参数,其实就是设备驱动程序里的设备扩展对象。
#014 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context;
#015 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
计算缓冲区里放入新按键位置。
#016 InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer;
读取端口轮询的最大次数。
#017 Counter = PortDeviceExtension->Settings.PollStatusIterations;
#018
#019 while (Counter)
#020 {
通过键盘端口读取状态。
#021 Status = i8042ReadStatus(PortDeviceExtension,&PortStatus);
#022 if (!NT_SUCCESS(Status))
#023 {
#024 WARN_(I8042PRT,"i8042ReadStatus() Failed with status 0x%08lx/n",Status);
#025 return FALSE;
#026 }
读取键盘输入的数据。
#027 Status = i8042ReadKeyboardData(PortDeviceExtension,&Output);
#028 if (NT_SUCCESS(Status))
#029 break;
暂停一会再进入下一次尝试读取。
#030 KeStallExecutionProcessor(1);
#031 Counter--;
#032 }
#033 if (Counter == 0)
#034 {
#035 WARN_(I8042PRT,"SpurIoUs i8042 keyboard interrupt/n");
#036 return FALSE;
#037 }
#038
#039 INFO_(I8042PRT,"Got: 0x%02x/n",Output);
#040
判断是否是CTRL + SCROLL组合键。
#041 if (PortDeviceExtension->Settings.CrashOnCtrlScroll)
#042 {
#043 /* Test for CTRL + SCROLL LOCK twice */
#044 static const UCHAR ScanCodes[] = { 0xe0,0x1d,0x46,0xc6,0 };
#045
#046 if (Output == ScanCodes[DeviceExtension->ComboPosition])
#047 {
#048 DeviceExtension->ComboPosition++;
#049 if (ScanCodes[DeviceExtension->ComboPosition] == 0)
#050 KeBugCheck(MANUALLY_INITIATED_CRASH);
#051 }
#052 else if (Output == ScanCodes[0])
#053 DeviceExtension->ComboPosition = 1;
#054 else
#055 DeviceExtension->ComboPosition = 0;
#056 }
#057
#058 if (i8042KbdCallIsrHook(DeviceExtension,PortStatus,Output,&ToReturn))
#059 return ToReturn;
#060
#061 if (i8042PacketIsr(PortDeviceExtension,Output))
#062 {
#063 if (PortDeviceExtension->PacketComplete)
#064 {
#065 TRACE_(I8042PRT,"Packet complete/n");
#066 KeInsertQueueDpc(&DeviceExtension->DpcKeyboard,NULL,NULL);
#067 }
#068 TRACE_(I8042PRT,"Irq eaten by packet/n");
#069 return TRUE;
#070 }
#071
#072 TRACE_(I8042PRT,"Irq is keyboard input/n");
#073
到这里,已经说明是键盘输入数据。
#074 if (DeviceExtension->KeyboardScanState == Normal)
#075 {
判断扫描码是E0码,还是E1码。
#076 switch (Output)
#077 {
#078 case 0xe0:
#079 DeviceExtension->KeyboardScanState = GotE0;
#080 return TRUE;
#081 case 0xe1:
#082 DeviceExtension->KeyboardScanState = GotE1;
#083 return TRUE;
#084 default:
#085 break;
#086 }
#087 }
#088
更新输入的数据。
#089 /* Update InputData */
#090 InputData->Flags = 0;
置位是E0码,还是E1码。
#091 switch (DeviceExtension->KeyboardScanState)
#092 {
#093 case GotE0:
#094 InputData->Flags |= KEY_E0;
#095 break;
#096 case GotE1:
#097 InputData->Flags |= KEY_E1;
#098 break;
#099 default:
#100 break;
#101 }
设置按键是按下码,还是弹起码。
当键盘上有键被按下,松开,按住,键盘将产生扫描码( Scan Code ),这些扫描码将被 i8048 直接得到。扫描码有两种,Make Code 和 Break Code。当一个键被按下或按住时产生的是 Make Code ,当一个键被松开产生的是 Break Code。每个键被分配了唯一的 Make Code 和 Break Code ,这样主机通过扫描码就可以知道是哪一个键。简单的说就是按下键,产生一个 Make Code。松开键,产生一个 Break Code。
#102 DeviceExtension->KeyboardScanState = Normal;
#103 if (Output & 0x80)
#104 InputData->Flags |= KEY_BREAK;
#105 else
#106 InputData->Flags |= KEY_MAKE;
只需要保存低7F值。
#107 InputData->MakeCode = Output & 0x7f;
#108 InputData->Reserved = 0;
#109
调用键盘队列返回包。其实这个函数是把数据放到环形缓冲区里,然后插入一个事件到DPC队列里,再由DPC队列来完成每个IRP包。
#110 DeviceExtension->KeyboardHook.QueueKeyboardPacket(DeviceExtension->KeyboardHook.CallContext);
#111
#112 return TRUE;
#113 }
#114