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

📄 interrupt.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 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 + -