📄 cem840x.c
字号:
/********************************************************************************************//* cem840x.c : Implementation of the EM8400/EM8401 interface* REALmagic Quasar Hardware Library* Created by Aurelia Popa-Radu* Copyright Sigma Designs Inc* Sigma Designs Proprietary and confidential* Created on 8/1/01* Description:/********************************************************************************************/#include "pch.h"#if defined EM840X_OBJECT#include "cquasar.h"#include "em840x.h"#include "regs840x.h"/****v* HwLib/Q3 * NAME * Q3 * DESCRIPTION * Global array of symbols used to send commands and data to EM8400 through microcode./********************************************************************************************/Q3SymbolTable Q3;UCHAR UCodeQuasar3[] = { #ifdef MICROCODE_NO_DOLBY #include "quasar3/tst_no_dolby.h" // doesn't play dolby no matter the bonding of the chip #else #include "quasar3/tst.h" // play dolby no matter the bonding of the chip #endif};QRESULT InitializeSymbolsTable( IDecoder* pIDecoder );QRESULT CEM840X__SetMicrocode(IDecoder* pIDecoder, DWORD Id){ CQuasar *this = (CQuasar*) pIDecoder; if(Id == ebiUcode_MpegDecode) { this->pUCode = (BYTE*)UCodeQuasar3; this->UCodeSize = sizeof(UCodeQuasar3); this->pQ = (void*)&Q3; // symbol table this->SymbolTableSize = sizeof(Q3); return InitializeSymbolsTable(pIDecoder); } else return E_NOT_SUPPORTED;}/****f* HwLib/IDecoder_InitPtsFifo * USAGE * void IDecoder_InitPtsFifo(IDecoder* pIDecoder, DWORD type) * void CEM840X__InitPtsFifo(IDecoder* pIDecoder, DWORD type) * DESCRIPTION * IDecoder_InitPtsFifo initialize the PTS_FIFO structure associated with "type" stream. * The decoder object keeps 3 PACKETS_FIFO structures for video, audio, subpicture and osd. * IDecoder_InitPtsFifo is called by IDecoderBoard_VideoHwStop, IDecoderBoard_AudioHwStop, * IDecoder_HwReset. * PARAMETERS * IN IDecoder* pIDecoder - pointer to the decoder object * IN DWORD type - one of VIDEO, AUDIO, SUBPICTURE. * SEE ALSO * IDecoder_PtsFifoEmptiness, IDecoder_WritePts/********************************************************************************************/void CEM840X__InitPtsFifo(IDecoder* pIDecoder, DWORD type){#define VPTS_ENTRIES_SIZE 4 // 16 bits words#define APTS_ENTRIES_SIZE 4 // 16 bits words#define SPTS_ENTRIES_SIZE 2 // 16 bits words CQuasar *this = (CQuasar*) pIDecoder; PTS_FIFO* p = &this->PtsFifo[type]; DWORD i; switch (type) { case AUDIO: p->Start = Q3.Audio_PTSFifo.addr; p->EntrySize = APTS_ENTRIES_SIZE; p->Size = CQuasar__ReadDM(pIDecoder, Q3.Audio_PTSSize.addr) / p->EntrySize; CQuasar__WriteDM(pIDecoder, Q3.Audio_PTSRdPtr.addr, p->Start); for (i=0;i<p->Size;i++) CQuasar__WriteDM(pIDecoder, p->Start + 3 + i * p->EntrySize, 0); // disable new PTS entry break; case SUBPICTURE: p->Start = Q3.SP_PTSFifo.addr; p->EntrySize = SPTS_ENTRIES_SIZE; p->Size = CQuasar__ReadDM(pIDecoder, Q3.SP_PTSSize.addr) / p->EntrySize; CQuasar__WriteDM(pIDecoder, Q3.SP_PTSRdPtr.addr, p->Start); for (i=0;i<p->Size;i++) CQuasar__WriteDM(pIDecoder, p->Start + 1 + i * p->EntrySize, 0); // disable new PTS entry break; case VIDEO: default: p->Start = Q3.MV_PTSFifo.addr; p->EntrySize = VPTS_ENTRIES_SIZE; p->Size = CQuasar__ReadDM(pIDecoder, Q3.MV_PTSSize.addr) / p->EntrySize; CQuasar__WriteDM(pIDecoder, Q3.MV_PTSRdPtr.addr, p->Start); for (i=0;i<p->Size;i++) CQuasar__WriteDM(pIDecoder, p->Start + 3 + i * p->EntrySize, 0); // disable new PTS entry break; } p->RdPtr = 0; p->WrPtr = 0; p->Emptiness = p->Size; p->Fullness = 0;}/****f* HwLib/IDecoder_PtsFifoEmptiness * USAGE * DWORD IDecoder_PtsFifoEmptiness(IDecoder* pIDecoder, DWORD type) * DWORD CEM840X__PtsFifoEmptiness(IDecoder* pIDecoder, DWORD type) * DESCRIPTION * IDecoder_PtsFifoEmptiness updates from hardware the RdPtr in PTS_FIFO and calculates * Emptiness and Fullness members of PTS_FIFO. * The fifo is empty when RdPtr==WrPtr and in this case Emptiness=Size, Fullness=0. * The fifo is full when there is only one entry empty and in this case Emptiness=1, Fullness=Size-1. * It is called by IDecoderBoard_SendVideoPayload, IDecoderBoard_SendAudioPayload, * IDecoderBoard_SendSpuPayload, IDecoderBoard_PtsFifoEmptiness. * PARAMETERS * IN IDecoder* pIDecoder - pointer to the decoder object * IN DWORD type - one of VIDEO, AUDIO, SUBPICTURE. * RETURN VALUE * returns Emptiness of the PTS fifo * SEE ALSO * IDecoder_InitPtsFifo, IDecoder_WritePts/********************************************************************************************/DWORD CEM840X__PtsFifoEmptiness(IDecoder* pIDecoder, DWORD type){ CQuasar *this = (CQuasar*) pIDecoder; PTS_FIFO* p = &this->PtsFifo[type]; switch (type) { case AUDIO: p->RdPtr = (CQuasar__ReadDM(pIDecoder, Q3.Audio_PTSRdPtr.addr) - p->Start) / p->EntrySize; break; case SUBPICTURE: p->RdPtr = (CQuasar__ReadDM(pIDecoder, Q3.SP_PTSRdPtr.addr) - p->Start) / p->EntrySize; break; case VIDEO: default: p->RdPtr = (CQuasar__ReadDM(pIDecoder, Q3.MV_PTSRdPtr.addr) - p->Start) / p->EntrySize; break; } p->Emptiness = (p->Size + p->RdPtr - p->WrPtr - 1) % p->Size + 1;// number of empty entries p->Fullness = p->Size - p->Emptiness;// number of non-empty entries if( p->Emptiness == 1) { QDbgLog((QLOG_TRACE, QDebugLevelTrace, TEXT("%s FifoPts E=%x F=%x Rd=%x Wr=%x"), (type==AUDIO)?"A": (type==VIDEO)?"V":"S", p->Emptiness, p->Fullness, p->RdPtr, p->WrPtr )); } return p->Emptiness;}/****f* HwLib/IDecoder_WritePTS * USAGE * BOOL IDecoder_WritePTS(IDecoder* pIDecoder, DWORD type, DWORD ByteCount, MPEG_SCR pts) * BOOL CEM840X__WritePTS(IDecoder* pIDecoder, DWORD type, DWORD ByteCount, MPEG_SCR pts) * DESCRIPTION * SCR(system clock reference) and PTS(presentation time stamp) have 90kHz unit and they * are represeted on 33 bits. * Our Mpeg2 decoder has 45kHz unit for SCR and PTS in order to use only 32 bits representation. * IDecoder_WritePTS writes a PTS in the circular PTS_FIFO without checking if there is * place for a new entry. This means that it is possible to overwrite a PTS not consummed * yet by the decoder. The caller should check overwriting using IDecoder_PtsFifoEmptiness. * It is called by IDecoderBoard_SendVideoPayload, IDecoderBoard_SendAudioPayload, * IDecoderBoard_SendSpuPayload. * PARAMETERS * IN IDecoder* pIDecoder - pointer to the decoder object * IN DWORD type - one of VIDEO, AUDIO, SUBPICTURE. * IN DWORD ByteCount - number of bytes sent already to the hardware. * IN DWORD pts - presentation time stamp in 90KHz units of the next packet of data. * RETURN VALUE * TRUE * SEE ALSO * IDecoder_InitPtsFifo, IDecoder_PtsFifoEmptiness/********************************************************************************************/BOOL CEM840X__WritePTS(IDecoder* pIDecoder, DWORD type, DWORD ByteCount, MPEG_SCR PtsIn){// pts is in 45kHz units = 22.(2)us units CQuasar *this = (CQuasar*) pIDecoder; PTS_FIFO* p = &this->PtsFifo[type & ~CTS_AVAILABLE_FLAG]; // Size, RdPtr, WrPtr are in "EntrySize" units, RdPtr, WrPtr are relative to Start int AbsoluteWrPtr = p->Start + p->EntrySize * p->WrPtr; DWORD pts = DWORDLONG_Cast_DWORD(PtsIn); p->WrPtr = (p->WrPtr + 1)%p->Size; QDbgLog((QLOG_TRACE, QDebugLevelTrace, TEXT("%s WrPTS45k= %x n= %x"), (type==AUDIO)?"A": (type==VIDEO)?"V":"S", pts, ByteCount)); switch (type) { case SUBPICTURE: CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 0, HIWORD(pts)); CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 1, (LOWORD(pts)) | 1); // enable new PTS entry break; case AUDIO: case VIDEO: default: CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 0, HIWORD(ByteCount)); CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 1, LOWORD(ByteCount)); CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 2, HIWORD(pts)); CQuasar__WriteDM(pIDecoder, AbsoluteWrPtr + 3, (LOWORD(pts)) | 1); // enable new PTS entry break; } return TRUE;}/****f* HwLib/IDecoder_WritePCR * USAGE * QRESULT IDecoder_WritePCR(IDecoder* pIDecoder, MPEG_SCR pcr) * QRESULT CEM840X__WritePCR(IDecoder* pIDecoder, MPEG_SCR pcr) * DESCRIPTION * PCR has 45kHz unit in order to use only 32 bits representation. * IDecoder_WritePCR writes a PCR after checking if there is place for a new entry. This means that it is possible to overwrite a PTS not consummed/********************************************************************************************/QRESULT CEM840X__WritePCR(IDecoder* pIDecoder, MPEG_SCR PcrIn){ // pts is in 45kHz units = 22.(2)us units DWORD pts = DWORDLONG_Cast_DWORD(PcrIn); if( IDecoder_ReadDM(pIDecoder, Q3.PCR_Frac.addr) == 0 ) { IDecoder_WriteDM(pIDecoder, Q3.PCR_Hi.addr, HIWORD(pts) ); IDecoder_WriteDM(pIDecoder, Q3.PCR_Lo.addr, LOWORD(pts) ); IDecoder_WriteDM(pIDecoder, Q3.PCR_Frac.addr, 1 ); return Q_OK; } return Q_FAIL;}QRESULT CEM840X__SetProperty( IDecoder* pIDecoder, DWORD PropSet, DWORD PropId, DWORD Flags, void* pData, DWORD dwSizeIn, DWORD* pdwSizeOut){ CQuasar *this = (CQuasar*) pIDecoder; // DECODER use DWORD for changing information and size condition is already checked DWORD Value = *(DWORD*)pData; // QRESULT qr = Q_OK; QDbgLog((QLOG_TRACE, QDebugLevelTrace, TEXT(" --> CEM840X__SetProperty: set=%x id=%x flags=%x sz=%x value=%x"), PropSet, PropId, Flags, dwSizeIn, Value)); switch(PropId) { case edecAudioInOutConfig: // Normal=I2SInv doesn't need EM84xx frame inversion! this->SerialCtrl0Config = Q3_ASctrl0_CkoutInverted | Q3_ASctrl0_MSbitfirst; // I2S needs EM84xx frame inversion! if(Value == I2S_SCkinSCIN_Jda1CkinGCK_ScinIN_DamckIN) this->SerialCtrl0Config |= Q3_ASctrl0_FrameInverted; this->SerialCtrl1Config = Q3_ASctrl1_Irclkin; return E_NOT_SUPPORTED; default: return CQuasar__SetProperty(pIDecoder, PropSet, PropId, Flags, pData, dwSizeIn, pdwSizeOut); } return Q_OK;}QRESULT CEM840X__GetProperty( IDecoder* pIDecoder, DWORD PropSet, DWORD PropId, DWORD Flags, void* pData, DWORD dwSizeIn, DWORD* pdwSizeOut){ // CQuasar *this = (CQuasar*) pIDecoder; // DECODER use DWORD for changing information and size condition is already checked DWORD Value; switch(PropId) { case edecAudioInOutConfig: return E_NOT_SUPPORTED; default: return CQuasar__GetProperty(pIDecoder, PropSet, PropId, Flags, pData, dwSizeIn, pdwSizeOut); } *(DWORD*)pData = Value; QDbgLog((QLOG_TRACE, QDebugLevelTrace, TEXT(" <-- CEM840X__GetProperty: set=%x id=%x flags=%x sz=%x value=%x"), PropSet, PropId, Flags, dwSizeIn, Value)); return Q_OK;}void CEM840X__InitPropertySet(IDecoder* pIDecoder, void* pPropSet, DWORD dwSize){ CQuasar *this = (CQuasar*) pIDecoder; if(dwSize != sizeof(PROPERTY_SET_ITEM)) return; InitPropSet(pIDecoder, pPropSet, DECODER_SET, edecMax,\ this->DecoderPropertyList, CEM840X__SetProperty, CEM840X__GetProperty)}QRESULT CEM840X__SetPIODir(IDecoder* pIDecoder, DWORD PIONumber, DWORD Dir){ CQuasar *this = (CQuasar*) pIDecoder; if(PIONumber < 8) CQuasar__WriteReg(pIDecoder, this->Pio07DirReg, ((Dir ? 0x0101:0x0100) << PIONumber) ); else return Q_FAIL; return Q_OK;}QRESULT CEM840X__WritePIO(IDecoder* pIDecoder, DWORD PIONumber, DWORD Data){ CQuasar *this = (CQuasar*) pIDecoder; // don't assume that PIO is output if(PIONumber < 8) { CQuasar__WriteReg(pIDecoder, this->Pio07DataReg, ((Data? 0x0101:0x0100) << PIONumber)); CQuasar__WriteReg(pIDecoder, this->Pio07DirReg, (0x0101 << PIONumber)); } else return Q_FAIL; return Q_OK;}QRESULT CEM840X__ReadPIO(IDecoder* pIDecoder, DWORD PIONumber, DWORD* pData){ CQuasar *this = (CQuasar*) pIDecoder; // don't assume that PIO is input if(PIONumber < 8) { CQuasar__WriteReg(pIDecoder, this->Pio07DirReg, (0x0100 << PIONumber) ); *pData = (CQuasar__ReadReg(pIDecoder, this->Pio07DataReg) & (0x0100 << PIONumber)) ? 1:0; } else return Q_FAIL; return Q_OK;}QRESULT CEM840X__SetAudioSampleRate(IDecoder* pIDecoder, DWORD Rate){ CQuasar *this = (CQuasar*) pIDecoder; this->CurrentAudioRate = Rate; QDbgLog((QLOG_TRACE, QDebugLevelTrace, TEXT(" CQ__SetAudioSampleRate=%lu"), Rate)); if( this->AudioSampleRateSupport_96kHz ) { this->ChannelStatus = (this->ChannelStatus & ~Q3_ASpdifStat1_rate) | ((Rate==32000) ? Q3_ASpdifStat1_32k : ((Rate==44100) ? Q3_ASpdifStat1_44k : ((Rate==88200) ? Q3_ASpdifStat1_88k : ((Rate==96000) ? Q3_ASpdifStat1_96k : Q3_ASpdifStat1_48k)))); } else { this->ChannelStatus = (this->ChannelStatus & ~Q3_ASpdifStat1_rate) |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -