TInt CreateChunkAt(TUint32 addr,TInt minsize, TInt maxsize )
{
  TInt err = g_code_chunk->CreateLocalCode( minsize, maxsize );
  if( err )
	  return err;
  if ((TUint32)g_code_chunk->Base() != addr)
      {
      TUint offset = (TInt)g_code_chunk->Base();
      offset = addr-offset;
      g_code_chunk->Close();
      RChunk temp;
      if( offset > 0x7FFFFFFF )
    	  {
    	  //shit, offset too big :(
    	  return KErrNoMemory;
    	  }
      TInt chunkoffset = (TInt) offset;
      err = temp.CreateLocal(0,chunkoffset);
      if( err )
    	  {
    	  temp.Close();
    	  return err;
    	  }
      err = g_code_chunk->CreateLocalCode(minsize,maxsize);        
      temp.Close();
      }
  return err;
}
Beispiel #2
0
void DeAllocateBuffers()
{
    test.Printf(_L("DeAllocate Buffers -"));

    if (gFragSharedMemory || gSharedMemory)
    {
        test.Printf(_L("Shared Memory\n"));
        test.Printf(_L("Close user chunk handle\n"));
        TheChunk.Close();

        test.Printf(_L("Close kernel chunk handle\n"));
        TInt r = Ldd.CloseChunk();
        test_Value(r, r == 1);

        test.Printf(_L("Check chunk is destroyed\n"));
        r = Ldd.IsDestroyed();
        test_Value(r, r == 1);

        test.Printf(_L("Close test driver\n"));
        Ldd.Close();
    }
    else
    {
        test.Printf(_L("Heap Memory\n"));
        test.Printf(_L("Delete Heap Buffer\n"));
        delete DataBufH;
    }
}
Beispiel #3
0
GLDEF_C TInt E32Main()
	{
	test.Title();
	test.Start(_L("Create chunk"));
	RChunk c;
	TInt r=c.CreateDisconnectedLocal(0,0x1000,0x100000);
	test(r==KErrNone);
	r=c.Commit(0x10000,0x1000);
	test(r==KErrNone);
	TUint8* pBuf1=c.Base();
	TUint8* pBuf2=pBuf1+0x10000;

	TInt s;
	TInt d;
	TInt l;

	for (l=1; l<300; l+=3)
		{
		for (s=0; s<=4096-l; s+=227)
			{
			test.Printf(_L("\ns=%4d l=%4d: "),s,l);
			for (d=0; d<=4096-l; d+=229)
				{
				DoTest(pBuf1,pBuf2,4096,s,d,l,0);
				DoTest(pBuf1,pBuf2,4096,s,d,l,1);
				}
			}
		}

	for (l=1; l<300; l+=3)
		{
		for (s=4096-l; s>=0; s-=227)
			{
			test.Printf(_L("\ns=%4d l=%4d: "),s,l);
			for (d=4096-l; d>=0; d-=229)
				{
				DoTest(pBuf1,pBuf2,4096,s,d,l,0);
				DoTest(pBuf1,pBuf2,4096,s,d,l,1);
				}
			}
		}
	
	for (l=1; l<400; l+=((l<=64)?1:3) )
		{
		test.Printf(_L("\nOverlap test: l=%4d: "),l);
		for (s=32; s<=4096-32-l; s+=101)	// want s to take all values 0...31 modulo 32
			{
			for (d=s-32; d<=s+32; ++d)
				{
				DoOverlapTest(pBuf1,pBuf2,4096,s,d,l);
				}
			}
		}
	
	c.Close();
	test.End();
	return 0;
	}
// ---------------------------------------------------------------------------
// CloseChunkL
// ---------------------------------------------------------------------------
//
void CAlfHierarchyModel::CloseChunk( TInt32 aChunkHandle )
    {
    __ALFLOGSTRING1("CAlfHierarchyModel::CloseChunkL: closing %d", aChunkHandle );
    RChunk* chunk = iCacheChunks.Find( aChunkHandle );
    iCacheChunks.Remove( aChunkHandle );
    if ( chunk )
        {
        chunk->Close();
        }
    else
        {
        __ALFLOGSTRING1( "CAlfHierarchyModel::CloseChunkL - Warning: chunk %d not found!", aChunkHandle );
        }
    }
