⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupt.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
字号:
//
// Permedia3 Sample Display Driver
// interrupt.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This module manages the interrupts coming from the Permedia3. It sets
// up the software necessary to process those interrupts, sets the
// Permedia3 to genertae the desired interrupts, and calls the appropriate
// helper code when an interrupt occurs.

#include "pch.h"  // Precompiled header support.
#include "debug.h"
#include "struct.h"
#include "global.h"
#include "const.h"
#include "proto.h"
#include "register.h"

// This structure is passed to the kernel IO control to turn a  PCI IRQ to
// a system IRQ.

typedef struct t_HAL_TRANSLATE_IRQ_BUFFER {

  ULONG InterruptNumber;
  ULONG InterruptVector;

} HAL_TRANSLATE_IRQ_BUFFER;

// We need a thread to act as the IST, and event for the kernel to set to
// activate the IST thread.

static HANDLE l_IstThread;
static HANDLE l_IstEvent;

// The interrupt's system identifier.

static ULONG l_Irq;

// These are used when we have a thread waiting for the vertical retrace
// interrupt.

static BOOL l_IsVsyncEvent;
static HANDLE l_VsyncEvent;

// These are used when we have a pending flip.

static BOOL l_IsFlipWaiting;
static LPVOID l_NewPrimary;

// Internal prototypes. These functions are not exposed outside this module.

static DWORD 
IstThreadProcess(
  LPVOID Parameter 
  );

BOOL
InitializeInterrupts()
{
  // InitializeInterrupts
  // This function sets up the thread that will respond to Permedia3 
  // interrupts, and configures the card to generate interrupts on the
  // events we need.

  // Local variables.

  BOOL                      FnRetVal = FALSE;
  HAL_TRANSLATE_IRQ_BUFFER  Buffer;
  ULONG                     BytesReturned = 0;

  Enter(L"InitializeInterrupts");

  // Bind the event and thread to the interrupt. First, map the PCI IRQ
  // to a system IRQ.

  Buffer.InterruptNumber = g_Config.PciCommonConfig.u.type0.InterruptLine;
  Buffer.InterruptVector = 0;

  if (KernelIoControl(IOCTL_HAL_TRANSLATE_IRQ,
                      &Buffer,
                      sizeof(Buffer),
                      &l_Irq,
                      sizeof(l_Irq),
                      &BytesReturned)) {

    // Assert(BytesReturned == sizeof(l_Irq));

    // Create the kernel objects necessary for interrupt support.

    l_IstEvent = CreateEvent(NULL,  // No security descriptors in CE
                             FALSE, // Auto reset
                             FALSE, // Initially not signaled
                             NULL); // No name
    if (l_IstEvent != NULL) {

      // This is a system call, don't confuse with InitializeInterrupts,
      // the call we are in now. This converts the regular event into an
      // interrupt event. This must happen before the IST is created/started.

      if (InterruptInitialize(l_Irq,
                              l_IstEvent,
                              NULL,  // No data block
                              0)) {  // No data block

        l_IstThread = CreateThread(NULL,  // No security descriptor on CE
                                   0,     // default stack size
                                   IstThreadProcess,
                                   NULL,  // No parameters to IstThreadProcess
                                   0,     // Run immeditatly
                                   NULL); // No thread id

        if (l_IstThread != NULL) {

          // Initialize command variables to reasonable defaults.

          l_IsFlipWaiting = FALSE;
          l_NewPrimary = NULL;

          l_IsVsyncEvent = FALSE;
          l_VsyncEvent = CreateEvent(NULL,  // No security descriptor on CE
                                     FALSE, // Auto-reset
                                     FALSE, // Initially not signaled
                                     NULL); // No name

          if (l_VsyncEvent != NULL) {

            // This causes the IST to run, and block on the IstEvent, waiting
            // for the first interrupt.

            CeSetThreadPriority(l_IstThread, IST_PRIORITY);

            WaitForInputFIFO(1);

            // Enable the vertical blank interrupts.

            WriteRegUlong(r_IntEnable,
                          b_IntEnable_VerticalRetraceInterruptEnable);

            FnRetVal = TRUE;

            Message(L"Vertical retrace interrupt enabled.\n");

          }
          else {
            Error(L"Unable to create event for waiting on vsync.\n");
          }
        }
        else {
          Error(L"Unable to crate thread for IST.\n");
        }
      }
      else {
        Error(L"Unable to get system IRQ value.\n");
      }
    }
    else {
      Error(L"Unable to create event for IST.\n");
    }
  }
  else {
    Error(L"Unable to bind interrupt event.\n");
  }

  Exit(L"InitializeInterrupts");

  return FnRetVal;
}

