os/kernelhwsrv/kerneltest/e32test/dma/t_dma.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\dma\t_dma.cpp
    15 // Overview:
    16 // Test the DMA channel functionality.
    17 // API Information:
    18 // RBusLogicalChannel, DLogicalChannelBase, DLogicalDevice
    19 // Details:	
    20 // - Load the DMA LDD, create a critical section, an active scheduler and
    21 // a CPeriodic object.
    22 // - Test one shot single buffer transfers: test simple transfer, request 
    23 // reconfiguration and cancelling. Verify results are as expected.
    24 // - Test one shot double buffer transfers: test simple transfer, request 
    25 // reconfiguration and cancelling. Verify results are as expected.
    26 // - Test streaming single buffer transfers: test simple transfer and
    27 // cancelling. Test that framework behaves correctly if one or more DMA
    28 // interrupts are missed. Verify results are as expected.
    29 // - Test streaming double buffer transfers: test simple transfer and
    30 // cancelling. Test that framework behaves correctly if one or more DMA
    31 // interrupts are missed. Verify results are as expected.
    32 // - Test streaming scatter/gather transfers: test simple transfer and
    33 // cancelling. Test that framework behaves correctly if one or more DMA
    34 // interrupts are missed. Verify results are as expected.
    35 // Platforms/Drives/Compatibility:
    36 // Hardware (Automatic).
    37 // Assumptions/Requirement/Pre-requisites:
    38 // Failures and causes:
    39 // Base Port information:
    40 // 
    41 //
    42 
    43 #define __E32TEST_EXTENSION__
    44 #include <e32test.h>
    45 #include "d_dma.h"
    46 #include <e32debug.h>
    47 #include <e32svr.h>
    48 #include <e32def.h>
    49 #include <e32def_private.h>
    50 #include "u32std.h"
    51 
    52 #ifdef __DMASIM__
    53 RTest test(_L("T_DMASIM"));
    54 #else
    55 RTest test(_L("T_DMA"));
    56 #endif
    57 
    58 //////////////////////////////////////////////////////////////////////////////
    59 // Mini-framework for running tests either in a single thread or in
    60 // several concurrent ones.
    61 
    62 RTestDma::TInfo Info;
    63 TBool JitEnabled;
    64 RCriticalSection TheCriticalSection;						// protect following variables
    65 TInt ThreadCount;											// decremented when tester thread dies
    66 CPeriodic* Bipper;											// display dots during tests to detect lock-ups
    67 
    68 // Test macro used inside tester threads
    69 _LIT(KTestFailure, "XTEST");
    70 static void TestPanic(TInt aLine, TUint32 a1, TUint32 a2, TUint32 a3)
    71 	{
    72 	RDebug::Printf("Line %d test failed a1=%08x a2=%08x a3=%08x", aLine, a1, a2, a3);
    73 	RThread().Panic(KTestFailure, aLine);
    74 	}
    75 #define XTEST(e)				if (!(e)) TestPanic(__LINE__, 0, 0, 0)
    76 #define XTEST1(e,a1)			if (!(e)) TestPanic(__LINE__, (a1), 0, 0)
    77 #define XTEST2(e,a1,a2)			if (!(e)) TestPanic(__LINE__, (a1), (a2), 0)
    78 #define XTEST3(e,a1,a2,a3)		if (!(e)) TestPanic(__LINE__, (a1), (a2), (a3))
    79 
    80 
    81 /**
    82 Specifies a DMA test
    83 @note Have not inherited from CBase so that implicit copy ctors are used
    84 */
    85 class CTest
    86 	{
    87 public:
    88 	typedef void (*TTestFunction)(RTestDma aChannel, TInt aMaxFragment, TInt aFragmentSize);
    89 
    90 	CTest(TTestFunction aFn, TInt aMaxIter)
    91 		:iTestFn(aFn), iChannelId(0), iMaxIter(aMaxIter)
    92 		{}
    93 
    94 	virtual ~CTest()
    95 		{}
    96 
    97 	TInt RunTest();
    98 
    99 	virtual TBool OpenChannel(TInt aDesCount, TInt aMaxFragmentSize=0);
   100 
   101 	virtual void AnnounceTest(TDes& aDes)
   102 		{aDes.AppendFormat(_L("Channel Id %d, iMaxIter %d"), iChannelId, iMaxIter);}
   103 	virtual void ReportState(TDes& aDes)
   104 		{aDes.AppendFormat(_L("Channel Id %d, iCurIter %d"), iChannelId, iCurIter);}
   105 
   106 
   107 	void SetChannelId(TUint32 aChannelId)
   108 		{iChannelId = aChannelId;}
   109 
   110 	TInt MaxIter() const {return iMaxIter;}
   111 	TInt CurIter() const {return iCurIter;}
   112 
   113 	/**
   114 	@return A copy of this test
   115 	*/	
   116 	virtual	CTest* Clone() const =0;
   117 
   118 protected:
   119 	TInt virtual DoRunTest() =0;
   120 
   121 	const TTestFunction iTestFn;
   122 	TUint32 iChannelId;
   123 	const TInt iMaxIter;
   124 	TInt iCurIter;
   125 	RTestDma iChannel;
   126 	};	
   127 
   128 /**
   129 Specifies a DMA test where the maximum fragmentation is
   130 explicitly limited. This tests that requests are split
   131 in to the number of fragments expected.
   132 
   133 This test also requires that physically contiguous buffers
   134 are used. For this reason the product of iMaxFragment and
   135 iMaxFragmentSize should be kept small
   136 */
   137 class CFragmentationTest : public CTest
   138 	{
   139 public:
   140 	CFragmentationTest(TTestFunction aFn, TInt aMaxIter, TInt aMaxFragment, TInt aMaxFragmentSize)
   141 		: CTest(aFn, aMaxIter), iMaxFragment(aMaxFragment), iMaxFragmentSize(aMaxFragmentSize), iCurFragment(0)
   142 	{}
   143 
   144 	TInt virtual DoRunTest();
   145 
   146 	virtual void AnnounceTest(TDes& aDes)
   147 		{
   148 		aDes.AppendFormat(_L("CFragmentationTest: Frag count = [1..%d], Max Frag Size = 0x%08x bytes: "), iMaxFragment, iMaxFragmentSize);
   149 		CTest::AnnounceTest(aDes);
   150 		}
   151 
   152 	virtual void ReportState(TDes& aDes)
   153 		{
   154 		aDes.AppendFormat(_L("CFragmentationTest: Current Fragment %d: "), iCurFragment);
   155 		CTest::ReportState(aDes);
   156 		}
   157 
   158 	CTest* Clone() const
   159 		{return new CFragmentationTest(*this);}
   160 
   161 private:
   162 	const TInt iMaxFragment;
   163 	TInt iMaxFragmentSize;
   164 	TInt iCurFragment;
   165 	};
   166 
   167 /**
   168 Specifies a DMA test where the maximum fragment size is
   169 not limited - and we do not care how many fragments are
   170 used
   171 
   172 - This checks that transfers work correctly with the DMAC's
   173 default fragment size
   174 */
   175 class CDefaultFragTest : public CTest
   176 	{
   177 public:
   178 	CDefaultFragTest(TTestFunction aFn, TInt aMaxIter, TUint aTotalTransferSize)
   179 		: CTest(aFn, aMaxIter), iTotalTransferSize(aTotalTransferSize)
   180 		{}
   181 
   182 	TInt virtual DoRunTest();
   183 
   184 	virtual void AnnounceTest(TDes& aDes)
   185 		{
   186 		aDes.AppendFormat(_L("CDefaultFragTest: Transfer = 0x%08x bytes: "), iTotalTransferSize);
   187 		CTest::AnnounceTest(aDes);
   188 		}
   189 
   190 	CTest* Clone() const
   191 		{return new CDefaultFragTest(*this);}
   192 
   193 	const TInt iTotalTransferSize;
   194 	};
   195 
   196 
   197 //
   198 // Active object used to create a tester thread, log on to it and
   199 // interpret its exit status.
   200 //
   201 class CTesterThread : public CActive
   202 	{
   203 public:
   204 	CTesterThread(TInt aIdx, CTest* aTest);
   205 	~CTesterThread()
   206 		{
   207 		delete iTest;
   208 		}
   209 private:
   210 	static TInt ThreadFunction(TAny* aSelf);
   211 	TInt StartThread();
   212 	// from CActive
   213 	virtual void DoCancel();
   214 	virtual void RunL();
   215 private:
   216 	RThread iThread;
   217 	CTest* iTest;
   218 	};
   219 
   220 
   221 /**
   222 Run the test for iMaxIter iterations
   223 */
   224 TInt CTest::RunTest()
   225 	{
   226 	TInt r = KErrNone;
   227 	for (iCurIter=0; iCurIter<iMaxIter; ++iCurIter)
   228 		{
   229 		r =  DoRunTest();
   230 		if(KErrNone != r)
   231 			break;
   232 		}
   233 	return r;
   234 	}
   235 
   236 /**
   237 Open iChannel
   238 
   239 @pre iChannel is not open
   240 @return
   241    - KErrNotSupported Channel does not exist on DMAC
   242    - KErrNone Success
   243    - KErrInUse
   244 */
   245 TInt CTest::OpenChannel(TInt aDesCount, TInt aMaxFragmentSize)
   246 		{
   247 		ASSERT(!iChannel.Handle());
   248 		const TInt r = iChannel.Open(iChannelId, aDesCount, aMaxFragmentSize);
   249 		if (r == KErrNotSupported)
   250 			return r;
   251 		XTEST1(KErrNone == r || KErrInUse == r, r);
   252 		
   253 		if(KErrInUse == r)
   254 			{
   255 			// Channel is in use.
   256 			RDebug::Printf("\nDMA Channel %d is in use",iChannelId);
   257 			if(0 == iCurIter)
   258 				{
   259 				// Terminate thread by returning this error code KErrInUse.
   260 				return r;
   261 				}
   262 			else
   263 				{
   264 #ifdef __WINS__
   265 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
   266 #endif // __WINS__
   267 				XTEST1(EFalse, iCurIter);
   268 #ifdef __WINS__
   269 #pragma warning( default : 4127 ) // warning C4127: conditional expression is constant
   270 #endif // __WINS__
   271 				}
   272 			}
   273 		return r;
   274 		}
   275 
   276 
   277 
   278 // Spawn thread. Will auto-delete when thread exits.
   279 CTesterThread::CTesterThread(TInt aIdx, CTest* aTest)
   280 	: CActive(EPriorityStandard), iTest(aTest)
   281 	{
   282 	CActiveScheduler::Add(this);
   283 	TBuf<16> name;
   284 	name = _L("TESTER-");
   285 	name.AppendNum(aIdx);
   286 	test(iThread.Create(name, ThreadFunction, 0x1000, NULL, this) == KErrNone);
   287 	iThread.SetPriority(EPriorityLess);
   288 	iThread.Logon(iStatus);
   289 	SetActive();
   290 	iThread.Resume();
   291 	}
   292 
   293 
   294 TInt CTesterThread::ThreadFunction(TAny* aSelf)
   295 	{
   296 	CTesterThread* self = (CTesterThread*)aSelf;
   297 	return self->StartThread();
   298 	}
   299 
   300 TInt CTesterThread::StartThread()
   301 	{
   302 	return iTest->RunTest();
   303 	}
   304 
   305 
   306 
   307 TInt CFragmentationTest::DoRunTest()
   308 	{
   309 	// In case iMaxFragmentSize was larger than suppported (we need to know what fragment
   310 	// size will actually be used)
   311 	iMaxFragmentSize = Min(iMaxFragmentSize, Info.iMaxTransferSize);
   312 
   313 	// Open channel with enough descriptors for 3 open DMA
   314 	// requests (see TestStreaming).
   315 	TInt r = OpenChannel(3* iMaxFragment, iMaxFragmentSize);
   316 	if(r != KErrNone)
   317 		return r;
   318 
   319 	//we are controlling fragment size, so we know how
   320 	//many to expect
   321 	for (iCurFragment=1; iCurFragment<=iMaxFragment; iCurFragment*=2)
   322 		{
   323 		const TInt size = iCurFragment * ( iMaxFragmentSize & ~Info.iMemAlignMask);
   324 		iTestFn(iChannel, iCurFragment, size);
   325 		}
   326 	iChannel.Close();
   327 	return KErrNone;
   328 	}
   329 
   330 TInt CDefaultFragTest::DoRunTest()
   331 	{
   332 	// +1 so we don't underestimate maxFragount for inexact division
   333 	const TUint maxFragCount = (iTotalTransferSize / Info.iMaxTransferSize) +1;
   334 
   335 	// Open channel with enough descriptors for 3 open DMA
   336 	// requests (see TestStreaming).
   337 	const TUint descriptorCount = 3 * maxFragCount;
   338 
   339 	TInt r = OpenChannel(descriptorCount);
   340 	if(r != KErrNone)
   341 		return r;
   342 
   343 	iTestFn(iChannel, 0, iTotalTransferSize);
   344 	
   345 	iChannel.Close();
   346 	return KErrNone;
   347 	}
   348 
   349 
   350 // Called when thread completed.
   351 void CTesterThread::RunL()
   352 	{
   353 	TExitType et = iThread.ExitType();
   354 	TInt er = iThread.ExitReason();
   355 	TExitCategoryName ec = iThread.ExitCategory();
   356 	TName name = iThread.Name();
   357 	CLOSE_AND_WAIT(iThread);
   358 
   359 	switch (et)
   360 		{
   361 	case EExitKill:
   362 		// nothing to do
   363 		break;
   364 	case EExitPanic:
   365 			{
   366 			User::SetJustInTime(JitEnabled);
   367 			TBuf<128> buffer;
   368 			iTest->ReportState(buffer);
   369 			test.Printf(_L("Tester Thread Panic: %S: Test: %S\n"),
   370 						&name, &buffer);
   371 			if (ec.Match(KTestFailure) == 0)
   372 				test.Panic(_L("Test failure line %d"), er);
   373 			else
   374 				test.Panic(_L("Unexpected panic: %S-%d"), &ec, er);
   375 			break;
   376 			}
   377 	default:
   378 		test.Panic(_L("Invalid thread exit type"));
   379 		}
   380 
   381 	TheCriticalSection.Wait();
   382 	if (--ThreadCount == 0)
   383 		{
   384 		Bipper->Cancel();
   385 		test.Console()->Printf(_L("\n"));
   386 		CActiveScheduler::Stop();
   387 		}
   388 	TheCriticalSection.Signal();
   389 
   390 	// We commit suicide as the alternative (being deleted by
   391 	// RunTest()) implies keeping a list of all instances in
   392 	// RunTest().
   393 	delete this;
   394 	}
   395 
   396 
   397 void CTesterThread::DoCancel()
   398 	{
   399 	test.Panic(_L("CTesterThread::DoCancel called"));
   400 	}
   401 
   402 
   403 static TInt Bip(TAny*)
   404 	{
   405 	test.Console()->Printf(_L("."));
   406 	return 0;
   407 	}
   408 
   409 
   410 // Execute provided test object in one or more tester threads.
   411 void RunTest(TUint32 aChannelIds[], TInt aMaxThread, CTest* aTest)			 
   412 	{
   413 	test_NotNull(aTest);
   414 
   415 	if (aMaxThread == 0)
   416 		{
   417 		delete aTest;
   418 		test.Printf(_L("transfer mode not supported - skipped\n"));
   419 		return;
   420 		}
   421 
   422 	test.Printf(_L("Using %d thread(s)\n"), aMaxThread);
   423 
   424 	// We don't want JIT debugging here because the tester threads may panic
   425 	JitEnabled = User::JustInTime();
   426 	User::SetJustInTime(EFalse);
   427 
   428 	// must be set before spawning threads to avoid premature active scheduler stop
   429 	ThreadCount = aMaxThread;
   430 
   431 	TBuf<128> buffer;
   432 	for (TInt i=0; i<aMaxThread; ++i)
   433 		{
   434 		//each CTesterThread needs its own CTest object
   435 		CTest* dmaTest = aTest->Clone();
   436 		test_NotNull(dmaTest);
   437 
   438 		dmaTest->SetChannelId(aChannelIds[i]);
   439 
   440 		buffer.Zero();
   441 		dmaTest->AnnounceTest(buffer);
   442 		test.Printf(_L("Thread %d: %S\n"), i, &buffer);
   443 		
   444 		test(new CTesterThread(i, dmaTest) != NULL);
   445 		dmaTest = NULL; //ownership transferred to CTesterThread
   446 		}
   447 	//the orginal isn't needed
   448 	delete aTest;
   449 	aTest = NULL;
   450 
   451 	const TTimeIntervalMicroSeconds32 KPeriod = 1000000;	// 1s
   452 	Bipper->Start(KPeriod, KPeriod, Bip);
   453 
   454 	CActiveScheduler::Start();
   455 
   456 	User::SetJustInTime(JitEnabled);
   457 	}
   458 
   459 
   460 inline void RunSbTest(TInt aMaxThread, CTest* aTest)
   461 	{
   462 	RunTest(Info.iSbChannels, Min(aMaxThread,Info.iMaxSbChannels), aTest);
   463 	}
   464 
   465 inline void RunDbTest(TInt aMaxThread, CTest* aTest)
   466 	{
   467 	RunTest(Info.iDbChannels, Min(aMaxThread,Info.iMaxDbChannels), aTest);
   468 	}
   469 
   470 inline void RunSgTest(TInt aMaxThread, CTest* aTest)
   471 	{
   472 	RunTest(Info.iSgChannels, Min(aMaxThread,Info.iMaxSgChannels), aTest);
   473 	}
   474 //////////////////////////////////////////////////////////////////////////////
   475 
   476 static void GetChannelInfo()
   477 	{
   478 	RTestDma channel;
   479 	test(channel.GetInfo(Info) == KErrNone);
   480 	test(Info.iMaxSbChannels>0 || Info.iMaxDbChannels>0 || Info.iMaxSgChannels>0);
   481 	}
   482 
   483 
   484 static void TestOneShot(RTestDma aChannel, TInt aFragmentCount, TInt aSize)
   485 	{
   486 	const TInt KRequest = 0;
   487 	const TInt KSrcBuf = 0;
   488 	const TInt KDestBuf1 = 1;
   489 	const TInt KDestBuf2 = 2;
   490 
   491 	TInt r = aChannel.AllocBuffer(KSrcBuf, aSize);
   492 	XTEST2(r == KErrNone, r, aSize);
   493 	aChannel.FillBuffer(KSrcBuf, 'A');
   494 	r = aChannel.AllocBuffer(KDestBuf1, aSize);
   495 	XTEST2(r == KErrNone, r, aSize);
   496 	aChannel.FillBuffer(KDestBuf1, '\0');
   497 	r = aChannel.AllocBuffer(KDestBuf2, aSize);
   498 	XTEST2(r == KErrNone, r, aSize);
   499 	aChannel.FillBuffer(KDestBuf2, '\0');
   500 
   501 	// Test simple transfer
   502 	TRequestStatus rs;
   503 	r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf1, aSize, &rs);
   504 	XTEST2(r == KErrNone, r, aSize);
   505 	test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   506 	r = aChannel.Execute(_L8("Q0"));
   507 	XTEST1(r == KErrNone, r);
   508 	User::WaitForRequest(rs);
   509 	XTEST1(rs == KErrNone, rs.Int());
   510 	XTEST(aChannel.CheckBuffer(KDestBuf1, 'A'));
   511 
   512 	// Test request reconfiguration.
   513 	aChannel.FillBuffer(KDestBuf1, '\0');
   514 	r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf2, aSize, &rs);
   515 	XTEST2(r == KErrNone, r, aSize);
   516 	test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   517 	r = aChannel.Execute(_L8("Q0"));
   518 	XTEST1(r == KErrNone, r);
   519 	User::WaitForRequest(rs);
   520 	XTEST1(rs == KErrNone, rs.Int());
   521 	XTEST(aChannel.CheckBuffer(KDestBuf1, '\0'));			// previous dest unchanged?
   522 	XTEST(aChannel.CheckBuffer(KDestBuf2, 'A'));
   523 
   524 	// Test cancelling
   525 	aChannel.FillBuffer(KDestBuf1, '\0');
   526 	r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf1, aSize);
   527 	XTEST2(r == KErrNone, r, aSize);
   528 	test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   529 	r = aChannel.Execute(_L8("Q0C"));
   530 	XTEST1(r == KErrNone, r);
   531 	// Part of the destination buffer should be unchanged if the
   532 	// cancel occured before the transfer completed.
   533 #ifdef __DMASIM__
   534 	// At least part of the last destination buffer should be
   535 	// unchanged if cancel occured before the transfer completed.
   536 	// Assert only on WINS as real DMACs are too fast.
   537 	XTEST(! aChannel.CheckBuffer(KDestBuf2, 'C'));
   538 #endif
   539 
   540 	// Perform another transfer to ensure cancel operation let the
   541 	// framework in a consistent state.
   542 	aChannel.FillBuffer(KDestBuf1, '\0');
   543 	r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf1, aSize, &rs);
   544 	XTEST2(r == KErrNone, r, aSize);
   545 	test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   546 	r = aChannel.Execute(_L8("Q0"));
   547 	XTEST1(r == KErrNone, r);
   548 	User::WaitForRequest(rs);
   549 	XTEST1(rs == KErrNone, rs.Int());
   550 	XTEST(aChannel.CheckBuffer(KDestBuf1, 'A'));
   551 
   552 	//
   553 	// Test failure if the underlying DMA kernel extension allows it.
   554 	//
   555 	// As long as only "CancelAllFragments" is supported, it's okay to
   556 	// always fail on the first fragment.
   557 	//
   558 
   559 	if (aChannel.FailNext(1) == KErrNone)
   560 		{
   561 		aChannel.FillBuffer(KDestBuf1, '\0');
   562 		r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf1, aSize, &rs);
   563 		XTEST2(r == KErrNone, r, aSize);
   564 		test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   565 		r = aChannel.Execute(_L8("Q0"));
   566 		XTEST1(r == KErrNone, r);
   567 		User::WaitForRequest(rs);
   568 		XTEST1(rs != KErrNone, rs.Int());
   569 		XTEST(! aChannel.CheckBuffer(KDestBuf1, 'A'));
   570 		r = aChannel.Execute(_L8("C"));
   571 		XTEST1(r == KErrNone, r);
   572 
   573 		// Perform another transfer to ensure we are still in a
   574 		// consistent state.
   575 		aChannel.FillBuffer(KDestBuf1, '\0');
   576 		r = aChannel.Fragment(KRequest, KSrcBuf, KDestBuf1, aSize, &rs);
   577 		XTEST2(r == KErrNone, r, aSize);
   578 		test(aChannel.FragmentCheck(KRequest, aFragmentCount));
   579 		r = aChannel.Execute(_L8("Q0"));
   580 		XTEST1(r == KErrNone, r);
   581 		User::WaitForRequest(rs);
   582 		XTEST1(rs == KErrNone, rs.Int());
   583 		XTEST(aChannel.CheckBuffer(KDestBuf1, 'A'));
   584 		}
   585 
   586 	aChannel.FreeAllBuffers();
   587 	}
   588 
   589 
   590 static void TestStreaming(RTestDma aChannel, TInt aFragmentCount, TInt aSize)
   591 	{
   592 	const TInt KRequest0 = 0;
   593 	const TInt KRequest1 = 1;
   594 	const TInt KRequest2 = 2;
   595 	const TInt KSrcBuf0 = 0;
   596 	const TInt KSrcBuf1 = 1;
   597 	const TInt KSrcBuf2 = 2;
   598 	const TInt KDestBuf0 = 3;
   599 	const TInt KDestBuf1 = 4;
   600 	const TInt KDestBuf2 = 5;
   601 
   602 	//
   603 	// Allocate and initialise source buffers
   604 	//
   605 
   606 	TInt r = aChannel.AllocBuffer(KSrcBuf0, aSize);
   607 	XTEST2(r == KErrNone, r, aSize);
   608 	aChannel.FillBuffer(KSrcBuf0, 'A');
   609 
   610 	r = aChannel.AllocBuffer(KSrcBuf1, aSize);
   611 	XTEST2(r == KErrNone, r, aSize);
   612 	aChannel.FillBuffer(KSrcBuf1, 'B');
   613 
   614 	r = aChannel.AllocBuffer(KSrcBuf2, aSize);
   615 	XTEST2(r == KErrNone, r, aSize);
   616 	aChannel.FillBuffer(KSrcBuf2, 'C');
   617 
   618 	//
   619 	// Allocate destination buffers
   620 	//
   621 
   622 	r = aChannel.AllocBuffer(KDestBuf0, aSize);
   623 	XTEST2(r == KErrNone, r, aSize);
   624 	r = aChannel.AllocBuffer(KDestBuf1, aSize);
   625 	XTEST2(r == KErrNone, r, aSize);
   626 	r = aChannel.AllocBuffer(KDestBuf2, aSize);
   627 	XTEST2(r == KErrNone, r, aSize);
   628 
   629 	//
   630 	// Test simple transfer.
   631 	// (no need to test for request reconfiguration afterwards because
   632 	// this was exercised in the one-shot test case)
   633 	//
   634 
   635 	TRequestStatus rs0;
   636 	r = aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize, &rs0);
   637 	XTEST2(r == KErrNone, r, aSize);
   638 	test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   639 	TRequestStatus rs1;
   640  	r = aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize, &rs1);
   641 	XTEST2(r == KErrNone, r, aSize);
   642 	test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   643 	TRequestStatus rs2;
   644 	r = aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2);
   645 	XTEST2(r == KErrNone, r, aSize);
   646 	test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   647 
   648 	r = aChannel.Execute(_L8("Q0Q1Q2"));
   649 	XTEST1(r == KErrNone, r);
   650 	User::WaitForRequest(rs0);
   651 	XTEST1(rs0 == KErrNone, rs0.Int());
   652 	XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   653 	User::WaitForRequest(rs1);
   654 	XTEST1(rs1 == KErrNone, rs1.Int());
   655 	XTEST(aChannel.CheckBuffer(KDestBuf1, 'B'));
   656 	User::WaitForRequest(rs2);
   657 	XTEST1(rs2 == KErrNone, rs2.Int());
   658 	XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   659 
   660 	//
   661 	// Test cancel
   662 	//
   663 
   664 	aChannel.FillBuffer(KDestBuf0, '\0');
   665 	aChannel.FillBuffer(KDestBuf1, '\0');
   666 	aChannel.FillBuffer(KDestBuf2, '\0');
   667 
   668 	r = aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize);
   669 	XTEST2(r == KErrNone, r, aSize);
   670 	test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   671  	r = aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize);
   672 	XTEST2(r == KErrNone, r, aSize);
   673 	test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   674 	r = aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize);
   675 	XTEST2(r == KErrNone, r, aSize);
   676 	test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   677 
   678 	r = aChannel.Execute(_L8("Q0Q1Q2C"));
   679 	XTEST1(r == KErrNone, r);
   680 #ifdef __DMASIM__
   681 	// At least part of the last destination buffer should be
   682 	// unchanged if cancel occured before the transfer completed.
   683 	// Assert only on WINS as real DMACs are too fast.
   684 	XTEST(! aChannel.CheckBuffer(KDestBuf2, 'C'));
   685 #endif
   686 
   687 	//
   688 	// Perform another transfer to ensure cancel operation let the
   689 	// framework in a consistent state.
   690 	//
   691 
   692 	aChannel.FillBuffer(KDestBuf0, '\0');
   693 	aChannel.FillBuffer(KDestBuf1, '\0');
   694 	aChannel.FillBuffer(KDestBuf2, '\0');
   695 	// Reconfigure last request to enable transfer completion notification
   696 	r = aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2);
   697 	XTEST2(r == KErrNone, r, aSize);
   698 	test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   699 	r = aChannel.Execute(_L8("Q0Q1Q2"));
   700 	XTEST1(r == KErrNone, r);
   701 	User::WaitForRequest(rs2);
   702 	XTEST1(rs2 == KErrNone, rs2.Int());
   703 	XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   704 	XTEST(aChannel.CheckBuffer(KDestBuf1, 'B'));
   705 	XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   706 
   707 	//
   708 	// Test for proper implementation of UnlinkHwDes() in the PSL.
   709 	//
   710 
   711 	aChannel.FillBuffer(KDestBuf0, '\0');
   712 	aChannel.FillBuffer(KDestBuf1, '\0');
   713 	aChannel.FillBuffer(KDestBuf2, '\0');
   714 	// Reconfigure last request to enable transfer completion notification
   715 	r = aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2);
   716 	XTEST2(r == KErrNone, r, aSize);
   717 	test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   718 	// Queue first request (Q0)
   719 	r = aChannel.Execute(_L8("Q0"));
   720 	// Wait a second, so next request will be queued on its own
   721 	// (instead of being appended to the previous one)
   722 	User::After(1000000);
   723 	// Queue third request (Q2)
   724 	r = aChannel.Execute(_L8("Q2"));
   725 	XTEST1(r == KErrNone, r);
   726 	User::WaitForRequest(rs2);
   727 	XTEST1(rs2 == KErrNone, rs2.Int());
   728 	XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   729 	// KDestBuf1 should have been left untouched!
   730 	// If we find all B's in KDestBuf1, that means the last descriptor of the
   731 	// first request (Q0) wasn't properly unlinked and still points to the Q1
   732 	// descriptor chain from the previous run.
   733 	XTEST(aChannel.CheckBuffer(KDestBuf1, '\0'));
   734 	XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   735 
   736 	//
   737 	// Test failure if the underlying DMA kernel extension allows it.
   738 	//
   739 	// As long as only "CancelAllFragments" is supported, it's okay to
   740 	// always fail on the first fragment.
   741 	//
   742 
   743 	if (aChannel.FailNext(1) == KErrNone)
   744 		{
   745 		aChannel.FillBuffer(KDestBuf0, '\0');
   746 		aChannel.FillBuffer(KDestBuf1, '\0');
   747 		aChannel.FillBuffer(KDestBuf2, '\0');
   748 		XTEST(aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize, &rs0) == KErrNone);
   749 		test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   750 		XTEST(aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize) == KErrNone);
   751 		test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   752 		XTEST(aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize) == KErrNone);
   753 		test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   754 		XTEST(aChannel.Execute(_L8("Q0Q1Q2")) == KErrNone);
   755 		User::WaitForRequest(rs0);
   756 		XTEST(rs0 != KErrNone);
   757 		XTEST(! aChannel.CheckBuffer(KDestBuf0, 'A'));
   758 		XTEST(! aChannel.CheckBuffer(KDestBuf1, 'B'));
   759 		XTEST(! aChannel.CheckBuffer(KDestBuf2, 'C'));
   760 		XTEST(aChannel.Execute(_L8("C")) == KErrNone);
   761 
   762 		// Transfer again to ensure cancel cleaned-up correctly
   763 		aChannel.FillBuffer(KDestBuf0, '\0');
   764 		aChannel.FillBuffer(KDestBuf1, '\0');
   765 		aChannel.FillBuffer(KDestBuf2, '\0');
   766 		XTEST(aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize, &rs0) == KErrNone);
   767 		test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   768 		XTEST(aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize, &rs1) == KErrNone);
   769 		test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   770 		XTEST(aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2) == KErrNone);
   771 		test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   772 		XTEST(aChannel.Execute(_L8("Q0Q1Q2")) == KErrNone);
   773 		User::WaitForRequest(rs0);
   774 		XTEST(rs0 == KErrNone);
   775 		User::WaitForRequest(rs1);
   776 		XTEST(rs1 == KErrNone);
   777 		User::WaitForRequest(rs2);
   778 		XTEST(rs2 == KErrNone);
   779 		XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   780 		XTEST(aChannel.CheckBuffer(KDestBuf1, 'B'));
   781 		XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   782 		}
   783 
   784 	//
   785 	// Test that framework behaves correctly if one or more DMA interrupts are
   786 	// missed.
   787 	//
   788 
   789 	if (aChannel.MissNextInterrupts(1) == KErrNone)
   790 		{
   791 		aChannel.FillBuffer(KDestBuf0, '\0');
   792 		aChannel.FillBuffer(KDestBuf1, '\0');
   793 		aChannel.FillBuffer(KDestBuf2, '\0');
   794 		XTEST(aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize, &rs0) == KErrNone);
   795 		test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   796 		XTEST(aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize, &rs1) == KErrNone);
   797 		test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   798 		XTEST(aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2) == KErrNone);
   799 		test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   800 		XTEST(aChannel.Execute(_L8("Q0Q1Q2")) == KErrNone);
   801 		User::WaitForRequest(rs0);
   802 		XTEST(rs0 == KErrNone);
   803 		User::WaitForRequest(rs1);
   804 		XTEST(rs1 == KErrNone);
   805 		User::WaitForRequest(rs2);
   806 		XTEST(rs2 == KErrNone);
   807 		XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   808 		XTEST(aChannel.CheckBuffer(KDestBuf1, 'B'));
   809 		XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   810 		}
   811 
   812 	if (aChannel.MissNextInterrupts(2) == KErrNone)
   813 		{
   814 		aChannel.FillBuffer(KDestBuf0, '\0');
   815 		aChannel.FillBuffer(KDestBuf1, '\0');
   816 		aChannel.FillBuffer(KDestBuf2, '\0');
   817 		XTEST(aChannel.Fragment(KRequest0, KSrcBuf0, KDestBuf0, aSize, &rs0) == KErrNone);
   818 		test(aChannel.FragmentCheck(KRequest0, aFragmentCount));
   819 		XTEST(aChannel.Fragment(KRequest1, KSrcBuf1, KDestBuf1, aSize, &rs1) == KErrNone);
   820 		test(aChannel.FragmentCheck(KRequest1, aFragmentCount));
   821 		XTEST(aChannel.Fragment(KRequest2, KSrcBuf2, KDestBuf2, aSize, &rs2) == KErrNone);
   822 		test(aChannel.FragmentCheck(KRequest2, aFragmentCount));
   823 		XTEST(aChannel.Execute(_L8("Q0Q1Q2")) == KErrNone);
   824 		User::WaitForRequest(rs0);
   825 		XTEST(rs0 == KErrNone);
   826 		User::WaitForRequest(rs1);
   827 		XTEST(rs1 == KErrNone);
   828 		User::WaitForRequest(rs2);
   829 		XTEST(rs2 == KErrNone);
   830 		XTEST(aChannel.CheckBuffer(KDestBuf0, 'A'));
   831 		XTEST(aChannel.CheckBuffer(KDestBuf1, 'B'));
   832 		XTEST(aChannel.CheckBuffer(KDestBuf2, 'C'));
   833 		}
   834 
   835 	aChannel.FreeAllBuffers();
   836 	}
   837 
   838 
   839 static TBool ParseCmdLine(TBool& aCrashDbg, TInt& aMaxfrag, TInt& aMaxIter, TInt& aMaxchannel, TInt& aMaxFragSize)
   840 //
   841 // The command line. Syntax is:
   842 //
   843 //     t_dma [enableCrashDebugger [aMaxFrag [aMaxIter [aMaxchannel [aMaxFragSize]]]]]
   844 //
   845 	{
   846 	TBuf<256> cmdline;
   847 	User::CommandLine(cmdline);
   848 	TLex lex(cmdline);
   849 
   850 	lex.SkipSpace();
   851 
   852 	if (lex.Eos())
   853 		return ETrue;
   854 	if (lex.Val(aCrashDbg) != KErrNone)
   855 		return EFalse;
   856 	lex.SkipSpace();
   857 	if (lex.Eos())
   858 		return ETrue;
   859 	if (lex.Val(aMaxfrag) != KErrNone)
   860 		return EFalse;
   861 	lex.SkipSpace();
   862 	if (lex.Eos())
   863 		return ETrue;
   864 	if (lex.Val(aMaxIter) != KErrNone)
   865 		return EFalse;
   866 	lex.SkipSpace();
   867 	if (lex.Eos())
   868 		return ETrue;
   869 	if (lex.Val(aMaxchannel) != KErrNone)
   870 		return EFalse;
   871 	lex.SkipSpace();
   872 	if (lex.Eos())
   873 		return ETrue;
   874 
   875 	return lex.Val(aMaxFragSize) == KErrNone;
   876 	}
   877 
   878 
   879 TInt E32Main()
   880 	{
   881 	test.Title();
   882 
   883 	test.Start(_L("Parsing command-line"));
   884 	// Default values when run with empty command-line
   885 	TInt maxfrag = 16; // 5 fragments needed to exercise fully double-buffering state machine
   886 	TInt maxIter = 3;
   887 	TInt maxchannel = KMaxTInt;
   888 	TBool crashDbg = EFalse;
   889 	TInt maxFragSize = 0x4000; //16k
   890 
   891 	(void) ParseCmdLine(crashDbg, maxfrag, maxIter, maxchannel, maxFragSize);
   892 
   893 	if (crashDbg)
   894 		{
   895 		User::SetCritical(User::ESystemCritical);
   896 		User::SetProcessCritical(User::ESystemCritical);
   897 		}
   898 
   899 
   900 	TInt r;
   901 #if defined(__DMASIM__) && defined(__WINS__)
   902 	test.Next(_L("Loading DMA simulator"));
   903 	r = User::LoadLogicalDevice(_L("DMASIM.DLL"));
   904 	test(r == KErrNone || r == KErrAlreadyExists);
   905 #endif
   906 
   907 	test.Next(_L("Loading test LDD"));
   908 #ifdef __DMASIM__
   909 	r = User::LoadLogicalDevice(_L("D_DMASIM"));
   910 	test(r == KErrNone || r == KErrAlreadyExists);
   911 #else
   912 	//load either the original test ldd, d_dma.ldd,
   913 	//or d_dma_compat.ldd - an ldd providing the same interface
   914 	//but linked against the new MHA dma framework
   915 	_LIT(KDma, "D_DMA.LDD");
   916 	r = User::LoadLogicalDevice(KDma);
   917 	const TBool dmaPresent = (r == KErrNone || r == KErrAlreadyExists);
   918 
   919 	_LIT(KDmaCompat, "D_DMA_COMPAT.LDD");
   920 	r = User::LoadLogicalDevice(KDmaCompat);
   921 	const TBool dmaCompatPresent = (r == KErrNone || r == KErrAlreadyExists);
   922 
   923 	if (!(dmaPresent || dmaCompatPresent))
   924 		{
   925 		test.Printf(_L("DMA test driver not found - test skipped\n"));
   926 		return 0;
   927 		}
   928 	else if (dmaPresent && !dmaCompatPresent)
   929 		{
   930 		test.Printf(_L("Loaded %S\n"), &KDma);
   931 		}
   932 	else if (!dmaPresent && dmaCompatPresent)
   933 		{
   934 		test.Printf(_L("Loaded %S\n"), &KDmaCompat);
   935 		}
   936 	else
   937 		{
   938 		test.Printf(_L("The ROM contains %S and %S - only one should be present\n"), &KDma, &KDmaCompat);
   939 		test(EFalse);
   940 		}
   941 #endif
   942 
   943 	// Turn off evil lazy dll unloading
   944 	RLoader l;
   945 	test(l.Connect()==KErrNone);
   946 	test(l.CancelLazyDllUnload()==KErrNone);
   947 	l.Close();
   948 
   949 	__UHEAP_MARK;
   950 	__KHEAP_MARK;
   951 
   952 	test.Next(_L("Creating critical section"));
   953 	test(TheCriticalSection.CreateLocal() == KErrNone);
   954 
   955 	test.Next(_L("Creating active scheduler"));
   956 	CActiveScheduler* pS = new CActiveScheduler;
   957 	test(pS != NULL);
   958 	CActiveScheduler::Install(pS);
   959 
   960 	test.Next(_L("Creating bipper"));
   961 	Bipper = CPeriodic::New(CActive::EPriorityStandard);
   962 	test(Bipper != NULL);
   963 
   964 	test.Next(_L("Getting channel info"));
   965 	GetChannelInfo();
   966 
   967 	// Size for the single transfer test
   968 	TInt totalTransferSize = 64 * KKilo;
   969 
   970 	test.Next(_L("Testing one shot single buffer transfer"));
   971 	RunSbTest(maxchannel, new CFragmentationTest(TestOneShot, maxIter, maxfrag, maxFragSize));
   972 	RunSbTest(maxchannel, new CDefaultFragTest(TestOneShot, maxIter, totalTransferSize));
   973 
   974 	test.Next(_L("Testing one shot double buffer transfer"));
   975 	RunDbTest(maxchannel, new CFragmentationTest(TestOneShot, maxIter, maxfrag, maxFragSize));
   976 	RunDbTest(maxchannel, new CDefaultFragTest(TestOneShot, maxIter, totalTransferSize));
   977 
   978 	test.Next(_L("Testing one shot scatter/gather transfer"));
   979 	RunSgTest(maxchannel, new CFragmentationTest(TestOneShot, maxIter, maxfrag, maxFragSize));
   980 	RunSgTest(maxchannel, new CDefaultFragTest(TestOneShot, maxIter, totalTransferSize));
   981 
   982 	test.Next(_L("Testing streaming single buffer transfer"));
   983 	RunSbTest(maxchannel, new CFragmentationTest(TestStreaming, maxIter, maxfrag, maxFragSize));
   984 	RunSbTest(maxchannel, new CDefaultFragTest(TestStreaming, maxIter, totalTransferSize));
   985 
   986 	test.Next(_L("Testing streaming double buffer transfer"));
   987 	RunDbTest(maxchannel, new CFragmentationTest(TestStreaming, maxIter, maxfrag, maxFragSize));
   988 	RunDbTest(maxchannel, new CDefaultFragTest(TestStreaming, maxIter, totalTransferSize));
   989 
   990 	test.Next(_L("Testing streaming scatter/gather transfer"));
   991 	RunSgTest(maxchannel, new CFragmentationTest(TestStreaming, maxIter, maxfrag, maxFragSize));
   992 	RunSgTest(maxchannel, new CDefaultFragTest(TestStreaming, maxIter, totalTransferSize));
   993 
   994 	delete pS;
   995 	delete Bipper;
   996 	TheCriticalSection.Close();
   997 
   998 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
   999 	__KHEAP_MARKEND;
  1000 	__UHEAP_MARKEND;
  1001 
  1002 	test.End();
  1003 	return 0;
  1004 	}