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

📄 ssp.cpp

📁 Sm501 VGA芯片wince下驱动代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// -----------------------------------------------------------------------------
//
//  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:	ssp.cpp
//
//  Abstract:		SSP API
//
// -----------------------------------------------------------------------------

#include "precomp.h"


///////////////////////////////////////////////////////////////////////////////
// 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


#ifndef DISABLE_INTERRUPT_MANAGEMENT

///////////////////////////////////////////////////////////////////////////////
// SSP read buffer class.

CDataBuffer::CDataBuffer(DWORD dwSize, PWORD pBuffer)
	: m_bOwnBuffer(FALSE)
	, m_pBuffer(NULL)
{
	if (pBuffer)
		SetData(pBuffer, dwSize);
	else
		SetBuffer(dwSize);
}

CDataBuffer::~CDataBuffer()
{
	SetBuffer(0);
}

BOOL CDataBuffer::PutWord(WORD data)
{
	// Fail if full
	if (IsFull())
	{
		m_bOverrun = TRUE;
		return FALSE;
	}

	// Do not advance if the buffer is empty
	if (m_count)
		m_head = next(m_head);

	// Store the data
	m_pBuffer[m_head] = data;

	// Update the data counter
	m_count++;

	return TRUE;
}

BOOL CDataBuffer::GetWord(WORD& data, DWORD timeout)
{
	MESSAGE(MESSAGE_ZONE, (TEXT("[CDataBuffer::GetWord] +++\r\n")));

	// Wait for the data to arrive
	DWORD start = GetTickCount();
	while (IsEmpty())
	{
		if (timeout != INFINITE)
		{
			DWORD elapsed = GetTickCount() - start;
			if (elapsed > timeout)
				return FALSE;
		}
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("[CDataBuffer::GetWord] buffer=0x%p, size=%d, count=%d, head=%d, tail=%d\r\n"),
		m_pBuffer, m_size, m_count, m_head, m_tail));

	// Read the data
	data = m_pBuffer[m_tail];

	// Update the data counter
	m_count--;

	// Do not advance if the buffer is empty
	if (m_count)
		m_tail = next(m_tail);

	MESSAGE(MESSAGE_ZONE, (TEXT("[CDataBuffer::GetWord] updated tail=%d\r\n"), m_tail));

	MESSAGE(MESSAGE_ZONE, (TEXT("[CDataBuffer::GetWord] ---\r\n")));
	return TRUE;
}

BOOL CDataBuffer::IsFull()
{
	return (m_count >= m_size);
}

BOOL CDataBuffer::IsEmpty()
{
	return (m_count == 0);
}

DWORD CDataBuffer::GetLength()
{
	return m_count;
}

VOID CDataBuffer::Reset()
{
	m_count = 0;
	m_head = 0;
	m_tail = 0;
	m_bOverrun = FALSE;
}

VOID CDataBuffer::SetBuffer(DWORD dwSize)
{
	// Delete existing own if any
	if (m_pBuffer)
	{
		if (m_bOwnBuffer)
		{
			delete m_pBuffer;
			m_bOwnBuffer = FALSE;
		}
		m_size = 0;
		m_pBuffer = NULL;
	}

	// Set new buffer
	if (dwSize)
	{
		m_pBuffer = new WORD[dwSize];
		m_size = dwSize;
		m_bOwnBuffer = TRUE;
	}

	// Reset pointers and status info
	Reset();
}

VOID CDataBuffer::SetData(PWORD pBuffer, DWORD dwSize)
{
	// Delete existing own if any
	SetBuffer(0);

	// Set new buffer
	if (pBuffer && dwSize)
	{
		m_pBuffer = pBuffer;
		m_size = dwSize;
		m_bOwnBuffer = FALSE;
		m_count = m_size;
		m_head = m_count - 1;
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("[CDataBuffer::SetData] buffer=0x%p, size=%d, count=%d, head=%d, tail=%d\r\n"),
		m_pBuffer, m_size, m_count, m_head, m_tail));
}

DWORD CDataBuffer::next(DWORD pos)
{
	pos++;
	if (pos >= m_size)
		pos = 0;
	return pos;
}


///////////////////////////////////////////////////////////////////////////////
// SSP Interrupt Handler Entries.

VOID ssp0IntHandlerEntry(SMI* pSMI)
{
	pSMI->sspIntHandler(SSP0);
}

VOID ssp1IntHandlerEntry(SMI* pSMI)
{
	pSMI->sspIntHandler(SSP1);
}

#endif	// DISABLE_INTERRUPT_MANAGEMENT


///////////////////////////////////////////////////////////////////////////////
// SSP API Command Handler.

