diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kerneltest/e32test/dma/dmasim.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kerneltest/e32test/dma/dmasim.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,927 @@ +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\dma\dmasim.cpp +// DMA framework Platform Specific Layer (PSL) for software-emulated +// DMA controller used for testing the DMA framework PIL. +// +// + +#include +#include + + +const char KDmaPanicCat[] = "DMASIM"; + +const TInt KMaxTransferSize = 0x1FFF; +const TInt KMemAlignMask = 3; // memory addresses passed to DMAC must be multiple of 4 +const TInt KBurstSize = 0x800; + +typedef void (*TPseudoIsr)(); + +const TInt KChannelCount = 4; // # of channels per controller +const TInt KDesCount = 256; // # of descriptors allocated per controller + +////////////////////////////////////////////////////////////////////////////// +// SOFTWARE DMA CONTROLLER SIMULATION +////////////////////////////////////////////////////////////////////////////// + +class DmacSb +/** Single-buffer DMA controller software simulation */ + { +public: + enum { ECsRun = 0x80000000 }; +public: + static void DoTransfer(); +private: + static void BurstTransfer(); +private: + static TInt CurrentChannel; +public: + // pseudo registers + static TUint8* SrcAddr[KChannelCount]; + static TUint8* DestAddr[KChannelCount]; + static TInt Count[KChannelCount]; + static TUint32 ControlStatus[KChannelCount]; + static TUint32 CompletionInt; + static TUint32 ErrorInt; + // hook for pseudo ISR + static TPseudoIsr Isr; + // transfer failure simulation + static TInt FailCount[KChannelCount]; + }; + +TUint8* DmacSb::SrcAddr[KChannelCount]; +TUint8* DmacSb::DestAddr[KChannelCount]; +TInt DmacSb::Count[KChannelCount]; +TUint32 DmacSb::ControlStatus[KChannelCount]; +TUint32 DmacSb::CompletionInt; +TUint32 DmacSb::ErrorInt; +TPseudoIsr DmacSb::Isr; +TInt DmacSb::FailCount[KChannelCount]; +TInt DmacSb::CurrentChannel; + +void DmacSb::DoTransfer() + { + if (ControlStatus[CurrentChannel] & ECsRun) + { + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) + { + ControlStatus[CurrentChannel] &= ~ECsRun; + ErrorInt |= 1 << CurrentChannel; + Isr(); + } + else + { + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer channel %d", CurrentChannel)); + if (Count[CurrentChannel] == 0) + { + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer transfer complete")); + ControlStatus[CurrentChannel] &= ~ECsRun; + CompletionInt |= 1 << CurrentChannel; + Isr(); + } + else + BurstTransfer(); + } + } + + CurrentChannel++; + if (CurrentChannel >= KChannelCount) + CurrentChannel = 0; + } + +void DmacSb::BurstTransfer() + { + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::BurstTransfer")); + TInt s = Min(Count[CurrentChannel], KBurstSize); + memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s); + Count[CurrentChannel] -= s; + SrcAddr[CurrentChannel] += s; + DestAddr[CurrentChannel] += s; + } + +////////////////////////////////////////////////////////////////////////////// + +class DmacDb +/** Double-buffer DMA controller software simulation */ + { +public: + enum { ECsRun = 0x80000000, ECsPrg = 0x40000000 }; +public: + static void Enable(TInt aIdx); + static void DoTransfer(); +private: + static TInt CurrentChannel; +private: + // internal pseudo-registers + static TUint8* ActSrcAddr[KChannelCount]; + static TUint8* ActDestAddr[KChannelCount]; + static TInt ActCount[KChannelCount]; +public: + // externally accessible pseudo-registers + static TUint32 ControlStatus[KChannelCount]; + static TUint8* PrgSrcAddr[KChannelCount]; + static TUint8* PrgDestAddr[KChannelCount]; + static TInt PrgCount[KChannelCount]; + static TUint32 CompletionInt; + static TUint32 ErrorInt; + // hook for pseudo ISR + static TPseudoIsr Isr; + // transfer failure simulation + static TInt FailCount[KChannelCount]; + static TInt InterruptsToMiss[KChannelCount]; + }; + +TUint8* DmacDb::PrgSrcAddr[KChannelCount]; +TUint8* DmacDb::PrgDestAddr[KChannelCount]; +TInt DmacDb::PrgCount[KChannelCount]; +TUint8* DmacDb::ActSrcAddr[KChannelCount]; +TUint8* DmacDb::ActDestAddr[KChannelCount]; +TInt DmacDb::ActCount[KChannelCount]; +TUint32 DmacDb::ControlStatus[KChannelCount]; +TUint32 DmacDb::CompletionInt; +TUint32 DmacDb::ErrorInt; +TPseudoIsr DmacDb::Isr; +TInt DmacDb::FailCount[KChannelCount]; +TInt DmacDb::InterruptsToMiss[KChannelCount]; +TInt DmacDb::CurrentChannel; + +void DmacDb::Enable(TInt aIdx) + { + if (ControlStatus[aIdx] & ECsRun) + ControlStatus[aIdx] |= ECsPrg; + else + { + ActSrcAddr[aIdx] = PrgSrcAddr[aIdx]; + ActDestAddr[aIdx] = PrgDestAddr[aIdx]; + ActCount[aIdx] = PrgCount[aIdx]; + ControlStatus[aIdx] |= ECsRun; + } + } + +void DmacDb::DoTransfer() + { + if (ControlStatus[CurrentChannel] & ECsRun) + { + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) + { + ControlStatus[CurrentChannel] &= ~ECsRun; + ErrorInt |= 1 << CurrentChannel; + Isr(); + } + else + { + if (ActCount[CurrentChannel] == 0) + { + if (ControlStatus[CurrentChannel] & ECsPrg) + { + ActSrcAddr[CurrentChannel] = PrgSrcAddr[CurrentChannel]; + ActDestAddr[CurrentChannel] = PrgDestAddr[CurrentChannel]; + ActCount[CurrentChannel] = PrgCount[CurrentChannel]; + ControlStatus[CurrentChannel] &= ~ECsPrg; + } + else + ControlStatus[CurrentChannel] &= ~ECsRun; + if (InterruptsToMiss[CurrentChannel] > 0) + InterruptsToMiss[CurrentChannel]--; + else + { + CompletionInt |= 1 << CurrentChannel; + Isr(); + } + } + else + { + TInt s = Min(ActCount[CurrentChannel], KBurstSize); + memcpy(ActDestAddr[CurrentChannel], ActSrcAddr[CurrentChannel], s); + ActCount[CurrentChannel] -= s; + ActSrcAddr[CurrentChannel] += s; + ActDestAddr[CurrentChannel] += s; + } + } + } + + CurrentChannel++; + if (CurrentChannel >= KChannelCount) + CurrentChannel = 0; + } + + +////////////////////////////////////////////////////////////////////////////// + +class DmacSg +/** Scatter/gather DMA controller software simulation */ + { +public: + enum { EChannelBitRun = 0x80000000 }; + enum { EDesBitInt = 1 }; + struct SDes + { + TUint8* iSrcAddr; + TUint8* iDestAddr; + TInt iCount; + TUint iControl; + SDes* iNext; + }; +public: + static void DoTransfer(); + static void Enable(TInt aIdx); +private: + static TInt CurrentChannel; + static TBool IsDescriptorLoaded[KChannelCount]; +public: + // externally accessible pseudo-registers + static TUint32 ChannelControl[KChannelCount]; + static TUint8* SrcAddr[KChannelCount]; + static TUint8* DestAddr[KChannelCount]; + static TInt Count[KChannelCount]; + static TUint Control[KChannelCount]; + static SDes* NextDes[KChannelCount]; + static TUint32 CompletionInt; + static TUint32 ErrorInt; + // hook for pseudo ISR + static TPseudoIsr Isr; + // transfer failure simulation + static TInt FailCount[KChannelCount]; + static TInt InterruptsToMiss[KChannelCount]; + }; + +TUint32 DmacSg::ChannelControl[KChannelCount]; +TUint8* DmacSg::SrcAddr[KChannelCount]; +TUint8* DmacSg::DestAddr[KChannelCount]; +TInt DmacSg::Count[KChannelCount]; +TUint DmacSg::Control[KChannelCount]; +DmacSg::SDes* DmacSg::NextDes[KChannelCount]; +TUint32 DmacSg::CompletionInt; +TUint32 DmacSg::ErrorInt; +TPseudoIsr DmacSg::Isr; +TInt DmacSg::FailCount[KChannelCount]; +TInt DmacSg::InterruptsToMiss[KChannelCount]; +TInt DmacSg::CurrentChannel; +TBool DmacSg::IsDescriptorLoaded[KChannelCount]; + + +void DmacSg::DoTransfer() + { + if (ChannelControl[CurrentChannel] & EChannelBitRun) + { + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0) + { + ChannelControl[CurrentChannel] &= ~EChannelBitRun; + ErrorInt |= 1 << CurrentChannel; + Isr(); + } + else + { + if (IsDescriptorLoaded[CurrentChannel]) + { + if (Count[CurrentChannel] == 0) + { + IsDescriptorLoaded[CurrentChannel] = EFalse; + if (Control[CurrentChannel] & EDesBitInt) + { + if (InterruptsToMiss[CurrentChannel] > 0) + InterruptsToMiss[CurrentChannel]--; + else + { + CompletionInt |= 1 << CurrentChannel; + Isr(); + } + } + } + else + { + TInt s = Min(Count[CurrentChannel], KBurstSize); + memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s); + Count[CurrentChannel] -= s; + SrcAddr[CurrentChannel] += s; + DestAddr[CurrentChannel] += s; + } + } + // Need to test again as new descriptor must be loaded if + // completion has just occured. + if (! IsDescriptorLoaded[CurrentChannel]) + { + if (NextDes[CurrentChannel] != NULL) + { + SrcAddr[CurrentChannel] = NextDes[CurrentChannel]->iSrcAddr; + DestAddr[CurrentChannel] = NextDes[CurrentChannel]->iDestAddr; + Count[CurrentChannel] = NextDes[CurrentChannel]->iCount; + Control[CurrentChannel] = NextDes[CurrentChannel]->iControl; + NextDes[CurrentChannel] = NextDes[CurrentChannel]->iNext; + IsDescriptorLoaded[CurrentChannel] = ETrue; + } + else + ChannelControl[CurrentChannel] &= ~EChannelBitRun; + } + } + } + + CurrentChannel++; + if (CurrentChannel >= KChannelCount) + CurrentChannel = 0; + } + + +void DmacSg::Enable(TInt aIdx) + { + SrcAddr[aIdx] = NextDes[aIdx]->iSrcAddr; + DestAddr[aIdx] = NextDes[aIdx]->iDestAddr; + Count[aIdx] = NextDes[aIdx]->iCount; + Control[aIdx] = NextDes[aIdx]->iControl; + NextDes[aIdx] = NextDes[aIdx]->iNext; + IsDescriptorLoaded[aIdx] = ETrue; + ChannelControl[aIdx] |= EChannelBitRun; + } + +////////////////////////////////////////////////////////////////////////////// + +class DmacSim +/** + Harness calling the various DMA controller simulators periodically. + */ + { +public: + static void StartEmulation(); + static void StopEmulation(); +private: + enum { KPeriod = 1 }; // in ms + static void TickCB(TAny* aThis); + static NTimer Timer; + }; + +NTimer DmacSim::Timer; + +void DmacSim::StartEmulation() + { + new (&Timer) NTimer(&TickCB, 0); + __DMA_ASSERTA(Timer.OneShot(KPeriod, EFalse) == KErrNone); + } + +void DmacSim::StopEmulation() + { + Timer.Cancel(); + } + +void DmacSim::TickCB(TAny*) + { + DmacSb::DoTransfer(); + DmacDb::DoTransfer(); + DmacSg::DoTransfer(); + __DMA_ASSERTA(Timer.Again(KPeriod) == KErrNone); + } + +////////////////////////////////////////////////////////////////////////////// +// PSL FOR DMA SIMULATION +////////////////////////////////////////////////////////////////////////////// + +class DSimSbController : public TDmac + { +public: + DSimSbController(); +private: + static void Isr(); + // from TDmac + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); + virtual void StopTransfer(const TDmaChannel& aChannel); + virtual TInt FailNext(const TDmaChannel& aChannel); + virtual TBool IsIdle(const TDmaChannel& aChannel); + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); +public: + static const SCreateInfo KInfo; + TDmaSbChannel iChannels[KChannelCount]; + }; + +DSimSbController SbController; + +const TDmac::SCreateInfo DSimSbController::KInfo = + { + KChannelCount, + KDesCount, + 0, + sizeof(SDmaPseudoDes), + 0, + }; + +DSimSbController::DSimSbController() + : TDmac(KInfo) + { + DmacSb::Isr = Isr; + } + + +void DSimSbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) + { + TUint32 i = aChannel.PslId(); + const SDmaPseudoDes& des = HdrToDes(aHdr); + DmacSb::SrcAddr[i] = (TUint8*) des.iSrc; + DmacSb::DestAddr[i] = (TUint8*) des.iDest; + DmacSb::Count[i] = des.iCount; + DmacSb::ControlStatus[i] |= DmacSb::ECsRun; + } + + +void DSimSbController::StopTransfer(const TDmaChannel& aChannel) + { + __e32_atomic_and_ord32(&DmacSb::ControlStatus[aChannel.PslId()], (TUint32)~DmacSb::ECsRun); + } + + +TInt DSimSbController::FailNext(const TDmaChannel& aChannel) + { + DmacSb::FailCount[aChannel.PslId()] = 1; + return KErrNone; + } + + +TBool DSimSbController::IsIdle(const TDmaChannel& aChannel) + { + return (DmacSb::ControlStatus[aChannel.PslId()] & DmacSb::ECsRun) == 0; + } + + +TInt DSimSbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMaxTransferSize; + } + + +TUint DSimSbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMemAlignMask; + } + + +void DSimSbController::Isr() + { + for (TInt i = 0; i < KChannelCount; i++) + { + TUint32 mask = (1 << i); + if (DmacSb::CompletionInt & mask) + { + DmacSb::CompletionInt &= ~mask; + HandleIsr(SbController.iChannels[i], ETrue); + } + if (DmacSb::ErrorInt & mask) + { + DmacSb::ErrorInt &= ~mask; + HandleIsr(SbController.iChannels[i], EFalse); + } + } + } + +////////////////////////////////////////////////////////////////////////////// + +class DSimDbController : public TDmac + { +public: + DSimDbController(); +private: + static void Isr(); + // from TDmac + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); + virtual void StopTransfer(const TDmaChannel& aChannel); + virtual TInt FailNext(const TDmaChannel& aChannel); + virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount); + virtual TBool IsIdle(const TDmaChannel& aChannel); + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); +public: + static const SCreateInfo KInfo; + TDmaDbChannel iChannels[KChannelCount]; + }; + +DSimDbController DbController; + +const TDmac::SCreateInfo DSimDbController::KInfo = + { + KChannelCount, + KDesCount, + 0, + sizeof(SDmaPseudoDes), + 0, + }; + + +DSimDbController::DSimDbController() + : TDmac(KInfo) + { + DmacDb::Isr = Isr; + } + + +void DSimDbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) + { + TUint32 i = aChannel.PslId(); + const SDmaPseudoDes& des = HdrToDes(aHdr); + DmacDb::PrgSrcAddr[i] = (TUint8*) des.iSrc; + DmacDb::PrgDestAddr[i] = (TUint8*) des.iDest; + DmacDb::PrgCount[i] = des.iCount; + DmacDb::Enable(i); + } + + +void DSimDbController::StopTransfer(const TDmaChannel& aChannel) + { + __e32_atomic_and_ord32(&DmacDb::ControlStatus[aChannel.PslId()], (TUint32)~(DmacDb::ECsRun|DmacDb::ECsPrg)); + } + + +TInt DSimDbController::FailNext(const TDmaChannel& aChannel) + { + DmacDb::FailCount[aChannel.PslId()] = 1; + return KErrNone; + } + + +TInt DSimDbController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount) + { + __DMA_ASSERTD((DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0); + __DMA_ASSERTD(aInterruptCount >= 0); + // At most one interrupt can be missed with double-buffer controller + if (aInterruptCount == 1) + { + DmacDb::InterruptsToMiss[aChannel.PslId()] = aInterruptCount; + return KErrNone; + } + else + return KErrNotSupported; + } + + +TBool DSimDbController::IsIdle(const TDmaChannel& aChannel) + { + return (DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0; + } + + +TInt DSimDbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMaxTransferSize; + } + + +TUint DSimDbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMemAlignMask; + } + + +void DSimDbController::Isr() + { + for (TInt i = 0; i < KChannelCount; i++) + { + TUint32 mask = (1 << i); + if (DmacDb::CompletionInt & mask) + { + DmacDb::CompletionInt &= ~mask; + HandleIsr(DbController.iChannels[i], ETrue); + } + if (DmacDb::ErrorInt & mask) + { + DmacDb::ErrorInt &= ~mask; + HandleIsr(DbController.iChannels[i], EFalse); + } + } + } + +////////////////////////////////////////////////////////////////////////////// + +class DSimSgController : public TDmac + { +public: + DSimSgController(); +private: + static void Isr(); + // from TDmac + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); + virtual void StopTransfer(const TDmaChannel& aChannel); + virtual TBool IsIdle(const TDmaChannel& aChannel); + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); + virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, + TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); + virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); + virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, + const SDmaDesHdr& aNewHdr); + virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); + virtual TInt FailNext(const TDmaChannel& aChannel); + virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount); +private: + inline DmacSg::SDes* HdrToHwDes(const SDmaDesHdr& aHdr); +public: + static const SCreateInfo KInfo; + TDmaSgChannel iChannels[KChannelCount]; + }; + +DSimSgController SgController; + +const TDmac::SCreateInfo DSimSgController::KInfo = + { + KChannelCount, + KDesCount, + KCapsBitHwDes, + sizeof(DmacSg::SDes), +#ifdef __WINS__ + 0, +#else + EMapAttrSupRw|EMapAttrFullyBlocking, +#endif + }; + + +inline DmacSg::SDes* DSimSgController::HdrToHwDes(const SDmaDesHdr& aHdr) + { + return static_cast(TDmac::HdrToHwDes(aHdr)); + } + + +DSimSgController::DSimSgController() + : TDmac(KInfo) + { + DmacSg::Isr = Isr; + } + + +void DSimSgController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) + { + TUint32 i = aChannel.PslId(); + DmacSg::NextDes[i] = HdrToHwDes(aHdr); + DmacSg::Enable(i); + } + + +void DSimSgController::StopTransfer(const TDmaChannel& aChannel) + { + __e32_atomic_and_ord32(&DmacSg::ChannelControl[aChannel.PslId()], (TUint32)~DmacSg::EChannelBitRun); + } + + +void DSimSgController::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, + TUint /*aFlags*/, TUint32 /*aPslInfo*/, TUint32 /*aCookie*/) + { + DmacSg::SDes& des = *HdrToHwDes(aHdr); + des.iSrcAddr = reinterpret_cast(aSrc); + des.iDestAddr = reinterpret_cast(aDest); + des.iCount = static_cast(aCount); + des.iControl |= DmacSg::EDesBitInt; + des.iNext = NULL; + } + + +void DSimSgController::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) + { + DmacSg::SDes& des = *HdrToHwDes(aHdr); + des.iControl &= ~DmacSg::EDesBitInt; + des.iNext = HdrToHwDes(aNextHdr); + } + + +void DSimSgController::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, + const SDmaDesHdr& aNewHdr) + { + TUint32 i = aChannel.PslId(); + DmacSg::SDes* pNewDes = HdrToHwDes(aNewHdr); + TInt prevLevel = NKern::DisableAllInterrupts(); + + if ((DmacSg::ChannelControl[i] & DmacSg::EChannelBitRun) == 0) + { + DmacSg::NextDes[i] = pNewDes; + DmacSg::Enable(i); + } + else if (DmacSg::NextDes[i] == NULL) + DmacSg::NextDes[i] = pNewDes; + else + HdrToHwDes(aLastHdr)->iNext = pNewDes; + + NKern::RestoreInterrupts(prevLevel); + } + + +void DSimSgController::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr) + { + DmacSg::SDes* pD = HdrToHwDes(aHdr); + pD->iNext = NULL; + pD->iControl |= DmacSg::EDesBitInt; + } + + +TInt DSimSgController::FailNext(const TDmaChannel& aChannel) + { + __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0); + DmacSg::FailCount[aChannel.PslId()] = 1; + return KErrNone; + } + + +TInt DSimSgController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount) + { + __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0); + __DMA_ASSERTD(aInterruptCount >= 0); + DmacSg::InterruptsToMiss[aChannel.PslId()] = aInterruptCount; + return KErrNone; + } + + +TBool DSimSgController::IsIdle(const TDmaChannel& aChannel) + { + return (DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0; + } + + +TInt DSimSgController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMaxTransferSize; + } + + +TUint DSimSgController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/) + { + return KMemAlignMask; + } + + +void DSimSgController::Isr() + { + for (TInt i = 0; i < KChannelCount; i++) + { + TUint32 mask = (1 << i); + if (DmacSg::CompletionInt & mask) + { + DmacSg::CompletionInt &= ~mask; + HandleIsr(SgController.iChannels[i], ETrue); + } + if (DmacSg::ErrorInt & mask) + { + DmacSg::ErrorInt &= ~mask; + HandleIsr(SgController.iChannels[i], EFalse); + } + } + } + + +////////////////////////////////////////////////////////////////////////////// +// Channel opening/closing + +enum TController { ESb=0, EDb=1, ESg=2 }; + +const TUint32 KControllerMask = 0x30; +const TUint32 KControllerShift = 4; +const TUint32 KChannelIdxMask = 3; + +#define MKCHN(type, idx) (((type)<> KControllerShift; + __DMA_ASSERTD(dmac < 3); + TInt i = aOpenId & KChannelIdxMask; + TDmaChannel* pC = NULL; + TDmac* controller = NULL; + switch (dmac) + { + case ESb: + pC = SbController.iChannels + i; + controller = &SbController; + break; + case EDb: + pC = DbController.iChannels + i; + controller = &DbController; + break; + case ESg: + pC = SgController.iChannels + i; + controller = &SgController; + break; + default: + __DMA_CANT_HAPPEN(); + } + + if (++OpenChannelCount == 1) + { + __KTRACE_OPT(KDMA, Kern::Printf("Enabling DMA simulation")); + DmacSim::StartEmulation(); + } + if (pC->IsOpened()) + return NULL; + pC->iController = controller; + pC->iPslId = i; + return pC; + } + + +void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/) + { + if (--OpenChannelCount == 0) + { + DmacSim::StopEmulation(); + __KTRACE_OPT(KDMA, Kern::Printf("Stopping DMA simulation")); + } + } + +TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/) + { + return KErrNotSupported; + } + +////////////////////////////////////////////////////////////////////////////// + +// +// On hardware, this code is inside a kernel extension. +// + +DECLARE_STANDARD_EXTENSION() + { + __KTRACE_OPT(KDMA, Kern::Printf("Starting DMA simulator...")); + TInt r; + r = SbController.Create(DSimSbController::KInfo); + if (r != KErrNone) + return r; + r = DbController.Create(DSimDbController::KInfo); + if (r != KErrNone) + return r; + r = SgController.Create(DSimSgController::KInfo); + if (r != KErrNone) + return r; + + return KErrNone; + } + +// +// On WINS, this code is inside a LDD (see mmp file) so we need some +// bootstrapping code to call the kernel extension entry point. +// + +class DDummyLdd : public DLogicalDevice + { +public: + // from DLogicalDevice + TInt Install(); + void GetCaps(TDes8& aDes) const; + TInt Create(DLogicalChannelBase*& aChannel); + }; + +TInt DDummyLdd::Create(DLogicalChannelBase*& aChannel) + { + aChannel=NULL; + return KErrNone; + } + +TInt DDummyLdd::Install() + { + _LIT(KLddName, "DmaSim"); + TInt r = SetName(&KLddName); + if (r == KErrNone) + r = InitExtension(); + return r; + } + +void DDummyLdd::GetCaps(TDes8& /*aDes*/) const + { + } + +EXPORT_C DLogicalDevice* CreateLogicalDevice() + { + return new DDummyLdd; + } + + +//---