reactos操作系统实现(99)

下面来分析键盘的中断处理函数的实现,如下:

#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     }

 

轮询次数计数为0,那么说明读取键盘硬件失败。

#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, 0x46, 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 

 

调用ISR的回调函数,如果已经处理这个按键就返回。

#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  

你可能感兴趣的:(react)