ULONG SMI::HandleSMISSPAPI(ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::HandleSMISSPAPI\r\n")));
	ULONG ulRetVal = VGXI2C_INVALID_PARAMETER;

	if ((cjIn >= sizeof(VGXSSP_STRUCT)) && (pvIn != NULL))
	{
		PVGXSSP_STRUCT pIn = (PVGXSSP_STRUCT)pvIn;

		switch (pIn->command)
		{
		case VGXSSPCMD_OPEN:
			if ((cjIn == sizeof(VGXSSP_OPEN_STRUCT)) &&
				(cjOut == 0) && (pvOut == NULL))
			{
				ulRetVal = sspOpen((PVGXSSP_OPEN_STRUCT)pvIn);
			}
			break;

		case VGXSSPCMD_CLOSE:
			if ((cjIn == sizeof(VGXSSP_STRUCT)) &&
				(cjOut == 0) && (pvOut == NULL))
			{
				ulRetVal = sspClose(((PVGXSSP_STRUCT)pvIn)->ssp);
			}
			break;

		case VGXSSPCMD_READ:
			if ((cjIn == sizeof(VGXSSP_STRUCT)) &&
				(cjOut > sizeof(VGXSSP_TRANSMIT_RESULT)) && (pvOut != NULL))
			{
				ulRetVal = sspRead(
					((PVGXSSP_STRUCT)pvIn)->ssp,						// SSP number
					(PBYTE)pvOut + sizeof(VGXSSP_TRANSMIT_RESULT),		// Read buffer pointer
					cjOut - sizeof(VGXSSP_TRANSMIT_RESULT),				// Number of bytes to read
					((PVGXSSP_TRANSMIT_RESULT)pvOut)->read);			// Number of data units read
			}
			break;

		case VGXSSPCMD_WRITE:
			if ((cjIn > sizeof(VGXSSP_STRUCT)) &&
				(cjOut == sizeof(VGXSSP_TRANSMIT_RESULT)) && (pvOut != NULL))
			{
				ulRetVal = sspWrite(
					((PVGXSSP_STRUCT)pvIn)->ssp,						// SSP number
					(PBYTE)pvIn + sizeof(VGXSSP_STRUCT),				// Write buffer
					cjIn - sizeof(VGXSSP_STRUCT),						// Number of bytes to write
					((PVGXSSP_TRANSMIT_RESULT)pvOut)->written);			// Number of data units written
			}
			break;

		case VGXSSPCMD_RESET_BUFFER:
			if ((cjIn == sizeof(VGXSSP_STRUCT)) &&
				(cjOut == 0) && (pvOut == NULL))
			{
				ulRetVal = sspResetBuffer(((PVGXSSP_STRUCT)pvIn)->ssp);
			}
			break;

		default:
			MESSAGE(MESSAGE_ZONE, (TEXT("SMI::HandleSMISSPAPI: invalid command has been specified\r\n")));
		}
	}
	else
	{
		MESSAGE(MESSAGE_ZONE,
			(TEXT("SMI::HandleSMISSPAPI: invalid input structure\r\n")));
	}

	MESSAGE(MESSAGE_ZONE, (TEXT("-SMI::HandleSMISSPAPI\r\n")));
	return ulRetVal;
}


///////////////////////////////////////////////////////////////////////////////
// SSP Start-up Initialization.

VOID SMI::InitSSP()
{
#ifndef DISABLE_INTERRUPT_MANAGEMENT

	for (INT i = 0; i < SSP_COUNT; i++)
	{
		m_SSPInfo[i].Active = FALSE;
		m_SSPInfo[i].writeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	}

	m_SSPInfo[SSP0].IntHandler     = ssp0IntHandlerEntry;
	m_SSPInfo[SSP0].dwIntMask      = _F_MASK(INT_MASK_SSP0);
	m_SSPInfo[SSP0].dwControl0Reg  = SSP_0_CONTROL_0;
	m_SSPInfo[SSP0].dwControl1Reg  = SSP_0_CONTROL_1;
	m_SSPInfo[SSP0].dwDataReg      = SSP_0_DATA;
	m_SSPInfo[SSP0].dwStatusReg    = SSP_0_STATUS;
	m_SSPInfo[SSP0].dwPrescaleReg  = SSP_0_CLOCK_PRESCALE;
	m_SSPInfo[SSP0].dwIntStatusReg = SSP_0_INTERRUPT_STATUS;

	m_SSPInfo[SSP1].IntHandler     = ssp1IntHandlerEntry;
	m_SSPInfo[SSP1].dwIntMask      = _F_MASK(INT_MASK_SSP1);
	m_SSPInfo[SSP1].dwControl0Reg  = SSP_1_CONTROL_0;
	m_SSPInfo[SSP1].dwControl1Reg  = SSP_1_CONTROL_1;
	m_SSPInfo[SSP1].dwDataReg      = SSP_1_DATA;
	m_SSPInfo[SSP1].dwStatusReg    = SSP_1_STATUS;
	m_SSPInfo[SSP1].dwPrescaleReg  = SSP_1_CLOCK_PRESCALE;
	m_SSPInfo[SSP1].dwIntStatusReg = SSP_1_INTERRUPT_STATUS;

#endif	// DISABLE_INTERRUPT_MANAGEMENT
}


