1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/dma/dmasim.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,927 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\dma\dmasim.cpp
1.18 +// DMA framework Platform Specific Layer (PSL) for software-emulated
1.19 +// DMA controller used for testing the DMA framework PIL.
1.20 +//
1.21 +//
1.22 +
1.23 +#include <drivers/dma.h>
1.24 +#include <kernel/kern_priv.h>
1.25 +
1.26 +
1.27 +const char KDmaPanicCat[] = "DMASIM";
1.28 +
1.29 +const TInt KMaxTransferSize = 0x1FFF;
1.30 +const TInt KMemAlignMask = 3; // memory addresses passed to DMAC must be multiple of 4
1.31 +const TInt KBurstSize = 0x800;
1.32 +
1.33 +typedef void (*TPseudoIsr)();
1.34 +
1.35 +const TInt KChannelCount = 4; // # of channels per controller
1.36 +const TInt KDesCount = 256; // # of descriptors allocated per controller
1.37 +
1.38 +//////////////////////////////////////////////////////////////////////////////
1.39 +// SOFTWARE DMA CONTROLLER SIMULATION
1.40 +//////////////////////////////////////////////////////////////////////////////
1.41 +
1.42 +class DmacSb
1.43 +/** Single-buffer DMA controller software simulation */
1.44 + {
1.45 +public:
1.46 + enum { ECsRun = 0x80000000 };
1.47 +public:
1.48 + static void DoTransfer();
1.49 +private:
1.50 + static void BurstTransfer();
1.51 +private:
1.52 + static TInt CurrentChannel;
1.53 +public:
1.54 + // pseudo registers
1.55 + static TUint8* SrcAddr[KChannelCount];
1.56 + static TUint8* DestAddr[KChannelCount];
1.57 + static TInt Count[KChannelCount];
1.58 + static TUint32 ControlStatus[KChannelCount];
1.59 + static TUint32 CompletionInt;
1.60 + static TUint32 ErrorInt;
1.61 + // hook for pseudo ISR
1.62 + static TPseudoIsr Isr;
1.63 + // transfer failure simulation
1.64 + static TInt FailCount[KChannelCount];
1.65 + };
1.66 +
1.67 +TUint8* DmacSb::SrcAddr[KChannelCount];
1.68 +TUint8* DmacSb::DestAddr[KChannelCount];
1.69 +TInt DmacSb::Count[KChannelCount];
1.70 +TUint32 DmacSb::ControlStatus[KChannelCount];
1.71 +TUint32 DmacSb::CompletionInt;
1.72 +TUint32 DmacSb::ErrorInt;
1.73 +TPseudoIsr DmacSb::Isr;
1.74 +TInt DmacSb::FailCount[KChannelCount];
1.75 +TInt DmacSb::CurrentChannel;
1.76 +
1.77 +void DmacSb::DoTransfer()
1.78 + {
1.79 + if (ControlStatus[CurrentChannel] & ECsRun)
1.80 + {
1.81 + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
1.82 + {
1.83 + ControlStatus[CurrentChannel] &= ~ECsRun;
1.84 + ErrorInt |= 1 << CurrentChannel;
1.85 + Isr();
1.86 + }
1.87 + else
1.88 + {
1.89 + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer channel %d", CurrentChannel));
1.90 + if (Count[CurrentChannel] == 0)
1.91 + {
1.92 + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer transfer complete"));
1.93 + ControlStatus[CurrentChannel] &= ~ECsRun;
1.94 + CompletionInt |= 1 << CurrentChannel;
1.95 + Isr();
1.96 + }
1.97 + else
1.98 + BurstTransfer();
1.99 + }
1.100 + }
1.101 +
1.102 + CurrentChannel++;
1.103 + if (CurrentChannel >= KChannelCount)
1.104 + CurrentChannel = 0;
1.105 + }
1.106 +
1.107 +void DmacSb::BurstTransfer()
1.108 + {
1.109 + //__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::BurstTransfer"));
1.110 + TInt s = Min(Count[CurrentChannel], KBurstSize);
1.111 + memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s);
1.112 + Count[CurrentChannel] -= s;
1.113 + SrcAddr[CurrentChannel] += s;
1.114 + DestAddr[CurrentChannel] += s;
1.115 + }
1.116 +
1.117 +//////////////////////////////////////////////////////////////////////////////
1.118 +
1.119 +class DmacDb
1.120 +/** Double-buffer DMA controller software simulation */
1.121 + {
1.122 +public:
1.123 + enum { ECsRun = 0x80000000, ECsPrg = 0x40000000 };
1.124 +public:
1.125 + static void Enable(TInt aIdx);
1.126 + static void DoTransfer();
1.127 +private:
1.128 + static TInt CurrentChannel;
1.129 +private:
1.130 + // internal pseudo-registers
1.131 + static TUint8* ActSrcAddr[KChannelCount];
1.132 + static TUint8* ActDestAddr[KChannelCount];
1.133 + static TInt ActCount[KChannelCount];
1.134 +public:
1.135 + // externally accessible pseudo-registers
1.136 + static TUint32 ControlStatus[KChannelCount];
1.137 + static TUint8* PrgSrcAddr[KChannelCount];
1.138 + static TUint8* PrgDestAddr[KChannelCount];
1.139 + static TInt PrgCount[KChannelCount];
1.140 + static TUint32 CompletionInt;
1.141 + static TUint32 ErrorInt;
1.142 + // hook for pseudo ISR
1.143 + static TPseudoIsr Isr;
1.144 + // transfer failure simulation
1.145 + static TInt FailCount[KChannelCount];
1.146 + static TInt InterruptsToMiss[KChannelCount];
1.147 + };
1.148 +
1.149 +TUint8* DmacDb::PrgSrcAddr[KChannelCount];
1.150 +TUint8* DmacDb::PrgDestAddr[KChannelCount];
1.151 +TInt DmacDb::PrgCount[KChannelCount];
1.152 +TUint8* DmacDb::ActSrcAddr[KChannelCount];
1.153 +TUint8* DmacDb::ActDestAddr[KChannelCount];
1.154 +TInt DmacDb::ActCount[KChannelCount];
1.155 +TUint32 DmacDb::ControlStatus[KChannelCount];
1.156 +TUint32 DmacDb::CompletionInt;
1.157 +TUint32 DmacDb::ErrorInt;
1.158 +TPseudoIsr DmacDb::Isr;
1.159 +TInt DmacDb::FailCount[KChannelCount];
1.160 +TInt DmacDb::InterruptsToMiss[KChannelCount];
1.161 +TInt DmacDb::CurrentChannel;
1.162 +
1.163 +void DmacDb::Enable(TInt aIdx)
1.164 + {
1.165 + if (ControlStatus[aIdx] & ECsRun)
1.166 + ControlStatus[aIdx] |= ECsPrg;
1.167 + else
1.168 + {
1.169 + ActSrcAddr[aIdx] = PrgSrcAddr[aIdx];
1.170 + ActDestAddr[aIdx] = PrgDestAddr[aIdx];
1.171 + ActCount[aIdx] = PrgCount[aIdx];
1.172 + ControlStatus[aIdx] |= ECsRun;
1.173 + }
1.174 + }
1.175 +
1.176 +void DmacDb::DoTransfer()
1.177 + {
1.178 + if (ControlStatus[CurrentChannel] & ECsRun)
1.179 + {
1.180 + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
1.181 + {
1.182 + ControlStatus[CurrentChannel] &= ~ECsRun;
1.183 + ErrorInt |= 1 << CurrentChannel;
1.184 + Isr();
1.185 + }
1.186 + else
1.187 + {
1.188 + if (ActCount[CurrentChannel] == 0)
1.189 + {
1.190 + if (ControlStatus[CurrentChannel] & ECsPrg)
1.191 + {
1.192 + ActSrcAddr[CurrentChannel] = PrgSrcAddr[CurrentChannel];
1.193 + ActDestAddr[CurrentChannel] = PrgDestAddr[CurrentChannel];
1.194 + ActCount[CurrentChannel] = PrgCount[CurrentChannel];
1.195 + ControlStatus[CurrentChannel] &= ~ECsPrg;
1.196 + }
1.197 + else
1.198 + ControlStatus[CurrentChannel] &= ~ECsRun;
1.199 + if (InterruptsToMiss[CurrentChannel] > 0)
1.200 + InterruptsToMiss[CurrentChannel]--;
1.201 + else
1.202 + {
1.203 + CompletionInt |= 1 << CurrentChannel;
1.204 + Isr();
1.205 + }
1.206 + }
1.207 + else
1.208 + {
1.209 + TInt s = Min(ActCount[CurrentChannel], KBurstSize);
1.210 + memcpy(ActDestAddr[CurrentChannel], ActSrcAddr[CurrentChannel], s);
1.211 + ActCount[CurrentChannel] -= s;
1.212 + ActSrcAddr[CurrentChannel] += s;
1.213 + ActDestAddr[CurrentChannel] += s;
1.214 + }
1.215 + }
1.216 + }
1.217 +
1.218 + CurrentChannel++;
1.219 + if (CurrentChannel >= KChannelCount)
1.220 + CurrentChannel = 0;
1.221 + }
1.222 +
1.223 +
1.224 +//////////////////////////////////////////////////////////////////////////////
1.225 +
1.226 +class DmacSg
1.227 +/** Scatter/gather DMA controller software simulation */
1.228 + {
1.229 +public:
1.230 + enum { EChannelBitRun = 0x80000000 };
1.231 + enum { EDesBitInt = 1 };
1.232 + struct SDes
1.233 + {
1.234 + TUint8* iSrcAddr;
1.235 + TUint8* iDestAddr;
1.236 + TInt iCount;
1.237 + TUint iControl;
1.238 + SDes* iNext;
1.239 + };
1.240 +public:
1.241 + static void DoTransfer();
1.242 + static void Enable(TInt aIdx);
1.243 +private:
1.244 + static TInt CurrentChannel;
1.245 + static TBool IsDescriptorLoaded[KChannelCount];
1.246 +public:
1.247 + // externally accessible pseudo-registers
1.248 + static TUint32 ChannelControl[KChannelCount];
1.249 + static TUint8* SrcAddr[KChannelCount];
1.250 + static TUint8* DestAddr[KChannelCount];
1.251 + static TInt Count[KChannelCount];
1.252 + static TUint Control[KChannelCount];
1.253 + static SDes* NextDes[KChannelCount];
1.254 + static TUint32 CompletionInt;
1.255 + static TUint32 ErrorInt;
1.256 + // hook for pseudo ISR
1.257 + static TPseudoIsr Isr;
1.258 + // transfer failure simulation
1.259 + static TInt FailCount[KChannelCount];
1.260 + static TInt InterruptsToMiss[KChannelCount];
1.261 + };
1.262 +
1.263 +TUint32 DmacSg::ChannelControl[KChannelCount];
1.264 +TUint8* DmacSg::SrcAddr[KChannelCount];
1.265 +TUint8* DmacSg::DestAddr[KChannelCount];
1.266 +TInt DmacSg::Count[KChannelCount];
1.267 +TUint DmacSg::Control[KChannelCount];
1.268 +DmacSg::SDes* DmacSg::NextDes[KChannelCount];
1.269 +TUint32 DmacSg::CompletionInt;
1.270 +TUint32 DmacSg::ErrorInt;
1.271 +TPseudoIsr DmacSg::Isr;
1.272 +TInt DmacSg::FailCount[KChannelCount];
1.273 +TInt DmacSg::InterruptsToMiss[KChannelCount];
1.274 +TInt DmacSg::CurrentChannel;
1.275 +TBool DmacSg::IsDescriptorLoaded[KChannelCount];
1.276 +
1.277 +
1.278 +void DmacSg::DoTransfer()
1.279 + {
1.280 + if (ChannelControl[CurrentChannel] & EChannelBitRun)
1.281 + {
1.282 + if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
1.283 + {
1.284 + ChannelControl[CurrentChannel] &= ~EChannelBitRun;
1.285 + ErrorInt |= 1 << CurrentChannel;
1.286 + Isr();
1.287 + }
1.288 + else
1.289 + {
1.290 + if (IsDescriptorLoaded[CurrentChannel])
1.291 + {
1.292 + if (Count[CurrentChannel] == 0)
1.293 + {
1.294 + IsDescriptorLoaded[CurrentChannel] = EFalse;
1.295 + if (Control[CurrentChannel] & EDesBitInt)
1.296 + {
1.297 + if (InterruptsToMiss[CurrentChannel] > 0)
1.298 + InterruptsToMiss[CurrentChannel]--;
1.299 + else
1.300 + {
1.301 + CompletionInt |= 1 << CurrentChannel;
1.302 + Isr();
1.303 + }
1.304 + }
1.305 + }
1.306 + else
1.307 + {
1.308 + TInt s = Min(Count[CurrentChannel], KBurstSize);
1.309 + memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s);
1.310 + Count[CurrentChannel] -= s;
1.311 + SrcAddr[CurrentChannel] += s;
1.312 + DestAddr[CurrentChannel] += s;
1.313 + }
1.314 + }
1.315 + // Need to test again as new descriptor must be loaded if
1.316 + // completion has just occured.
1.317 + if (! IsDescriptorLoaded[CurrentChannel])
1.318 + {
1.319 + if (NextDes[CurrentChannel] != NULL)
1.320 + {
1.321 + SrcAddr[CurrentChannel] = NextDes[CurrentChannel]->iSrcAddr;
1.322 + DestAddr[CurrentChannel] = NextDes[CurrentChannel]->iDestAddr;
1.323 + Count[CurrentChannel] = NextDes[CurrentChannel]->iCount;
1.324 + Control[CurrentChannel] = NextDes[CurrentChannel]->iControl;
1.325 + NextDes[CurrentChannel] = NextDes[CurrentChannel]->iNext;
1.326 + IsDescriptorLoaded[CurrentChannel] = ETrue;
1.327 + }
1.328 + else
1.329 + ChannelControl[CurrentChannel] &= ~EChannelBitRun;
1.330 + }
1.331 + }
1.332 + }
1.333 +
1.334 + CurrentChannel++;
1.335 + if (CurrentChannel >= KChannelCount)
1.336 + CurrentChannel = 0;
1.337 + }
1.338 +
1.339 +
1.340 +void DmacSg::Enable(TInt aIdx)
1.341 + {
1.342 + SrcAddr[aIdx] = NextDes[aIdx]->iSrcAddr;
1.343 + DestAddr[aIdx] = NextDes[aIdx]->iDestAddr;
1.344 + Count[aIdx] = NextDes[aIdx]->iCount;
1.345 + Control[aIdx] = NextDes[aIdx]->iControl;
1.346 + NextDes[aIdx] = NextDes[aIdx]->iNext;
1.347 + IsDescriptorLoaded[aIdx] = ETrue;
1.348 + ChannelControl[aIdx] |= EChannelBitRun;
1.349 + }
1.350 +
1.351 +//////////////////////////////////////////////////////////////////////////////
1.352 +
1.353 +class DmacSim
1.354 +/**
1.355 + Harness calling the various DMA controller simulators periodically.
1.356 + */
1.357 + {
1.358 +public:
1.359 + static void StartEmulation();
1.360 + static void StopEmulation();
1.361 +private:
1.362 + enum { KPeriod = 1 }; // in ms
1.363 + static void TickCB(TAny* aThis);
1.364 + static NTimer Timer;
1.365 + };
1.366 +
1.367 +NTimer DmacSim::Timer;
1.368 +
1.369 +void DmacSim::StartEmulation()
1.370 + {
1.371 + new (&Timer) NTimer(&TickCB, 0);
1.372 + __DMA_ASSERTA(Timer.OneShot(KPeriod, EFalse) == KErrNone);
1.373 + }
1.374 +
1.375 +void DmacSim::StopEmulation()
1.376 + {
1.377 + Timer.Cancel();
1.378 + }
1.379 +
1.380 +void DmacSim::TickCB(TAny*)
1.381 + {
1.382 + DmacSb::DoTransfer();
1.383 + DmacDb::DoTransfer();
1.384 + DmacSg::DoTransfer();
1.385 + __DMA_ASSERTA(Timer.Again(KPeriod) == KErrNone);
1.386 + }
1.387 +
1.388 +//////////////////////////////////////////////////////////////////////////////
1.389 +// PSL FOR DMA SIMULATION
1.390 +//////////////////////////////////////////////////////////////////////////////
1.391 +
1.392 +class DSimSbController : public TDmac
1.393 + {
1.394 +public:
1.395 + DSimSbController();
1.396 +private:
1.397 + static void Isr();
1.398 + // from TDmac
1.399 + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
1.400 + virtual void StopTransfer(const TDmaChannel& aChannel);
1.401 + virtual TInt FailNext(const TDmaChannel& aChannel);
1.402 + virtual TBool IsIdle(const TDmaChannel& aChannel);
1.403 + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.404 + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.405 +public:
1.406 + static const SCreateInfo KInfo;
1.407 + TDmaSbChannel iChannels[KChannelCount];
1.408 + };
1.409 +
1.410 +DSimSbController SbController;
1.411 +
1.412 +const TDmac::SCreateInfo DSimSbController::KInfo =
1.413 + {
1.414 + KChannelCount,
1.415 + KDesCount,
1.416 + 0,
1.417 + sizeof(SDmaPseudoDes),
1.418 + 0,
1.419 + };
1.420 +
1.421 +DSimSbController::DSimSbController()
1.422 + : TDmac(KInfo)
1.423 + {
1.424 + DmacSb::Isr = Isr;
1.425 + }
1.426 +
1.427 +
1.428 +void DSimSbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
1.429 + {
1.430 + TUint32 i = aChannel.PslId();
1.431 + const SDmaPseudoDes& des = HdrToDes(aHdr);
1.432 + DmacSb::SrcAddr[i] = (TUint8*) des.iSrc;
1.433 + DmacSb::DestAddr[i] = (TUint8*) des.iDest;
1.434 + DmacSb::Count[i] = des.iCount;
1.435 + DmacSb::ControlStatus[i] |= DmacSb::ECsRun;
1.436 + }
1.437 +
1.438 +
1.439 +void DSimSbController::StopTransfer(const TDmaChannel& aChannel)
1.440 + {
1.441 + __e32_atomic_and_ord32(&DmacSb::ControlStatus[aChannel.PslId()], (TUint32)~DmacSb::ECsRun);
1.442 + }
1.443 +
1.444 +
1.445 +TInt DSimSbController::FailNext(const TDmaChannel& aChannel)
1.446 + {
1.447 + DmacSb::FailCount[aChannel.PslId()] = 1;
1.448 + return KErrNone;
1.449 + }
1.450 +
1.451 +
1.452 +TBool DSimSbController::IsIdle(const TDmaChannel& aChannel)
1.453 + {
1.454 + return (DmacSb::ControlStatus[aChannel.PslId()] & DmacSb::ECsRun) == 0;
1.455 + }
1.456 +
1.457 +
1.458 +TInt DSimSbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.459 + {
1.460 + return KMaxTransferSize;
1.461 + }
1.462 +
1.463 +
1.464 +TUint DSimSbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.465 + {
1.466 + return KMemAlignMask;
1.467 + }
1.468 +
1.469 +
1.470 +void DSimSbController::Isr()
1.471 + {
1.472 + for (TInt i = 0; i < KChannelCount; i++)
1.473 + {
1.474 + TUint32 mask = (1 << i);
1.475 + if (DmacSb::CompletionInt & mask)
1.476 + {
1.477 + DmacSb::CompletionInt &= ~mask;
1.478 + HandleIsr(SbController.iChannels[i], ETrue);
1.479 + }
1.480 + if (DmacSb::ErrorInt & mask)
1.481 + {
1.482 + DmacSb::ErrorInt &= ~mask;
1.483 + HandleIsr(SbController.iChannels[i], EFalse);
1.484 + }
1.485 + }
1.486 + }
1.487 +
1.488 +//////////////////////////////////////////////////////////////////////////////
1.489 +
1.490 +class DSimDbController : public TDmac
1.491 + {
1.492 +public:
1.493 + DSimDbController();
1.494 +private:
1.495 + static void Isr();
1.496 + // from TDmac
1.497 + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
1.498 + virtual void StopTransfer(const TDmaChannel& aChannel);
1.499 + virtual TInt FailNext(const TDmaChannel& aChannel);
1.500 + virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
1.501 + virtual TBool IsIdle(const TDmaChannel& aChannel);
1.502 + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.503 + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.504 +public:
1.505 + static const SCreateInfo KInfo;
1.506 + TDmaDbChannel iChannels[KChannelCount];
1.507 + };
1.508 +
1.509 +DSimDbController DbController;
1.510 +
1.511 +const TDmac::SCreateInfo DSimDbController::KInfo =
1.512 + {
1.513 + KChannelCount,
1.514 + KDesCount,
1.515 + 0,
1.516 + sizeof(SDmaPseudoDes),
1.517 + 0,
1.518 + };
1.519 +
1.520 +
1.521 +DSimDbController::DSimDbController()
1.522 + : TDmac(KInfo)
1.523 + {
1.524 + DmacDb::Isr = Isr;
1.525 + }
1.526 +
1.527 +
1.528 +void DSimDbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
1.529 + {
1.530 + TUint32 i = aChannel.PslId();
1.531 + const SDmaPseudoDes& des = HdrToDes(aHdr);
1.532 + DmacDb::PrgSrcAddr[i] = (TUint8*) des.iSrc;
1.533 + DmacDb::PrgDestAddr[i] = (TUint8*) des.iDest;
1.534 + DmacDb::PrgCount[i] = des.iCount;
1.535 + DmacDb::Enable(i);
1.536 + }
1.537 +
1.538 +
1.539 +void DSimDbController::StopTransfer(const TDmaChannel& aChannel)
1.540 + {
1.541 + __e32_atomic_and_ord32(&DmacDb::ControlStatus[aChannel.PslId()], (TUint32)~(DmacDb::ECsRun|DmacDb::ECsPrg));
1.542 + }
1.543 +
1.544 +
1.545 +TInt DSimDbController::FailNext(const TDmaChannel& aChannel)
1.546 + {
1.547 + DmacDb::FailCount[aChannel.PslId()] = 1;
1.548 + return KErrNone;
1.549 + }
1.550 +
1.551 +
1.552 +TInt DSimDbController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount)
1.553 + {
1.554 + __DMA_ASSERTD((DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0);
1.555 + __DMA_ASSERTD(aInterruptCount >= 0);
1.556 + // At most one interrupt can be missed with double-buffer controller
1.557 + if (aInterruptCount == 1)
1.558 + {
1.559 + DmacDb::InterruptsToMiss[aChannel.PslId()] = aInterruptCount;
1.560 + return KErrNone;
1.561 + }
1.562 + else
1.563 + return KErrNotSupported;
1.564 + }
1.565 +
1.566 +
1.567 +TBool DSimDbController::IsIdle(const TDmaChannel& aChannel)
1.568 + {
1.569 + return (DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0;
1.570 + }
1.571 +
1.572 +
1.573 +TInt DSimDbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.574 + {
1.575 + return KMaxTransferSize;
1.576 + }
1.577 +
1.578 +
1.579 +TUint DSimDbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.580 + {
1.581 + return KMemAlignMask;
1.582 + }
1.583 +
1.584 +
1.585 +void DSimDbController::Isr()
1.586 + {
1.587 + for (TInt i = 0; i < KChannelCount; i++)
1.588 + {
1.589 + TUint32 mask = (1 << i);
1.590 + if (DmacDb::CompletionInt & mask)
1.591 + {
1.592 + DmacDb::CompletionInt &= ~mask;
1.593 + HandleIsr(DbController.iChannels[i], ETrue);
1.594 + }
1.595 + if (DmacDb::ErrorInt & mask)
1.596 + {
1.597 + DmacDb::ErrorInt &= ~mask;
1.598 + HandleIsr(DbController.iChannels[i], EFalse);
1.599 + }
1.600 + }
1.601 + }
1.602 +
1.603 +//////////////////////////////////////////////////////////////////////////////
1.604 +
1.605 +class DSimSgController : public TDmac
1.606 + {
1.607 +public:
1.608 + DSimSgController();
1.609 +private:
1.610 + static void Isr();
1.611 + // from TDmac
1.612 + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
1.613 + virtual void StopTransfer(const TDmaChannel& aChannel);
1.614 + virtual TBool IsIdle(const TDmaChannel& aChannel);
1.615 + virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.616 + virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
1.617 + virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
1.618 + TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
1.619 + virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
1.620 + virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
1.621 + const SDmaDesHdr& aNewHdr);
1.622 + virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
1.623 + virtual TInt FailNext(const TDmaChannel& aChannel);
1.624 + virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
1.625 +private:
1.626 + inline DmacSg::SDes* HdrToHwDes(const SDmaDesHdr& aHdr);
1.627 +public:
1.628 + static const SCreateInfo KInfo;
1.629 + TDmaSgChannel iChannels[KChannelCount];
1.630 + };
1.631 +
1.632 +DSimSgController SgController;
1.633 +
1.634 +const TDmac::SCreateInfo DSimSgController::KInfo =
1.635 + {
1.636 + KChannelCount,
1.637 + KDesCount,
1.638 + KCapsBitHwDes,
1.639 + sizeof(DmacSg::SDes),
1.640 +#ifdef __WINS__
1.641 + 0,
1.642 +#else
1.643 + EMapAttrSupRw|EMapAttrFullyBlocking,
1.644 +#endif
1.645 + };
1.646 +
1.647 +
1.648 +inline DmacSg::SDes* DSimSgController::HdrToHwDes(const SDmaDesHdr& aHdr)
1.649 + {
1.650 + return static_cast<DmacSg::SDes*>(TDmac::HdrToHwDes(aHdr));
1.651 + }
1.652 +
1.653 +
1.654 +DSimSgController::DSimSgController()
1.655 + : TDmac(KInfo)
1.656 + {
1.657 + DmacSg::Isr = Isr;
1.658 + }
1.659 +
1.660 +
1.661 +void DSimSgController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
1.662 + {
1.663 + TUint32 i = aChannel.PslId();
1.664 + DmacSg::NextDes[i] = HdrToHwDes(aHdr);
1.665 + DmacSg::Enable(i);
1.666 + }
1.667 +
1.668 +
1.669 +void DSimSgController::StopTransfer(const TDmaChannel& aChannel)
1.670 + {
1.671 + __e32_atomic_and_ord32(&DmacSg::ChannelControl[aChannel.PslId()], (TUint32)~DmacSg::EChannelBitRun);
1.672 + }
1.673 +
1.674 +
1.675 +void DSimSgController::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
1.676 + TUint /*aFlags*/, TUint32 /*aPslInfo*/, TUint32 /*aCookie*/)
1.677 + {
1.678 + DmacSg::SDes& des = *HdrToHwDes(aHdr);
1.679 + des.iSrcAddr = reinterpret_cast<TUint8*>(aSrc);
1.680 + des.iDestAddr = reinterpret_cast<TUint8*>(aDest);
1.681 + des.iCount = static_cast<TInt16>(aCount);
1.682 + des.iControl |= DmacSg::EDesBitInt;
1.683 + des.iNext = NULL;
1.684 + }
1.685 +
1.686 +
1.687 +void DSimSgController::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
1.688 + {
1.689 + DmacSg::SDes& des = *HdrToHwDes(aHdr);
1.690 + des.iControl &= ~DmacSg::EDesBitInt;
1.691 + des.iNext = HdrToHwDes(aNextHdr);
1.692 + }
1.693 +
1.694 +
1.695 +void DSimSgController::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
1.696 + const SDmaDesHdr& aNewHdr)
1.697 + {
1.698 + TUint32 i = aChannel.PslId();
1.699 + DmacSg::SDes* pNewDes = HdrToHwDes(aNewHdr);
1.700 + TInt prevLevel = NKern::DisableAllInterrupts();
1.701 +
1.702 + if ((DmacSg::ChannelControl[i] & DmacSg::EChannelBitRun) == 0)
1.703 + {
1.704 + DmacSg::NextDes[i] = pNewDes;
1.705 + DmacSg::Enable(i);
1.706 + }
1.707 + else if (DmacSg::NextDes[i] == NULL)
1.708 + DmacSg::NextDes[i] = pNewDes;
1.709 + else
1.710 + HdrToHwDes(aLastHdr)->iNext = pNewDes;
1.711 +
1.712 + NKern::RestoreInterrupts(prevLevel);
1.713 + }
1.714 +
1.715 +
1.716 +void DSimSgController::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
1.717 + {
1.718 + DmacSg::SDes* pD = HdrToHwDes(aHdr);
1.719 + pD->iNext = NULL;
1.720 + pD->iControl |= DmacSg::EDesBitInt;
1.721 + }
1.722 +
1.723 +
1.724 +TInt DSimSgController::FailNext(const TDmaChannel& aChannel)
1.725 + {
1.726 + __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0);
1.727 + DmacSg::FailCount[aChannel.PslId()] = 1;
1.728 + return KErrNone;
1.729 + }
1.730 +
1.731 +
1.732 +TInt DSimSgController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount)
1.733 + {
1.734 + __DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0);
1.735 + __DMA_ASSERTD(aInterruptCount >= 0);
1.736 + DmacSg::InterruptsToMiss[aChannel.PslId()] = aInterruptCount;
1.737 + return KErrNone;
1.738 + }
1.739 +
1.740 +
1.741 +TBool DSimSgController::IsIdle(const TDmaChannel& aChannel)
1.742 + {
1.743 + return (DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0;
1.744 + }
1.745 +
1.746 +
1.747 +TInt DSimSgController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.748 + {
1.749 + return KMaxTransferSize;
1.750 + }
1.751 +
1.752 +
1.753 +TUint DSimSgController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
1.754 + {
1.755 + return KMemAlignMask;
1.756 + }
1.757 +
1.758 +
1.759 +void DSimSgController::Isr()
1.760 + {
1.761 + for (TInt i = 0; i < KChannelCount; i++)
1.762 + {
1.763 + TUint32 mask = (1 << i);
1.764 + if (DmacSg::CompletionInt & mask)
1.765 + {
1.766 + DmacSg::CompletionInt &= ~mask;
1.767 + HandleIsr(SgController.iChannels[i], ETrue);
1.768 + }
1.769 + if (DmacSg::ErrorInt & mask)
1.770 + {
1.771 + DmacSg::ErrorInt &= ~mask;
1.772 + HandleIsr(SgController.iChannels[i], EFalse);
1.773 + }
1.774 + }
1.775 + }
1.776 +
1.777 +
1.778 +//////////////////////////////////////////////////////////////////////////////
1.779 +// Channel opening/closing
1.780 +
1.781 +enum TController { ESb=0, EDb=1, ESg=2 };
1.782 +
1.783 +const TUint32 KControllerMask = 0x30;
1.784 +const TUint32 KControllerShift = 4;
1.785 +const TUint32 KChannelIdxMask = 3;
1.786 +
1.787 +#define MKCHN(type, idx) (((type)<<KControllerShift)|idx)
1.788 +
1.789 +static TUint32 TestSbChannels[] = { MKCHN(ESb,0), MKCHN(ESb,1), MKCHN(ESb,2), MKCHN(ESb,3) };
1.790 +static TUint32 TestDbChannels[] = { MKCHN(EDb,0), MKCHN(EDb,1), MKCHN(EDb,2), MKCHN(EDb,3) };
1.791 +static TUint32 TestSgChannels[] = { MKCHN(ESg,0), MKCHN(ESg,1), MKCHN(ESg,2), MKCHN(ESg,3) };
1.792 +
1.793 +static TDmaTestInfo TestInfo =
1.794 + {
1.795 + KMaxTransferSize,
1.796 + KMemAlignMask,
1.797 + 0,
1.798 + KChannelCount,
1.799 + TestSbChannels,
1.800 + KChannelCount,
1.801 + TestDbChannels,
1.802 + KChannelCount,
1.803 + TestSgChannels,
1.804 + };
1.805 +
1.806 +EXPORT_C const TDmaTestInfo& DmaTestInfo()
1.807 + {
1.808 + return TestInfo;
1.809 + }
1.810 +
1.811 +// Keep track of opened channels so Tick callback used to fake DMA
1.812 +// transfers is enabled only when necessary.
1.813 +static TInt OpenChannelCount = 0;
1.814 +
1.815 +
1.816 +TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
1.817 + {
1.818 + TInt dmac = (aOpenId & KControllerMask) >> KControllerShift;
1.819 + __DMA_ASSERTD(dmac < 3);
1.820 + TInt i = aOpenId & KChannelIdxMask;
1.821 + TDmaChannel* pC = NULL;
1.822 + TDmac* controller = NULL;
1.823 + switch (dmac)
1.824 + {
1.825 + case ESb:
1.826 + pC = SbController.iChannels + i;
1.827 + controller = &SbController;
1.828 + break;
1.829 + case EDb:
1.830 + pC = DbController.iChannels + i;
1.831 + controller = &DbController;
1.832 + break;
1.833 + case ESg:
1.834 + pC = SgController.iChannels + i;
1.835 + controller = &SgController;
1.836 + break;
1.837 + default:
1.838 + __DMA_CANT_HAPPEN();
1.839 + }
1.840 +
1.841 + if (++OpenChannelCount == 1)
1.842 + {
1.843 + __KTRACE_OPT(KDMA, Kern::Printf("Enabling DMA simulation"));
1.844 + DmacSim::StartEmulation();
1.845 + }
1.846 + if (pC->IsOpened())
1.847 + return NULL;
1.848 + pC->iController = controller;
1.849 + pC->iPslId = i;
1.850 + return pC;
1.851 + }
1.852 +
1.853 +
1.854 +void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
1.855 + {
1.856 + if (--OpenChannelCount == 0)
1.857 + {
1.858 + DmacSim::StopEmulation();
1.859 + __KTRACE_OPT(KDMA, Kern::Printf("Stopping DMA simulation"));
1.860 + }
1.861 + }
1.862 +
1.863 +TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
1.864 + {
1.865 + return KErrNotSupported;
1.866 + }
1.867 +
1.868 +//////////////////////////////////////////////////////////////////////////////
1.869 +
1.870 +//
1.871 +// On hardware, this code is inside a kernel extension.
1.872 +//
1.873 +
1.874 +DECLARE_STANDARD_EXTENSION()
1.875 + {
1.876 + __KTRACE_OPT(KDMA, Kern::Printf("Starting DMA simulator..."));
1.877 + TInt r;
1.878 + r = SbController.Create(DSimSbController::KInfo);
1.879 + if (r != KErrNone)
1.880 + return r;
1.881 + r = DbController.Create(DSimDbController::KInfo);
1.882 + if (r != KErrNone)
1.883 + return r;
1.884 + r = SgController.Create(DSimSgController::KInfo);
1.885 + if (r != KErrNone)
1.886 + return r;
1.887 +
1.888 + return KErrNone;
1.889 + }
1.890 +
1.891 +//
1.892 +// On WINS, this code is inside a LDD (see mmp file) so we need some
1.893 +// bootstrapping code to call the kernel extension entry point.
1.894 +//
1.895 +
1.896 +class DDummyLdd : public DLogicalDevice
1.897 + {
1.898 +public:
1.899 + // from DLogicalDevice
1.900 + TInt Install();
1.901 + void GetCaps(TDes8& aDes) const;
1.902 + TInt Create(DLogicalChannelBase*& aChannel);
1.903 + };
1.904 +
1.905 +TInt DDummyLdd::Create(DLogicalChannelBase*& aChannel)
1.906 + {
1.907 + aChannel=NULL;
1.908 + return KErrNone;
1.909 + }
1.910 +
1.911 +TInt DDummyLdd::Install()
1.912 + {
1.913 + _LIT(KLddName, "DmaSim");
1.914 + TInt r = SetName(&KLddName);
1.915 + if (r == KErrNone)
1.916 + r = InitExtension();
1.917 + return r;
1.918 + }
1.919 +
1.920 +void DDummyLdd::GetCaps(TDes8& /*aDes*/) const
1.921 + {
1.922 + }
1.923 +
1.924 +EXPORT_C DLogicalDevice* CreateLogicalDevice()
1.925 + {
1.926 + return new DDummyLdd;
1.927 + }
1.928 +
1.929 +
1.930 +//---