GLDEF_C TInt E32Main()
    {
#ifdef __WINS__1
    RChunk heapc;
    
    TInt err=heapc.OpenGlobal(_L("jaikusettings_heap"), ETrue);
    if (err!=KErrNone) {
    	return CSensorRunner::RunSensorsInThread(0);
    }
	RThread thread;
	TInt heap=*(TInt*)heapc.Base();
	heapc.Close();
	err=thread.Create(_L("context_log2"), 
		&CSensorRunner::RunSensorsInThread, // thread's main function
		20*1024, /* stack */
		heap, /* min heap */
		heap, /* max heap */
		0,
		EOwnerProcess);
	if (err!=KErrNone) return err;
	thread.SetPriority(EPriorityNormal);
	TRequestStatus s;
	thread.Logon(s);
	thread.Resume();
	User::WaitForRequest(s);
	TExitCategoryName n=thread.ExitCategory();
	TInt reason=thread.ExitReason();
	TExitType exittype=thread.ExitType();
	thread.Close();
	if (exittype==EExitPanic) {
		User::Panic( n, reason);
	}
	return reason;
#else
    SwitchToBetterHeap(KHeap);

    return CSensorRunner::RunSensorsInThread(0);
#endif
}
Beispiel #6
0
void RDmaSession::SelfTest(TBool aSimulatedDmac)
	{
	test.Start(_L("Simple transfer test"));

	RDmaSession session;
	TInt r = KErrUnknown;
	if (aSimulatedDmac)
		{
		test.Next(_L("Open session (simulated DMA)"));
		r = session.OpenSim();
		}
	else
		{
		test.Next(_L("Open session"));
		r = session.Open();
		}

	test_KErrNone(r);

	test.Next(_L("Get test info"));
	TDmaV2TestInfo testInfo;
	r = session.GetTestInfo(testInfo);
	test_KErrNone(r);

	if(gVerboseOutput)
	{
	Print(testInfo);
	}

	// Self test just needs 1 channel
	// The real test will test all available ones
	test.Next(_L("Select test channel"));
	TUint testChannel = 0;
	if(testInfo.iMaxSbChannels > 0)
		{
		testChannel = testInfo.iSbChannels[0];
		}
	else if(testInfo.iMaxDbChannels > 0)
		{
		testChannel = testInfo.iDbChannels[0];
		}
	else if(testInfo.iMaxSgChannels > 0)
		{
		testChannel = testInfo.iSgChannels[0];
		}
	else
		{
		test.Printf(_L("Driver exposes no channels to test"));
		test(EFalse);
		}

	test.Printf(_L("using PSL cookie %d (0x%08x)\n"), testChannel, testChannel);
	test.Next(_L("Open channel"));
	TUint channelCookie=0;
	r = session.ChannelOpen(testChannel, channelCookie);
	test.Printf(_L("cookie recived = 0x%08x\n"), channelCookie);
	test_KErrNone(r);

	test.Next(_L("Get Channel caps"));
	SDmacCaps channelCaps;
	r = session.ChannelCaps(channelCookie, channelCaps);
	test_KErrNone(r);
	if(gVerboseOutput)
	{
	PRINT(channelCaps.iChannelPriorities);
	PRINT(channelCaps.iChannelPauseAndResume);
	PRINT(channelCaps.iAddrAlignedToElementSize);
	PRINT(channelCaps.i1DIndexAddressing);
	PRINT(channelCaps.i2DIndexAddressing);
	PRINT(channelCaps.iSynchronizationTypes);
	PRINT(channelCaps.iBurstTransactions);
	PRINT(channelCaps.iDescriptorInterrupt);
	PRINT(channelCaps.iFrameInterrupt);
	PRINT(channelCaps.iLinkedListPausedInterrupt);
	PRINT(channelCaps.iEndiannessConversion);
	PRINT(channelCaps.iGraphicsOps);
	PRINT(channelCaps.iRepeatingTransfers);
	PRINT(channelCaps.iChannelLinking);
	PRINT(channelCaps.iHwDescriptors);
	PRINT(channelCaps.iSrcDstAsymmetry);
	PRINT(channelCaps.iAsymHwDescriptors);
	PRINT(channelCaps.iBalancedAsymSegments);
	PRINT(channelCaps.iAsymCompletionInterrupt);
	PRINT(channelCaps.iAsymDescriptorInterrupt);
	PRINT(channelCaps.iAsymFrameInterrupt);
	PRINT(channelCaps.iReserved[0]);
	PRINT(channelCaps.iReserved[1]);
	PRINT(channelCaps.iReserved[2]);
	PRINT(channelCaps.iReserved[3]);
	PRINT(channelCaps.iReserved[4]);	
	}

	test.Next(_L("Get extended Channel caps (TDmacTestCaps)"));
	TDmacTestCaps extChannelCaps;
	r = session.ChannelCaps(channelCookie, extChannelCaps);
	test_KErrNone(r);
	test.Printf(_L("PIL version = %d\n"), extChannelCaps.iPILVersion);

	const TBool newPil = (extChannelCaps.iPILVersion > 1);

	test.Next(_L("Create Dma request - max fragment size 32K"));
	TUint reqCookie=0;
	r = session.RequestCreateOld(channelCookie, reqCookie, 32 * KKilo);
	test.Printf(_L("cookie recived = 0x%08x\n"), reqCookie);
	test_KErrNone(r);

	if(newPil)
		{
		test.Next(_L("Create Dma request (with new-style callback)"));
		TUint reqCookieNewStyle=0;
		r = session.RequestCreate(channelCookie, reqCookieNewStyle);
		test.Printf(_L("cookie recived = 0x%08x\n"), reqCookieNewStyle );
		test_KErrNone(r);

		if(!aSimulatedDmac)
			{
			test.Next(_L("Fragment for ISR callback"));
			const TInt size = 128 * KKilo;
			TDmaTransferArgs transferArgs(0, size, size, KDmaMemAddr, KDmaSyncAuto, KDmaRequestCallbackFromIsr);
			r = session.FragmentRequest(reqCookieNewStyle, transferArgs);
			test_KErrNone(r);

			TIsrRequeArgs reque;
			test.Next(_L("Queue ISR callback - with default re-queue"));
			r = session.QueueRequestWithRequeue(reqCookieNewStyle, &reque, 1);
			test_KErrNone(r);
			}

		test.Next(_L("Destroy new-style Dma request"));
		r = session.RequestDestroy(reqCookieNewStyle);
		test_KErrNone(r);

		test.Next(_L("Attempt to destroy request again "));
		r = session.RequestDestroy(reqCookieNewStyle);
		test_Equal(KErrNotFound, r);
		}

	test.Next(_L("Open chunk handle"));
	RChunk chunk;
	r = session.OpenSharedChunk(chunk);
	test_KErrNone(r);
	if(gVerboseOutput)
	{
	test.Printf(_L("chunk base = 0x%08x\n"), chunk.Base());
	test.Printf(_L("chunk size = %d\n"), chunk.Size());
	}
	test(chunk.IsWritable());
	test(chunk.IsReadable());

	if(!aSimulatedDmac)
		{
		test.Next(_L("Fragment(old style)"));
		const TInt size = 128 * KKilo;
		TInt i;
		for(i = 0; i<10; i++)
			{
			TUint64 time = 0;
			TDmaTransferArgs transferArgs(0, size, size, KDmaMemAddr);
			r = session.FragmentRequestOld(reqCookie, transferArgs, &time);
			test_KErrNone(r);
			if(gVerboseOutput)
				{
				test.Printf(_L("%lu us\n"), time);
				}
			}

		test.Next(_L("Queue"));
		TRequestStatus status;

		for(i = 0; i<10; i++)
			{
			TUint64 time = 0;
			r = session.QueueRequest(reqCookie, status, 0, &time);
			User::WaitForRequest(status);
			test_KErrNone(r);
			if(gVerboseOutput)
				{
				test.Printf(_L("%lu us\n"), time);
				}
			}

		if(newPil)
			{
			test.Next(_L("Fragment(new style)"));
			TDmaTransferArgs transferArgs;
			transferArgs.iSrcConfig.iAddr = 0;
			transferArgs.iDstConfig.iAddr = size;
			transferArgs.iSrcConfig.iFlags = KDmaMemAddr;
			transferArgs.iDstConfig.iFlags = KDmaMemAddr;
			transferArgs.iTransferCount = size;

			for(i = 0; i<10; i++)
				{
				TUint64 time = 0;
				r = session.FragmentRequest(reqCookie, transferArgs, &time);
				test_KErrNone(r);
				if(gVerboseOutput)
					{
					test.Printf(_L("%lu us\n"), time);
					}
				}
			}

		test.Next(_L("Queue"));
		TCallbackRecord record;
		r = session.QueueRequest(reqCookie, &record);
		test_KErrNone(r);

		test.Next(_L("check TCallbackRecord record"));
		if(gVerboseOutput)
		{
		record.Print();
		}
		const TCallbackRecord expected(TCallbackRecord::EThread, 1);
		if(!(record == expected))
			{
			test.Printf(_L("TCallbackRecords did not match"));
			if(gVerboseOutput)
				{
				test.Printf(_L("expected:"));
				expected.Print();
				}
			TEST_FAULT;
			}
		}

	test.Next(_L("Destroy Dma request"));
	r = session.RequestDestroy(reqCookie);
	test_KErrNone(r);

	test.Next(_L("Close chunk handle"));
	chunk.Close();

	test.Next(_L("Channel close"));
	r = session.ChannelClose(channelCookie);
	test_KErrNone(r);

	test.Next(_L("Channel close (same again)"));
	r = session.ChannelClose(channelCookie);
	test_Equal(KErrNotFound, r);

	test.Next(_L("Close session"));
	RTest::CloseHandleAndWaitForDestruction(session);

	test.End();
	}