#ifndef DISABLE_INTERRUPT_MANAGEMENT

///////////////////////////////////////////////////////////////////////////////
// SSP Interrupt Handler.

VOID SMI::sspIntHandler(VGXSSP_ENUM ssp)
{
	// Read interrupt status.
	DWORD dwIntStatus = peekRegisterDWord(m_SSPInfo[ssp].dwIntStatusReg);

	// Check for "transmit FIFO" interrupt.
	if (FIELD_GET(dwIntStatus, SSP_0_INTERRUPT_STATUS, TRANSMIT)
		== SSP_0_INTERRUPT_STATUS_TRANSMIT_ACTIVE)
	{
		while (FIELD_GET(peekRegisterDWord(m_SSPInfo[ssp].dwStatusReg), SSP_0_STATUS, TRANSMIT_FIFO) !=
			SSP_0_STATUS_TRANSMIT_FIFO_FULL)
		{
			WORD data;
			if (!m_SSPInfo[ssp].writeBuffer.GetWord(data))
			{
				// No more data to transmit - disable "transmit FIFO" interrupt
				pokeRegisterDWord(m_SSPInfo[ssp].dwControl1Reg,
					FIELD_SET(peekRegisterDWord(m_SSPInfo[ssp].dwControl1Reg),
						SSP_0_CONTROL_1, TRANSMIT_INTERRUPT, DISABLE));

				// Set the event
				SetEvent(m_SSPInfo[ssp].writeEvent);

				// Stop the cycle
				break;
			}

			// Send the data out
			pokeRegisterDWord(m_SSPInfo[ssp].dwDataReg, data);
		}
	}

	// Check for "receive FIFO" interrupt.
	if (FIELD_GET(dwIntStatus, SSP_0_INTERRUPT_STATUS, RECEIVE)
		== SSP_0_INTERRUPT_STATUS_RECEIVE_ACTIVE)
	{
		while (FIELD_GET(peekRegisterDWord(m_SSPInfo[ssp].dwStatusReg), SSP_0_STATUS, RECEIVE_FIFO) !=
			SSP_0_STATUS_RECEIVE_FIFO_EMPTY)
		{
			m_SSPInfo[ssp].readBuffer.PutWord(
				(WORD)peekRegisterDWord(m_SSPInfo[ssp].dwDataReg));
		}
	}

	// Check for "read FIFO" overrun.
	if (FIELD_GET(dwIntStatus, SSP_0_INTERRUPT_STATUS, OVERRUN)
		== SSP_0_INTERRUPT_STATUS_OVERRUN_ACTIVE)
	{
		// Clear overrun interrupt.
		pokeRegisterDWord(m_SSPInfo[ssp].dwIntStatusReg, dwIntStatus);

		// Set overrun flag
		m_SSPInfo[ssp].readBuffer.m_bOverrun = TRUE;
	}
}

#endif	// DISABLE_INTERRUPT_MANAGEMENT


///////////////////////////////////////////////////////////////////////////////
// Opens specified SSP channel.

ULONG SMI::sspOpen(PVGXSSP_OPEN_STRUCT pInit)
{
	MESSAGE(MESSAGE_ZONE, (TEXT("+SMI::sspOpen\r\n")));

#ifdef DISABLE_INTERRUPT_MANAGEMENT

	ULONG nResult = VGXSSP_NOT_SUPPORTED;

#else
	
	ULONG nResult = VGXSSP_SUCCESS;

	do
	{
		// Validate "ssp"
		if ((pInit->ssp != SSP0) &&
			(pInit->ssp != SSP1))
		{
			nResult = VGXSSP_INVALID_SSP;
			break;
		}

		// Make sure UART1 is not active
		if ((pInit->ssp == SSP1) && IsUART1Active())
		{
			nResult = VGXSSP_UART1_ACTIVE;
			break;
		}

		if (m_SSPInfo[pInit->ssp].Active)
		{

⌨️ 快捷键说明

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