📄 ssp.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: 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 + -