diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kerneltest/e32test/lffs/tf_read.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kerneltest/e32test/lffs/tf_read.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1132 @@ +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +#include +#include +#include "randgen.h" +#include "user_config.h" + +RTest test( _L("TF_READ") ); + + +const TInt KTestUserDataSize = 1024; +const TInt KBufferGuardSize = 16384; + +const TInt KMaxWriteLength = 512; + +const TInt64 KSampleDataRandomSeed = MAKE_TINT64(0x3e000111,0xAFCBDF0F); +const TInt64 KRandomTestSeed = MAKE_TINT64(0x90009901,0xABEF1011); + +enum TPanicNo + { + EPanicGetDesOverflow, + EPanicGetDesInitialOverflow, + EPanicCheckOverflow + }; + +LOCAL_D void Panic( TPanicNo aPanic ) + { + _LIT( KPanicCat, "TF_READ" ); + User::Panic( KPanicCat, aPanic ); + } + + +class CCheckedBuffer : public CBase + { + public: + CCheckedBuffer( TInt auserDataSize, TInt aGuardSize ); + ~CCheckedBuffer(); + + void CreateL(); + void InitialiseGuard(); + TBool CheckGuard( TInt aUserDataLength ) const; + TBool CheckGuardAtStartOfUserData( TInt aGuardLength ) const; + void GetDes( TPtrC8& aDes ) const; + void GetDes( TPtr8& aDes, TInt aInitialLength, TInt aMaxLength ) const; + + + private: + CCheckedBuffer(); + + private: + TPtr8 iUserData; // pointer to user data area + const TInt iUserDataSize; + const TInt iGuardSize; + TUint8* iAllocCell; + }; + + + +CCheckedBuffer::CCheckedBuffer( TInt aUserDataSize, TInt aGuardSize ) + : iUserData(0,0), iUserDataSize( aUserDataSize ), iGuardSize( aGuardSize ) + { + } + +CCheckedBuffer::~CCheckedBuffer() + { + delete iAllocCell; + } + +void CCheckedBuffer::CreateL() + { + TInt totalCellSizeRequired = iUserDataSize + (2 * iGuardSize); + + iAllocCell = (TUint8*)User::AllocL( totalCellSizeRequired ); + + test.Printf( _L("Allocated heap cell for checked buffer\n") ); + + iUserData.Set( iAllocCell + iGuardSize, iUserDataSize, iUserDataSize ); + } + +void CCheckedBuffer::GetDes( TPtrC8& aDes ) const + // + // Create descriptor to the whole user data area in aDes + // + { + aDes.Set( iAllocCell + iGuardSize, iUserDataSize ); + } + +void CCheckedBuffer::GetDes( TPtr8& aDes, TInt aInitialLength, TInt aMaxLength ) const + // + // Create modifiable descriptor to the user data area in aDes, + // with a maximum length aMaxLength, and initial length aInitialLength + // + { + __ASSERT_ALWAYS( aMaxLength <= iUserDataSize, Panic(EPanicGetDesOverflow) ); + __ASSERT_ALWAYS( aInitialLength <= iUserDataSize, Panic(EPanicGetDesInitialOverflow) ); + aDes.Set( iAllocCell + iGuardSize, aInitialLength, aMaxLength ); + } + + +void CCheckedBuffer::InitialiseGuard() + // + // Create the guard regions + // + { + TInt totalCellSize = User::AllocLen( iAllocCell ); + Mem::Fill( iAllocCell, totalCellSize, 0x5A ); + } + +TBool CCheckedBuffer::CheckGuard( TInt aUserDataLength ) const + // + // Checks that the guard value is still present before the user data + // area, and after aUserDataLength bytes of user data + // + { + const TUint8* p = iAllocCell; + const TUint8* pUserDataStart = iUserData.Ptr(); + + for( ; p < pUserDataStart; p++ ) + { + if( 0x5a != *p ) + { + return EFalse; + } + } + + p = pUserDataStart + aUserDataLength; + const TUint8* pEnd = iAllocCell + User::AllocLen( iAllocCell ); + + for( ; p < pEnd; p++ ) + { + if( 0x5a != *p ) + { + return EFalse; + } + } + + return ETrue; + } + + +TBool CCheckedBuffer::CheckGuardAtStartOfUserData( TInt aGuardLength ) const + // + // Checks that the first aGuardLength bytes of the user data area + // contain the guard value + // + { + const TUint8* p = iUserData.Ptr(); + const TUint8* pEnd = p + aGuardLength; + + for( ; p < pEnd; p++ ) + { + if( 0x5a != *p ) + { + return EFalse; + } + } + + return ETrue; + } + + + +class CReadTest : public CBase + { + public: + ~CReadTest(); + + void CreateL(); + + void DoTest(); + + private: + static TInt DummyThread( TAny* aParam ); + + void CreateSampleData(); + static TBool CheckZero( const TPtrC8& aDes ); + void CreateTestData( TInt aBlockNumber, TBool aEndOfBlock ); + TBool CompareAgainstFlash( TInt aFlashOffset, const TPtrC8& aDes, TInt aDescOffset ); + + void TestSimpleReads(); + void TestSimpleThreadReads(); + void TestUnalignedReads(); + void TestUnalignedThreadReads(); + void TestOffsetBufferThreadReads(); + void TestOffsetBufferUnalignedThreadReads(); + void TestReadsFromAllBlocks(); + void TestSimpleScatterReads1(); + void TestSimpleScatterReads2(); + void TestScatterGather(); + void TestReadAcrossBlock(); + + void PerformCheckedRead( TInt aReadPos, TInt aReadLen ); + void PerformCheckedThreadRead( TInt aReadPos, TInt aReadLen, TInt aDescOffset ); + + private: + TInt iFlashSize; + TInt iBlockSize; + TInt iBlockCount; + + TBusLocalDrive iDrive; + TBool iDriveOpened; + TBuf8<512> iReadBuffer; + + TRandomGenerator iRandom; + + TBuf8 iSampleData; + + CCheckedBuffer* iBuffer; + + RThread iDummyThread; + }; + +CReadTest::~CReadTest() + { + if( iDriveOpened ) + { + iDrive.Disconnect(); + } + } + + + +void CReadTest::CreateL() + { + // + // Load the device drivers + // + TInt r; + +#ifndef SKIP_PDD_LOAD + test.Printf( _L("Loading %S\n"), &KLfsDriverName ); + r = User::LoadPhysicalDevice( KLfsDriverName ); + test( KErrNone == r || KErrAlreadyExists == r ); +#endif + +#ifdef UNMOUNT_DRIVE + RFs fs; + test( KErrNone == fs.Connect() ); +#if 0 // XXX - API violation on EKA2 + test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) ); +#endif + TFullName name; + fs.FileSystemName( name, KLffsLogicalDriveNumber ); + if( name.Length() > 0 ) + { + test.Printf( _L("Unmounting drive") ); + test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) ); + User::After( 2000000 ); + test.Printf( _L("Drive unmounted") ); + } + + fs.Close(); +#endif + + // + // Open a TBusLogicalDevice to it + // + test.Printf( _L("Opening media channel\n") ); + TBool changedFlag = EFalse; + r = iDrive.Connect( KDriveNumber, changedFlag ); + User::LeaveIfError( r ); + iDriveOpened = ETrue; + + // + // Get size of Flash drive + // + TLocalDriveCapsV2Buf info; + iDrive.Caps(info); + iFlashSize = I64LOW(info().iSize); + iBlockSize = info().iEraseBlockSize; + iBlockCount = iFlashSize / iBlockSize; + + test.Printf( _L("Flash size is 0x%x bytes\n"), iFlashSize ); + + // + // Create a dummy thread that we can use to force + // other-thread write operations + // +#if 0 + test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, 256, KMinHeapSize, KMinHeapSize, NULL ) ); +#else + // XXX TONYL + test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ) ); + +// test.Printf( _L("== do it")); +// TInt pas = iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ); +// test.Printf( _L("CREATE = %d"), pas); +// test (pas == KErrNone); +#endif +#if 1 + iDummyThread.Resume(); +#endif + + // + // Create a checked buffer + // + iBuffer = new(ELeave) CCheckedBuffer( KTestUserDataSize, KBufferGuardSize ); + iBuffer->CreateL(); + + // + // Seed the pseudo-random number generator + // + iRandom.SetSeed( KSampleDataRandomSeed ); + + test.Printf( _L("CreateL complete\n") ); + } + + + +TInt CReadTest::DummyThread( TAny* /* aParam */ ) + // + // Thread does nothing at all + // + { +#if 1 + test.Printf( _L("== do it")); +#endif + for(;;) + { + User::WaitForAnyRequest(); // just block + } + } + + +void CReadTest::TestSimpleReads() + // + // Makes reads of 1 byte to 512 bytes into the start of the + // checked buffer and tests that only the expected bytes have changed + // This uses the simple read function from TBusLocalDrive, and + // reads from an aligned Flash address + // + { + test.Next( _L("Testing simple reads\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + test.Printf( _L("Reading %d bytes\n"), readLen ); + + // + // Prepare the guard data + // + iBuffer->InitialiseGuard(); + + // + // Set up the descriptor, length=0, maxlen=readLen + // + iBuffer->GetDes( des, 0, readLen ); + + // + // Now read some data into it + // + test( KErrNone == iDrive.Read( 0, readLen, des ) ); + + // + // Check what we got + // + test( des.Length() == readLen ); + + TPtrC8 newDes; + + iBuffer->GetDes( newDes ); + + test( newDes.Ptr() == des.Ptr() ); + + test( iBuffer->CheckGuard( readLen ) ); + + test( CompareAgainstFlash( 0, des, 0 ) ); + + } + } + +void CReadTest::TestSimpleThreadReads() + // + // Makes reads of 1 byte to 512 bytes into the start of the + // checked buffer and tests that only the expected bytes have changed + // This uses the more complex read function from TBusLocalDrive, and + // reads from an aligned Flash address + // + { + test.Next( _L("Testing simple reads using other-thread read function\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + test.Printf( _L("Reading %d bytes\n"), readLen ); + + // + // Prepare the guard data + // + iBuffer->InitialiseGuard(); + test.Printf( _L("AA\n")); + + // + // Set up the descriptor, length=0, maxlen=readLen + // + iBuffer->GetDes( des, 0, readLen ); + test.Printf( _L("BB\n")); + + // + // Now read some data into it + // + test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, 0 ) ); + test.Printf( _L("CC\n")); +#if 0 + test( KErrNone == iDrive.Read( 0, readLen, &des, iDummyThread.Handle(), 0 ) ); +#else + // XXX - this works + test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, 0 ) ); +#endif + + // + // Check what we got + // + test.Printf( _L("DD\n")); + test.Printf( _L("DD\n")); + test.Printf( _L("DD\n")); + test.Printf( _L("DD\n")); + test( des.Length() == readLen ); + + TPtrC8 newDes; + test.Printf( _L("EE\n")); + iBuffer->GetDes( newDes ); + test.Printf( _L("FF\n")); + test( newDes.Ptr() == des.Ptr() ); + + test( iBuffer->CheckGuard( readLen ) ); + + test.Printf( _L("GG\n")); + test( CompareAgainstFlash( 0, des, 0 ) ); + test.Printf( _L("HH\n")); + + } + } + + +void CReadTest::TestUnalignedReads() + // + // Makes reads of 1 byte to 512 bytes into the start of the + // checked buffer and tests that only the expected bytes have changed + // This uses the simple read function from TBusLocalDrive. + // The data is read from an unaligned address (0ffset 1, 2, 3) + // + { + test.Next( _L("Testing unaligned reads\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + // + // Set up the descriptor, length=0, maxlen=readLen + // + iBuffer->GetDes( des, 0, readLen ); + + // + // Repeat for each offset + // + for( TInt offs = 1; offs < 4; offs++ ) + { + test.Printf( _L("Reading %d unaligned bytes from offset %d\n"), readLen, offs ); + + iBuffer->InitialiseGuard(); + test( KErrNone == iDrive.Read( offs, readLen, des ) ); + + test( des.Length() == readLen ); + + TPtrC8 newDes; + iBuffer->GetDes( newDes ); + test( newDes.Ptr() == des.Ptr() ); + + test( iBuffer->CheckGuard( readLen ) ); + + test( CompareAgainstFlash( offs, des, 0 ) ); + } + + } + } + + +void CReadTest::TestUnalignedThreadReads() + // + // Makes reads of 1 byte to 512 bytes into the start of the + // checked buffer and tests that only the expected bytes have changed + // This uses the thread read function from TBusLocalDrive. + // The data is read from an unaligned address (0ffset 1, 2, 3) + // + { + test.Next( _L("Testing unaligned other-thread reads\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + // + // Set up the descriptor, length=0, maxlen=readLen + // + iBuffer->GetDes( des, 0, readLen ); + + // + // Repeat for each offset + // + for( TInt offs = 1; offs < 4; offs++ ) + { + test.Printf( _L("Reading %d unaligned bytes from offset %d\n"), readLen, offs ); + + iBuffer->InitialiseGuard(); +#if 0 + test( KErrNone == iDrive.Read( offs, readLen, &des, iDummyThread.Handle(), 0 ) ); +#else + test( KErrNone == iDrive.Read( offs, readLen, &des, KLocalMessageHandle, 0 ) ); +#endif + + test( des.Length() == readLen ); + + TPtrC8 newDes; + iBuffer->GetDes( newDes ); + test( newDes.Ptr() == des.Ptr() ); + + test( iBuffer->CheckGuard( readLen ) ); + + test( CompareAgainstFlash( offs, des, 0 ) ); + } + + } + } + + +void CReadTest::TestOffsetBufferThreadReads() + // + // Makes reads of 1 byte to 512 bytes to an offset position in the + // checked buffer and tests that only the expected bytes have changed + // This uses the more complex read function from TBusLocalDrive, and + // reads from an aligned Flash address + // + { + test.Next( _L("Testing other-thread reads into offset position in descriptor\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + test.Printf( _L("Reading %d bytes\n"), readLen ); + + + // + // Repeat test for offsets 0..64 in buffer + // + for( TInt destOffset = 1; destOffset < 64; destOffset++ ) + { +// test.Printf( _L("... dest offset = %d"), destOffset ); + + // + // Prepare the guard data + // + iBuffer->InitialiseGuard(); + + // + // Set up the descriptor, length=0, maxlen=readLen+destOffset + // + iBuffer->GetDes( des, 0, readLen + destOffset ); + +#if 0 + test( KErrNone == iDrive.Read( 0, readLen, &des, iDummyThread.Handle(), destOffset ) ); +#else + test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, destOffset ) ); +#endif + + // + // Check what we got + // + test( des.Length() == readLen + destOffset ); + + TPtrC8 newDes; + iBuffer->GetDes( newDes ); + test( newDes.Ptr() == des.Ptr() ); + + // + // end of written data is at readLen + destOffset + // + test( iBuffer->CheckGuard( readLen+destOffset ) ); + // + // check the section between that start of the user data and + // the offset position still contains guard data + // + test( iBuffer->CheckGuardAtStartOfUserData( destOffset ) ); + + test( CompareAgainstFlash( 0, des, destOffset ) ); + } + + } + } + + +void CReadTest::TestOffsetBufferUnalignedThreadReads() + // + // Makes reads of 1 byte to 512 bytes to an offset position in the + // checked buffer and tests that only the expected bytes have changed + // This uses the more complex read function from TBusLocalDrive, and + // reads from an aligned Flash address + // + { + test.Next( _L("Testing other-thread unaligned reads into offset position in descriptor\n") ); + + // + // Descriptor to user data area, passed to media driver + // + TPtr8 des(0,0); + + for( TInt readLen = 1; readLen <= 500; readLen++ ) + { + test.Printf( _L("Reading %d bytes\n"), readLen ); + + + // + // Repeat test for offsets 0..64 in buffer + // + for( TInt destOffset = 1; destOffset < 64; destOffset++ ) + { +// test.Printf( _L("... dest offset = %d"), destOffset ); + + // + // repeat for each source offset + // + for( TInt offs = 1; offs < 4; offs++ ) + { + // + // Prepare the guard data + // + iBuffer->InitialiseGuard(); + + // + // Set up the descriptor, length=0, maxlen=readLen+destOffset + // + iBuffer->GetDes( des, 0, readLen + destOffset ); + +#if 0 + test( KErrNone == iDrive.Read( offs, readLen, &des, iDummyThread.Handle(), destOffset ) ); +#else + test( KErrNone == iDrive.Read( offs, readLen, &des, KLocalMessageHandle, destOffset ) ); +#endif + + + // + // Check what we got + // + test( des.Length() == readLen + destOffset ); + + TPtrC8 newDes; + iBuffer->GetDes( newDes ); + test( newDes.Ptr() == des.Ptr() ); + + // + // end of written data is at readLen + destOffset + // + test( iBuffer->CheckGuard( readLen+destOffset ) ); + // + // check the section between that start of the user data and + // the offset position still contains guard data + // + test( iBuffer->CheckGuardAtStartOfUserData( destOffset ) ); + + test( CompareAgainstFlash( offs, des, destOffset ) ); + } // end for + } + } + } + + +void CReadTest::PerformCheckedRead( TInt aReadPos, TInt aReadLen ) + { + TPtr8 des(0,0); + iBuffer->InitialiseGuard(); + iBuffer->GetDes( des, 0, aReadLen ); + + test.Printf( _L("Reading %d byte(s) from offset 0x%x\n"), aReadLen, aReadPos ); + test( KErrNone == iDrive.Read( aReadPos, aReadLen, des ) ); + test( des.Length() == aReadLen ); + test( iBuffer->CheckGuard( aReadLen ) ); + test( CompareAgainstFlash( aReadPos, des, 0 ) ); + } + +void CReadTest::PerformCheckedThreadRead( TInt aReadPos, TInt aReadLen, TInt aDescOffset ) + { + TPtr8 des(0,0); + iBuffer->InitialiseGuard(); + iBuffer->GetDes( des, 0, aReadLen + aDescOffset ); + + test.Printf( _L("Reading %d byte(s) from offset 0x%x to thread descriptor offset %d\n"), aReadLen, aReadPos, aDescOffset ); +#if 0 + test( KErrNone == iDrive.Read( aReadPos, aReadLen, &des, iDummyThread.Handle(), aDescOffset ) ); +#else + test( KErrNone == iDrive.Read( aReadPos, aReadLen, &des, KLocalMessageHandle, aDescOffset ) ); +#endif + +// test.Printf( _L("Check descriptor length") ); + test( des.Length() == aReadLen + aDescOffset ); +// test.Printf( _L("Check guard") ); + test( iBuffer->CheckGuard( aReadLen + aDescOffset ) ); +// test.Printf( _L("Check guard at start of descriptor") ); + test( iBuffer->CheckGuardAtStartOfUserData( aDescOffset ) ); + test( CompareAgainstFlash( aReadPos, des, aDescOffset ) ); + } + + +void CReadTest::TestReadsFromAllBlocks() + // + // Does some spot-test reads from all blocks to make sure + // that reading across the whole Flash works + // + { + test.Next( _L("Testing reads from all blocks\n") ); + + for( TInt block = 0; block < iBlockCount; block++ ) + { + test.Printf( _L("Reading from block %d"), block ); + TInt readBase = (block * iBlockSize); + + PerformCheckedRead( readBase, 1 ); + PerformCheckedRead( readBase, 24 ); + PerformCheckedRead( readBase, 99 ); + PerformCheckedRead( readBase, 511 ); + PerformCheckedRead( readBase+1, 1 ); + PerformCheckedRead( readBase+1, 24 ); + PerformCheckedRead( readBase+1, 99 ); + PerformCheckedRead( readBase+1, 511 ); + PerformCheckedRead( readBase+3, 1 ); + PerformCheckedRead( readBase+3, 24 ); + PerformCheckedRead( readBase+3, 99 ); + PerformCheckedRead( readBase+3, 511 ); + + PerformCheckedThreadRead( readBase, 1, 0 ); + PerformCheckedThreadRead( readBase, 24, 0 ); + PerformCheckedThreadRead( readBase, 99, 2 ); + PerformCheckedThreadRead( readBase, 511, 0 ); + PerformCheckedThreadRead( readBase+1, 1, 11 ); + PerformCheckedThreadRead( readBase+1, 24, 4 ); + PerformCheckedThreadRead( readBase+1, 99, 24 ); + PerformCheckedThreadRead( readBase+1, 511, 0 ); + PerformCheckedThreadRead( readBase+3, 1, 32 ); + PerformCheckedThreadRead( readBase+3, 24, 333 ); + PerformCheckedThreadRead( readBase+3, 99, 0 ); + PerformCheckedThreadRead( readBase+3, 511, 1 ); + } + } + +void CReadTest::TestSimpleScatterReads1() + // + // Does some simple reads of varying length from the + // blocks in pseudo-random order. + // + { + test.Next( _L("Testing simple scatter reads\n") ); + + TRandomGenerator random; + random.SetSeed( KRandomTestSeed ); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + TInt block = random.Next() % iBlockCount; + test.Printf( _L("Reading block %d"), block ); + TInt readBase = (block * iBlockSize); + PerformCheckedRead( readBase, readLen ); + } + } + +void CReadTest::TestSimpleScatterReads2() + // + // Does some simple reads of varying length from the + // blocks in pseudo-random order. + // + // This is similar to TestSimpleScatterReads1 except that + // as the length reduces the read position is moved along + // and the test uses the thread-read variant + // + { + test.Next( _L("Testing simple scatter reads\n") ); + + TRandomGenerator random; + random.SetSeed( KRandomTestSeed ); + + for( TInt readLen = 1; readLen <= 512; readLen++ ) + { + TInt block = random.Next() % iBlockCount; + test.Printf( _L("Reading block %d"), block ); + TInt readBase = (block * iBlockSize) + (512 - readLen); + PerformCheckedRead( readBase, readLen ); + } + } + +void CReadTest::TestScatterGather() + // + // This reads bytes from all over the Flash and concatenates + // them into a single descriptor. This isn't representative of + // anything a real filesystem would do (at present!) but + // is an interesting test of the media driver + // + { + test.Next( _L("Testing scatter-gather reads\n") ); + + TRandomGenerator random; + random.SetSeed( KRandomTestSeed ); + + const TInt KMaxReads = 500; + struct SReadInfo + { + TInt iOffset; + TInt iLength; + }; + + SReadInfo* readInfoArray = new SReadInfo[KMaxReads]; + test( NULL != readInfoArray ); + + TPtr8 des(0,0); + iBuffer->InitialiseGuard(); + iBuffer->GetDes( des, 0, KTestUserDataSize ); + TInt descOffset = 0; + + TInt readCount; + for( readCount = 0; readCount < KMaxReads; readCount++ ) + { + // + // Create random read position and length + // + TInt block = random.Next() % iBlockCount; + TInt blockOffset = random.Next() % 1000; + if( blockOffset > 500 ) + { + blockOffset = iBlockSize - 1 - blockOffset; + } + TInt readOffset = (block * iBlockSize) + blockOffset; + TInt readLength = (random.Next() % 8) + 1; + + if( des.Length() + readLength > des.MaxLength() ) + { + break; // finished + } + + // + // Save the position & length + // + readInfoArray[readCount].iOffset = readOffset; + readInfoArray[readCount].iLength = readLength; + + // + // do the read + // + _LIT( KScatterReadMsg, "Reading Flash @%x %d bytes to desc offset %d" ); + test.Printf( KScatterReadMsg, readOffset, readLength, descOffset ); +#if 0 + test( KErrNone == iDrive.Read( readOffset, readLength, &des, iDummyThread.Handle(), descOffset ) ); +#else + test( KErrNone == iDrive.Read( readOffset, readLength, &des, KLocalMessageHandle, descOffset ) ); +#endif + test( des.Length() == descOffset + readLength ); + + descOffset += readLength; + } + + // + // Now check all the data against the Flash contents + // + descOffset = 0; + for( TInt i = 0; i < readCount; i++ ) + { + TInt readOffset = readInfoArray[i].iOffset ; + TInt readLength = readInfoArray[i].iLength; + + TPtrC8 ptr( des.Ptr() + descOffset, readLength ); + test( CompareAgainstFlash( readOffset, ptr, 0 ) ); + descOffset += readLength; + } + + delete[] readInfoArray; + + } + + + +void CReadTest::TestReadAcrossBlock() + // + // Test reads that cross a block boundary + // + { + test.Next( _L("Testing reads across block boundary\n") ); + + for( TInt block = 1; block < iBlockCount - 1; block++ ) + { + for( TInt readLen = 2; readLen <= 1024; readLen++ ) + { + TInt blockBase = (block * iBlockSize); + TInt readOffs = blockBase + (iBlockSize - (readLen/2)); + PerformCheckedRead( readOffs, readLen ); + } + } + } + + + +void CReadTest::CreateSampleData() + // + // Fills iSampleData with pseudo-random test data + // + { + TUint32* p = (TUint32*)iSampleData.Ptr(); + for( TInt j = 0; j < KTestUserDataSize/4; j++ ) + { + *p++ = iRandom.Next(); + } + + iSampleData.SetLength( KTestUserDataSize ); + } + + +TBool CReadTest::CheckZero( const TPtrC8& aDes ) + // + // Checks that all bytes in aDes are zero + // + { + for( TInt i = aDes.Length(); i > 0; ) + { + --i; + if( 0 != aDes[i] ) + { + return EFalse; + } + } + return ETrue; + } + + + +void CReadTest::CreateTestData( TInt aBlockNumber, TBool aEndOfBlock ) + // + // Writes some test data to the Flash. If aEndOfBlock is EFalse the + // data is created at the start of the block. If it is ETrue then + // the data is created right at the end of the block + // + { + + test.Printf( _L("Writing test data to Flash block %d\n"), aBlockNumber ); + + // + // Generate some test data + // + CreateSampleData(); + + test.Printf( _L("Erasing block") ); + TInt writeBaseOffset = (aBlockNumber * iBlockSize); + test( KErrNone == iDrive.Format( writeBaseOffset, iBlockSize ) ); + + + TInt writeCount = iSampleData.Length() / KMaxWriteLength; + TInt r = KErrNone; + if( aEndOfBlock ) + { + writeBaseOffset += iBlockSize - iSampleData.Length(); + } + + TInt writeOffset = writeBaseOffset; + + const TUint8* src = iSampleData.Ptr(); + + test.Printf( _L("Writing data") ); + for( ; (writeCount > 0) && (KErrNone == r); writeCount-- ) + { + TPtrC8 buf( src, KMaxWriteLength ); + test( KErrNone == iDrive.Write( writeOffset, buf ) ); + writeOffset += KMaxWriteLength; + src += KMaxWriteLength; + } + test( r == KErrNone ); + + // + // check that the data was written ok + // + test.Printf( _L("Verifying data") ); + test( CompareAgainstFlash( writeBaseOffset, iSampleData, 0 ) ); + + test.Printf( _L("... test data written\n") ); + } + +TBool CReadTest::CompareAgainstFlash( TInt aFlashOffset, const TPtrC8& aDes, TInt aDescOffset ) + // + // Checks that the data in aDes matches that in the Flash at position + // aFlashOffset. + // The test starts at offset aDescOffset in aSampleData. The data length + // tested is aDes->Length() - aDescOffset + // + { + TInt dataLength = aDes.Length() - aDescOffset; + const TUint8* srcPtr = aDes.Ptr() + aDescOffset; + + TUint offset = aFlashOffset; + + TBool failed = EFalse; + const TInt readBufLen = iReadBuffer.MaxLength(); + + while( (dataLength > 0) && !failed ) + { + TInt len = Min( dataLength, readBufLen ); + TInt r = iDrive.Read( offset, len, iReadBuffer ); + if( r != KErrNone ) + { + test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset ); + test( KErrNone == r ); + } + test( iReadBuffer.Length() == len ); + + if( 0 != Mem::Compare( srcPtr, len, iReadBuffer.Ptr(), len ) ) + { + test.Printf( _L("... FAIL: mismatch around offset 0x%x\n"), offset ); + failed = ETrue; + } + offset += len; + dataLength -= len; + srcPtr += len; + } + + return !failed; + } + + + +void CReadTest::DoTest() + // + // Main test dispatcher + // + { + // + // Create some test data at start of block 0 + // + CreateTestData( 0, EFalse ); + + // + // Now do the simple tests, all reads will return zeros + // +#if 0 + TestSimpleReads(); +#endif + TestSimpleThreadReads(); + TestUnalignedReads(); + TestUnalignedThreadReads(); + TestOffsetBufferThreadReads(); + TestOffsetBufferUnalignedThreadReads(); + + // + // Create some more data at start of all other blocks + // + test.Next( _L("Creating more test data in other blocks") ); + for( TInt i = 1; i < iBlockCount; i++ ) + { + CreateTestData( i, EFalse ); + } + + // + // Make sure we can read valid data out of the other blocks + // + TestReadsFromAllBlocks(); + + // + // Now do some scatter-read tests + // + TestSimpleScatterReads1(); + TestSimpleScatterReads2(); + + // + // Create some more testdata at end of all blocks + // + test.Next( _L("Creating test data at end of blocks") ); + for( TInt i = 0; i < iBlockCount; i++ ) + { + CreateTestData( i, ETrue ); + } + + // + // Do a full scatter-gather test + // + TestScatterGather(); + + TestReadAcrossBlock(); + } + + + + + +TInt E32Main() + { + test.Title(); + test.Start(_L("Testing media read operations")); + + CReadTest reader; + TRAPD( ret, reader.CreateL() ); + test( KErrNone == ret ); + reader.DoTest(); + test.End(); + + return 0; + }