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

📄 ssp.cpp

📁 SM501基于ARMV4/ARMV4I平台
💻 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)
{
	SetBuffer(dwSize, pBuffer);
}

CDataBuffer::~CDataBuffer()
{
	if (m_bOwnBuffer && m_pBuffer)
		delete m_pBuffer;
}

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

	m_head = next(m_head);
	m_pBuffer[m_head] = data;
	return TRUE;
}

BOOL CDataBuffer::GetWord(WORD& data, DWORD timeout)
{
	DWORD start = GetTickCount();
	while (IsEmpty())
	{
		if (timeout != INFINITE)
		{
			DWORD elapsed = GetTickCount() - start;
			if (elapsed > timeout)
				return FALSE;
		}
	}

	m_tail = next(m_tail);
	data = m_pBuffer[m_tail];
	return TRUE;
}

BOOL CDataBuffer::IsFull()
{
	return (next(m_head) == m_tail);
}

BOOL CDataBuffer::IsEmpty()
{
	return (m_head == m_tail);
}

DWORD CDataBuffer::GetLength()
{
	if (m_head >= m_tail)
		return m_head - m_tail;
	else
		return m_size + m_head - m_tail;
}

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

VOID CDataBuffer::SetBuffer(DWORD dwSize, PWORD pBuffer)
{
	// Delete existing own if any
	if (m_bOwnBuffer && m_pBuffer)
	{
		delete m_pBuffer;
		m_pBuffer = NULL;
		m_bOwnBuffer = FALSE;
	}

	// Determine the type of the buffer
	if (pBuffer)
	{
		m_pBuffer = pBuffer;
		m_size = dwSize;
		m_bOwnBuffer = FALSE;
	}
	else
	{
		if (dwSize != 0)
		{
			m_pBuffer = new WORD[dwSize];
			m_size = dwSize;
			m_bOwnBuffer = TRUE;
		}
	}

	// Reset pointers
	Reset();
}

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)
		{
			// Already "open"
			break;
		}

		// Validate "clock_prescale"
		if ((pInit->clock_prescale < 2) ||
			(pInit->clock_prescale > 254) ||
			(pInit->clock_prescale & 1))
		{
			nResult = VGXSSP_INVALID_PRESCALE;
			break;
		}

		// Validate "data_size"
		if ((pInit->data_size < 4) ||
			(pInit->data_size > 16))
		{
			nResult = VGXSSP_INVALID_DATA_SIZE;
			break;

⌨️ 快捷键说明

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