Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.
// 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 <drivers/dma.h>
#include <kernel/kern_priv.h>
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<DmacSg::SDes*>(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<TUint8*>(aSrc);
des.iDestAddr = reinterpret_cast<TUint8*>(aDest);
des.iCount = static_cast<TInt16>(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)|idx)
static TUint32 TestSbChannels[] = { MKCHN(ESb,0), MKCHN(ESb,1), MKCHN(ESb,2), MKCHN(ESb,3) };
static TUint32 TestDbChannels[] = { MKCHN(EDb,0), MKCHN(EDb,1), MKCHN(EDb,2), MKCHN(EDb,3) };
static TUint32 TestSgChannels[] = { MKCHN(ESg,0), MKCHN(ESg,1), MKCHN(ESg,2), MKCHN(ESg,3) };
static TDmaTestInfo TestInfo =
{
KMaxTransferSize,
KMemAlignMask,
0,
KChannelCount,
TestSbChannels,
KChannelCount,
TestDbChannels,
KChannelCount,
TestSgChannels,
};
EXPORT_C const TDmaTestInfo& DmaTestInfo()
{
return TestInfo;
}
// Keep track of opened channels so Tick callback used to fake DMA
// transfers is enabled only when necessary.
static TInt OpenChannelCount = 0;
TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
{
TInt dmac = (aOpenId & KControllerMask) >> 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;
}
//---