LOCAL_C TInt WavRecord()
	{
	// Parse the commandline and get a filename to use
	TLex l(CommandLine);
	TParse destinationName;
	if (destinationName.SetNoWild(l.NextToken(),0,0)!=KErrNone)
		{
		Test.Printf(_L("No arg, skipping\r\n"));
		return(KErrArgument);
		}
	Test.Next(_L("Record Wav file"));

	// Open the file for writing
	TInt r;
	RFile destination;
	r = destination.Replace(Fs,destinationName.FullName(),EFileWrite);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Open file for write failed(%d)\n"), r);
		return(r);
		}		
	Test.Printf(_L("File opened for write\r\n"));
	
	Test.Next(_L("Preparing to record"));
	
	// Get the rate
	TLex cl(l.NextToken());
	TUint32 tmpRate;
	TSoundRate rate;
	r = cl.Val(tmpRate,EDecimal);
	if (r == KErrNone && (r=SamplesPerSecondToRate(tmpRate,rate))==KErrNone)
		{
		Test.Printf(_L("Parsed rate: %d\r\n"), tmpRate);
		RecordFormatBuf().iRate = rate;
		}
	else
		{
		Test.Printf(_L("Parse rate failed(%d)\r\n"),r);
		RecordFormatBuf().iRate = ESoundRate32000Hz;
		}

	// Get number of channels
	TLex cl_chan(l.NextToken());
	TUint32 tmpChannels;
	r = cl_chan.Val(tmpChannels,EDecimal);
	if (r == KErrNone)
		{
		Test.Printf(_L("Parsed %d channels\r\n"),tmpChannels);
		RecordFormatBuf().iChannels = tmpChannels;
		}
	else
		{
		Test.Printf(_L("Parse channels failed(%d)\r\n"), r);
		RecordFormatBuf().iChannels = 2;
		}

	RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
	
	// Set the record buffer configuration.
	RChunk chunk;
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=4;
	bufferConfig.iBufferSizeInBytes=RecordBufferSizeInBytes(RecordFormatBuf());
	if (RecordCapsBuf().iRequestMinSize)
		bufferConfig.iBufferSizeInBytes&=~(RecordCapsBuf().iRequestMinSize-1); 	// Keep the buffer length valid for the driver.
	bufferConfig.iFlags=0;	
	PrintBufferConf(bufferConfig,Test);
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Buffer configuration not supported(%d)\r\n"),r);
		return(r);
		}
	
	// Set the audio record configuration.
	RxSoundDevice.SetVolume(KSoundMaxVolume);
	PrintConfig(RecordFormatBuf(),Test);
	r=RxSoundDevice.SetAudioFormat(RecordFormatBuf);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Format not supported\r\n"));
		return(r);
		}

	// Get length in seconds
	TLex cl_seconds(l.NextToken());
	TUint32 tmpSeconds;
	r = cl_seconds.Val(tmpSeconds,EDecimal);
	if (r == KErrNone)
		{
		Test.Printf(_L("Parsed %d seconds\r\n"),tmpSeconds);
		}
	else
		{
		Test.Printf(_L("Parse seconds failed(%d)\r\n"),r);
		tmpSeconds=10;
		}
	TInt bytesToRecord = BytesPerSecond(RecordFormatBuf())*tmpSeconds;	
		
	Test.Next(_L("Recording..."));
	
	// Lay down a file header
	WAVEheader header;
	TPtr8 headerDes((TUint8 *)&header, sizeof(struct WAVEheader), sizeof(struct WAVEheader));

	// "RIFF"
	header.ckID[0] = 'R'; header.ckID[1] = 'I';
	header.ckID[2] = 'F'; header.ckID[3] = 'F';
	// "WAVE"
	header.wave_ckID[0] = 'W'; header.wave_ckID[1] = 'A';
	header.wave_ckID[2] = 'V'; header.wave_ckID[3] = 'E';
	// "fmt "
	header.fmt_ckID[0] = 'f'; header.fmt_ckID[1] = 'm';
	header.fmt_ckID[2] = 't'; header.fmt_ckID[3] = ' ';
	// "data"
	header.data_ckID[0] = 'd'; header.data_ckID[1] = 'a';
	header.data_ckID[2] = 't'; header.data_ckID[3] = 'a';

	header.nChannels		= (TUint16)RecordFormatBuf().iChannels;
	header.nSamplesPerSec	= RateInSamplesPerSecond(RecordFormatBuf().iRate);
	header.nBitsPerSample	= 16;
	header.nBlockAlign		= TUint16((RecordFormatBuf().iChannels == 2) ? 4 : 2);
	header.formatTag		= 1;	// type 1 is PCM
	header.fmt_ckSize		= 16;
	header.nAvgBytesPerSec	= BytesPerSecond(RecordFormatBuf());
	header.data_ckSize		= bytesToRecord;
	header.ckSize			= bytesToRecord + sizeof(struct WAVEheader) - 8;

	Test.Printf(_L("Header rate:%d channels:%d tag:%d bits:%d (%d bytes/s) align %d datalen:%d fmt_ckSize:%d ckSize:%d\r\n"),
			header.nSamplesPerSec, header.nChannels, header.formatTag, header.nBitsPerSample,
			header.nAvgBytesPerSec, header.nBlockAlign, header.data_ckSize, header.fmt_ckSize, header.ckSize, sizeof(struct WAVEheader));

	r = destination.Write(headerDes);

	TRequestStatus stat;
	TInt length;
	TPtrC8 buf;

	TTime startTime;
	startTime.HomeTime();
	
	// Start off by issuing a record request.
	TTime starttime;
	starttime.HomeTime();
	TInt bytesRecorded = 0;
	RxSoundDevice.RecordData(stat,length);

	TInt pausesToDo = 10;
	pausesToDo = 0;
	FOREVER
		{
		// Wait for the outstanding record request to complete.
        User::After(6000);

		User::WaitForAnyRequest();
		if (stat==KRequestPending)
			return(KErrGeneral);

		TTime currentTime;
		currentTime.HomeTime();
		TInt64 elapsedTime = currentTime.Int64()-startTime.Int64();	// us
		TTimeIntervalMicroSecondsBuf timeRecordedBuf;
		if(RxSoundDevice.TimeRecorded(timeRecordedBuf) == KErrNone)
			{
			// Compare TimeRecorded with the actual elapsed time. They should be different, but not drift apart too badly...
			TInt32 offset = TInt32(elapsedTime - timeRecordedBuf().Int64());
			Test.Printf(_L("\telapsedTime - TimeRecorded = %d ms\n"), offset/1000);
			}		
			
		// Check whether the record request was succesful.
		TInt retOffset=stat.Int();
		if (retOffset<0)
			{
			Test.Printf(_L("Record failed(%d)\r\n"),retOffset);
			return(retOffset);
			}
		
		// Successfully recorded another buffer so write the recorded data to the record file and release the buffer.
		buf.Set((const TUint8*)(chunk.Base()+retOffset),length);
		r=destination.Write(buf);
		if (r!=KErrNone)
			{
			Test.Printf(_L("File write failed(%d)\r\n"),r);
			return(r);
			}
		r=RxSoundDevice.ReleaseBuffer(retOffset);
		if (r!=KErrNone)
			{
			Test.Printf(_L("Release buffer failed(%d)\r\n"),r);
			return(r);
			}
		
		Test.Printf(_L("Recorded %d more bytes - %d\r\n"),length,retOffset);

		if((pausesToDo > 0) && (bytesRecorded > bytesToRecord/2))
			{
			--pausesToDo;
			Test.Printf(_L("Pause\r\n"));
			RxSoundDevice.Pause();
			Test.Printf(_L("Paused, sleeping for 0.5 seconds\r\n"));
			User::After(500*1000);
            Test.Printf(_L("Resume\r\n"));
			RxSoundDevice.Resume();
			}
		
		// Check whether we have now recorded all the data. If more to record then queue a further request
		bytesRecorded+=length;
		if (bytesRecorded<bytesToRecord)
		    {
            Test.Printf(_L("RecordData\r\n"));
			RxSoundDevice.RecordData(stat,length);
		    }
		else
			break;
		}
	
	RxSoundDevice.CancelRecordData();	// Stop the driver from recording.
	
	TTime endtime;
	endtime.HomeTime();

	TInt64 elapsedTime = endtime.Int64()-starttime.Int64();	// us
	Test.Printf(_L("Delta time = %d\r\n"),I64LOW(elapsedTime));
	Test.Printf(_L("Seconds in buffer: %d (%d)\r\n"), bytesRecorded / header.nAvgBytesPerSec, (bytesRecorded / header.nAvgBytesPerSec)*1000000);

	if (I64LOW(elapsedTime) <= (bytesRecorded / header.nAvgBytesPerSec)*1000000)
		{
		Test.Printf(_L("Time travelling; record took less time than it should have done\r\n"));
		return(KErrGeneral);
		}
	
	chunk.Close();
	destination.Close();

	Test.Printf(_L("Record finished\r\n"));
	return(KErrNone);
	}
