📄 interrupt.cpp
字号:
// -----------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// Copyright (c) 2002 Silicon Motion, Inc.
//
// Module Name: interrupt.cpp
//
// Abstract: Interrupt Management
//
// -----------------------------------------------------------------------------
#include "precomp.h"
#include <windev.h>
#include "smi.h"
#ifndef DISABLE_INTERRUPT_MANAGEMENT
///////////////////////////////////////////////////////////////////////////////
// Macro for printing debug messages
#if 1
// Print messages only in DEBUG mode
#define MESSAGE DEBUGMSG
#define MESSAGE_ZONE GPE_ZONE_WARNING
#else
// Force messages even in RELEASE mode
#define MESSAGE RETAILMSG
#define MESSAGE_ZONE 0
#endif
///////////////////////////////////////////////////////////////////////////////
// Interrupt thread entry
DWORD WINAPI InterruptThreadEntry(LPVOID lpParameter)
{
return ((SMI*)lpParameter)->InterruptThread();
}
///////////////////////////////////////////////////////////////////////////////
// Interrupt thread
DWORD SMI::InterruptThread()
{
while (1)
{
// Wait for interrupt
if (WaitForSingleObject(m_SMISettings.m_IntInfo.hEvent, INFINITE) == WAIT_OBJECT_0)
{
// Determine which module produced the interrupt
DWORD dwStatus = peekRegisterDWord(INT_STATUS);
if (dwStatus)
{
// Clear the mask register. By doing so we set the interrupt line
// low allowing other interrupts to be detected while handling
// the current interrupt
DWORD dwMask = peekRegisterDWord(INT_MASK);
pokeRegisterDWord(INT_MASK, 0x00000000);
// Scan handlers and find the right one
BOOL bCalled = FALSE;
for (INT i = 0; dwStatus; i++)
{
if (dwStatus & 1)
{
if (m_SMISettings.m_IntInfo.pfnHandler[i])
{
m_SMISettings.m_IntInfo.pfnHandler[i](this);
bCalled = TRUE;
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("SMI::InterruptThread() - no handler is registered (bit %d)\r\n"), i));
}
}
dwStatus >>= 1;
}
// Signal the end of interrupt
if (bCalled)
{
InterruptDone(m_SMISettings.m_IntInfo.SYSINTR);
}
// Restore the mask register
pokeRegisterDWord(INT_MASK, dwMask);
}
// Check if termination is requested
if (m_SMISettings.m_IntInfo.Stop)
return 0;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Interrupt Initialization
void SMI::InitInterrupt()
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::InitInterrupt()\r\n")));
// Init vars
TCHAR* lpszErrCause = NULL;
ZeroMemory(&m_GIISRInfo, sizeof(m_GIISRInfo));
// Determine which handler to use.
m_bStandardISR = (m_SMISettings.m_IntInfo.SYSINTR == 0);
__try
{
// Try to get a SYSINTR from OS
if (m_bStandardISR)
{
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::InitInterrupt()] using the standard ISR handler\r\n")));
// Get SYSINTR for our IRQ
DWORD IRQ = m_SMISettings.m_IRQ; // Has to be a DWORD
DWORD BytesReturned;
if (!KernelIoControl(IOCTL_HAL_TRANSLATE_IRQ,
&IRQ, sizeof(IRQ),
&m_SMISettings.m_IntInfo.SYSINTR, sizeof(m_SMISettings.m_IntInfo.SYSINTR),
&BytesReturned))
{
lpszErrCause = TEXT("IOCTL_HAL_TRANSLATE_IRQ");
__leave;
}
// Report int values
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::InitInterrupt()] IRQ = %d\r\n"), m_SMISettings.m_IRQ));
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::InitInterrupt()] SYSINTR = %d\r\n"), m_SMISettings.m_IntInfo.SYSINTR));
// Load the standard ISR
m_hIsrHandle = LoadIntChainHandler(
TEXT("giisr.dll"),
TEXT("ISRHandler"),
m_SMISettings.m_IRQ);
if (m_hIsrHandle == NULL)
{
lpszErrCause = TEXT("LoadIntChainHandler()");
__leave;
}
// Translate a bus-relative address to a system or logical address,
// then it creates a static, process independent, virtual address mapping for that location
DWORD PortIsIO = FALSE;
PVOID PhysAddr = (PVOID)m_nREGPhysical;
PHYSICAL_ADDRESS PortAddress = {(DWORD)PhysAddr, 0};
if (!TransBusAddrToStatic(
PCIBus, // IN: interface type
m_SMISettings.m_nBusNo, // IN: bus number of the device
PortAddress, // IN: bs-relative address of registers and ports
0x70, // IN: Number of bytes to map on the device
&PortIsIO, // IN/OUT: I/O space or memory space
&PhysAddr)) // OUT: Virtual address where the physical address mapped
{
lpszErrCause = TEXT("TransBusAddrToStatic()");
__leave;
}
// Set up ISR handler
m_GIISRInfo.SysIntr = m_SMISettings.m_IntInfo.SYSINTR;
m_GIISRInfo.CheckPort = TRUE;
m_GIISRInfo.PortIsIO = PortIsIO;
m_GIISRInfo.UseMaskReg = FALSE;
m_GIISRInfo.PortAddr = (DWORD)PhysAddr + 0x2C;
m_GIISRInfo.PortSize = sizeof(DWORD);
m_GIISRInfo.Mask = 0x00000000;
if (!KernelLibIoControl(m_hIsrHandle, IOCTL_GIISR_INFO,
&m_GIISRInfo, sizeof(m_GIISRInfo), NULL, 0, NULL))
{
lpszErrCause = TEXT("IOCTL_GIISR_INFO");
__leave;
}
}
else
{
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::InitInterrupt()] using SMI ISR handler\r\n")));
}
m_bIntInitDone = TRUE;
}
__finally
{
if (lpszErrCause)
{
// Report the error
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::InitInterrupt()] %s returned %d\r\n"), lpszErrCause, GetLastError()));
if (m_hIsrHandle != NULL)
{
FreeIntChainHandler(m_hIsrHandle);
m_hIsrHandle = NULL;
}
}
}
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::InitInterrupt()\r\n")));
}
///////////////////////////////////////////////////////////////////////////////
// Creates an interrupt thread with specified parameters
BOOL SMI::StartIntThread(INTERRUPT_INFO& IntInfo, VGXINTENTRY pfnIntEntry)
{
// Make sure the SYSINTR is initialized
if (IntInfo.SYSINTR == 0)
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::StartIntThread()] SYSINTR is not initialized!\r\n")));
return FALSE;
}
// Create an interrupt event if not created yet
if (IntInfo.hEvent == NULL)
{
IntInfo.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (IntInfo.hEvent == NULL)
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::StartIntThread()] CreateEvent has failed (%d)\r\n"),
GetLastError()));
return FALSE;
}
// Associate SYSINTR with the new event
if (!InterruptInitialize(IntInfo.SYSINTR, IntInfo.hEvent, NULL, 0))
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::StartIntThread()] InterruptInitialize has failed (%d)\r\n"),
GetLastError()));
return FALSE;
}
}
// Create an interrupt thread. The thread has an infinite loop
// waiting for the interrupt event to trigger.
if (IntInfo.hThread == NULL)
{
IntInfo.hThread = CreateThread(NULL, 0, pfnIntEntry, this, 0, NULL);
if (IntInfo.hThread == NULL)
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::StartIntThread()] CreateThread has failed (%d)\r\n"),
GetLastError()));
return FALSE;
}
// Increase the thread priotity (by default its 251)
if (!CeSetThreadPriority(IntInfo.hThread, 5))
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::StartIntThread()] CeSetThreadPriority has failed (%d)\r\n"),
GetLastError()));
return FALSE;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// Deletes an interrupt thread with specified parameters
void SMI::StopIntThread(INTERRUPT_INFO& IntInfo)
{
if (IntInfo.hThread)
{
// Disable the interrupt
InterruptDisable(IntInfo.SYSINTR);
// Stop the thread
IntInfo.Stop = TRUE;
SetEvent(IntInfo.hEvent);
WaitForSingleObject(IntInfo.hThread, INFINITE);
// Release the system resources
CloseHandle(IntInfo.hEvent);
IntInfo.hEvent = NULL;
CloseHandle(IntInfo.hThread);
IntInfo.hThread = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
// Add a custom interrupt handler
BOOL SMI::RegisterHandler(VGXINTHANDLER Handler, DWORD dwMask)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::RegisterHandler()\r\n")));
MESSAGE(MESSAGE_ZONE, (TEXT("[SMI::RegisterHandler()] mask = 0x%08X\r\n"), dwMask));
BOOL bResult = TRUE;
// Make sure the basic init has completed successfuly
if (!m_bIntInitDone)
{
MESSAGE(MESSAGE_ZONE,
(TEXT("[SMI::RegisterHandler()] basic initialization has failed!\r\n")));
bResult = FALSE;
}
else
{
// Verify whether already registered
if ((m_GIISRInfo.Mask & dwMask) != dwMask)
{
// Register the handler
DWORD dwTemp = dwMask;
for (INT i = 0; dwTemp; i++)
{
if (dwTemp & 1)
{
// Register the handler for the interrupt
m_SMISettings.m_IntInfo.pfnHandler[i] = Handler;
}
dwTemp >>= 1;
}
// Create an interrupt thread
if (!StartIntThread(m_SMISettings.m_IntInfo, InterruptThreadEntry))
{
// Reset handler pointers
dwTemp = dwMask;
for (i = 0; dwTemp; i++)
{
if (dwTemp & 1)
m_SMISettings.m_IntInfo.pfnHandler[i] = NULL;
dwTemp >>= 1;
}
bResult = FALSE;
}
else
{
if (m_bStandardISR)
{
// Update the ISR handler
m_GIISRInfo.Mask |= dwMask;
KernelLibIoControl(m_hIsrHandle, IOCTL_GIISR_INFO,
&m_GIISRInfo, sizeof(m_GIISRInfo), NULL, 0, NULL);
}
// Enable the requested interrupt(s)
dwMask |= peekRegisterDWord(INT_MASK);
pokeRegisterDWord(INT_MASK, dwMask);
}
}
}
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::RegisterHandler()\r\n")));
return bResult;
}
///////////////////////////////////////////////////////////////////////////////
// Remove the specified interrupt handler
void SMI::DisableHandler(DWORD dwMask)
{
MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::DisableHandler()\r\n")));
// Verify whether registered
if ((m_GIISRInfo.Mask & dwMask) != 0)
{
// Disable the requested interrupt(s)
DWORD dwNewMask = peekRegisterDWord(INT_MASK) & ~dwMask;
pokeRegisterDWord(INT_MASK, dwNewMask);
if (m_bStandardISR)
{
// Update the ISR handler
if (m_GIISRInfo.PortAddr)
{
m_GIISRInfo.Mask &= ~dwMask;
if (!KernelLibIoControl(m_hIsrHandle, IOCTL_GIISR_INFO,
&m_GIISRInfo, sizeof(m_GIISRInfo), NULL, 0, NULL))
MESSAGE(MESSAGE_ZONE, (TEXT("IOCTL_GIISR_INFO failed!\r\n")));
}
}
// Stop the thread and free resources
if (dwNewMask == 0)
StopIntThread(m_SMISettings.m_IntInfo);
// Blank the handler address
DWORD dwTemp = dwMask;
for (INT i = 0; dwTemp; i++)
{
if (dwTemp & 1)
{
m_SMISettings.m_IntInfo.pfnHandler[i] = NULL;
}
dwTemp >>= 1;
}
}
MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::DisableHandler()\r\n")));
}
#endif // DISABLE_INTERRUPT_MANAGEMENT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -