--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/dmav2/t_dma2.cpp Tue Aug 31 16:34:26 2010 +0300
@@ -0,0 +1,2851 @@
+// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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\dmav2\t_dma2.cpp
+
+#include "d_dma2.h"
+#include "u32std.h"
+#include "t_dma2.h"
+#include "cap_reqs.h"
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32debug.h>
+#include <e32svr.h>
+#include <e32def_private.h>
+
+// DMA test framework command parameter options
+
+// SelfTest option
+_LIT(KArgSelfTest, "/SELFTEST");
+_LIT(KArgSelfTest2, "/S");
+
+//Verbose option
+_LIT(KArgVerboseOutput, "/VERBOSE");
+_LIT(KArgVerboseOutput2, "/V");
+
+//Simple transfer test option
+_LIT(KArgSimpleTest, "/simple");
+
+//Callback test option
+_LIT(KArgCallBackTest, "/callback");
+
+//Suspend test option
+_LIT(KArgSuspendTest, "/suspend");
+
+//Multipart transfer tests
+_LIT(KArgMultiPartTest, "/multi");
+
+//Isr and dfc test option
+_LIT(KArgIsrDfcTest, "/isrdfc");
+
+//Isr reque test option
+_LIT(KArgIsrequeTest, "/isreque");
+
+//Benchmark test option
+_LIT(KArgBenchmarkTest, "/bench");
+
+//Graphics test option
+_LIT(KArgGraphicTest, "/graphic");
+
+//DMA channel (opening and closing) test option
+_LIT(KArgChannelTest, "/channel");
+
+//Queue test option
+_LIT(KArgQueueTest, "/queue");
+
+//Fragment test option
+_LIT(KArgFragmentTest, "/fragment");
+
+//Request test option
+_LIT(KArgRequestTest, "/request");
+
+
+
+TBool gHelpRequested; // print usage
+TBool gVerboseOutput; // enable verbose output
+TBool gSelfTest; // run SelfTest
+TBool gSimpleTest; // run only Simple transfer test
+TBool gCallBack; // run only Callback test
+TBool gSuspend; // run only Pause and resume tests
+TBool gIsrReque; // run only IsrReque tests
+TBool gMultiPart; // run only Multipart tests
+TBool gIsrAndDfc; // run only IsrAndDfc tests
+TBool gBenchmark; // run only Benchmark tests
+TBool gGraphic; // run only Graphic tests
+TBool gFragment; // run only Fragment related tests
+TBool gChannel; // run only Channel(open/close)tests
+TBool gQueue; // run only Queue related tests
+TBool gRequest; // run only Request related tests
+
+/**
+This function prints out the PSL test Information
+*/
+void Print(const TDmaV2TestInfo& aInfo)
+ {
+ PRINT(aInfo.iMaxTransferSize);
+ PRINT(aInfo.iMemAlignMask);
+ PRINT(aInfo.iMemMemPslInfo);
+ PRINT(aInfo.iMaxSbChannels);
+ for(TInt i=0; i<aInfo.iMaxSbChannels; i++)
+ {
+ PRINT(aInfo.iSbChannels[i]);
+ }
+ PRINT(aInfo.iMaxDbChannels);
+ for(TInt j=0; j<aInfo.iMaxDbChannels; j++)
+ {
+ PRINT(aInfo.iDbChannels[j]);
+ }
+ PRINT(aInfo.iMaxSgChannels);
+ for(TInt k=0; k<aInfo.iMaxSgChannels; k++)
+ {
+ PRINT(aInfo.iSgChannels[k]);
+ }
+ }
+
+void CDmaTest::PrintTestInfo() const
+ {
+ TBuf<32> buf;
+ buf.AppendFormat(_L("DMA channel %d"), iChannelCookie);
+ RDebug::RawPrint(buf);
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CDmaTest
+//////////////////////////////////////////////////////////////////////
+
+void CDmaTest::OpenDmaSession()
+ {
+ // Only open a new session if one
+ // was not already supplied
+ if(iDmaSession.Handle() == KNullHandle)
+ {
+ TInt r = iDmaSession.Open();
+ if(KErrNone != r)
+ {
+ RDebug::Printf("CDmaTest::OpenDmaSession = %d\n", r);
+ }
+ TEST_ASSERT(r == KErrNone);
+ r = iDmaSession.OpenSharedChunk(iChunk);
+ TEST_ASSERT(r == KErrNone);
+ }
+ }
+
+// Open another handle to the test driver
+void CDmaTest::OpenDmaSession(const RDmaSession& aSession)
+ {
+ iDmaSession = aSession;
+ TInt r = iDmaSession.Duplicate(RThread(), EOwnerThread);
+ TEST_ASSERT(r == KErrNone);
+
+ // open another handle to the test driver chunk
+ r = iDmaSession.OpenSharedChunk(iChunk);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+void CDmaTest::CloseDmaSession()
+ {
+ iChunk.Close();
+ iDmaSession.Close();
+ }
+
+void CDmaTest::PreTransferSetup()
+ {
+ }
+
+TInt CDmaTest::DoPostTransferCheck()
+ {
+ return KErrNotSupported;
+ }
+
+void CDmaTest::ChannelPause(TUint aChannelSessionCookie)
+{
+ TInt r = iDmaSession.ChannelPause(aChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+}
+
+void CDmaTest::ChannelResume(TUint aChannelSessionCookie)
+{
+ TInt r = iDmaSession.ChannelResume(aChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+}
+//////////////////////////////////////////////////////////////////////
+// CSingleTransferTest
+//////////////////////////////////////////////////////////////////////
+void CSingleTransferTest::RunTest()
+ {
+ OpenDmaSession();
+ PreTransferSetup();
+
+ OpenChannel();
+ CreateDmaRequest();
+ Fragment();
+ Queue();
+ FreeRequest();
+ CloseChannel();
+ PostTransferCheck();
+
+ CloseDmaSession();
+ }
+
+void CSingleTransferTest::OpenChannel()
+ {
+ iActual.iChannelOpenResult =
+ iDmaSession.ChannelOpen(iChannelCookie, iChannelSessionCookie);
+ }
+
+void CSingleTransferTest::CreateDmaRequest()
+ {
+ if(iUseNewRequest)
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Calling New Request API\n");
+ }
+ iActual.iRequestResult.iCreate =
+ iDmaSession.RequestCreate(iChannelSessionCookie, iRequestSessionCookie, iMaxFragmentSize);
+ }
+ else
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Calling Old Request API\n");
+ }
+ iActual.iRequestResult.iCreate =
+ iDmaSession.RequestCreateOld(iChannelSessionCookie, iRequestSessionCookie, iMaxFragmentSize);
+ }
+ }
+
+void CSingleTransferTest::Fragment()
+ {
+ if(iActual.iRequestResult.iCreate != KErrNone)
+ return;
+
+ if(iUseNewFragment)
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Calling New Fragment API\n");
+ }
+ iActual.iRequestResult.iFragmentationResult =
+ iDmaSession.FragmentRequest(iRequestSessionCookie, iTransferArgs);
+ }
+ else
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Calling Old Fragment API\n");
+ }
+ iActual.iRequestResult.iFragmentationResult =
+ iDmaSession.FragmentRequestOld(iRequestSessionCookie, iTransferArgs);
+ }
+
+ const TInt fragmentCount = iDmaSession.RequestFragmentCount(iRequestSessionCookie);
+
+ // Record the fragment count if a non-zero value was expected,
+ // or if it was an error value
+ if(iExpected.iRequestResult.iFragmentCount != 0 || fragmentCount < 0)
+ iActual.iRequestResult.iFragmentCount = fragmentCount;
+ }
+
+void CSingleTransferTest::Queue()
+ {
+ if(iActual.iRequestResult.iFragmentationResult == KErrNone)
+ {
+ iActual.iRequestResult.iQueueResult = iDmaSession.QueueRequest(iRequestSessionCookie, &iActual.iCallbackRecord);
+ }
+ }
+
+void CSingleTransferTest::PostTransferCheck()
+ {
+ if(iPostTransferCheck)
+ iActual.iPostTransferCheck = DoPostTransferCheck();
+ }
+
+TInt CSingleTransferTest::DoPostTransferCheck()
+ {
+ return iPostTransferCheck->Check(*this);
+ }
+
+void CSingleTransferTest::FreeRequest()
+ {
+ if(iActual.iRequestResult.iCreate == KErrNone)
+ {
+ TInt r = iDmaSession.RequestDestroy(iRequestSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+ }
+
+void CSingleTransferTest::CloseChannel()
+ {
+ if(iActual.iChannelOpenResult == KErrNone)
+ {
+ TInt r = iDmaSession.ChannelClose(iChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+ }
+
+void CSingleTransferTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Single transfer"));
+ }
+
+void CSingleTransferTest::PrintTestInfo() const
+ {
+ CDmaTest::PrintTestInfo();
+
+ // State which API versions are being used
+ if(iUseNewFragment)
+ RDebug::RawPrint(_L(", Fragment v2,"));
+ else
+ RDebug::RawPrint(_L(", Fragment v1,"));
+
+ if(iUseNewRequest)
+ RDebug::RawPrint(_L(" DDmaRequest v2"));
+ else
+ RDebug::RawPrint(_L(" DDmaRequest v1"));
+ }
+
+void CSingleTransferTest::PreTransferSetup()
+ {
+ if(iPreTransfer)
+ iPreTransfer->Setup(*this); //initialize test
+ }
+
+TBool CSingleTransferTest::Result()
+ {
+ const TBool result = iExpected == iActual;
+ if(!result)
+ {
+ RDebug::Printf("TResultSets do not match");
+ }
+ if(!result || gVerboseOutput)
+ {
+ RDebug::Printf("\nExpected error codes:");
+ iExpected.Print();
+ RDebug::Printf("Expected callback record:");
+ iExpected.iCallbackRecord.Print();
+
+ RDebug::Printf("\nActual error codes:");
+ iActual.Print();
+ RDebug::Printf("Actual callback record:");
+ iActual.iCallbackRecord.Print();
+ }
+ return result;
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CDmaTestDecorator
+//////////////////////////////////////////////////////////////////////
+
+CDmaTestDecorator::CDmaTestDecorator(CDmaTest* aDecoratedTest)
+ : CDmaTest(_L("Decorated Test"), 1, NULL, NULL), iDecoratedTest(aDecoratedTest)
+ {}
+
+CDmaTestDecorator::CDmaTestDecorator(const CDmaTestDecorator& aOther)
+ : CDmaTest(aOther), iDecoratedTest( static_cast<CDmaTest*>( aOther.iDecoratedTest->Clone() ) )
+ // Need cast because Clone does not have a covariant return type,
+ // as not all compillers allow it
+ {}
+
+//////////////////////////////////////////////////////////////////////
+// CMultiVersionTest
+//////////////////////////////////////////////////////////////////////
+
+CMultiVersionTest::CMultiVersionTest(CSingleTransferTest* aDmaTest)
+ : CDmaTestDecorator(aDmaTest), iNewVersionTest(NULL)
+ {
+ }
+
+CMultiVersionTest::CMultiVersionTest(const CMultiVersionTest& aOther)
+ : CDmaTestDecorator(aOther), iNewVersionTest( aOther.iNewVersionTest ? static_cast<CSingleTransferTest*>(aOther.iNewVersionTest->Clone()) : NULL)
+ {
+ }
+
+CMultiVersionTest::~CMultiVersionTest()
+ {
+ delete iDecoratedTest;
+ delete iNewVersionTest;
+ }
+
+void CMultiVersionTest::SetupL()
+ {
+ // Open a tempory dma session to find out the
+ // capabilities of the dma channel.
+ OpenDmaSession();
+ Configure();
+ CloseDmaSession();
+ }
+
+void CMultiVersionTest::Announce() const
+ {
+ CTest::Announce();
+
+ iDecoratedTest->Announce();
+
+ if(iNewVersionTest)
+ iNewVersionTest->Announce();
+ }
+
+void CMultiVersionTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Multi version test wrapper"));
+ }
+
+void CMultiVersionTest::PrintTestInfo() const
+ {
+ if(iNewVersionTest)
+ {
+ RDebug::RawPrint(_L("Running tests using Version 2 PIL"));
+ }
+ else
+ {
+ RDebug::RawPrint(_L("Running tests using Version 1 PIL"));
+ }
+ }
+
+void CMultiVersionTest::RunTest()
+ {
+ OpenDmaSession();
+
+ // iDecoratedTest is the test, in the old configuration
+ // iNewVersionTest is the same test, configured
+ // to use the new APIs
+ //
+ // 2 objects are needed since they can each store
+ // their own results
+
+ iDecoratedTest->OpenDmaSession(iDmaSession);
+ (*iDecoratedTest)();
+
+ if(iNewVersionTest)
+ {
+ iNewVersionTest->OpenDmaSession(iDmaSession);
+ (*iNewVersionTest)();
+ }
+
+ CloseDmaSession();
+ }
+
+/**
+Maybe create another test object to run with new API
+
+Pass on the cookie for the channel they must test
+*/
+void CMultiVersionTest::Configure()
+ {
+ static_cast<CSingleTransferTest*>(iDecoratedTest)->UseNewDmaApi(EFalse);
+ iDecoratedTest->SetChannelCookie(iChannelCookie);
+
+ if(Version2PILAvailable())
+ {
+ iNewVersionTest = static_cast<CSingleTransferTest*>(iDecoratedTest->Clone());
+ TEST_ASSERT(iNewVersionTest != NULL);
+
+ iNewVersionTest->UseNewDmaApi(ETrue);
+ iNewVersionTest->SetChannelCookie(iChannelCookie);
+ }
+ }
+
+/**
+Discover from DMA channel what PIL versions are available.
+In practice V1 APIs will always be available, V2 may be.
+*/
+TBool CMultiVersionTest::Version2PILAvailable()
+ {
+ TUint channelSessionCookie;
+ TInt r = iDmaSession.ChannelOpen(iChannelCookie, channelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+
+ TDmacTestCaps channelCaps;
+ r = iDmaSession.ChannelCaps(channelSessionCookie, channelCaps);
+ TEST_ASSERT(r == KErrNone);
+
+ r = iDmaSession.ChannelClose(channelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+
+ return channelCaps.iPILVersion >= 2;
+ }
+
+TBool CMultiVersionTest::Result()
+ {
+ TBool v1Result = iDecoratedTest->Result();
+ if(gVerboseOutput || !v1Result)
+ RDebug::Printf("V1 API result: %s", v1Result ? "success" : "failure");
+
+ TBool v2Result = iNewVersionTest ? iNewVersionTest->Result() : ETrue;
+ if(gVerboseOutput || !v1Result)
+ RDebug::Printf("V2 API result: %s", v2Result ? "success" : "failure");
+ return v1Result && v2Result;
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CDmaBenchmark
+//////////////////////////////////////////////////////////////////////
+CDmaBenchmark::CDmaBenchmark(const TDesC& aName, TInt aIterations, const TResultSet& aExpectedResults, const TDmaTransferArgs& aTransferArgs, TUint aMaxFragmentSize)
+ :CSingleTransferTest(aName, aIterations, aTransferArgs, aExpectedResults, aMaxFragmentSize, NULL, NULL)
+ {
+ UseNewDmaApi(EFalse);
+ }
+
+CDmaBenchmark::CDmaBenchmark(const CDmaBenchmark& aOriginal)
+ :CSingleTransferTest(aOriginal)
+ {
+ CopyL(aOriginal.iResultArray, iResultArray);
+ }
+
+CDmaBenchmark::~CDmaBenchmark()
+ {
+ iResultArray.Close();
+ }
+
+TUint64 CDmaBenchmark::MeanResult()
+ {
+ if(gVerboseOutput)
+ RDebug::Printf("CDmaBenchmark::MeanResult\n");
+
+ const TInt count = iResultArray.Count();
+
+ TEST_ASSERT(count > 0);
+ TEST_ASSERT(count == iIterations);
+
+ TUint64 sum = 0;
+
+ for(TInt i = 0; i < count; i++)
+ {
+ const TUint64 value = iResultArray[i];
+ if(gVerboseOutput)
+ RDebug::Printf("iResultArray[%d]: %lu", i, value);
+
+ sum += value;
+ }
+
+ return sum / count;
+ }
+
+TBool CDmaBenchmark::Result()
+ {
+ const TBool result = CSingleTransferTest::Result();
+ if(result)
+ {
+ RDebug::Printf(" Mean time: %lu us", MeanResult());
+ }
+
+ return result;
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CDmaBmFragmentation
+//////////////////////////////////////////////////////////////////////
+CDmaBmFragmentation::CDmaBmFragmentation(const TDesC& aName, TInt aIterations, const TDmaTransferArgs& aTransferArgs, TUint aMaxFragmentSize)
+ :CDmaBenchmark(aName, aIterations, ExpectedResults, aTransferArgs, aMaxFragmentSize)
+ {}
+
+const TResultSet CDmaBmFragmentation::ExpectedResults(KErrNone,
+ TRequestResults(KErrNone, 0, KErrNone, KErrUnknown),
+ KErrUnknown,
+ TCallbackRecord::Empty()
+ );
+
+void CDmaBmFragmentation::Fragment()
+ {
+ TUint64 time;
+ iActual.iRequestResult.iFragmentationResult =
+ iDmaSession.FragmentRequestOld(iRequestSessionCookie, iTransferArgs, &time);
+ iResultArray.Append(time);
+ }
+
+void CDmaBmFragmentation::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Fragmentation Benchmark"));
+ }
+
+void CDmaBmFragmentation::RunTest()
+ {
+ OpenDmaSession();
+
+ OpenChannel();
+ CreateDmaRequest();
+ Fragment();
+ FreeRequest();
+ CloseChannel();
+ CloseDmaSession();
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CPauseResumeTest
+//
+// -Time how long a given transfer takes
+// -Pause the channel
+// -repeat the transfer (queued asynchronously)
+// -wait for some time (say, 3 times the time measured)
+// -read the value of the TRequestStatus object, to check it is still pending
+// -resume the channel
+// -Wait on the request
+// -Confirm that the request completed
+//////////////////////////////////////////////////////////////////////
+CPauseResumeTest::~CPauseResumeTest()
+ {
+ }
+
+void CPauseResumeTest::RunTest()
+ {
+ OpenDmaSession();
+
+ //Open a single DMA channel for a transfer
+ OpenChannel();
+
+ RDebug::Printf("Resume unpaused idle channel");
+ TInt r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrCompletion == r);
+
+ RDebug::Printf("Pause idle channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ RDebug::Printf("Pause paused idle Channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrCompletion == r);
+
+ RDebug::Printf("Resume paused idle channel");
+ r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ //Setup a DMA request and Fragment the request.
+ CreateDmaRequest();
+ Fragment();
+
+ //Queue the DMA request and time how long a transfer takes
+ TUint64 queueTime;
+ DoCalibrationTransfer(queueTime);
+
+ RDebug::Printf("Calibration transfer completed in %Lu us",queueTime);
+ TUint32 waitQueueReqTime = I64LOW(queueTime*3); //3 times the time measured in DoCalibrationTransfer
+ TEST_ASSERT(I64HIGH(queueTime*3) == 0); // If transfer takes over an hour, something has gone wrong anyway
+
+ // Initialise buffers, after calibration transfer
+ PreTransferSetup();
+
+ RDebug::Printf("Resume unpaused channel");
+ r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrCompletion == r);
+
+ //Pause DMA Transfer
+ RDebug::Printf("Pausing DMA Channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ RDebug::Printf("Pause paused Channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrCompletion == r);
+
+ //Repeat the transfer (queued asynchronously)
+ TRequestStatus queueRequestStatus;
+ iActual.iRequestResult.iQueueResult = QueueAsyncRequest(queueRequestStatus,queueTime);
+ RDebug::Printf("Queue a DMA Request and wait for %u us ", waitQueueReqTime);
+
+ User::After(waitQueueReqTime);
+ RDebug::Printf("Finished waiting");
+ TEST_ASSERT(queueRequestStatus.Int() == KRequestPending);
+
+ TBool queueEmpty = ETrue;
+ r = iDmaSession.ChannelIsQueueEmpty(iChannelSessionCookie,queueEmpty);
+ TEST_ASSERT(r == KErrNone);
+ TEST_ASSERT(!queueEmpty);
+
+ //Resume DMA channel
+ RDebug::Printf("Resuming paused DMA Channel");
+ r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ //Wait for transfer to complete
+ User::WaitForRequest(queueRequestStatus);
+ if (queueRequestStatus.Int() == KErrNone)
+ {
+ RDebug::Printf("DMA QueueAsyncRequest completed");
+ }
+
+ FreeRequest();
+ CloseChannel();
+
+ PostTransferCheck();
+ CloseDmaSession();
+ }
+
+/**
+Time how long transfer takes, with no pausing
+*/
+void CPauseResumeTest::DoCalibrationTransfer(TUint64 &atime)
+ {
+ //Queue the DMA request.
+ TCallbackRecord pCallbackRecord;
+ TInt r = iDmaSession.QueueRequest(iRequestSessionCookie,&pCallbackRecord,&atime);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+TInt CPauseResumeTest::QueueAsyncRequest(TRequestStatus &aRequestState, TUint64 &atime)
+ {
+ return iDmaSession.QueueRequest(iRequestSessionCookie,aRequestState, &iActual.iCallbackRecord, &atime);
+ }
+
+void CPauseResumeTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Pause and Resume API Test"));
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CPauseResumeNegTest
+//
+// -Open DMA Channel
+// -Pause and Resume DMA channel
+// -Check that KErrNotSupported is returned
+// -Close DMA Channel
+//////////////////////////////////////////////////////////////////////
+CPauseResumeNegTest::~CPauseResumeNegTest()
+ {
+ }
+
+void CPauseResumeNegTest::RunTest()
+ {
+ OpenDmaSession();
+
+ //Open a single DMA channel for a transfer
+ OpenChannel();
+
+ RDebug::Printf("Resume unpaused idle channel");
+ TInt r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ RDebug::Printf("Pause idle channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ RDebug::Printf("Pause paused idle Channel");
+ r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ RDebug::Printf("Resume paused idle channel");
+ r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ CloseChannel();
+ CloseDmaSession();
+ }
+
+void CPauseResumeNegTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Pause and Resume API Test - Negative Test"));
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CLinkChannelTest
+//
+// -Open DMA Channel
+// -Link and Unlink DMA channel
+// -Check that KErrNotSupported is returned
+// -Close DMA Channel
+//
+//////////////////////////////////////////////////////////////////////
+CLinkChannelTest::~CLinkChannelTest()
+ {
+ }
+
+void CLinkChannelTest::RunTest()
+ {
+ OpenDmaSession();
+
+ //Open a single DMA channel for a transfer
+ OpenChannel();
+
+ RDebug::Printf("Linking DMA channels");
+ TInt r = iDmaSession.ChannelLinking(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ RDebug::Printf("Unlinking DMA channels");
+ r = iDmaSession.ChannelUnLinking(iChannelSessionCookie);
+ TEST_ASSERT(KErrNotSupported == r);
+
+ CloseChannel();
+ CloseDmaSession();
+ }
+
+void CLinkChannelTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Channel Linking API Test - Negative Test"));
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CElementCountingTest
+//
+// -Open DMA Channel
+// -Create Request
+// -Fragment and Make calls to Element Counting APIs
+// -Check that TotalNumDstElementsTransferred() and TotalNumSrcElementsTransferred()
+// return non zero values
+// -Check that KErrNone(from test driver) returned for other API calls
+// -Queue Request
+// -Close DMA Channel
+//////////////////////////////////////////////////////////////////////
+CElementCountingTest::~CElementCountingTest()
+ {
+ }
+
+void CElementCountingTest::RunTest()
+ {
+ OpenDmaSession();
+ PreTransferSetup();
+
+ //Open a single DMA channel for a transfer
+ OpenChannel();
+
+ //Setup a DMA request and Fragment the request.
+ RDebug::Printf("Create and Fragment DMA Request");
+ CreateDmaRequest();
+ Fragment();
+
+ //Enable src/dst counting
+ RDebug::Printf("Enable DstElementCounting");
+ TInt r = iDmaSession.RequestEnableDstElementCounting(iRequestSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ RDebug::Printf("Enable SrcElementCounting");
+ r = iDmaSession.RequestEnableSrcElementCounting(iRequestSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ //Queue request
+ RDebug::Printf("Queue DMA Request");
+ Queue();
+
+ //Disable src/dst counting
+ RDebug::Printf("Disable DstElementCounting");
+ r = iDmaSession.RequestDisableDstElementCounting(iRequestSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ RDebug::Printf("Disable SrcElementCounting");
+ r = iDmaSession.RequestDisableSrcElementCounting(iRequestSessionCookie);
+ TEST_ASSERT(KErrNone == r);
+
+ //check total src/dst elements transferred
+ RDebug::Printf("Get Total Number of DstElementsTransferred");
+ r = iDmaSession.RequestTotalNumDstElementsTransferred(iRequestSessionCookie);
+ TEST_ASSERT(r >= 0);
+
+ RDebug::Printf("Get Total Number of SrcElementsTransferred");
+ r = iDmaSession.RequestTotalNumSrcElementsTransferred(iRequestSessionCookie);
+ TEST_ASSERT(r >= 0);
+
+ FreeRequest();
+ CloseChannel();
+
+ PostTransferCheck();
+ CloseDmaSession();
+ }
+
+void CElementCountingTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Element Counting Tests"));
+ }
+
+//////////////////////////////////////////////////////////////////////
+// COpenCloseTest
+//////////////////////////////////////////////////////////////////////
+COpenCloseTest::~COpenCloseTest()
+ {
+ }
+
+TBool COpenCloseTest::DoRunClose()
+ {
+ // For storing cookie during neagtive test i,e open channel twice
+ TUint testChannelSessionCookie = 0;
+
+ // Open a single DMA channel
+ TInt r = iDmaSession.ChannelOpen(iChannelCookie, iChannelSessionCookie);
+ if (r == KErrNone)//Check that DMA channel opened with no errors
+ {
+ RDebug::Printf("DMA channel opened");
+ }
+ else
+ {
+ RDebug::Printf("Open DMA channel failed");
+ return EFalse;
+ }
+
+ // Open DMA channel again and check that opening DMA channel again fails
+ r = iDmaSession.ChannelOpen(iChannelCookie, testChannelSessionCookie);
+ if (r == KErrInUse)
+ {
+ RDebug::Printf("Opening DMA channel again fails as expected");
+ }
+ else
+ {
+ RDebug::Printf("Open DMA channel again failed");
+ return EFalse;
+ }
+
+ // Close the DMA channel and check that DMA channel closes with no errors
+ r =iDmaSession.ChannelClose(iChannelSessionCookie);
+ if (r == KErrNone)
+ {
+ RDebug::Printf("DMA channel closes with no errors");
+ }
+ else
+ {
+ RDebug::Printf("Close the DMA channel failed");
+ return EFalse;
+ }
+
+ // Verify that the DMA channel was actually closed by opening DMA channel
+ r = iDmaSession.ChannelOpen(iChannelCookie, iChannelSessionCookie);
+ if (r == KErrNone)
+ {
+ RDebug::Printf("DMA channel opened after a previous close operation");
+ return ETrue;
+ }
+ else
+ {
+ RDebug::Printf("Open DMA channel to verify that the DMA channel closed failed");
+ return EFalse;
+ }
+ }
+
+TBool COpenCloseTest::DoRunOpen()
+ {
+ // Open a single DMA channel
+ TInt r = iDmaSession.ChannelOpen(iChannelCookie, iChannelSessionCookie);
+ if (r == KErrNone)//Check that DMA channel opened with no errors
+ {
+ RDebug::Printf("DoRunOpen:DMA channel opened");
+ }
+ else
+ {
+ RDebug::Printf("DoRunOpenDMA channel failed to open");
+ return EFalse;
+ }
+
+ // Verify that channel is really open by closing DMA channel
+ // and checking that DMA channel closes with no errors
+ r = iDmaSession.ChannelClose(iChannelSessionCookie);
+ if (r == KErrNone)
+ {
+ RDebug::Printf("DoRunOpen:DMA channel closes with no errors");
+ return ETrue;
+ }
+ else
+ {
+ RDebug::Printf("DoRunOpen:DMA channel failed to close");
+ return EFalse;
+ }
+ }
+
+TBool COpenCloseTest::DoRunOpenExposed()
+ {
+ SCreateInfoTest TOpenInfo;
+ TOpenInfo.iCookie =iChannelCookie;
+ TOpenInfo.iDfcPriority = 3;
+
+ const TInt desCount[3] = {0,1,128};
+ const TBool dynChannel[3] = {EFalse,EFalse,ETrue};
+ const TInt expectedResults[3] = {KErrArgument,KErrNone,KErrInUse};
+ TInt actualResults[3] = {1, 1, 1};
+
+ for (TInt i =0; i<3; i++)
+ {
+ TOpenInfo.iDesCount = desCount[i];
+ TOpenInfo.iDynChannel = dynChannel[i];
+
+ // Open a single DMA channel
+ RDebug::Printf("DoRunOpenExposed:Trying to open DMA channel using iDesCount(%d) and iDynChannel(%d) ", TOpenInfo.iDesCount,TOpenInfo.iDynChannel);
+ actualResults[i] = iDmaSession.ChannelOpen(iChannelSessionCookie, TOpenInfo);
+ if (actualResults[i] == KErrNone)// Verify that channel is really open by closing DMA channel
+ {
+ TInt err = iDmaSession.ChannelClose(iChannelSessionCookie);
+ TEST_ASSERT(err == KErrNone)//Check that DMA channel closed with no errors
+ }
+ }
+
+ // This case should fail if idesCount = 0.
+ // PIL has been changed to return KErrArgument instead of using an assertion check
+ if (expectedResults[0] == actualResults[0])
+ {
+ RDebug::Printf("DoRunOpenExposed:DMA channel failed to open as expected as for iDesCount = 0 ");
+ }
+ else
+ {
+ RDebug::Printf("DoRunOpenExposed:Error code returned (%d), expected KErrArgument as iDesCount= 0) ", actualResults[0]);
+ return EFalse;
+ }
+
+ // For this case( idesCount = 1), DMA channel should open with no issues
+ if (expectedResults[1] == actualResults[1])
+ {
+ RDebug::Printf("DoRunOpenExposed:DMA channel closes with no errors as expected for iDesCount = 1 ");
+ }
+ else
+ {
+ RDebug::Printf("DoRunOpenExposed:Failed to open DMA channel with error code (%d)", actualResults[1]);
+ return EFalse;
+ }
+
+ // For this case(dynaChannel=ETrue), DMA channel now returns KErrInUse. dynaChannel is not supported in the PSL.
+ // PSL now returns a NULL pointer when dynaChannel is requested. The PIL interprets a NULL
+ // pointer being returned from opening a DMA channel as a channel in use. Hence, KErrInUse is returned.
+ if (expectedResults[2] == actualResults[2])
+ {
+ RDebug::Printf("DoRunOpenExposed:DMA channel failed to open as expected as dynamic channel is not supported");
+ }
+ else
+ {
+ RDebug::Printf("DoRunOpenExposed:Error code returned (%d), expected KErrInUse as as dynamic channel is not supported", actualResults[2]);
+ return EFalse;
+ }
+
+ return ETrue;
+ }
+
+void COpenCloseTest::RunTest()
+ {
+ OpenDmaSession();
+
+ if (iRunOpen)
+ { // Run Open() API test
+ iOpenCloseResult = DoRunOpenExposed();
+ if(iOpenCloseResult)
+ iOpenCloseResult = DoRunOpen();
+ }
+ else
+ {
+ // Run Close() API test
+ iOpenCloseResult = DoRunClose();
+ }
+
+ CloseDmaSession();
+ }
+
+void COpenCloseTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Close/Open API Test"));
+
+ }
+
+TBool COpenCloseTest::Result()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Results for Close/Open API Test");
+ }
+
+ if(!iOpenCloseResult)
+ {
+ RDebug::Printf("Open/Close test sequence failed");
+ }
+
+ return iOpenCloseResult;
+ }
+//////////////////////////////////////////////////////////////////////
+// CDmaBmTransfer
+//////////////////////////////////////////////////////////////////////
+CDmaBmTransfer::CDmaBmTransfer(const TDesC& aName, TInt aIterations, const TDmaTransferArgs& aTransferArgs, TUint aMaxFragmentSize)
+ :CDmaBenchmark(aName, aIterations,
+ TResultSet(KErrNone, TRequestResults(), KErrUnknown, TCallbackRecord(TCallbackRecord::EThread,1)),
+ aTransferArgs, aMaxFragmentSize)
+ {}
+
+void CDmaBmTransfer::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Transfer Benchmark"));
+ }
+
+void CDmaBmTransfer::RunTest()
+ {
+ OpenDmaSession();
+
+ OpenChannel();
+ CreateDmaRequest();
+ Fragment();
+ Queue();
+ FreeRequest();
+ CloseChannel();
+
+ CloseDmaSession();
+ }
+
+void CDmaBmTransfer::Queue()
+ {
+ if(iActual.iRequestResult.iFragmentationResult == KErrNone)
+ {
+ TUint64 time;
+ iActual.iRequestResult.iQueueResult = iDmaSession.QueueRequest(iRequestSessionCookie, &iActual.iCallbackRecord, &time);
+ iResultArray.Append(time);
+ }
+ }
+
+/*
+1. Open a DMA channel for a transfer.
+2. Queue multiple request on the DMA channel.
+3. Call CancelAll () on the DMA channel.
+4. Verify that all transfers have been cancelled.
+5. Open a DMA channel for a transfer. This channel should support pause and resume.
+6. Call Pause () on the channel.
+7. Queue multiple request on the DMA channel.
+8. Call CancelAll () on the channel.
+9. Verify that all transfers have been cancelled.
+
+ Note: This check does not add results to TResultSet like some
+ other tests as its operation is different. The test checks for
+ the the cancelllation of all transfers queued on a channel by
+ calling iDmaSession.ChannelIsQueueEmpty();
+*/
+
+//////////////////////////////////////////////////////////////////////
+// CCancelAllTest
+//////////////////////////////////////////////////////////////////////
+
+
+CCancelAllTest::CCancelAllTest(const TDesC& aName, TInt aIterations,
+ const TDmaTransferArgs* aTransferArgs, const TResultSet* aResultSets,
+ TInt aCount)
+ :CMultiTransferTest(aName, aIterations, aTransferArgs, aResultSets, aCount)
+ {}
+
+void CCancelAllTest::RunTest()
+ {
+ OpenDmaSession();
+ PreTransferSetup();
+
+ // Open a DMA channel for a transfer.This channel should support pause and resume.
+ OpenChannel();
+
+ //Call Pause () on the channel
+ RDebug::Printf("Pausing DMA Channel");
+ ChannelPause(iChannelSessionCookie);
+
+ // Queue multiple request on the DMA channel.
+ CreateDmaRequests();
+ Fragment();
+
+ QueueRequestsAsync();
+
+ // Call CancelAll () on the DMA channel and Verify that all transfers have been cancelled.
+ TInt r = CancelAllRequests();
+ TEST_ASSERT(r == KErrNone);
+
+ //Call Resume () on the channel.
+ RDebug::Printf("Cancel should clear Pause state: resuming channel should fail");
+ ChannelResume(iChannelSessionCookie);
+ //TEST_ASSERT(r == KErrCompletion);
+
+ r = DoPostTransferCheck();
+ TEST_ASSERT(r == KErrNone);
+ //Destroy request
+ for(TInt i=0; i<2; i++)
+ {
+ r = iDmaSession.RequestDestroy(iRequestCookies[i]);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+ //Close DMA channel
+ CloseChannel();
+
+ CloseDmaSession();
+ }
+
+TInt CCancelAllTest::CancelAllRequests()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("CCancelAllTest::CancelAllRequests()");
+ }
+ TInt r = KErrGeneral;
+ r = iDmaSession.ChannelCancelAll(iChannelSessionCookie);
+ if (r != KErrNone)
+ return r;
+
+ TBool queueEmpty;
+ r = iDmaSession.ChannelIsQueueEmpty(iChannelSessionCookie,queueEmpty);
+ if (r != KErrNone)
+ return r;
+
+ if(!queueEmpty)
+ return KErrGeneral;
+
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Both current and pending requests cancelled");
+ }
+ return KErrNone;
+ }
+
+void CCancelAllTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("CCancelAllTest"));
+ }
+
+void CCancelAllTest::QueueRequestsAsync()
+ {
+ if(iPauseWhileQueuing)
+ {
+ TInt r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+ // Queue all the DMA requests asynchronously
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ TResultSet& resultSet = iActualResults[i];
+ if(resultSet.iRequestResult.iFragmentationResult != KErrNone)
+ continue;
+
+ TInt r = iDmaSession.QueueRequest(iRequestCookies[i], iDummyRequestStatus, &resultSet.iCallbackRecord, NULL);
+ resultSet.iRequestResult.iQueueResult = r;
+ }
+
+ if(iPauseWhileQueuing)
+ {
+ TInt r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CIsQueueEmptyTest
+//////////////////////////////////////////////////////////////////////
+CIsQueueEmptyTest::CIsQueueEmptyTest(const TDesC& aName, TInt aIterations, const TDmaTransferArgs* aTransferArgs,
+ const TResultSet* aResultSets, TInt aCount)
+ :CMultiTransferTest(aName, aIterations, aTransferArgs, aResultSets, aCount)
+ {}
+
+CIsQueueEmptyTest::CIsQueueEmptyTest(const CIsQueueEmptyTest& aOther)
+ :CMultiTransferTest(aOther)
+ {}
+
+CIsQueueEmptyTest::~CIsQueueEmptyTest()
+ {
+ }
+
+void CIsQueueEmptyTest::RunTest()
+ {
+ OpenDmaSession();
+ PreTransferSetup();
+
+ OpenChannel();
+
+ CreateDmaRequests();
+ Fragment();
+ QueueRequests();
+
+ TInt r = DoPostTransferCheck();
+ TEST_ASSERT(r == KErrNone);
+
+ CloseDmaSession();
+ }
+
+void CIsQueueEmptyTest::DoIsQueueEmpty()
+ {
+ TBool queueEmpty;
+ TInt r = iDmaSession.ChannelIsQueueEmpty(iChannelSessionCookie,queueEmpty);
+ TEST_ASSERT(r == KErrNone);
+
+ if(queueEmpty)
+ {
+ RDebug::Printf("Verified that calling IsQueueEmpty() returns ETrue before calling Queue()");
+ }
+ else
+ {
+ RDebug::Printf("IsQueueEmpty() fails to return ETrue before calling Queue()");
+ TEST_ASSERT(queueEmpty);
+ }
+ }
+
+void CIsQueueEmptyTest::DoQueueNotEmpty()
+ {
+ TBool queueEmpty;
+ TInt r = iDmaSession.ChannelIsQueueEmpty(iChannelSessionCookie,queueEmpty);
+ TEST_ASSERT(r == KErrNone);
+
+ if (!queueEmpty)
+ {
+ RDebug::Printf("Verified that calling IsQueueEmpty() returns EFalse after calling Queue()");
+ }
+ else
+ {
+ RDebug::Printf("IsQueueEmpty() fails to return EFalse after calling Queue()");
+ TEST_ASSERT(!queueEmpty);
+ }
+ }
+
+void CIsQueueEmptyTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("IsQueue Empty Test using Multi Transfer"));
+ }
+
+void CIsQueueEmptyTest::QueueRequests()
+ {
+ // Queue all the DMA requests asynchronously
+ TInt i;
+ RArray<TRequestStatus> requestStates;
+
+ ChannelPause(iChannelSessionCookie);
+ DoIsQueueEmpty();
+
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ for(i=0; i<iTransferArgsCount; i++)
+ {
+ TResultSet& resultSet = iActualResults[i];
+ if(resultSet.iRequestResult.iFragmentationResult != KErrNone)
+ continue;
+
+ TInt r = requestStates.Append(TRequestStatus());
+ TEST_ASSERT(r == KErrNone);
+
+ r = iDmaSession.QueueRequest(iRequestCookies[i], requestStates[i], &resultSet.iCallbackRecord, NULL);
+ resultSet.iRequestResult.iQueueResult = r;
+
+ DoQueueNotEmpty();
+ }
+
+ ChannelResume(iChannelSessionCookie);
+
+ // wait for all transfers to complete
+ const TInt count = requestStates.Count();
+
+ for(i=0; i<count; i++)
+ {
+ User::WaitForRequest(requestStates[i]);
+ }
+
+ requestStates.Close();
+ }
+
+//////////////////////////////////////////////////////////////////////
+// CMultiTransferTest
+//////////////////////////////////////////////////////////////////////
+CMultiTransferTest::CMultiTransferTest(const TDesC& aName, TInt aIterations, const TDmaTransferArgs* aTransferArgs,
+ const TResultSet* aResultSets, TInt aCount)
+ : CDmaTest(aName, aIterations, NULL, NULL), iTransferArgs(aTransferArgs), iTransferArgsCount(aCount), iNewDmaApi(ETrue),
+ iChannelSessionCookie(0), iExpectedArray(aResultSets), iPauseWhileQueuing(EFalse)
+ {}
+
+CMultiTransferTest::CMultiTransferTest(const CMultiTransferTest& aOther)
+ : CDmaTest(aOther), iTransferArgs(aOther.iTransferArgs), iTransferArgsCount(aOther.iTransferArgsCount),
+ iNewDmaApi(aOther.iNewDmaApi),
+ iExpectedArray(aOther.iExpectedArray), iPauseWhileQueuing(aOther.iPauseWhileQueuing)
+ {
+ CopyL(aOther.iRequestCookies, iRequestCookies);
+ }
+
+CMultiTransferTest::~CMultiTransferTest()
+ {
+ iRequestCookies.Close();
+ iActualResults.Close();
+ }
+
+TBool CMultiTransferTest::Result()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Results for %d transfers:", iTransferArgsCount);
+ }
+
+ TBool result = EFalse;
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ result = Result(i);
+ if(!result)
+ break;
+ }
+ return result;
+ }
+
+TBool CMultiTransferTest::Result(TInt aTransfer)
+ {
+ const TResultSet& expected = iExpectedArray[aTransfer];
+ const TResultSet& actual = iActualResults[aTransfer];
+ const TBool result = expected == actual;
+ if(!result || gVerboseOutput)
+ {
+ RDebug::Printf("Compairing results for transfer %d", aTransfer);
+ }
+
+ if(!result)
+ {
+ RDebug::Printf("TResultSets do not match");
+ }
+ if(!result || gVerboseOutput)
+ {
+ RDebug::Printf("\nExpected error codes:");
+ expected.Print();
+ RDebug::Printf("Expected callback record:");
+ expected.iCallbackRecord.Print();
+
+ RDebug::Printf("\nActual error codes:");
+ actual.Print();
+ RDebug::Printf("Actual callback record:");
+ actual.iCallbackRecord.Print();
+ }
+ return result;
+ }
+void CMultiTransferTest::RunTest()
+ {
+ OpenDmaSession();
+
+ PreTransferSetup();
+ OpenChannel();
+
+ CreateDmaRequests();
+ Fragment();
+
+ QueueRequests();
+
+ TInt r = DoPostTransferCheck();
+ TEST_ASSERT(r == KErrNone);
+
+ CloseDmaSession();
+ }
+
+void CMultiTransferTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("Multi Transfer"));
+ }
+
+const TDmaTransferArgs& CMultiTransferTest::TransferArgs(TInt aIndex) const
+ {
+ TEST_ASSERT(Rng(0, aIndex, iTransferArgsCount-1));
+
+ return iTransferArgs[aIndex];
+ }
+
+void CMultiTransferTest::SetPostTransferResult(TInt aIndex, TInt aErrorCode)
+ {
+ TEST_ASSERT(Rng(0, aIndex, iTransferArgsCount-1));
+
+ iActualResults[aIndex].iPostTransferCheck = aErrorCode;
+ }
+
+void CMultiTransferTest::OpenChannel()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("CMultiTransferTest::OpenChannel()");
+ }
+ TInt r = iDmaSession.ChannelOpen(iChannelCookie, iChannelSessionCookie);
+
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ // In a multi transfer test a series of requests are created and queued.
+ // They all use the same channel, is opened here at the beginning of the test
+ //
+ // Each transfer has a TResultSet which holds a result for the channel opening,
+ // which we store here. Although in this case it is redundant,
+ // in future it might be that different transfers open
+ // different channels.
+ iActualResults[i].iChannelOpenResult = r;
+ }
+ }
+
+TInt CMultiTransferTest::CloseChannel()
+ {
+ return iDmaSession.ChannelClose(iChannelSessionCookie);
+ }
+
+void CMultiTransferTest::CreateDmaRequests()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("CMultiTransferTest::CreateDmaRequests() %d", iTransferArgsCount);
+ }
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ //create a DMA request for each transfer arg struct
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ if(iActualResults[i].iChannelOpenResult != KErrNone)
+ continue;
+
+ TUint cookie = 0;
+ TInt r = KErrGeneral;
+
+ if(iNewDmaApi)
+ {
+ r = iDmaSession.RequestCreate(iChannelSessionCookie, cookie);
+ }
+ else
+ {
+ r = iDmaSession.RequestCreateOld(iChannelSessionCookie, cookie);
+ }
+ iActualResults[i].iRequestResult.iCreate = r;
+
+ if(r == KErrNone)
+ {
+ r = iRequestCookies.Append(cookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+ }
+ }
+
+void CMultiTransferTest::Fragment()
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("CMultiTransferTest::Fragment() %d", iTransferArgsCount);
+ }
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ // Fragment each dma request
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ TRequestResults& result = iActualResults[i].iRequestResult;
+ if(result.iCreate != KErrNone)
+ continue;
+
+ TInt r = KErrGeneral;
+ if(iNewDmaApi)
+ r = iDmaSession.FragmentRequest(iRequestCookies[i], iTransferArgs[i]);
+ else
+ r = iDmaSession.FragmentRequestOld(iRequestCookies[i], iTransferArgs[i]);
+
+ result.iFragmentationResult = r;
+ }
+ }
+
+void CMultiTransferTest::QueueRequests()
+ {
+ if(iPauseWhileQueuing)
+ {
+ TInt r = iDmaSession.ChannelPause(iChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+ // Queue all the DMA requests asynchronously
+ TInt i;
+ RArray<TRequestStatus> requestStates;
+
+ TEST_ASSERT(iActualResults.Count() == iTransferArgsCount);
+ for(i=0; i<iTransferArgsCount; i++)
+ {
+ TResultSet& resultSet = iActualResults[i];
+ if(resultSet.iRequestResult.iFragmentationResult != KErrNone)
+ continue;
+
+ TInt r = requestStates.Append(TRequestStatus());
+ TEST_ASSERT(r == KErrNone);
+
+ r = iDmaSession.QueueRequest(iRequestCookies[i], requestStates[i], &resultSet.iCallbackRecord, NULL);
+ resultSet.iRequestResult.iQueueResult = r;
+ }
+
+ if(iPauseWhileQueuing)
+ {
+ TInt r = iDmaSession.ChannelResume(iChannelSessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ }
+
+ // wait for all transfers to complete
+ const TInt count = requestStates.Count();
+
+ for(i=0; i<count; i++)
+ {
+ User::WaitForRequest(requestStates[i]);
+ }
+
+ requestStates.Close();
+ }
+
+void CMultiTransferTest::PreTransferSetup()
+ {
+ // TODO this is the wrong place to do this!
+ for(TInt i=0; i<iTransferArgsCount; i++)
+ {
+ //pre-fill actual results with error values
+ TInt r = iActualResults.Append(TResultSet(EFalse));
+ TEST_ASSERT(r == KErrNone);
+ }
+ if(iPreTransfer)
+ iPreTransfer->Setup(*this); //initialize test
+ }
+
+TInt CMultiTransferTest::DoPostTransferCheck()
+ {
+ if(iPostTransferCheck)
+ return iPostTransferCheck->Check(*this);
+ else
+ return KErrNone;
+ }
+//////////////////////////////////////////////////////////////////////
+// CIsrRequeTest
+//////////////////////////////////////////////////////////////////////
+CIsrRequeTest::CIsrRequeTest(const TDesC& aName, TInt aIterations, const TDmaTransferArgs& aArgs,
+ TIsrRequeArgs* aRequeueArgs, TInt aCount,
+ const TResultSet& aExpected,const MPreTransfer* aPreTfer,const MPostTransferCheck* aPostTferChk, TUint aMaxFragmentSize)
+ :CSingleTransferTest(aName, aIterations, aArgs, aExpected, aMaxFragmentSize, aPostTferChk, aPreTfer), iRequeArgSet(aRequeueArgs, aCount)
+ {}
+
+void CIsrRequeTest::Queue()
+ {
+ if(iActual.iRequestResult.iFragmentationResult == KErrNone)
+ {
+ iActual.iRequestResult.iQueueResult = iDmaSession.QueueRequestWithRequeue(iRequestSessionCookie, iRequeArgSet.iRequeArgs, iRequeArgSet.iCount, &iActual.iCallbackRecord);
+ }
+ }
+
+void CIsrRequeTest::PrintTestType() const
+ {
+ RDebug::RawPrint(_L("ISR Requeue"));
+ }
+
+void CIsrRequeTest::PreTransferSetup()
+ {
+ if(iPreTransfer)
+ iPreTransfer->Setup(*this); //initialize test
+ }
+
+TInt CIsrRequeTest::DoPostTransferCheck()
+ {
+ return iPostTransferCheck->Check(*this);
+ }
+
+//////////////////////////////////////////////////////////////////////
+// TResultSet
+//////////////////////////////////////////////////////////////////////
+void TResultSet::Print() const
+ {
+ PRINT(iChannelOpenResult);
+ PRINT(iRequestResult.iCreate);
+ PRINT(iRequestResult.iFragmentCount);
+ PRINT(iRequestResult.iFragmentationResult);
+ PRINT(iRequestResult.iQueueResult);
+ PRINT(iPostTransferCheck);
+ }
+
+TBool TResultSet::operator == (const TResultSet& aOther) const
+ {
+ return (memcompare((TUint8*)this, sizeof(*this), (TUint8*)&aOther, sizeof(aOther)) == 0);
+ }
+
+//////////////////////////////////////////////////////////////////////
+// MPostTransferCheck classes
+//////////////////////////////////////////////////////////////////////
+TInt TCompareSrcDst::Check(const CSingleTransferTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Comparing CSingleTransferTest buffers");
+ }
+ return Check(aTest.TransferArgs(), aTest.Chunk().Base());
+ }
+
+// Note: this check will not deal correctly with transfers were subsequent
+// requeues overlap previous sources or destinations
+// or where the source of transfer depends on a previous transfer.
+// This is because it simply compares the source and destination
+// pairwise for each transfer
+//
+// If TPreTransferIncrBytes is used for the pre-test then the transfers
+// will be checked however.
+TInt TCompareSrcDst::Check(const CIsrRequeTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Comparing CIsrRequeTest buffers");
+ }
+ TUint8* chunkBase = aTest.Chunk().Base();
+ const TDmaTransferArgs& transferArgs = aTest.TransferArgs();
+ // check first transfer
+ TInt r = Check(transferArgs, chunkBase);
+
+ if(r != KErrNone)
+ return r;
+
+ // check re-queued transfers
+ const TIsrRequeArgsSet& requeueArgs = aTest.GetRequeueArgs();
+ return Check(requeueArgs, chunkBase, transferArgs);
+ }
+
+TInt TCompareSrcDst::Check(const TDmaTransferArgs& aTransferArgs, TUint8* aChunkBase) const
+ {
+ const TUint32 srcOffset = aTransferArgs.iSrcConfig.iAddr;
+ const TUint32 dstOffset = aTransferArgs.iDstConfig.iAddr;
+ const TInt size = aTransferArgs.iTransferCount;
+
+ const TUint8* src = srcOffset + aChunkBase;
+ const TUint8* dst = dstOffset + aChunkBase;
+
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Comparing TDmaTransferArgs buffers src=0x%08x dst=0x%08x size=0x%08x",
+ src, dst, size);
+ }
+
+ return memcompare(src, size, dst, size);
+ }
+
+TInt TCompareSrcDst::Check(const TIsrRequeArgsSet& aRequeueArgSet, TUint8* aChunkBase, const TDmaTransferArgs& aTferArgs) const
+ {
+ TIsrRequeArgsSet argSet(aRequeueArgSet); //copy since Fixup will mutate object
+
+ argSet.Substitute(aTferArgs); // replace any default (0) values with the values in aTferArgs
+
+ argSet.Fixup((TLinAddr)aChunkBase); //convert address offsets to virtual user mode addresses
+
+ TInt r = KErrCorrupt;
+ while(!argSet.IsEmpty())
+ {
+ r = Check(argSet.GetArgs());
+ if(r != KErrNone)
+ break;
+ }
+ return r;
+ }
+
+TInt TCompareSrcDst::Check(const TIsrRequeArgs& aRequeueArgs) const
+ {
+ const TUint8* src = (TUint8*)aRequeueArgs.iSrcAddr;
+ const TUint8* dst = (TUint8*)aRequeueArgs.iDstAddr;
+ const TInt size = aRequeueArgs.iTransferCount;
+
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Comparing TIsrRequeArgs: src=0x%08x dst=0x%08x size=0x%08x",
+ src, dst, size);
+ }
+
+ return memcompare(src, size, dst, size);
+ }
+
+// Note: this check will not deal correctly with transfers were subsequent
+// requeues overlap previous sources or destinations
+// or where the source of trasnfer depends on a previous trasnfer.
+// This is because it simply compares the source and destination
+// pairwise for each transfer
+//
+// If TCompareSrcDst is used for the pre-test then the transfers
+// will be checked however.
+TInt TCompareSrcDst::Check(CMultiTransferTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Comparing CMultiTransferTest buffers");
+ }
+
+ const TInt transferCount = aTest.TransferCount();
+ TUint8* const chunkBase = aTest.Chunk().Base();
+
+ // check buffers for each transfer
+ for(TInt i=0; i<transferCount; i++)
+ {
+ TInt r = Check(aTest.TransferArgs(i), chunkBase);
+ aTest.SetPostTransferResult(i, r);
+ }
+ // CMultiTransferTest is handled differently to the others.
+ // Whereas CSingleTransferTest logs just the return value
+ // of the check, here, we write back a result for each transfer
+ // so the return value from this function is not important
+ return KErrNone;
+ }
+
+TInt TCompare2D::Check(const CSingleTransferTest& aTest) const
+ {
+ const TDmaTransferArgs& args = aTest.TransferArgs();
+ TUint8* const chunkBase = aTest.Chunk().Base();
+
+ TInt ret = KErrNone;
+
+ TTransferIter src_iter(args.iSrcConfig, chunkBase);
+ TTransferIter dst_iter(args.iDstConfig, chunkBase);
+ TTransferIter end;
+ for (; (src_iter != end) && (dst_iter !=end); ++src_iter, ++dst_iter)
+ {
+ if(*src_iter != *dst_iter)
+ {
+ ret = KErrCorrupt;
+ break;
+ }
+ }
+ return ret;
+ }
+
+TInt TCompare2D::Check(const CIsrRequeTest&) const
+ {
+ return KErrNotSupported;
+ }
+
+TInt TCompare2D::Check(CMultiTransferTest&) const
+ {
+ return KErrNotSupported;
+ }
+
+
+TInt TCheckNoTransfer::Check(const CSingleTransferTest&) const
+ {
+ return KErrNotSupported;
+ }
+
+TInt TCheckNoTransfer::Check(const CIsrRequeTest&) const
+ {
+ return KErrNotSupported;
+ }
+
+TInt TCheckNoTransfer::Check(CMultiTransferTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("TCheckNoTransfer Comparing CMultiTransferTest buffers");
+ }
+
+ const TInt transferCount = aTest.TransferCount();
+ TUint8* const chunkBase = aTest.Chunk().Base();
+
+ // check buffers for each transfer
+ for(TInt i=0; i<transferCount; i++)
+ {
+ TInt r = KErrCorrupt;
+ if(IsZeroed(aTest.TransferArgs(i), chunkBase))
+ {
+ r = KErrNone;
+ }
+
+ aTest.SetPostTransferResult(i, r);
+ }
+ // CMultiTransferTest is handled differently to the others.
+ // Whereas CSingleTransferTest logs just the return value
+ // of the check, here, we write back a result for each transfer
+ // so the return value from this function is not important
+ return KErrNone;
+ }
+
+TBool TCheckNoTransfer::IsZeroed(const TDmaTransferArgs& aTransferArgs, TUint8* aChunkBase) const
+ {
+ TAddressParms parms = GetAddrParms(aTransferArgs);
+ parms.Fixup(reinterpret_cast<TLinAddr>(aChunkBase));
+ const TAddrRange destination = parms.DestRange();
+
+ return destination.IsFilled(0);
+ }
+//////////////////////////////////////////////////////////////////////
+// MPreTransfer classes
+//////////////////////////////////////////////////////////////////////
+void TPreTransferIncrBytes::Setup(const CSingleTransferTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("TPreTransferIncrBytes(CSingleTransferTest)");
+ }
+ TAddressParms params = GetAddrParms(aTest.TransferArgs());
+
+ TUint8* const chunkBase = aTest.Chunk().Base();
+ params.Fixup((TLinAddr)chunkBase);
+
+
+ Setup(params);
+ }
+
+void TPreTransferIncrBytes::Setup(const TAddressParms& aParams) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("TPreTransferIncrBytes: setup memory buffers: src=0x%08x dst=0x%08x size=0x%08x",
+ aParams.iSrcAddr, aParams.iDstAddr, aParams.iTransferCount);
+ }
+ TUint8* const src = (TUint8*) aParams.iSrcAddr;
+ const TInt size = aParams.iTransferCount;
+
+ for(TInt i=0; i<size; i++)
+ {src[i] = (TUint8)i;} //each src byte holds its own offset (mod 256)
+
+ TUint8* const dst = (TUint8*) aParams.iDstAddr;
+ memclr(dst, size); //clear destination
+ }
+
+void TPreTransferIncrBytes::Setup(const CIsrRequeTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("TPreTransferIncrBytes(CIsrRequeTest)");
+ }
+ if(!CheckBuffers(aTest))
+ {
+ RDebug::Printf("Successive transfer destinations may not overlap previous src or dst buffers");
+ RDebug::Printf("unless the whole transfer is an exact repeat of a previous one");
+ TEST_FAULT;
+ }
+
+ Setup(static_cast<CSingleTransferTest>(aTest)); // prepare the CSingleTransferTest parts
+
+ TIsrRequeArgsSet requeSet(aTest.GetRequeueArgs());
+
+ requeSet.Substitute(aTest.TransferArgs());
+
+ const TLinAddr chunkBase = (TLinAddr) aTest.Chunk().Base();
+ requeSet.Fixup(chunkBase);
+
+ while(!requeSet.IsEmpty())
+ {
+ TIsrRequeArgs args = requeSet.GetArgs();
+ Setup(args); // perform the setup operation for each TIsrRequeArgs
+ }
+ }
+
+void TPreTransferIncrBytes::Setup(const CMultiTransferTest& aTest) const
+ {
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("TPreTransferIncrBytes(CMultiTransferTest)");
+ }
+
+ if(!CheckBuffers(aTest))
+ {
+ RDebug::Printf("Successive transfer destinations may not overlap previous src or dst buffers");
+ TEST_FAULT;
+ }
+
+ TUint8* const chunkBase = aTest.Chunk().Base();
+ const TInt transferCount = aTest.TransferCount();
+
+ // initialise buffers for each transfer
+ for(TInt i=0; i<transferCount; i++)
+ {
+ TAddressParms params = GetAddrParms(aTest.TransferArgs(i));
+
+ params.Fixup((TLinAddr)chunkBase);
+
+ Setup(params);
+ }
+ }
+
+TBool TPreTransferIncrBytes::CheckBuffers(const CIsrRequeTest& aTest) const
+ {
+ RArray<const TAddressParms> array;
+ array.AppendL(TAddressParms(aTest.TransferArgs()));
+
+ TIsrRequeArgsSet requeSet(aTest.GetRequeueArgs());
+ requeSet.Substitute(aTest.TransferArgs());
+
+ const TLinAddr chunkBase = (TLinAddr) aTest.Chunk().Base();
+ requeSet.Fixup(chunkBase);
+ while(!requeSet.IsEmpty())
+ {
+ const TIsrRequeArgs requeArgs = requeSet.GetArgs();
+ array.AppendL(requeArgs);
+ }
+
+ const TBool result = CheckBuffers(array);
+
+ array.Close();
+ return result;
+ }
+
+/**
+A CMultiTransferTest will wait for all transfers to complete
+before comapairing source and destination buffers. For this to be successful
+each transfer must be independent ie. no destination or source may be
+overwritten by another transfer and source buffers may not depend on an
+earlier transfer
+*/
+TBool TPreTransferIncrBytes::CheckBuffers(const CMultiTransferTest& aTest) const
+ {
+ TUint8* const chunkBase = aTest.Chunk().Base();
+ const TInt transferCount = aTest.TransferCount();
+
+ // assemble an array of TAddressParams from aTest, that
+ // can then be passed to CheckBuffers(RArray<TAddressParms>)
+ RArray<const TAddressParms> array;
+
+ for(TInt i=0; i<transferCount; i++)
+ {
+ TAddressParms params = GetAddrParms(aTest.TransferArgs(i));
+ params.Fixup((TLinAddr)chunkBase);
+
+ array.AppendL(params);
+ }
+
+ // 2nd arg EFalse as there is no need to permit exact repeats
+ const TBool r = CheckBuffers(array, EFalse);
+
+ array.Close();
+ return r;
+ }
+
+/**
+Check that the destination of each TAddressParms does not overlap with
+any previous source or destination or that if it does the whole transfer
+matches.
+This is so that successive transfers do not overwrite the destinations or
+sources of preceeding ones.
+
+If aAllowExactRepeat is true then exactly matching transfers are allowed
+to test the case where a repeat transfer is required - though it can't
+then be determined just from looking at the buffers that the repeat was
+successful
+*/
+TBool TPreTransferIncrBytes::CheckBuffers(const RArray<const TAddressParms>& aTransferParams, TBool aAllowExactRepeat) const
+ {
+
+ const TInt count = aTransferParams.Count();
+
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("CheckBuffers, %d transfers", count);
+ }
+
+ TBuf<128> buf;
+ for(TInt i=1; i<count; i++)
+ {
+ const TAddressParms& current = aTransferParams[i];
+
+ if(gVerboseOutput)
+ {
+ buf.Zero();
+ current.AppendString(buf);
+ RDebug::Print(_L("Check current: %S, against:"), &buf);
+ }
+
+ for(TInt j=0; j<i; j++)
+ {
+ const TAddressParms& previous = aTransferParams[j];
+ if(gVerboseOutput)
+ {
+ buf.Zero();
+ previous.AppendString(buf);
+ RDebug::Print(_L("Previous: %S"), &buf);
+ }
+
+ const TBool curDstOverlapsPrevTfer = previous.Overlaps(current.DestRange());
+ const TBool curSrcDependsOnPrevDest = current.SourceRange().Overlaps(previous.DestRange());
+ const TBool permitExactRepeat = aAllowExactRepeat && (current == previous);
+
+ const TBool ok = !(curDstOverlapsPrevTfer || curSrcDependsOnPrevDest) || permitExactRepeat;
+ if(!ok)
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+//////////////////////////////////////////////////////////////////////
+// TTransferIter class
+//////////////////////////////////////////////////////////////////////
+void TTransferIter::operator++ ()
+ {
+ iPtr++; //the standard post increment
+ if(iElem < (iCfg->iElementsPerFrame-1))
+ {
+ iPtr += iCfg->iElementSkip;
+ iElem++;
+ iBytes++;
+ }
+ else
+ {
+ TEST_ASSERT(iElem == iCfg->iElementsPerFrame-1);
+ if(iFrame < iCfg->iFramesPerTransfer-1)
+ {
+ iPtr += iCfg->iFrameSkip;
+ iFrame++;
+ iBytes++;
+ iElem = 0;
+ }
+ else
+ {
+ //we have reached the end
+ TEST_ASSERT(iFrame == iCfg->iFramesPerTransfer-1);
+ iPtr = NULL;
+ }
+ }
+
+ Invariant();
+ }
+
+void TTransferIter::Invariant() const
+ {
+ const TInt elemSize = iCfg->iElementSize;
+ RTest test(_L("TTransferIter invariant"));
+ const TUint bytesTransfered = (
+ elemSize * (iFrame * iCfg->iElementsPerFrame + iElem)
+ + ((TUint)iPtr % (elemSize))
+ );
+ test_Equal(iBytes, bytesTransfered);
+ test.Close();
+ }
+
+///////////////////////////////////////////////////////////
+// TTestCase
+///////////////////////////////////////////////////////////
+TTestCase::TTestCase(CDmaTest* aTest,
+ TBool aConcurrent,
+ const TDmaCapability aCap1,
+ const TDmaCapability aCap2,
+ const TDmaCapability aCap3,
+ const TDmaCapability aCap4,
+ const TDmaCapability aCap5
+ )
+:
+ iTest(aTest), iConcurrentTest(aConcurrent)
+ {
+ iChannelCaps[0] = aCap1;
+ iChannelCaps[1] = aCap2;
+ iChannelCaps[2] = aCap3;
+ iChannelCaps[3] = aCap4;
+ iChannelCaps[4] = aCap5;
+ }
+
+TResult TTestCase::TestCaseValid(const SDmacCaps& aChannelCaps) const
+ {
+ const TDmaCapability* cap = &iChannelCaps[0];
+
+ TResult ret = ERun;
+ //We assume that the array is empty at the first ENone found
+ //any caps after this wil be ignored
+ while(cap->iCapsReq != ENone)
+ {
+ TResult t = cap->CompareToDmaCaps(aChannelCaps);
+ if(t > ret) //this relies on the enum ordering
+ ret = t;
+ cap++;
+ }
+ return ret;
+ }
+
+TResult TTestCase::TestCaseValid(const TDmacTestCaps& aChannelCaps) const
+ {
+ const TDmaCapability* cap = &iChannelCaps[0];
+
+ TResult ret = ERun;
+ //We assume that the array is empty at the first ENone found
+ //any caps after this wil be ignored
+ while(cap->iCapsReq != ENone)
+ {
+ TResult t = cap->CompareToDmaCaps(aChannelCaps);
+ if(t > ret) //this relies on the enum ordering
+ ret = t;
+ cap++;
+ }
+ return ret;
+ }
+/**
+Will report whether a value held in aChannelCaps satisfies a
+requirement specfied by this object
+*/
+TBool TDmaCapability::RequirementSatisfied(const SDmacCaps& aChannelCaps) const
+ {
+ switch(iCapsReq)
+ {
+ case ENone:
+ return ETrue;
+ case EChannelPriorities:
+ TEST_FAULT;
+ case EChannelPauseAndResume:
+ return aChannelCaps.iChannelPauseAndResume == (TBool)iValue;
+ case EAddrAlignedToElementSize:
+ TEST_FAULT;
+ case E1DAddressing:
+ return aChannelCaps.i1DIndexAddressing == (TBool)iValue;
+ case E2DAddressing:
+ return aChannelCaps.i2DIndexAddressing == (TBool)iValue;
+ case ESynchronizationTypes:
+ case EBurstTransactions:
+ case EDescriptorInterrupt:
+ case EFrameInterrupt:
+ case ELinkedListPausedInterrupt:
+ case EEndiannessConversion:
+ case EGraphicsOps:
+ case ERepeatingTransfers:
+ case EChannelLinking:
+ return aChannelCaps.iChannelLinking == (TBool)iValue;
+ case EHwDescriptors:
+ return aChannelCaps.iHwDescriptors == (TBool)iValue;
+ case ESrcDstAsymmetry:
+ case EAsymHwDescriptors:
+ TEST_FAULT;
+ case EBalancedAsymSegments:
+ return aChannelCaps.iBalancedAsymSegments == (TBool)iValue;
+ case EAsymCompletionInterrupt:
+ return aChannelCaps.iAsymCompletionInterrupt == (TBool)iValue;
+ case EAsymDescriptorInterrupt:
+ return aChannelCaps.iAsymDescriptorInterrupt == (TBool)iValue;
+ case EAsymFrameInterrupt:
+ return aChannelCaps.iAsymFrameInterrupt == (TBool)iValue;
+ default:
+ TEST_FAULT;
+ }
+
+ return EFalse;
+ }
+
+/**
+Will report whether a value held in aChannelCaps satisfies a
+requirement specfied by this object
+*/
+TBool TDmaCapability::RequirementSatisfied(const TDmacTestCaps& aChannelCaps) const
+ {
+ switch(iCapsReq)
+ {
+ case EPilVersion:
+ return TestValue(aChannelCaps.iPILVersion);
+ default:
+ return RequirementSatisfied(static_cast<SDmacCaps>(aChannelCaps));
+ }
+ }
+
+TResult TDmaCapability::CompareToDmaCaps(const SDmacCaps& aChannelCaps) const
+ {
+ const TBool reqSatisfied = RequirementSatisfied(aChannelCaps);
+ if(reqSatisfied)
+ {
+ return ERun;
+ }
+ else
+ {
+ return iFail ? EFail : ESkip;
+ }
+ }
+
+TResult TDmaCapability::CompareToDmaCaps(const TDmacTestCaps& aChannelCaps) const
+ {
+ const TBool reqSatisfied = RequirementSatisfied(aChannelCaps);
+ if(reqSatisfied)
+ {
+ return ERun;
+ }
+ else
+ {
+ return iFail ? EFail : ESkip;
+ }
+ }
+/**
+Test that aValue satisfies the comparrison (iCapsReqType) with the
+reference value held in iValue
+*/
+TBool TDmaCapability::TestValue(TUint aValue) const
+ {
+ switch(iCapsReqType)
+ {
+ case EEqual:
+ return aValue == iValue;
+ case EGTE:
+ return aValue >= iValue;
+ case ELTE:
+ return aValue <= iValue;
+ case EBitsSet:
+ case EBitsClear:
+ default:
+ TEST_FAULT;
+ }
+ return EFalse;
+ }
+
+static RTest test(_L("DMAv2 test"));
+
+//////////////////////////////////////////////////////////////////////
+// TTestRunner
+//////////////////////////////////////////////////////////////////////
+TTestRunner::TTestRunner()
+ {
+ // Open RDmaSession handle
+ TInt r = iDmaSession.Open();
+ TEST_ASSERT(r == KErrNone);
+
+ // Get PSI Test info
+ r = iDmaSession.GetTestInfo(iPslTestInfo);
+ TEST_ASSERT(r == KErrNone);
+
+ //Retrieve PSL cookies
+ GetPslCookie();
+
+ //Generate the DMA channel records
+ GenerateChannelRecord();
+ }
+
+TTestRunner::~TTestRunner()
+ {
+ RTest::CloseHandleAndWaitForDestruction(iDmaSession);
+ iTestCases.Close(); //TestRunner does not own test cases
+ iChannelRecords.Close();
+ iPslCookies.Close();
+ }
+
+void TTestRunner::AddTestCases(RPointerArray<TTestCase>& aTTestCases)
+ {
+ const TInt count = aTTestCases.Count();
+ for(TInt i=0; i < count; i++)
+ {
+ iTestCases.AppendL(aTTestCases[i]);
+ }
+ }
+
+void TTestRunner::RunTests()
+ {
+ //Print PslTestInfo
+ if(gVerboseOutput)
+ {
+ Print(iPslTestInfo);
+ }
+
+ //iterate through the test case array
+ const TInt testCaseCount = iTestCases.Count();
+ for(TInt i=0; i < testCaseCount; i++)
+ {
+ const TTestCase& testCase = *iTestCases[i];
+
+ //Here, we must create a test thread for each channel
+ RPointerArray<CTest> concurrentTests;
+
+ const TInt chanRecCount = iChannelRecords.Count();
+ for(TInt j=0; j < chanRecCount; j++)
+ {
+ const TChannelRecord& record = iChannelRecords[j];
+ const TDmacTestCaps& caps = record.iChannelCaps;
+
+ const TResult t = testCase.TestCaseValid(caps);
+
+ switch(t)
+ {
+ case ERun:
+ {
+ CDmaTest* dmaTest = static_cast<CDmaTest*>(testCase.iTest->Clone());
+ TEST_ASSERT(dmaTest != NULL);
+
+ dmaTest->SetChannelCookie(record.iCookie);
+ dmaTest->SetupL();
+ if(testCase.iConcurrentTest)
+ {
+ //Add test to array to be run concurrently
+ TInt r = concurrentTests.Append(dmaTest);
+ TEST_ASSERT(r == KErrNone);
+ }
+ else
+ {
+ dmaTest->Announce();
+ //Run test in this thread
+ (*dmaTest)();
+ TBool result = dmaTest->Result();
+ TEST_ASSERT(result);
+
+ delete dmaTest;
+ }
+
+ break;
+ }
+ case ESkip:
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Skipping test-case %S, PSL channel %d", &testCase.iTest->Name(), record.iCookie);
+ }
+ break;
+ case EFail:
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Failling test-case %S, PSL channel %d", &testCase.iTest->Name(), record.iCookie);
+ }
+ TEST_FAULT;
+ default:
+ TEST_FAULT;
+ }
+ //Depending on the value of iConcurrentTest the test runner will either block until the thread has completed or
+ //alternatively run the current test case on the next channel:
+
+ //if the test case has been run on all channels it will then wait for all threads to complete.
+ }
+
+ // Run the tests which should happen concurrently
+ const TInt count = concurrentTests.Count();
+ if(count>0)
+ {
+ RDebug::Printf("== Begin concurrent test run ==");
+
+ TInt i; // VC++
+ for(i=0; i<count; i++)
+ {
+ concurrentTests[i]->Announce();
+ }
+
+ MultipleTestRun(concurrentTests);
+ for(i=0; i<count; i++)
+ {
+ TBool result = static_cast<CDmaTest*>(concurrentTests[i])->Result();
+ TEST_ASSERT(result);
+ }
+ RDebug::Printf("== End concurrent test run ==");
+ }
+
+ concurrentTests.ResetAndDestroy();
+ }
+ }
+
+void TTestRunner::GetPslCookie()
+ {
+ //Get Sb Channel cookies
+ for(TInt sb_channelcount=0; sb_channelcount<iPslTestInfo.iMaxSbChannels; sb_channelcount++)
+ {
+ iPslCookies.AppendL(iPslTestInfo.iSbChannels[sb_channelcount]);
+ }
+
+ //Get Db Channel cookies
+ for(TInt db_channelcount=0; db_channelcount<iPslTestInfo.iMaxDbChannels; db_channelcount++)
+ {
+ iPslCookies.AppendL(iPslTestInfo.iDbChannels[db_channelcount]);
+ }
+
+ //Get Sg Channel cookies
+ for(TInt sg_channelcount=0; sg_channelcount<iPslTestInfo.iMaxSgChannels; sg_channelcount++)
+ {
+ iPslCookies.AppendL(iPslTestInfo.iSgChannels[sg_channelcount]);
+ }
+ }
+
+void TTestRunner::GenerateChannelRecord()
+ {
+ //for each PSL cookie
+ for(TInt count=0; count<iPslCookies.Count(); count++)
+ {
+ //Get channel cookie
+ const TUint pslCookie = iPslCookies[count];
+ TUint sessionCookie;
+ TInt r = iDmaSession.ChannelOpen(pslCookie, sessionCookie);
+ TEST_ASSERT(r == KErrNone);
+ if(gVerboseOutput)
+ {
+ RDebug::Printf("Channel PSL Cookie[%d] :0x%08x",count,pslCookie);
+ }
+
+ TChannelRecord dmaChannelRecord;
+ dmaChannelRecord.iCookie = pslCookie;
+
+ //Get Channel Caps
+ r = iDmaSession.ChannelCaps(sessionCookie, dmaChannelRecord.iChannelCaps);
+ TEST_ASSERT(r == KErrNone);
+
+ r = iDmaSession.ChannelClose(sessionCookie);
+ TEST_ASSERT(r == KErrNone);
+
+ //Append array
+ iChannelRecords.AppendL(dmaChannelRecord);
+ }
+ }
+//////////////////////////////////////////////////////////////////////
+// Global test functions and E32Main
+//////////////////////////////////////////////////////////////////////
+
+/**
+Displayed if used supplied no parameters, garbage, or a ? in the parameters
+*/
+void PrintUsage()
+ {
+ test.Printf(_L("*** DMA TEST FRAMEWORK ***\n"));
+ test.Printf(_L("Usage : t_dma2.exe [/option]\n"));
+ test.Printf(_L(" /V or /VERBOSE = Control test output\n"));
+ test.Printf(_L(" /S or /SELFTEST = Run DMA self tests\n"));
+ test.Printf(_L(" /simple = Run only simple transfer tests\n"));
+ test.Printf(_L(" /callback = Run only callback tests\n"));
+ test.Printf(_L(" /multi = Run only multipart transfer tests\n"));
+ test.Printf(_L(" /isrdfc = Run only isr and dfc tests\n"));
+ test.Printf(_L(" /isreque = Run only isr reque tests\n"));
+ test.Printf(_L(" /bench = Run only benchmark tests\n"));
+ test.Printf(_L(" /suspend = Run only pause and resume tests\n"));
+ test.Printf(_L(" /graphic = Run only graphic tests\n"));
+ test.Printf(_L(" /channel = Run only DMA channel (opening and closing) tests\n"));
+ test.Printf(_L(" /queue = Run only queue tests\n"));
+ test.Printf(_L(" /fragment = Run only fragmentation related tests\n"));
+ test.Printf(_L(" /request = Run only requests tests related tests\n"));
+ test.Printf(_L("\n"));
+ }
+
+void ProcessCommandLineL()
+{
+ test.Printf(_L("Process command line arguments\n"));
+
+ TInt cmdLineLength(User::CommandLineLength());
+ HBufC* cmdLine = HBufC::NewMaxLC(cmdLineLength);
+ TPtr cmdLinePtr = cmdLine->Des();
+ User::CommandLine(cmdLinePtr);
+ TBool tokenParsed(EFalse);
+
+ TLex args(*cmdLine);
+ args.SkipSpace(); // args are separated by spaces
+
+ // first arg is the exe name, skip it
+ TPtrC cmdToken = args.NextToken();
+ HBufC* tc = HBufC::NewLC(KParameterTextLenMax);
+ *tc = cmdToken;
+ while (tc->Length())
+ {
+ tokenParsed = EFalse;
+
+ // '/?' help wanted flag '?' or /? parameter
+ if ((0== tc->FindF(_L("?"))) || (0==tc->FindF(_L("/?"))))
+ {
+ gHelpRequested = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/SELFTEST'
+ if ((0== tc->FindF(KArgSelfTest)) || (0==tc->FindF(KArgSelfTest2)))
+ {
+ // Run self test
+ test.Printf(_L("Command Line Options:Selftest option specified.\n"));
+ gSelfTest = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/VERBOSE' option
+ if ((0== tc->FindF(KArgVerboseOutput)) || (0==tc->FindF(KArgVerboseOutput2)))
+ {
+ test.Printf(_L("Command Line Options:Verbose option specified.\n"));
+ gVerboseOutput = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/suspend' option
+ if ((0== tc->FindF(KArgSuspendTest)))
+ {
+ gSuspend = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/simple' option
+ if ((0== tc->FindF(KArgSimpleTest)))
+ {
+ gSimpleTest = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/multi' option
+ if ((0== tc->FindF(KArgMultiPartTest)))
+ {
+ gMultiPart = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/callback' option
+ if ((0== tc->FindF(KArgCallBackTest)))
+ {
+ gCallBack = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/IsrAndDfc' option
+ if ((0== tc->FindF(KArgIsrDfcTest)))
+ {
+ gIsrAndDfc = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/IsrReque' option
+ if ((0== tc->FindF(KArgIsrequeTest)))
+ {
+ gIsrReque = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Benchmark' option
+ if ((0== tc->FindF(KArgBenchmarkTest)))
+ {
+ gBenchmark = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Queue' option
+ if ((0== tc->FindF(KArgQueueTest)))
+ {
+ gQueue = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Fragment' option
+ if ((0== tc->FindF(KArgFragmentTest)))
+ {
+ gFragment = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Channel' option
+ if ((0== tc->FindF(KArgChannelTest)))
+ {
+ gChannel = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Graphic' option
+ if ((0== tc->FindF(KArgGraphicTest)))
+ {
+ gGraphic = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ // '/Request' option
+ if ((0== tc->FindF(KArgRequestTest)))
+ {
+ gRequest = ETrue;
+ tokenParsed = ETrue;
+ }
+
+ if (!tokenParsed)
+ {
+ // warn about unparsed parameter
+ test.Printf(_L("Warning: '%lS'??? not parsed\n"), tc);
+ gHelpRequested = ETrue;
+ }
+
+ // next parameter
+ *tc = args.NextToken();
+ }
+ CleanupStack::PopAndDestroy(tc);
+ CleanupStack::PopAndDestroy(cmdLine);
+}
+
+void RunDMATests()
+ {
+ test.Start(_L("Creating test runner\n"));
+ TTestRunner testRunner;
+
+ test.Next(_L("Add global test cases to test runner\n"));
+
+ if (gSimpleTest) //Add only simple tranfer test cases
+ {
+ testRunner.AddTestCases(TestArraySimple);
+ }
+ else if (gCallBack) //Add only callback test cases
+ {
+ testRunner.AddTestCases(TestArrayCallback);
+ }
+ else if (gIsrReque) //Add only ISR Reque test cases
+ {
+ testRunner.AddTestCases(TestArrayIsrReque);
+ }
+ else if (gMultiPart) //Add only Multipart test cases
+ {
+ testRunner.AddTestCases(TestArrayMultiPart);
+ }
+ else if (gIsrAndDfc) //Add only IsrAndDfc test cases
+ {
+ testRunner.AddTestCases(TestArrayIsrAndDfc);
+ }
+ else if (gBenchmark) //Add only Benchmark test cases
+ {
+ testRunner.AddTestCases(TestArrayBenchmark);
+ }
+ else if (gGraphic) //Add only 2D test cases
+ {
+ testRunner.AddTestCases(TestArray2DTest);
+ }
+ else if (gFragment) //Add only Fragment test cases
+ {
+ testRunner.AddTestCases(TestArrayFragment);
+ }
+ else if (gChannel) //Add only Channel test cases
+ {
+ testRunner.AddTestCases(TestArrayChannel);
+ }
+ else if (gSuspend) //Add only Suspend test cases
+ {
+ testRunner.AddTestCases(TestArraySuspend);
+ }
+ else if (gQueue) //Add only queue test cases
+ {
+ testRunner.AddTestCases(TestArrayQueue);
+ }
+ else if (gRequest) //Add only request test cases
+ {
+ testRunner.AddTestCases(TestArrayRequest);
+ }
+ else
+ {
+ testRunner.AddTestCases(TestArray);//Add all test cases
+ }
+
+ test.Next(_L("call TTestRunner::RunTests()\n"));
+ testRunner.RunTests();
+
+ test.End();
+ }
+
+
+struct TSimTest
+ {
+ TUint iPslId;
+ TBool iFragment;
+ };
+
+const TSimTest KSimTests[] =
+ {
+ {0, EFalse},
+ {1, EFalse},
+ {2, ETrue},
+ {3, ETrue},
+ };
+
+const TInt KSimTestsCount = ARRAY_LENGTH(KSimTests);
+
+void RunSimDMATests()
+ {
+ test.Start(_L("Run simulated DMAC tests\n"));
+
+ test.Next(_L("Open session"));
+ RDmaSession session;
+ TInt r = session.OpenSim();
+ test_KErrNone(r);
+
+ for(TInt i=0; i<KSimTestsCount; i++)
+ {
+ TUint pslId = KSimTests[i].iPslId;
+ TBool doFrag = KSimTests[i].iFragment;
+
+ test.Start(_L("Open channel"));
+ TUint channelCookie=0;
+ r = session.ChannelOpen(pslId, channelCookie);
+ test.Printf(_L("Open channel %d, cookie recived = 0x%08x\n"), pslId, channelCookie);
+ test_KErrNone(r);
+
+ test.Next(_L("Create Dma request"));
+
+ TUint reqCookie=0;
+ r = session.RequestCreate(channelCookie, reqCookie);
+ test.Printf(_L("cookie recived = 0x%08x\n"), reqCookie );
+ test_KErrNone(r);
+
+ if(doFrag)
+ {
+ test.Next(_L("Fragment request"));
+ const TInt size = 128 * KKilo;
+ TDmaTransferArgs transferArgs(0, size, size, KDmaMemAddr);
+ r = session.FragmentRequest(reqCookie, transferArgs);
+ test_KErrNone(r);
+ }
+
+ test.Next(_L("Destroy Dma request"));
+ r = session.RequestDestroy(reqCookie);
+ test_KErrNone(r);
+
+ test.Next(_L("Channel close"));
+ r = session.ChannelClose(channelCookie);
+ test_KErrNone(r);
+ test.End();
+ }
+
+ test.Next(_L("Close session"));
+ RTest::CloseHandleAndWaitForDestruction(session);
+
+ test.End();
+ }
+
+TInt E32Main()
+ {
+ __UHEAP_MARK;
+ test.Title();
+
+ gHelpRequested = EFalse;
+ TInt r;
+
+ // Create the new trap-cleanup mechanism
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+
+ if (cleanup == NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ // Process the command line parameters for batch/etc
+ TRAPD(err, ProcessCommandLineL());
+ if (err != KErrNone)
+ {
+ User::Panic(_L("DMA test run memory failure"), KErrNoMemory);
+ }
+
+ if (gHelpRequested)
+ {
+ PrintUsage();
+ User::Leave(-2); // nothing to do!
+ }
+ test.Start(_L("Loading test LDD"));
+ //load either the new test ldd, d_dma2.ldd,
+ //or d_dma2_compat.ldd - an ldd linked against
+ //the old DMA framework
+ _LIT(KDma, "D_DMA2.LDD");
+ r = User::LoadLogicalDevice(KDma);
+ const TBool dma2Loaded = ((r == KErrNone) || (r == KErrAlreadyExists));
+
+ _LIT(KDma2Compat, "D_DMA2_COMPAT.LDD");
+ r = User::LoadLogicalDevice(KDma2Compat);
+ const TBool dma2CompatLoaded = ((r == KErrNone) || (r == KErrAlreadyExists));
+
+ if (!(dma2Loaded || dma2CompatLoaded))
+ {
+ test.Printf(_L("Hardware DMA test driver not found - will run tests on simulated DMAC only\n"));
+ }
+ else if (dma2Loaded && !dma2CompatLoaded)
+ {
+ test.Printf(_L("Loaded %S\n"), &KDma);
+ }
+ else if (!dma2Loaded && dma2CompatLoaded)
+ {
+ test.Printf(_L("Loaded %S\n"), &KDma2Compat);
+ }
+ else
+ {
+ test.Printf(_L("The ROM contains %S and %S - only one should be present\n"), &KDma, &KDma2Compat);
+ TEST_FAULT;
+ }
+
+ const TBool dmaHwPresent = (dma2Loaded || dma2CompatLoaded);
+
+ _LIT(KDma2Sim, "D_DMA2_SIM.LDD");
+
+ r = User::LoadLogicalDevice(KDma2Sim);
+ const TBool dma2SimLoaded = ((r == KErrNone) || (r == KErrAlreadyExists));
+ if (dma2SimLoaded)
+ {
+ test.Printf(_L("Loaded %S\n"), &KDma2Sim);
+ }
+ else
+ {
+ test.Printf(_L("Failed to load %S, r=%d\n"), &KDma2Sim, r);
+ test(EFalse);
+ }
+
+ // Turn off evil lazy dll unloading
+ RLoader l;
+ test(l.Connect()==KErrNone);
+ test(l.CancelLazyDllUnload()==KErrNone);
+ RTest::CloseHandleAndWaitForDestruction(l);
+
+ __KHEAP_MARK;
+
+ if (gSelfTest) //Run self tests if specified on command line
+ {
+ SelfTests();
+ }
+
+ RunSimDMATests();
+ if (dmaHwPresent)
+ {
+ RunDMATests();
+ }
+
+ // Wait for the supervisor thread to run and perform asynchronous
+ // cleanup, so that kernel heap space will be freed
+ r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
+ test_KErrNone(r);
+ __KHEAP_MARKEND;
+
+ if(dmaHwPresent)
+ {
+ r = User::FreeLogicalDevice(KTestDmaLddNameHw);
+ test_KErrNone(r);
+ }
+ r = User::FreeLogicalDevice(KTestDmaLddNameSim);
+ test_KErrNone(r);
+
+ test.End();
+ test.Close();
+
+ delete cleanup;
+
+ __UHEAP_MARKEND;
+ return 0;
+ }