LOCAL_C TInt WavPlay()
	{
	RChunk chunk;
	
	// Parse the commandline and get a filename to use
	TLex l(CommandLine);
	TFileName thisfile=RProcess().FileName();
	TPtrC token=l.NextToken();
	if (token.MatchF(thisfile)==0)
		token.Set(l.NextToken());

	if (token.Length()==0)
		{
		// No args, skip to end
		Test.Printf(_L("Invalid configuration\r\n"));
		return(KErrArgument);
		}
		
	Test.Next(_L("Play Wav file"));

	// Assume that the argument is a WAV filename
	TFileName wavFilename=token;
	TInt r;
	RFile source;
	r = source.Open(Fs,wavFilename,EFileRead);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Open failed(%d)\r\n"), r);
		return(r);
		}

	// Read the pcm header
	WAVEheader header;
	TPtr8 headerDes((TUint8 *)&header,sizeof(struct WAVEheader),sizeof(struct WAVEheader));
	r = source.Read(headerDes);
	if (r!=KErrNone)
		{
		source.Close();
		return(r);
		}
	Test.Printf(_L("Header Read %d bytes\r\n"),headerDes.Size());

	if (headerDes.Size() != sizeof(struct WAVEheader)) // EOF
		{
		Test.Printf(_L("Couldn't read a header(%d bytes)\r\n"),headerDes.Size());
		source.Close();
		return(KErrCorrupt);
		}

	Test.Printf(_L("Header rate:%d channels:%d tag:%d bits:%d (%d bytes/s) align %d datalen:%d fmt_ckSize:%d ckSize:%d\n"),
			header.nSamplesPerSec, header.nChannels, header.formatTag, header.nBitsPerSample,
			header.nAvgBytesPerSec, header.nBlockAlign, header.data_ckSize, header.fmt_ckSize, header.ckSize);

	if (header.formatTag != 1) // not pcm
		{
		Test.Printf(_L("Format not PCM(%d)\r\n"),header.formatTag);
		source.Close();
		return(KErrNotSupported);
		}

	if (header.nBitsPerSample != 16) // not 16 bit
		{
		Test.Printf(_L("Format not 16 bit PCM(%d bits)\r\n"),header.nBitsPerSample);
		source.Close();
		return(KErrNotSupported);
		}
		
	TSoundRate rate;	
	if (SamplesPerSecondToRate(header.nSamplesPerSec,rate)!=KErrNone)	
		{
		Test.Printf(_L("Format specifies a rate not supported(%d)\r\n"),header.nSamplesPerSec);
		source.Close();
		return(KErrNotSupported);
		}

	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	PlayFormatBuf().iChannels = header.nChannels;
	PlayFormatBuf().iRate = rate;
	PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
	
	// Set the play buffer configuration.
	TInt bufSize=BytesPerSecond(PlayFormatBuf())/8; 	// Large enough to hold 1/8th second of data.
	bufSize&=~(header.nBlockAlign-1);					// Keep the buffer length a multiple of the bytes per sample (assumes 16bitPCM, 1 or 2 chans).
	if (PlayCapsBuf().iRequestMinSize)
		bufSize&=~(PlayCapsBuf().iRequestMinSize-1); 	// Keep the buffer length valid for the driver.
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=3;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	PrintBufferConf(bufferConfig,Test);
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Buffer configuration not supported(%d)\r\n"),r);
		source.Close();
		return(r);
		}
	TxSoundDevice.GetBufferConfig(bufferConfigBuf);			// Read back the configuration - to get the buffer offsets
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);

	// Set the audio play configuration.
	TxSoundDevice.SetVolume(KSoundMaxVolume - (KSoundMaxVolume / 4)); // set volume to 75%
	PrintConfig(PlayFormatBuf(),Test);
	r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
	if (r!=KErrNone)
		{
		Test.Printf(_L("Format not supported\r\n"));
		source.Close();
		chunk.Close();
		return(r);
		}
	TxSoundDevice.ResetBytesTransferred();

	TInt32 bytesToPlay = header.data_ckSize;
	TTime starttime;
	starttime.HomeTime();

	TRequestStatus stat[3];
	TPtr8* tPtr[3];
	TInt i;
	for (i=0;i<3;i++)
		tPtr[i]=new TPtr8(NULL,0); 

	TTime startTime;
	startTime.HomeTime();
	
	// Start off by issuing a play request for each buffer (assuming that the file is long enough). Use the full size
	// of each buffer.
	TInt stillToRead=bytesToPlay;
	TInt stillNotPlayed=bytesToPlay;
	TUint flags;
	for (i=0 ; i<3 ; i++)
		{
		// Setup the descriptor for reading in the data from the file.
		tPtr[i]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[i],0,bufSize); 
		
		// If there is still data to read to play then read this into the descriptor
		// and then write it to the driver.
		if (stillToRead)
			{
			r=source.Read(*tPtr[i],Min(stillToRead,bufSize));
			if (r!=KErrNone)
				{
				Test.Printf(_L("Initial file read error(%d)\r\n"),r);
				source.Close();
				chunk.Close();
				return(r);
				}
			stillToRead-=tPtr[i]->Length();
			flags=(stillToRead>0)?0:KSndFlagLastSample;
			TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],tPtr[i]->Length(),flags);
			}
		else
			stat[i]=KRequestPending;	
		}	
		
	FOREVER
		{
		// Wait for any one of the outstanding play requests to complete.
		User::WaitForAnyRequest();

		TTime currentTime;
		currentTime.HomeTime();
		TInt64 elapsedTime = currentTime.Int64()-startTime.Int64();	// us
		TTimeIntervalMicroSecondsBuf timePlayedBuf;
		if(TxSoundDevice.TimePlayed(timePlayedBuf) == KErrNone)
			{
			// Compare TimePlayed with the actual elapsed time. They should be different, but not drift apart too badly...
			TInt32 offset = TInt32(elapsedTime - timePlayedBuf().Int64());
			Test.Printf(_L("\telapsedTime - TimePlayed = %d ms\n"), offset/1000);
			}		
	
		// Work out which buffer this applies to
		for (i=0 ; i<3 ; i++)
			{
			if (stat[i]!=KRequestPending)
				break;
			}
		if (i>=3)
			{
			Test.Printf(_L("I/O error\r\n"));
			source.Close();
			chunk.Close();
			return(KErrGeneral);
			}
	
		// Check that the transfer was succesful and whether we have now played all the file.
		if (stat[i]!=KErrNone)
			{
			Test.Printf(_L("Play error(%d)\r\n"),stat[i].Int());
			source.Close();
			chunk.Close();
			return(stat[i].Int());
			}
		Test.Printf(_L("Played %d bytes(%d) - %d\r\n"),tPtr[i]->Length(),i,stat[i].Int());
		stillNotPlayed-=tPtr[i]->Length();
		CHECK(stillNotPlayed>=0);
		if (!stillNotPlayed)
			break;
	
		// Still more to be played so read the next part of the file into the descriptor for this
		// buffer and then write it to the driver.
		if (stillToRead)
			{
			TInt len=Min(stillToRead,bufSize);
		
			// If we've got to the end of the file and the driver is particular about the request length then 
			// zero fill the entire buffer so we can play extra zeros after the last sample from the file.
			if (len<bufSize && PlayCapsBuf().iRequestMinSize)
				tPtr[i]->FillZ(bufSize);
		
			// Read the next part of the file 
			r=source.Read(*tPtr[i],len);			// This will alter the length of the descriptor
			if (r!=KErrNone)
				{
				Test.Printf(_L("File read error(%d)\r\n"),r);
				source.Close();
				chunk.Close();
				return(r);
				}
			stillToRead-=tPtr[i]->Length();
		
			// If we've got to the end of the file and the driver is particular about the request length then
			// round up the length to the next valid boundary. This is OK since we zero filled.
			if (tPtr[i]->Length() < bufSize && PlayCapsBuf().iRequestMinSize)
				{
				TUint m=PlayCapsBuf().iRequestMinSize-1;
				len=(tPtr[i]->Length() + m) & ~m;
				}
		
			// Write it to the driver.
			flags=(stillToRead>0)?0:KSndFlagLastSample;
			TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],len,flags);
			}
		else
			stat[i]=KRequestPending;		
		}
	
	// Delete all the variables again.	
	for (i=0 ; i<3 ; i++)
		delete tPtr[i];
	
	TTime endtime;
	endtime.HomeTime();

	Test.Printf(_L("Done playing\r\n"));
	Test.Printf(_L("Bytes played = %d\r\n"),TxSoundDevice.BytesTransferred());
	Test.Printf(_L("Delta time = %d\r\n"),endtime.Int64()-starttime.Int64());

	chunk.Close();
	source.Close();
	return(KErrNone);
	}