DWORD 
IstThreadProcess(
  LPVOID Parameter 
  )
{
  // IstThreadProcess
  // This is the function that the IST runs. It spends it's time waiting for
  // an interrupt to occur. When one does (the interrupt event is signaled,)
  // this thread handles it.

  // Local variables.

  ULONG IntFlags;

  // Check parameters.

  Assert(Parameter == NULL);

  Enter(L"IstThreadProcess");

  // !TODO! FIFO space checks?

  while (1) {

    WaitForSingleObject(l_IstEvent, INFINITE);

    // An interrupt has occured! Process it.

    IntFlags = ReadRegUlong(r_IntFlags);
    
    if (IntFlags & b_IntFlags_VerticalRetrace) {

      // Do DMA processing.

      DMAInterrupt();

      // Check to see if we have a thread waiting on the vertical retrace
      // interrupt.

      if (l_IsVsyncEvent) {

        SetEvent(l_VsyncEvent);
      }

      // If we have a pending flip, do it now.

      if (l_IsFlipWaiting) {

        SetScreenBase(l_NewPrimary);
        l_IsFlipWaiting = FALSE;
      }
    }

    // Simply clear all pending interrupts. Read the register to flush the
    // write.

    WriteRegUlong(r_IntFlags, IntFlags);
    IntFlags = ReadRegUlong(r_IntFlags);

    // We're finished with this interrupt.

    InterruptDone(l_Irq);
  }

  Exit(L"IstThreadProcess");

  return 0;  // We do not use the return value from this function.
}

BOOL
WaitForVerticalSync()
{
  // WaitForVerticalSync
  // This function is called to make the current thread sleep until the next
  // vertical retrace interrupt. It returns FALSE if another thread is already
  // waiting on the interrupt.

  // Local variables.

  BOOL  FnRetVal = FALSE;
  DWORD WaitReturn;

  Enter(L"WaitForVeticalSync");

  if (!l_IsVsyncEvent) {

    // Worse case : we are prempted right after l_IsVsyncEvent is set to
    // TRUE, and then we hit a vertical retrace. This causes l_VsyncEvent to
    // be harmlessly set with no threads waiting. We also miss that vsync.

    l_IsVsyncEvent = TRUE;
    
    WaitReturn = WaitForSingleObject(l_VsyncEvent,
                                     20000);

    l_IsVsyncEvent = FALSE;

    switch (WaitReturn) {

    case WAIT_OBJECT_0:

      FnRetVal = TRUE;
      break;

    case WAIT_TIMEOUT:

      Error(L"Timeout waiting for vertical retrace!\n");
      break;

    case WAIT_FAILED:

      Error(L"Wait on vertical retrace failed\n");
      break;
    }
  }
  else {

    Message(L"Another thread is already waiting on the vsync!\n");
  }

  Exit(L"WaitForVerticalSync");

  return FnRetVal;
}

BOOL
FlipPrimaryOnVSync(
  LPVOID NewPrimary
  )
{
  // FlipPrimaryOnVSync
  // This function is called with a pointer into video memory to use as the
  // new primary surface. (We assume it is the right size and format.) This
  // function schedules the flip to take place on the next vsync. It returns
  // FALSE if a flip is already pending.

  // Local variables.

  BOOL FnRetVal = FALSE;

  // Check parameters.

  // !TODO!

  Enter(L"FlipPrimaryOnVSync");

  if (!l_IsFlipWaiting) {

    l_NewPrimary = NewPrimary;
    l_IsFlipWaiting = TRUE;
    FnRetVal = TRUE;
  }
  else {

    Message(L"Flip already pending.\n");
  }

  Exit(L"FlipPrimaryOnVSync");

  return FnRetVal;
}

BOOL
IsFlipPending()
{
  // IsFlipPending
  // This function returns TRUE if a flip is still pending, FALSE otherwise.
  // No Enter/Exit semantics for inline candidates.

  return (l_IsFlipWaiting);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -