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是访问输入参数的自旋锁。

VectorPNP管理器分配的中断号。

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  }

posted @ 2009-09-25 21:16  ajuanabc  阅读(165)  评论(0编辑  收藏  举报