GLDEF_C TInt E32Main()
    {
	test.Title();
	if (!HaveMMU())
		{
		test.Printf(_L("This test requires an MMU\n"));
		return KErrNone;
		}

	test.Start(_L("Load test LDD"));
	TInt r=User::LoadLogicalDevice(KLddFileName);
	test(r==KErrNone || r==KErrAlreadyExists);

	test_KErrNone(UserHal::PageSizeInBytes(PageSize));

	// Determine which types of paging are supported
	TUint32 attrs = DPTest::Attributes();
	gRomPagingSupported = (attrs & DPTest::ERomPaging) != 0;
	gCodePagingSupported = (attrs & DPTest::ECodePaging) != 0;
	gDataPagingSupported = (attrs & DPTest::EDataPaging) != 0;

	// Does this memory model support pinning.
	TInt mm = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, 0, 0) & EMemModelTypeMask;
	gPinningSupported = mm >= EMemModelTypeFlexible;

	RPageMove pagemove;
	test.Next(_L("Open test LDD"));
	test_KErrNone(pagemove.Open());

	// Determine whether this is a smp device.
	NumberOfCpus = pagemove.NumberOfCpus();
	if (NumberOfCpus > 1)
		Repitions = 1000;	// SMP system therefore likely to get KErrInUse in less repitions.

	test.Next(_L("Attempting to move regular local data pages"));
		{
		const TInt size=16384;
		TUint8* array = new TUint8[size];
		test_NotNull(array);

		TestUserData(pagemove, array, size);

		_T_PRINTF(_L("Walk heap\n"));
		User::Check();

		delete [] array;
		}

	test.Next(_L("Attempting to move regular global coarse data pages"));
		{
		const TInt size=1<<20;	// Make this chunk multiple of 1MB so it is a coarse memory object on FMM
		RChunk chunk;
		test_KErrNone(chunk.CreateDisconnectedGlobal(_L("Dave"), 0, size, size));
		TUint8* array = chunk.Base();

		TestUserData(pagemove, array, size);
		TestMovingRealtime(pagemove, array, size, NULL, EFalse);
		TestCommitDecommit(pagemove, chunk);

		chunk.Close();
		}

	if (gDataPagingSupported)
		{
		test.Next(_L("Attempting to move demand paged fine local user data pages"));
		const TInt size=16384;
		TChunkCreateInfo createInfo;
		createInfo.SetDisconnected(0, size, size);
		createInfo.SetPaging(TChunkCreateInfo::EPaged);
		RChunk chunk;
		test_KErrNone(chunk.Create(createInfo));
		TUint8* array = chunk.Base();

		TestUserData(pagemove, array, size, ETrue);
		TestMovingRealtime(pagemove, array, size, NULL, EFalse, ETrue);
		TestPageTableDiscard(pagemove, array, size);
		TestCommitDecommit(pagemove, chunk);
		chunk.Close();

		test.Next(_L("Attempting to move demand paged coarse global user data pages"));
		const TInt sizeCoarse = 1 << 20; // Make this chunk multiple of 1MB so it is a coarse memory object on FMM
		TChunkCreateInfo createInfoCoarse;
		createInfoCoarse.SetDisconnected(0, sizeCoarse, sizeCoarse);
		createInfoCoarse.SetGlobal(_L("Dave"));
		createInfoCoarse.SetPaging(TChunkCreateInfo::EPaged);
		RChunk chunkCoarse;
		test_KErrNone(chunkCoarse.Create(createInfoCoarse));
		array = chunkCoarse.Base();

		TestUserData(pagemove, array, sizeCoarse, ETrue);
		TestMovingRealtime(pagemove, array, sizeCoarse, NULL, EFalse, ETrue);
		TestPageTableDiscard(pagemove, array, sizeCoarse);
		TestCommitDecommit(pagemove, chunkCoarse);
		chunkCoarse.Close();
		}

	test.Next(_L("Attempting to move DLL writable static data pages"));
		{
		const TInt size=16384;
		TUint8* array = DllWsd::Address();

		TestUserData(pagemove, array, size);
		}

	test.Next(_L("Attempting to move user self-mod code chunk page when IMB'ing and executing"));
	RChunk codeChunk;
	test_KErrNone(codeChunk.CreateLocalCode(PageSize,PageSize));
	TestMovingCodeChunk(pagemove, codeChunk, EFalse);
	codeChunk.Close();

	if (gDataPagingSupported)
		{
		test.Next(_L("Attempting to move paged user self-mod code chunk page when IMB'ing and executing"));
		TChunkCreateInfo createInfo;
		createInfo.SetCode(PageSize, PageSize);
		createInfo.SetPaging(TChunkCreateInfo::EPaged);

		RChunk pagedCodeChunk;
		test_KErrNone(pagedCodeChunk.Create(createInfo));
		TestMovingCodeChunk(pagemove, pagedCodeChunk, ETrue);
		pagedCodeChunk.Close();
		}

	test.Next(_L("Attempting to move RAM drive"));
	if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple)
		{
		for (TInt i=0; i<Repitions; i++)
			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0xA0000000));
		}
	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMoving)
		{
		for (TInt i=0; i<Repitions; i++)
			test_KErrNone(pagemove.TryMovingUserPage((TAny*)0x40000000));
		}
	else if ((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
		{
		// do nothing, RAM drive is not special
		}
	else
		{
		test.Printf(_L("Don't know where the RAM drive is!"));
		test(0);
		}
	
#if 0
	test.Next(_L("Attempting to move kernel heap pages"));
	for (TInt i=0; i<Repitions; i++)
		test_KErrNone(pagemove.TryMovingKHeap());
#endif

	if ((MemModelAttributes()&EMemModelTypeMask) != EMemModelTypeFlexible)
		{// Only the moving and multiple memory models move kernel stack pages.
		test.Next(_L("Attempting to move kernel stack pages"));
		for (TInt i=0; i<Repitions; i++)
			test_KErrNone(pagemove.TryMovingKStack());
		}

	test.Next(_L("Attempting to move ROM pages"));
	TestMovingRom(pagemove);

	test.Next(_L("Attempting to move kernel code pages"));
	for (TInt i=0; i<Repitions; i++)
		test_KErrNone(pagemove.TryMovingKCode());

	test.Next(_L("Attempting to move regular code pages"));
	TestMovingCode(pagemove, RamLoadedFunction);
	TestMovingRealtime(pagemove, NULL, 0, RamLoadedFunction, ETrue, EFalse);

	if (gCodePagingSupported)
		{
		test.Next(_L("Attempting to move demand paged code pages"));
		TestMovingCode(pagemove, DllTestFunction, ETrue);
		TestMovingRealtime(pagemove, NULL, 0, DllTestFunction, ETrue, ETrue);
		}

	/* Setup CodeModifier Test Driver */
	StartCodeModifierDriver();
	test(KErrNone==Device.InitialiseCodeModifier(/* Max break points */ 5 ));

	test.Next(_L("Attempting to move code page being modified\n"));
	test_KErrNone(TestCodeModification(pagemove));

	test.Next(_L("Attempting to move code (async) while page being modified"));
	test_KErrNone(TestCodeModificationAsync(pagemove));

	StopCodeModifierDriver();
	
	test.Next(_L("Attempting to move ROM Locale DLL Page"));
	test_KErrNone(E32TestLocale(1));

	test.Next(_L("Attempting to move RAM Locale DLL Page"));
	test_KErrNone(E32TestLocale(0));

	test.Next(_L("Close test LDD"));
	pagemove.Close();
	User::FreeLogicalDevice(KLddFileName);

	test.End();
	return(KErrNone);
    }
GLDEF_C TInt E32Main()

    {
	__UHEAP_MARK;

	Test.Title();

	TInt r;
	Test.Start(_L("Load sound PDD"));
	r=User::LoadPhysicalDevice(KSndPddFileName);
	if (r==KErrNotFound)
		{
		Test.Printf(_L("Shared chunk sound driver not supported - test skipped\r\n"));
		Test.End();
		Test.Close();
		__UHEAP_MARKEND;
		return(KErrNone);
		}
	Test(r==KErrNone || r==KErrAlreadyExists);
	
	Test.Next(_L("Load sound LDD"));
	r=User::LoadLogicalDevice(KSndLddFileName);
	Test(r==KErrNone || r==KErrAlreadyExists);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUNDMCHAN-224
	@SYMTestCaseDesc 		Opening the channel - more than one channel
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	With the LDD and PDD installed and with all channels closed on the device, 
								open a channel for playback on the device. 
							2)	Without closing the first playback channel, attempt to open a second channel 
								for playback on the same device. 
	@SYMTestExpectedResults	1)	KErrNone - Channel opens successfully. 
							2)	Should fail with KErrInUse.
	@SYMREQ					PREQ1073.4 */	
	
	__KHEAP_MARK;

	Test.Next(_L("Open a channel on the play device"));
	RSoundSc snddev;
	r=snddev.Open(KSoundScTxUnit0);
	Test(r==KErrNone);
	
	Test.Next(_L("Try opening the same unit a second time."));
	RSoundSc snddev2;
	r=snddev2.Open(KSoundScTxUnit0);
	Test(r==KErrInUse);
	
	Test.Next(_L("Query play formats supported"));
	TSoundFormatsSupportedV02Buf capsBuf;
	snddev.Caps(capsBuf);
	TSoundFormatsSupportedV02& caps=capsBuf();
	PrintCaps(caps,Test);
	
	Test.Next(_L("Try playing without setting the buffer config"));
	TRequestStatus pStat;
	snddev.PlayData(pStat,0,0x2000);	// 8K
	User::WaitForRequest(pStat);
	Test(pStat.Int()==KErrNotReady);

	Test.Next(_L("Configure the channel from a 2nd thread"));
	RThread thread;
	TRequestStatus tStat;
	SSecondaryThreadInfo sti;
	
	sti.iTestId=ESecThreadConfigPlayback;
	sti.iThreadId=RThread().Id();	// Get the ID of this thread
	sti.iDrvHandle=snddev.Handle();	// Pass the channel handle
	
	/**	@SYMTestCaseID 		PBASE-T_SOUNDMCHAN-225
	@SYMTestCaseDesc 		Opening the channel - sharing the handle between threads
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	With the LDD and PDD installed and with all channels closed on the device, open a 
								channel for playback on the device. Now create a second thread. Resume this 
								thread - passing the handle to the playback channel to it. Wait for the second 
								thread to terminate.
							2)	In the second thread, duplicate the playback channel handle.
							3)	In the second thread, using the duplicated handle, issue a request to set the audio configuration. 
							4)	In the second thread, using the duplicated handle, issue a request to set the volume. 
							5)	In the second thread, close the handle and exit the thread.
							6)	In the first thread, read back the audio configuration.
							7)	In the first thread, set the buffer configuration, and then issue a request to play 
								audio data. 
							8)	In the first thread, close the channel. 
	@SYMTestExpectedResults	1)	KErrNone - Channel opens successfully. 
							2)	KErrNone - Duplication of the handle succeeds.
							3)	KErrNone - Audio configured successfully.
							4)	KErrNone - Volume set successfully.
							5)	No errors occur closing the channel and exiting the thread.
							6)	The audio configuration should correspond to that set by the second thread.
							7)	KErrNone - Setting the buffer configuration and issuing a play request.
							8)	No errors occur closing the channel.
	@SYMREQ					PREQ1073.4 */	
	
	r=thread.Create(_L("Thread"),secondaryThread,KDefaultStackSize,KHeapSize,KHeapSize,&sti); // Create secondary thread
	Test(r==KErrNone);
	thread.Logon(tStat);
	thread.Resume();
	User::WaitForRequest(tStat);
	Test(tStat.Int()==KErrNone);
