reactos操作系统实现(96)
调用函数IoConnectInterrupt来设置键中断处理函数。 #028 Status = IoConnectInterrupt( #029 &PortDeviceExtension->KeyboardInterrupt.Object, #030 i8042KbdInterruptService, #031 DeviceExtension,&PortDeviceExtension->SpinLock, #032 PortDeviceExtension->KeyboardInterrupt.Vector,PortDeviceExtension->KeyboardInterrupt.Dirql,DirqlMax, #033 PortDeviceExtension->KeyboardInterrupt.InterruptMode,PortDeviceExtension->KeyboardInterrupt.ShareInterrupt, #034 PortDeviceExtension->KeyboardInterrupt.Affinity,FALSE); #035 if (!NT_SUCCESS(Status)) #036 { #037 WARN_(I8042PRT,"IoConnectInterrupt() failed with status 0x%08x/n",Status); #038 return Status; #039 } #040
设置最大的请求级别。 #041 if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql) #042 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
设置键盘已经初始化。 #043 PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED; #044 return STATUS_SUCCESS; #045 }
其实是调用IO管理器里的中断设置函数IoConnectInterrupt,实现如下: #001 NTSTATUS #002 NTAPI #003 IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject, #004 IN PKSERVICE_ROUTINE ServiceRoutine, #005 IN PVOID ServiceContext, #006 IN PKSPIN_LOCK SpinLock, #007 IN ULONG Vector, #008 IN KIRQL Irql, #009 IN KIRQL SynchronizeIrql, #010 IN KINTERRUPT_MODE InterruptMode, #011 IN BOOLEAN ShareVector, #012 IN KAFFINITY ProcessorEnableMask, #013 IN BOOLEAN FloatingSave) #014 { InterruptObject是返回中断处理对象。 ServiceRoutine是中断调用函数。 ServiceContext是中断调用函数使用的参数。 SpinLock是访问输入参数的自旋锁。 Vector是PNP管理器分配的中断号。 Irql是中断请求优先级。 SynchronizeIrql是同步请求优先级。 InterruptMode是中断的模式。 ShareVector是中断资源是否共享。 ProcessorEnableMask是中断允许发生的处理器。 FloatingSave指明是否保存浮点堆栈。
#015 PKINTERRUPT Interrupt; #016 PKINTERRUPT InterruptUsed; #017 PIO_INTERRUPT IoInterrupt; #018 PKSPIN_LOCK SpinLockUsed; #019 BOOLEAN FirstRun; #020 CCHAR Count = 0; #021 KAFFINITY Affinity; #022 PAGED_CODE(); #023
假定失败的返回结果。 #024 /* Assume failure */ #025 *InterruptObject = NULL; #026
获取处理器位。 #027 /* Get the affinity */ #028 Affinity = ProcessorEnableMask & KeActiveProcessors; #029 while (Affinity) #030 { #031 /* Increase count */ #032 if (Affinity & 1) Count++; #033 Affinity >>= 1; #034 } #035
确保这个CPU有中断响应。 #036 /* Make sure we have a valid CPU count */ #037 if (!Count) return STATUS_INVALID_PARAMETER; #038
分配一个IO中断结构。 #039 /* Allocate the array of I/O Interrupts */ #040 IoInterrupt = ExAllocatePoolWithTag(NonPagedPool, #041 (Count - 1) * sizeof(KINTERRUPT) + #042 sizeof(IO_INTERRUPT), #043 TAG_KINTERRUPT); #044 if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES; #045
如果驱动程序传入自旋锁,就使用驱动程序的,否则就使用内核分配的。 #046 /* Select which Spinlock to use */ #047 SpinLockUsed = SpinLock ? SpinLock : &IoInterrupt->SpinLock; #048
设置返回的中断对象。 #049 /* We first start with a built-in Interrupt inside the I/O Structure */ #050 *InterruptObject = &IoInterrupt->FirstInterrupt; #051 Interrupt = (PKINTERRUPT)(IoInterrupt + 1); #052 FirstRun = TRUE; #053
初始化中断对象结构。 #054 /* Start with a fresh structure */ #055 RtlZeroMemory(IoInterrupt,sizeof(IO_INTERRUPT)); #056
开始创建所有CPU的中断。 #057 /* Now create all the interrupts */ #058 Affinity = ProcessorEnableMask & KeActiveProcessors; #059 for (Count = 0; Affinity; Count++,Affinity >>= 1) #060 {
检查这个CPU是否有中断设置。 #061 /* Check if it's enabled for this CPU */ #062 if (Affinity & 1) #063 {
是否第一个CPU中断设置。 #064 /* Check which one we will use */ #065 InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt; #066
设置中断对象。 #067 /* Initialize it */ #068 KeInitializeInterrupt(InterruptUsed, #069 ServiceRoutine, #070 ServiceContext, #071 SpinLockUsed, #072 Vector, #073 Irql, #074 SynchronizeIrql, #075 InterruptMode, #076 ShareVector, #077 Count, #078 FloatingSave); #079 #080 /* Connect it */
调用内核函数KeConnectInterrupt设置中断。 #081 if (!KeConnectInterrupt(InterruptUsed)) #082 { #083 /* Check how far we got */ #084 if (FirstRun) #085 { #086 /* We failed early so just free this */ #087 ExFreePool(IoInterrupt); #088 } #089 else #090 {
如果没有设置中断成功,就返回出错。 #091 /* Far enough,so disconnect everything */ #092 IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt); #093 } #094 #095 /* And fail */ #096 return STATUS_INVALID_PARAMETER; #097 } #098
设置第一个中断响应,已经设置完成。 #099 /* Now we've used up our First Run */ #100 if (FirstRun) #101 { #102 FirstRun = FALSE; #103 } #104 else #105 {
把其它CPU的中断放到队列后面。 #106 /* Move on to the next one */ #107 IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++; #108 } #109 } #110 } #111 #112 /* Return Success */ #113 return STATUS_SUCCESS; #114 }
在这个函数主要到两个内核函数来设置中断,它就是函数KeInitializeInterrupt 和KeConnectInterrupt。下来分析函数KeConnectInterrupt实现,看看它是怎么样把中断服务器与内核连接在一起的,如下: #001 BOOLEAN #002 NTAPI #003 KeConnectInterrupt(IN PKINTERRUPT Interrupt) #004 { #005 BOOLEAN Connected,Error,Status; #006 KIRQL Irql,OldIrql; #007 UCHAR Number; #008 ULONG Vector; #009 DISPATCH_INFO Dispatch; #010
从中断里获取中断号所在CPU、中断向量、中断优先级。 #011 /* Get data from interrupt */ #012 Number = Interrupt->Number; #013 Vector = Interrupt->Vector; #014 Irql = Interrupt->Irql; #015
检查参数是否有效。 #016 /* Validate the settings */ #017 if ((Irql > HIGH_LEVEL) || #018 (Number >= KeNumberProcessors) || #019 (Interrupt->SynchronizeIrql < Irql) || #020 (Interrupt->FloatingSave)) #021 { #022 return FALSE; #023 } #024
设置缺省状态。 #025 /* Set defaults */ #026 Connected = FALSE; #027 Error = FALSE; #028
设置起作用的CPU。 #029 /* Set the system affinity and acquire the dispatcher lock */ #030 KeSetSystemAffinityThread(1 << Number); #031 OldIrql = KiAcquireDispatcherLock(); #032
检查中断是否已经连接到系统里。 #033 /* Check if it's already been connected */ #034 if (!Interrupt->Connected) #035 {
如果没有连接,就查找分发信息。 #036 /* Get vector dispatching information */ #037 KiGetVectorDispatch(Vector,&Dispatch); #038
如果分发器也没有连接这个中断。 #039 /* Check if the vector is already connected */ #040 if (Dispatch.Type == NoConnect) #041 {
开始连接这个中断处理函数。 #042 /* Do the connection */ #043 Interrupt->Connected = Connected = TRUE; #044 #045 /* Initialize the list */ #046 InitializeListHead(&Interrupt->InterruptListEntry); #047
连接中断处理,并启动这个中断。 #048 /* Connect and enable the interrupt */ #049 KiConnectVectorToInterrupt(Interrupt,NormalConnect); #050 Status = HalEnableSystemInterrupt(Vector,Irql,Interrupt->Mode); #051 if (!Status) Error = TRUE; #052 } #053 else if ((Dispatch.Type != UnknownConnect) && #054 (Interrupt->ShareVector) && #055 (Dispatch.Interrupt->ShareVector) && #056 (Dispatch.Interrupt->Mode == Interrupt->Mode)) #057 {
这里是处理共享中断的情况。 #058 /* The vector is shared and the interrupts are compatible */ #059 ASSERT(FALSE); // FIXME: NOT YET SUPPORTED/TESTED #060 Interrupt->Connected = Connected = TRUE; #061 ASSERT(Irql <= SYNCH_LEVEL); #062
是否为第一个连接。 #063 /* Check if this is the first chain */ #064 if (Dispatch.Type != ChainConnect) #065 { #066 /* Setup the chainned handler */ #067 KiConnectVectorToInterrupt(Dispatch.Interrupt,ChainConnect); #068 } #069
把这个中断放到中断响应列表里。 #070 /* Insert into the interrupt list */ #071 InsertTailList(&Dispatch.Interrupt->InterruptListEntry, #072 &Interrupt->InterruptListEntry); #073 } #074 } #075 #076 /* Unlock the dispatcher and revert affinity */ #077 KiReleaseDispatcherLock(OldIrql); #078 KeRevertToUserAffinityThread(); #079
如果连接失败,就准备下一次连接。 #080 /* Check if we failed while trying to connect */ #081 if ((Connected) && (Error)) #082 { #083 DPRINT1("HalEnableSystemInterrupt failed/n"); #084 KeDisconnectInterrupt(Interrupt); #085 Connected = FALSE; #086 } #087 #088 /* Return to caller */ #089 return Connected; #090} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |