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