//	Test.Printf(_L("Thread exit info: Cat:%S, Reason:%x, Type:%d\r\n"),&thread.ExitCategory(),thread.ExitReason(),thread.ExitType());
	Test(thread.ExitType()==EExitKill);
	thread.Close();
	User::After(10000);	// Wait 10ms
	
	Test.Next(_L("Read back the play configuration"));
	TCurrentSoundFormatV02Buf formatBuf;
	snddev.AudioFormat(formatBuf);
	TCurrentSoundFormatV02& format=formatBuf();
	PrintConfig(format,Test);
	
	Test.Next(_L("Set the buffer configuration"));
	RChunk chunk;
	TInt bufSize=BytesPerSecond(formatBuf()); 	 							// Large enough to hold 1 second of data.
	bufSize=ValidBufferSize(bufSize,caps.iRequestMinSize,formatBuf());		// Keep the buffer length valid for driver.
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=1;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=snddev.SetBufferChunkCreate(bufferConfigBuf,chunk);
	Test(r==KErrNone);
	snddev.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	Test(bufferConfig.iBufferSizeInBytes==bufSize);
	
	Test.Next(_L("Start playing"));
	r=MakeSineTable(format);
	Test(r==KErrNone);
	r=SetToneFrequency(660,format);
	Test(r==KErrNone); 
	TPtr8 ptr(chunk.Base()+bufferConfig.iBufferOffsetList[0],bufSize);
	WriteTone(ptr,format);
	snddev.PlayData(pStat,bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
	User::WaitForRequest(pStat);
	Test(tStat.Int()==KErrNone);
	
	Test.Next(_L("Close the drivers and the chunk"));
	chunk.Close();
	snddev.Close();
	
	__KHEAP_MARKEND;

	Test.Next(_L("Unload the drivers"));
	
	r=User::FreeLogicalDevice(KDevSoundScName);
	Test.Printf(_L("Unloading %S.LDD - %d\r\n"),&KDevSoundScName,r);
	Test(r==KErrNone);
	
	TName pddName(KDevSoundScName);
	_LIT(KPddWildcardExtension,".*");
	pddName.Append(KPddWildcardExtension);
	TFindPhysicalDevice findPD(pddName);
	TFullName findResult;
	r=findPD.Next(findResult);
	while (r==KErrNone)
		{
		r=User::FreePhysicalDevice(findResult);
		Test.Printf(_L("Unloading %S.PDD - %d\r\n"),&findResult,r);
		Test(r==KErrNone);
		findPD.Find(pddName); // Reset the find handle now that we have deleted something from the container.
		r=findPD.Next(findResult);
		} 
	
	Test.End();
	Test.Close();
	
	Cleanup();
	
	__UHEAP_MARKEND;

	return(KErrNone);
    }