reactos操作系统实现(99)

前端之家收集整理的这篇文章主要介绍了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,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相关文章