201015_11
authorhgs
Fri, 23 Apr 2010 22:20:31 +0100
changeset 123 fc55edbf3919
parent 122 70ba09fd07a5
child 124 5802e2ce68ed
201015_11
kernel/eka/bmarm/elocdu.def
kernel/eka/bwins/elocdu.def
kernel/eka/bx86/elocdu.def
kernel/eka/drivers/locmedia/dmasupport.cpp
kernel/eka/drivers/locmedia/locmedia.cpp
kernel/eka/drivers/medata/pccd_ata.cpp
kernel/eka/drivers/medint/iram.cpp
kernel/eka/drivers/medlfs/flash_media.cpp
kernel/eka/drivers/medmmc/medmmc.cpp
kernel/eka/eabi/elocdu.def
kernel/eka/include/d32locd.h
kernel/eka/include/drivers/locmedia.h
kernel/eka/include/e32ver.h
kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp
kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp
kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp
kernel/eka/memmodel/epoc/mmubase/mmubase.cpp
kernel/eka/release.txt
kerneltest/e32test/iic/t_iic.cpp
kerneltest/e32test/mediaext/d_nfe.cpp
kerneltest/e32test/mediaext/nfe.h
kerneltest/e32test/mediaext/t_nfe.cpp
kerneltest/e32test/mediaext/t_nfe.mmp
kerneltest/e32test/multimedia/t_sound2.cpp
kerneltest/f32test/demandpaging/t_nandpaging.cpp
kerneltest/f32test/filesystem/fat/t_scn32dr1.cpp
kerneltest/f32test/filesystem/fat/t_tscan32.cpp
kerneltest/f32test/group/bld.inf
kerneltest/f32test/group/t_nandpaging.mmp
kerneltest/f32test/group/wintest.bat
kerneltest/f32test/server/t_misc.cpp
userlibandfileserver/fileserver/group/release.txt
userlibandfileserver/fileserver/inc/f32ver.h
userlibandfileserver/fileserver/sfile/sf_drv.cpp
--- a/kernel/eka/bmarm/elocdu.def	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/bmarm/elocdu.def	Fri Apr 23 22:20:31 2010 +0100
@@ -52,4 +52,19 @@
 	GetNextPhysicalAddress__14TLocDrvRequestRUlRi @ 51 NONAME R3UNUSED ; TLocDrvRequest::GetNextPhysicalAddress(unsigned long &, int &)
 	RegisterDmaDevice__6LocDrvP17DPrimaryMediaBaseiii @ 52 NONAME ; LocDrv::RegisterDmaDevice(DPrimaryMediaBase *, int, int, int)
 	ReadFromPageHandler__14TLocDrvRequestPvii @ 53 NONAME ; TLocDrvRequest::ReadFromPageHandler(void *, int, int)
+	__21DMediaDriverExtensioni @ 54 NONAME R3UNUSED ; DMediaDriverExtension::DMediaDriverExtension(int)
+	Close__21DMediaDriverExtension @ 55 NONAME R3UNUSED ; DMediaDriverExtension::Close(void)
+	DoDrivePartitionInfo__21DMediaDriverExtensionR14TPartitionInfo @ 56 NONAME R3UNUSED ; DMediaDriverExtension::DoDrivePartitionInfo(TPartitionInfo &)
+	ForwardRequest__21DMediaDriverExtensionR14TLocDrvRequest @ 57 NONAME R3UNUSED ; DMediaDriverExtension::ForwardRequest(TLocDrvRequest &)
+	MediaBusy__21DMediaDriverExtensioni @ 58 NONAME R3UNUSED ; DMediaDriverExtension::MediaBusy(int)
+	NotifyEmergencyPowerDown__21DMediaDriverExtension @ 59 NONAME R3UNUSED ; DMediaDriverExtension::NotifyEmergencyPowerDown(void)
+	NotifyPowerDown__21DMediaDriverExtension @ 60 NONAME R3UNUSED ; DMediaDriverExtension::NotifyPowerDown(void)
+	Read__21DMediaDriverExtensionixUlUi @ 61 NONAME ; DMediaDriverExtension::Read(int, long long, unsigned long, unsigned int)
+	Write__21DMediaDriverExtensionixUlUi @ 62 NONAME ; DMediaDriverExtension::Write(int, long long, unsigned long, unsigned int)
+	"_._21DMediaDriverExtension" @ 63 NONAME R3UNUSED ; DMediaDriverExtension::~DMediaDriverExtension(void)
+	Caps__21DMediaDriverExtensioniR5TDes8 @ 64 NONAME R3UNUSED ; DMediaDriverExtension::Caps(int, TDes8 &)
+	SetTotalSizeInBytes__12DMediaDriverR17TLocalDriveCapsV4 @ 65 NONAME R3UNUSED ; DMediaDriver::SetTotalSizeInBytes(TLocalDriveCapsV4 &)
+	ReadPaged__21DMediaDriverExtensionixUlUi @ 66 NONAME ; DMediaDriverExtension::ReadPaged(int, long long, unsigned long, unsigned int)
+	WritePaged__21DMediaDriverExtensionixUlUi @ 67 NONAME ; DMediaDriverExtension::WritePaged(int, long long, unsigned long, unsigned int)
+	Caps__11DLocalDriveiR5TDes8 @ 68 NONAME R3UNUSED ; DLocalDrive::Caps(int, TDes8 &)
 
--- a/kernel/eka/bwins/elocdu.def	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/bwins/elocdu.def	Fri Apr 23 22:20:31 2010 +0100
@@ -49,4 +49,17 @@
 	?Set@TPartitionTableScanner@@QAEXPAEPAVTPartitionEntry@@H_J@Z @ 48 NONAME ; public: void __thiscall TPartitionTableScanner::Set(unsigned char *,class TPartitionEntry *,int,__int64)
 	?GetNextPhysicalAddress@TLocDrvRequest@@QAEHAAKAAH@Z @ 49 NONAME ; int TLocDrvRequest::GetNextPhysicalAddress(unsigned long &, int &)
 	?RegisterDmaDevice@LocDrv@@SAHPAVDPrimaryMediaBase@@HHH@Z @ 50 NONAME ; int LocDrv::RegisterDmaDevice(class DPrimaryMediaBase *, int, int, int)
+	??0DMediaDriverExtension@@QAE@H@Z @ 51 NONAME ; public: __thiscall DMediaDriverExtension::DMediaDriverExtension(int)
+	??1DMediaDriverExtension@@UAE@XZ @ 52 NONAME ; public: virtual __thiscall DMediaDriverExtension::~DMediaDriverExtension(void)
+	?Caps@DMediaDriverExtension@@QAEHHAAVTDes8@@@Z @ 53 NONAME ; public: int __thiscall DMediaDriverExtension::Caps(int,class TDes8 &)
+	?Close@DMediaDriverExtension@@UAEXXZ @ 54 NONAME ; public: virtual void __thiscall DMediaDriverExtension::Close(void)
+	?DoDrivePartitionInfo@DMediaDriverExtension@@QAEHAAVTPartitionInfo@@@Z @ 55 NONAME ; public: int __thiscall DMediaDriverExtension::DoDrivePartitionInfo(class TPartitionInfo &)
+	?ForwardRequest@DMediaDriverExtension@@QAEHAAVTLocDrvRequest@@@Z @ 56 NONAME ; public: int __thiscall DMediaDriverExtension::ForwardRequest(class TLocDrvRequest &)
+	?MediaBusy@DMediaDriverExtension@@QAEHH@Z @ 57 NONAME ; public: int __thiscall DMediaDriverExtension::MediaBusy(int)
+	?NotifyEmergencyPowerDown@DMediaDriverExtension@@UAEXXZ @ 58 NONAME ; public: virtual void __thiscall DMediaDriverExtension::NotifyEmergencyPowerDown(void)
+	?NotifyPowerDown@DMediaDriverExtension@@UAEXXZ @ 59 NONAME ; public: virtual void __thiscall DMediaDriverExtension::NotifyPowerDown(void)
+	?Read@DMediaDriverExtension@@QAEHH_JKI@Z @ 60 NONAME ; public: int __thiscall DMediaDriverExtension::Read(int,__int64,unsigned long,unsigned int)
+	?SetTotalSizeInBytes@DMediaDriver@@QAEXAAVTLocalDriveCapsV4@@@Z @ 61 NONAME ; public: void __thiscall DMediaDriver::SetTotalSizeInBytes(class TLocalDriveCapsV4 &)
+	?Write@DMediaDriverExtension@@QAEHH_JKI@Z @ 62 NONAME ; public: int __thiscall DMediaDriverExtension::Write(int,__int64,unsigned long,unsigned int)
+	?Caps@DLocalDrive@@SAHHAAVTDes8@@@Z @ 63 NONAME ; public: static int __cdecl DLocalDrive::Caps(int,class TDes8 &)
 
--- a/kernel/eka/bx86/elocdu.def	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/bx86/elocdu.def	Fri Apr 23 22:20:31 2010 +0100
@@ -52,4 +52,19 @@
 	?GetNextPhysicalAddress@TLocDrvRequest@@QAEHAAKAAH@Z @ 51 NONAME ; public: int __thiscall TLocDrvRequest::GetNextPhysicalAddress(unsigned long &,int &)
 	?RegisterDmaDevice@LocDrv@@SAHPAVDPrimaryMediaBase@@HHH@Z @ 52 NONAME ; public: static int __cdecl LocDrv::RegisterDmaDevice(class DPrimaryMediaBase *,int,int,int)
 	?ReadFromPageHandler@TLocDrvRequest@@QAEHPAXHH@Z @ 53 NONAME ; public: int __thiscall TLocDrvRequest::ReadFromPageHandler(void *,int,int)
+	??0DMediaDriverExtension@@QAE@H@Z @ 54 NONAME ; public: __thiscall DMediaDriverExtension::DMediaDriverExtension(int)
+	??1DMediaDriverExtension@@UAE@XZ @ 55 NONAME ; public: virtual __thiscall DMediaDriverExtension::~DMediaDriverExtension(void)
+	?Caps@DMediaDriverExtension@@QAEHHAAVTDes8@@@Z @ 56 NONAME ; public: int __thiscall DMediaDriverExtension::Caps(int,class TDes8 &)
+	?Close@DMediaDriverExtension@@UAEXXZ @ 57 NONAME ; public: virtual void __thiscall DMediaDriverExtension::Close(void)
+	?DoDrivePartitionInfo@DMediaDriverExtension@@QAEHAAVTPartitionInfo@@@Z @ 58 NONAME ; public: int __thiscall DMediaDriverExtension::DoDrivePartitionInfo(class TPartitionInfo &)
+	?ForwardRequest@DMediaDriverExtension@@QAEHAAVTLocDrvRequest@@@Z @ 59 NONAME ; public: int __thiscall DMediaDriverExtension::ForwardRequest(class TLocDrvRequest &)
+	?MediaBusy@DMediaDriverExtension@@QAEHH@Z @ 60 NONAME ; public: int __thiscall DMediaDriverExtension::MediaBusy(int)
+	?NotifyEmergencyPowerDown@DMediaDriverExtension@@UAEXXZ @ 61 NONAME ; public: virtual void __thiscall DMediaDriverExtension::NotifyEmergencyPowerDown(void)
+	?NotifyPowerDown@DMediaDriverExtension@@UAEXXZ @ 62 NONAME ; public: virtual void __thiscall DMediaDriverExtension::NotifyPowerDown(void)
+	?Read@DMediaDriverExtension@@QAEHH_JKI@Z @ 63 NONAME ; public: int __thiscall DMediaDriverExtension::Read(int,__int64,unsigned long,unsigned int)
+	?Write@DMediaDriverExtension@@QAEHH_JKI@Z @ 64 NONAME ; public: int __thiscall DMediaDriverExtension::Write(int,__int64,unsigned long,unsigned int)
+	?SetTotalSizeInBytes@DMediaDriver@@QAEXAAVTLocalDriveCapsV4@@@Z @ 65 NONAME ; public: void __thiscall DMediaDriver::SetTotalSizeInBytes(class TLocalDriveCapsV4 &)
+	?ReadPaged@DMediaDriverExtension@@QAEHH_JKI@Z @ 66 NONAME ; public: int __thiscall DMediaDriverExtension::ReadPaged(int,__int64,unsigned long,unsigned int)
+	?WritePaged@DMediaDriverExtension@@QAEHH_JKI@Z @ 67 NONAME ; public: int __thiscall DMediaDriverExtension::WritePaged(int,__int64,unsigned long,unsigned int)
+	?Caps@DLocalDrive@@SAHHAAVTDes8@@@Z @ 68 NONAME ; public: static int __cdecl DLocalDrive::Caps(int,class TDes8 &)
 
--- a/kernel/eka/drivers/locmedia/dmasupport.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/locmedia/dmasupport.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -278,7 +278,7 @@
 	TInt r;
 	do
 		{
-		__KTRACE_DMA(Kern::Printf(">PHYSADDR:SendReceive() iReqLen %d; iLenConsumed %d; fragments %d",iReqLen, iLenConsumed, fragments));
+		__KTRACE_DMA(Kern::Printf(">PHYSADDR:SendReceive() iReqLen %d; iLenConsumed %d; fragments %d",iReqLenClient, iLenConsumed, fragments));
 		OstTraceExt2( TRACE_DMASUPPORT, DDMAHELPER_SENDRECEIVE1, "PHYSADDR:SendReceive() iLenConsumed=%d; fragments=%d", iLenConsumed, fragments);
 		r = RequestStart();
 		if (r != KErrNone)
--- a/kernel/eka/drivers/locmedia/locmedia.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/locmedia/locmedia.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -71,6 +71,9 @@
 class DPrimaryMediaBase::DBody : public DBase
 	{
 public:
+	DBody(DPrimaryMediaBase& aPrimaryMediaBase);
+public:
+	DPrimaryMediaBase& iPrimaryMediaBase;	// ptr to parent
 	TInt iPhysDevIndex;
 	TInt iRequestCount;
 #ifdef __DEMAND_PAGING__
@@ -78,12 +81,24 @@
 	TInt iPageSizeMsk;			// Mask of page size (e.g. 4096-1 -> 4095)
 	TInt iMediaChanges;
 #endif
+
+	// This bit mask indicates which local drives the media is attached to
+	TUint32 iRegisteredDriveMask;
+
+	// Set to ETrue for media extension drivers
+	TBool iMediaExtension;
+	
+	// Media change DFCs to allow media change events from attached media
+	// to be handled in the context of an extension media's thread
+	TDfc iMediaChangeDfc;
+	TDfc iMediaPresentDfc;
 	};
 
 #ifdef __DEMAND_PAGING__
 DMediaPagingDevice* ThePagingDevices[KMaxLocalDrives];
 DPrimaryMediaBase* TheRomPagingMedia = NULL;
 DPrimaryMediaBase* TheDataPagingMedia = NULL;
+TLocDrv* TheDataPagingDrive = NULL;
 TBool DataPagingDeviceRegistered = EFalse;
 class DPinObjectAllocator;
 DPinObjectAllocator* ThePinObjectAllocator = NULL;
@@ -92,10 +107,29 @@
 // In this case, we need to avoid taking page faults on the non-paging media too, hence the need for these checks:
 inline TBool DataPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
 	{return TheDataPagingMedia && TheDataPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
+
+
+TBool DataPagingMedia(DPrimaryMediaBase* aPrimaryMedia)
+	{
+	for (TLocDrv* drv = TheDataPagingDrive; drv; drv = drv->iNextDrive)
+		if (drv->iPrimaryMedia == aPrimaryMedia)
+			return ETrue;
+	return EFalse;
+	}
+
 inline TBool RomPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
 	{return TheRomPagingMedia && TheRomPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
 
 
+#if defined(_DEBUG)
+	#define SETDEBUGFLAG(aBitNum) {Kern::SuperPage().iDebugMask[aBitNum >> 5] |= (1 << (aBitNum & 31));}
+	#define CLRDEBUGFLAG(aBitNum) {Kern::SuperPage().iDebugMask[aBitNum >> 5] &= ~(1 << (aBitNum & 31));}
+#else
+	#define SETDEBUGFLAG(aBitNum)
+	#define CLRDEBUGFLAG(aBitNum)
+#endif
+
+
 
 /* 
 DPinObjectAllocator
@@ -104,6 +138,7 @@
 	(1) a queue of pre-allocated TVirtualPinObject's; 
 	(2) a single pre-allocated DFragmentationPagingLock object: 
 		this may be used if there are no TVirtualPinObject's available or if Kern::PinVirtualMemory() fails
+@internalTechnology
 */
 NONSHARABLE_CLASS(DPinObjectAllocator) : public DBase
 	{
@@ -157,7 +192,7 @@
 		delete iPreAllocatedDataLock;
 		}
 
-	for (TInt n=0; n<iObjectCount; n++)
+	for (TInt n=0; iVirtualPinContainers!= NULL && n<iObjectCount; n++)
 		{
 		SVirtualPinContainer& virtualPinContainer = iVirtualPinContainers[n];
 		if (virtualPinContainer.iObject)
@@ -192,7 +227,7 @@
 	    }
 
 
-	SVirtualPinContainer* iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
+	iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
 	if (iVirtualPinContainers == NULL)
 	    {
 		OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT3, this, KErrNoMemory );
@@ -260,6 +295,98 @@
 #endif	// __DEMAND_PAGING__
 
 
+/* 
+TDriveIterator
+
+Internal class which supports iterating through all local drives (TLocDrv's)
+If there are media extensions present, then this will iterate through all attached drives.
+@internalTechnology
+*/
+class TDriveIterator
+	{
+public:
+	TDriveIterator();
+	TLocDrv* NextDrive();
+	inline TInt Index()
+		{return iIndex;}
+	static TLocDrv* GetDrive(TInt aDriveNum, DPrimaryMediaBase* aPrimaryMedia);
+	static TLocDrv* GetPhysicalDrive(TLocDrv* aDrv);
+
+#if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
+	static DMediaPagingDevice* PagingDevice(TInt aDriveNum, DPagingDevice::TType aType);
+#endif
+
+private:
+	TInt iIndex;
+	TLocDrv* iDrive;
+	};
+
+TDriveIterator::TDriveIterator() :
+	iIndex(0), iDrive(NULL)
+	{
+	}
+
+TLocDrv* TDriveIterator::NextDrive()
+	{
+	if (iDrive)	// i.e. if not first time
+		{
+		if (iDrive->iNextDrive)
+			{
+			iDrive = iDrive->iNextDrive;
+			return iDrive;
+			}
+		iIndex++;
+		}
+
+	for (iDrive = NULL; iIndex < KMaxLocalDrives; iIndex++)
+		{
+		iDrive = TheDrives[iIndex];
+		if (iDrive)
+			break;
+		}
+
+	return iDrive;
+	}
+
+/*
+Returns the first TLocDrv in the chain of attached drives which matches DPrimaryMediaBase
+*/
+TLocDrv* TDriveIterator::GetDrive(TInt aDriveNum, DPrimaryMediaBase* aPrimaryMedia)
+	{
+	TLocDrv* drive = TheDrives[aDriveNum];
+	while (drive && drive->iPrimaryMedia != aPrimaryMedia)
+		{
+		drive = drive->iNextDrive ? drive->iNextDrive : NULL;
+		}
+	return drive;
+	}
+
+/*
+Returns the last TLocDrv in the chain of attached drives - 
+i.e. the TLocDrv attached to physical media rather than a TLocDrv corresponding to a media extension 
+*/
+TLocDrv* TDriveIterator::GetPhysicalDrive(TLocDrv* aDrv)
+	{
+	__ASSERT_DEBUG(aDrv, LOCM_FAULT());
+	while (aDrv->iNextDrive)
+		aDrv = aDrv->iNextDrive;
+	return aDrv;
+	}
+
+#if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
+DMediaPagingDevice* TDriveIterator::PagingDevice(TInt aDriveNum, DPagingDevice::TType aType)
+	{
+	TLocDrv* drive = TheDrives[aDriveNum];
+	DMediaPagingDevice* pagingDevice = drive ? drive->iPrimaryMedia->iBody->iPagingDevice : NULL;
+	while (drive && (pagingDevice == NULL || (pagingDevice->iType & aType) == 0))
+		{
+		drive = drive->iNextDrive ? drive->iNextDrive : NULL;
+		pagingDevice = drive ? drive->iPrimaryMedia->iBody->iPagingDevice : NULL;
+		}
+	return pagingDevice;
+	}
+#endif
+
 /********************************************
  * Local drive device base class
  ********************************************/
@@ -312,7 +439,8 @@
 /********************************************
  * Local drive interface class
  ********************************************/
-DLocalDrive::DLocalDrive()
+DLocalDrive::DLocalDrive() :
+	iMediaChangeObserver(MediaChangeCallback, this, TCallBackLink::EDLocalDriveObject)
 	{
 //	iLink.iNext=NULL;
 	}
@@ -489,42 +617,6 @@
 			m.Length()=KMaxLocalDriveCapsLength;	// for pinning
 			r=iDrive->Request(m);
 
-			if(r == KErrNone && iDrive->iMedia != NULL && iDrive->iMedia->iDriver != NULL)
-				{
-				// Fill in default media size if not specified by the driver
-				//
-				// - This uses the members of TLocalDriveCapsV4 which was primarily used
-				//   to report NAND flash characteristics, but are general enough to be
-				//	 used to report the size of any type of media without adding yet
-				//	 another extension to TLocalDriveCapsVx.
-				//
-				
-				TLocalDriveCapsV4& caps = *(TLocalDriveCapsV4*)capsBuf.Ptr();
-				
-				if(caps.iSectorSizeInBytes == 0)
-					{
-					// Fill in a default value for the disk sector size
-					caps.iSectorSizeInBytes = 512;
-
-					// Zero the number of sectors, as a sector count makes no sense without a sector size
-					//  - Fault in debug mode if a sector count is provided to ensure that media driver creators
-					//	  set this value,but in release mode continue gracefully be recalculating the sector count.
-					__ASSERT_DEBUG(caps.iNumberOfSectors == 0, LOCM_FAULT());
-					caps.iNumberOfSectors  = 0;
-					caps.iNumPagesPerBlock = 1;	// ...to ensure compatiility with NAND semantics
-					}
-
-				if(caps.iNumberOfSectors == 0)
-					{
-					const Int64 totalSizeInSectors = iDrive->iMedia->iDriver->TotalSizeInBytes() / caps.iSectorSizeInBytes;
-					__ASSERT_DEBUG(I64HIGH(totalSizeInSectors) == 0, LOCM_FAULT());
-
-					if(I64HIGH(totalSizeInSectors) == 0)
-						{
-						caps.iNumberOfSectors = I64LOW(totalSizeInSectors);
-						}
-					}
-				}
 
 #if defined(OST_TRACE_COMPILER_IN_USE) && defined(_DEBUG)
 			const TLocalDriveCapsV5& caps=*(const TLocalDriveCapsV5*)capsBuf.Ptr();
@@ -593,7 +685,11 @@
 			{
 	        OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLISREMOVABLE, "EControlIsRemovable; TLocDrvRequest Object=0x%x", (TUint) &m);
 			TInt sockNum;
-			r=iDrive->iPrimaryMedia->IsRemovableDevice(sockNum);
+
+			// Pass request on to last chained drive
+			TLocDrv* drv = TDriveIterator::GetPhysicalDrive(iDrive);
+			r = drv->iPrimaryMedia->IsRemovableDevice(sockNum);
+
 			if (r)
 				kumemput32(a1,&sockNum,sizeof(TInt));
 			break;	
@@ -636,7 +732,11 @@
 			OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_CONTROLSETMOUNTINFO, "EControlSetMountInfo; TLocDrvRequest Object=0x%x", (TUint) &m);
 			m.Id()=ERead;
 			r=m.ProcessMessageData(a1);
-			DPrimaryMediaBase* pM=iDrive->iPrimaryMedia;
+
+			// Pass request on to last chained drive
+			TLocDrv* drv = TDriveIterator::GetPhysicalDrive(iDrive);
+			DPrimaryMediaBase* pM = drv->iPrimaryMedia;
+
 			if(!pM || r!=KErrNone)
 				break;
 
@@ -874,11 +974,15 @@
 			TBuf8<KMaxQueryDeviceLength> queryBuf;
 			queryBuf.SetMax();
 			queryBuf.FillZ();
-			
+
+			DThread* pT = m.Client();
+			r = Kern::ThreadDesRead(pT, (TDes8*)a2, queryBuf, 0 ,KChunkShiftBy0);
+
+			queryBuf.SetMax();
 			m.Id() = EQueryDevice;
-			m.iArg[0] = a1;		// RLocalDrive::TQueryDevice
+			m.iArg[0] = a1;							// RLocalDrive::TQueryDevice
 			m.RemoteDes() = (TAny*)queryBuf.Ptr();	// overload this
-			m.Length() = KMaxLocalDriveCapsLength;	// for pinning
+			m.Length() = KMaxQueryDeviceLength;
 			OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_QUERYDEVICE, "EQueryDevice; TLocDrvRequest Object=0x%x", (TUint) &m);
 			r=iDrive->Request(m);
 			OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DLOCALDRIVE_REQUEST_QUERYDEVICE_RETURN, "EQueryDevice Return; TLocDrvRequest Object=0x%x", (TUint) &m);
@@ -1033,7 +1137,7 @@
 	OstTrace1(TRACE_FLOW, DLOCALDRIVE_UNLOCKMOUNTINFO_ENTRY, "> DLocalDrive::UnlockMountInfo;aPrimaryMedia=%x", (TUint) &aPrimaryMedia);
 	
 	DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice; 
-	if (pagingDevice == NULL || pagingDevice->iMountInfoDataLock == NULL)
+	if (pagingDevice == NULL)
 	    {
 		OstTraceFunctionExit1( DLOCALDRIVE_UNLOCKMOUNTINFO_EXIT1, this );
 		return;
@@ -1065,50 +1169,52 @@
 	}
 #endif	// __DEMAND_PAGING__
 
-void DLocalDrive::NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange)
+void DLocalDrive::NotifyChange()
 	{
-    OstTraceExt2( TRACE_FLOW, DLOCALDRIVE_NOTIFYCHANGE_ENTRY, "> DLocalDrive::NotifyChange;aPrimaryMedia=%x;aMediaChange=%d", (TUint) &aPrimaryMedia, aMediaChange );
-#ifndef __DEMAND_PAGING__
-	aPrimaryMedia;
-#endif
-
-	// Complete any notification request on media change or power down
-	if (aMediaChange)
+    OstTrace0( TRACE_FLOW, DLOCALDRIVE_NOTIFYCHANGE_ENTRY, "> DLocalDrive::NotifyChange");
+
+
+	// Complete any notification request on media change
+	DThread* pC=NULL;
+	NKern::LockSystem();
+	if (iCleanup.iThread)
 		{
-		DThread* pC=NULL;
-		NKern::LockSystem();
-		if (iCleanup.iThread)
-			{
-			pC=iCleanup.iThread;
-			pC->Open();
-			}
-		NKern::UnlockSystem();
-		if (pC)
+		pC=iCleanup.iThread;
+		pC->Open();
+		}
+	NKern::UnlockSystem();
+	if (pC)
+		{
+		TBool b = ETrue;
+		// if change not yet queued, queue it now
+		if (iNotifyChangeRequest->IsReady())
 			{
-			TBool b = ETrue;
-			// if change not yet queued, queue it now
-			if (iNotifyChangeRequest->IsReady())
-				{
-				*((TBool*) iNotifyChangeRequest->Buffer()) = b;
-				Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrNone);
-				}
-			// If change has not even been requested by the client, maintain the pre-wdp behaviour 
-			// and write data immediately back to client (possibly taking a page fault)
-			// N.B. Must NOT do this on data paging media
+			*((TBool*) iNotifyChangeRequest->Buffer()) = b;
+			Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrNone);
+			}
+		// If change has not even been requested by the client, maintain the pre-wdp behaviour 
+		// and write data immediately back to client (possibly taking a page fault)
+		// N.B. Must NOT do this on data paging media
 #ifdef __DEMAND_PAGING__
-			else if (!DataPagingDfcQ(&aPrimaryMedia))
+		else if (!DataPagingDfcQ(iDrive->iPrimaryMedia))
 #else
-			else
+		else
 #endif
-				{
-				Kern::ThreadRawWrite(pC, iNotifyChangeRequest->DestPtr(), &b, sizeof(b), NULL);
-				}
-			pC->AsyncClose();
+			{
+			Kern::ThreadRawWrite(pC, iNotifyChangeRequest->DestPtr(), &b, sizeof(b), NULL);
 			}
+		pC->AsyncClose();
 		}
 	OstTraceFunctionExit1( DLOCALDRIVE_NOTIFYCHANGE_EXIT, this );
 	}
 
+// This function is called by the primary media when a media change occurs
+TInt DLocalDrive::MediaChangeCallback(TAny* aLocalDrive, TInt /* aNotifyType*/)
+	{
+	((DLocalDrive*) aLocalDrive)->NotifyChange();
+	return KErrNone;
+	}
+
 TLocalDriveCleanup::TLocalDriveCleanup()
 	{
 	}
@@ -1127,6 +1233,33 @@
 	NKern::LockSystem();
 	}
 
+
+EXPORT_C TInt DLocalDrive::Caps(TInt aDriveNumber, TDes8& aCaps)
+	{
+	if(!Kern::CurrentThreadHasCapability(ECapabilityTCB,__PLATSEC_DIAGNOSTIC_STRING("Checked by ELOCD.LDD (Local Media Driver)")))
+	    {
+		return KErrPermissionDenied;
+	    }
+	
+
+	if (aDriveNumber >= KMaxLocalDrives)
+		return KErrArgument;
+
+	TLocDrv* drive = TheDrives[aDriveNumber];
+	if (!drive)
+		return KErrNotSupported;
+
+	TLocDrvRequest request;
+	memclr(&request, sizeof(request));
+
+	request.Drive() = drive;
+	request.Id() = DLocalDrive::ECaps;
+	request.Length() = aCaps.Length();
+	request.RemoteDes() = (TAny*) aCaps.Ptr();
+
+	return request.SendReceive(&drive->iPrimaryMedia->iMsgQ);
+	}
+
 /********************************************
  * Local drive request class
  ********************************************/
@@ -1155,6 +1288,14 @@
 	{
 	OstTraceFunctionEntry1( TLOCDRVREQUEST_READREMOTE_ENTRY, this );
 	TInt r;
+
+	if (Flags() & TLocDrvRequest::EKernelBuffer)
+		{
+		(void)memcpy((TAny*) aDes->Ptr(), (TAny*)((TUint32)RemoteDes()+anOffset), aDes->MaxLength());
+		aDes->SetLength(aDes->MaxLength());
+		return KErrNone;
+		}
+
 	DThread* pT=RemoteThread();
 	if (!pT)
 		pT=Client();
@@ -1294,6 +1435,14 @@
 	{
     OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITEREMOTE_ENTRY, this );
     TInt r;
+
+	if (Flags() & TLocDrvRequest::EKernelBuffer)
+		{
+		(void)memcpy((TAny*)((TUint32)RemoteDes()+anOffset), (TAny*) aDes->Ptr(), aDes->Length());
+		OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT1, this, KErrNone );
+		return KErrNone;
+		}
+
 	DThread* pC=Client();
 	DThread* pT=RemoteThread();
 	if (!pT)
@@ -1303,12 +1452,12 @@
 	if (Flags() & ETClientBuffer)
 	    {
         r = Kern::ThreadBufWrite(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
-		OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT1, this, r );
+		OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT2, this, r );
 		return r;
 	    }
 #endif
 	r = Kern::ThreadDesWrite(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
-	OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT2, this, r );
+	OstTraceFunctionExitExt( TLOCDRVREQUEST_WRITEREMOTE_EXIT3, this, r );
 	return r;
 	}
 
@@ -1489,7 +1638,7 @@
 			OstTraceExt2( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION6, "Read/Write request length=0x%x; position=0x%x", (TUint) Length(), (TUint) Pos() );
 			if (DriverFlags() & RLocalDrive::ELocDrvWholeMedia)
 				{
-				if (d.iMedia && d.iMedia->iDriver && Pos()+Length() > d.iMedia->iDriver->iTotalSizeInBytes)
+				if (d.iMedia && d.iMedia->iDriver && Pos()+Length() > d.iMedia->iPartitionInfo.iMediaSizeInBytes)
 				    {
 					r = KErrArgument;
 					break;
@@ -1519,9 +1668,22 @@
 	memclr(this, sizeof(TLocDrv));
 	iDriveNumber=aDriveNumber;
 	iPartitionNumber=-1;
+	iMediaChangeObserver.iFunction = MediaChangeCallback;
+	iMediaChangeObserver.iPtr= this;
+	iMediaChangeObserver.iObjectType = TCallBackLink::ETLocDrvObject;
 	OstTraceFunctionExit1( TLOCDRV_TLOCDRV_EXIT, this );
 	}
 
+TInt TLocDrv::MediaChangeCallback(TAny* aLocDrv, TInt aNotifyType)
+	{
+	__ASSERT_DEBUG(aNotifyType == DPrimaryMediaBase::EMediaChange || aNotifyType == DPrimaryMediaBase::EMediaPresent, LOCM_FAULT());
+	if (aNotifyType == DPrimaryMediaBase::EMediaPresent)
+		return ((TLocDrv*) aLocDrv)->iPrimaryMedia->iBody->iMediaPresentDfc.Enque();
+	else
+		return ((TLocDrv*) aLocDrv)->iPrimaryMedia->iBody->iMediaChangeDfc.Enque();
+	}
+
+
 /**
 Initialises the DMedia entity with the media device number and ID.
  
@@ -1588,6 +1750,26 @@
 	OstTraceFunctionExit0( _HANDLEMSG_EXIT );
 	}
 
+
+void mediaChangeDfc(TAny* aPtr)
+	{
+	DPrimaryMediaBase* pM = (DPrimaryMediaBase*)aPtr;
+	pM->NotifyMediaChange();
+	}
+
+void mediaPresentDfc(TAny* aPtr)
+	{
+	DPrimaryMediaBase* pM = (DPrimaryMediaBase*)aPtr;
+	pM->NotifyMediaPresent();
+	}
+
+DPrimaryMediaBase::DBody::DBody(DPrimaryMediaBase& aPrimaryMediaBase) :
+	iPrimaryMediaBase(aPrimaryMediaBase),
+	iMediaChangeDfc(mediaChangeDfc, &aPrimaryMediaBase, KMaxDfcPriority),
+	iMediaPresentDfc(mediaPresentDfc, &aPrimaryMediaBase, KMaxDfcPriority)
+	{
+	}
+
 EXPORT_C DPrimaryMediaBase::DPrimaryMediaBase()
 	:	iMsgQ(handleMsg, this, NULL, 1),
 		iDeferred(NULL, NULL, NULL, 0),			// callback never used
@@ -1627,15 +1809,18 @@
 	    {
 		OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CREATE_EXIT1, this, r );
 		return r;
-	    }
-	iBody = new DBody;
+		}
+	iBody = new DBody(*this);
 	if (iBody == NULL)
 	    {
 		OstTraceFunctionExitExt( DPRIMARYMEDIABASE_CREATE_EXIT2, this, KErrNoMemory );
 		return KErrNoMemory;
-	    }
-	
-	
+		}
+	if (iDfcQ)
+		{
+		iBody->iMediaChangeDfc.SetDfcQ(iDfcQ);
+		iBody->iMediaPresentDfc.SetDfcQ(iDfcQ);
+		}
 
 #ifdef __DEMAND_PAGING__
 	TInt pageSize = Kern::RoundToPageSize(1);
@@ -1697,7 +1882,7 @@
 	
 	NKern::LockSystem();
 	TBool first=iConnectionQ.IsEmpty();
-	iConnectionQ.Add(&aLocalDrive->iLink);
+	iConnectionQ.Add(&aLocalDrive->iMediaChangeObserver.iLink);
 	NKern::UnlockSystem();
 	if (first)
 		{
@@ -1765,6 +1950,52 @@
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_DISCONNECT_EXIT2, this );
 	}
 
+
+/**
+Connects a TLocDrv containing a media extension to the next primary media in the chain
+*/
+TInt DPrimaryMediaBase::Connect(TLocDrv* aLocDrv)
+	{
+	TInt r = KErrNone;
+
+	NKern::LockSystem();
+	TBool first = iConnectionQ.IsEmpty();
+	iConnectionQ.Add(&aLocDrv->iMediaChangeObserver.iLink);
+	NKern::UnlockSystem();
+
+	if (first && !iDfcQ)
+		{
+		r = OpenMediaDriver();
+		if (r!=KErrNone)
+			{
+			NKern::LockSystem();
+			aLocDrv->iMediaChangeObserver.iLink.Deque();
+			NKern::UnlockSystem();
+			}
+		}
+	return r;
+	}
+
+TInt DPrimaryMediaBase::HandleMediaNotPresent(TLocDrvRequest& aReq)
+	{
+	TInt reqId = aReq.Id();
+
+	if (reqId == DLocalDrive::ECaps)
+		DefaultDriveCaps(*(TLocalDriveCapsV2*)aReq.RemoteDes());	// fill in stuff we know even if no media present
+
+	TInt r = QuickCheckStatus();
+	if (r != KErrNone && 
+		reqId != DLocalDrive::EForceMediaChange &&			// EForceMediaChange, and 
+		reqId != DLocalDrive::EReadPasswordStore &&			// Password store operations 
+		reqId != DLocalDrive::EWritePasswordStore &&			// do not require the media 
+		reqId != DLocalDrive::EPasswordStoreLengthInBytes)	// to be ready.)
+ 	 	{
+		return r;
+ 	  	}
+
+	return KErrNone;
+	}
+
 EXPORT_C TInt DPrimaryMediaBase::Request(TLocDrvRequest& aReq)
 /**
 Issues a local drive request. It is called from TLocDrv::Request() function .
@@ -1785,7 +2016,7 @@
 @see TLocDrvRequest
 */
 	{
-OstTraceFunctionEntry1( DPRIMARYMEDIABASE_REQUEST_ENTRY, this );
+	OstTraceFunctionEntry1( DPRIMARYMEDIABASE_REQUEST_ENTRY, this );
 
 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Request(%08x)",iMediaId,&aReq));
 	__KTRACE_OPT(KLOCDRV,Kern::Printf("this=%x, ReqId=%d, Pos=%lx, Len=%lx, remote thread %O",this,aReq.Id(),aReq.Pos(),aReq.Length(),aReq.RemoteThread()));
@@ -1794,18 +2025,13 @@
 	
 	TInt reqId = aReq.Id();
 
-	if (reqId == DLocalDrive::ECaps)
-		DefaultDriveCaps(*(TLocalDriveCapsV2*)aReq.RemoteDes());	// fill in stuff we know even if no media present
-
-	TInt r = QuickCheckStatus();
-	if (r != KErrNone && aReq.Id()!=DLocalDrive::EForceMediaChange &&			// EForceMediaChange, and 
- 			 			 aReq.Id()!=DLocalDrive::EReadPasswordStore &&			// Password store operations 
- 						 aReq.Id()!=DLocalDrive::EWritePasswordStore &&			// do not require the media 
- 						 aReq.Id()!=DLocalDrive::EPasswordStoreLengthInBytes)	// to be ready.)
- 	 	{
+	TInt r = HandleMediaNotPresent(aReq);
+	if (r != KErrNone)
+		{
 		OstTraceFunctionExitExt( DPRIMARYMEDIABASE_REQUEST_EXIT, this, r );
 		return r;
- 	  	}
+		}
+
  	  	
 
 	// for ERead & EWrite requests, get the linear address for pinning & DMA
@@ -2250,7 +2476,7 @@
 		case EConnect:
 			{
 			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
-			iConnectionQ.Add(&pD->iLink);
+			iConnectionQ.Add(&pD->iMediaChangeObserver.iLink);
 			m.Complete(KErrNone, EFalse);
 			OstTraceFunctionExit1( DPRIMARYMEDIABASE_HANDLEMSG_EXIT1, this );
 			return;
@@ -2274,6 +2500,22 @@
 			{
 			TUint flags = (TUint) m.Pos();
 
+			// For media extension drivers, send a copy of the request to the next drive in the chain and wait for it. 
+			TLocDrv* drv = m.Drive();
+			if (drv->iNextDrive)
+				{
+				TLocDrvRequest request;
+				request.Drive() = drv->iNextDrive;
+				request.Id() = DLocalDrive::EForceMediaChange;
+				request.Pos() = m.Pos();	// flags
+
+				request.SendReceive(&drv->iNextDrive->iPrimaryMedia->iMsgQ);
+
+				CompleteRequest(m, request.iValue);
+				return;
+				}
+
+
 			// if KForceMediaChangeReOpenDriver specified wait for power up, 
 			// and then re-open this drive's media driver
 			__KTRACE_OPT(KLOCDRV, Kern::Printf("EForceMediaChange, flags %08X\n", flags));
@@ -2504,18 +2746,18 @@
 	if (m.iValue == DLocalDrive::EForceMediaChange)
 		{
 		__ASSERT_DEBUG(((TUint) m.Pos()) == (TUint) KForceMediaChangeReOpenMediaDriver, LOCM_FAULT());
-
 		iCurrentReq=NULL;
 
 		TLocDrv* pL = m.Drive();
 		DMedia* media = pL->iMedia;
+
 		if (media && media->iDriver)
 			CloseMediaDrivers(media);
 
 		iState=EOpening;
 		StartOpenMediaDrivers();
 
-		NotifyClients(ETrue,pL);
+		NotifyClients(EMediaChange, pL);
 		CompleteRequest(m, r);
 		OstTraceFunctionExitExt( DPRIMARYMEDIABASE_DOREQUEST_EXIT, this, r );
 		return r;
@@ -2542,7 +2784,7 @@
 		if (!(m.Flags() & TLocDrvRequest::EAdjusted))
 			{
 			// If this isn't the only partition, don't allow access to the whole media 
-			if (iTotalPartitionsOpened > 1)
+			if (TDriveIterator::GetPhysicalDrive(m.Drive())->iPrimaryMedia->iTotalPartitionsOpened > 1)
 				m.DriverFlags() &= ~RLocalDrive::ELocDrvWholeMedia;
 			r=m.CheckAndAdjustForPartition();
 			}
@@ -2686,7 +2928,7 @@
 	// we mustn't ever close the media driver if it's responsible for data paging as re-opening the drive
 	// would involve memory allocation which might cause deadlock if the kernel heap were to grow
 #ifdef __DEMAND_PAGING__
-	if (DataPagingDfcQ(this))
+	if (DataPagingMedia(this))
 		{
 		__KTRACE_OPT(KLOCDRV,Kern::Printf("CloseMediaDrivers aborting for data paging media %08X", this));
 		OstTrace1(TRACE_FLOW, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS_EXIT1, "CloseMediaDrivers aborting for data paging media 0x%08x", this);
@@ -2694,21 +2936,30 @@
 		}
 #endif
 
-	TInt i;
-	for (i=0; i<KMaxLocalDrives; i++)
+
+	// Don't close any media extension drivers either, since it won't serve any purpose
+	// and keeping the driver open allows it to maintain internal state
+	if (iBody->iMediaExtension)
 		{
-		TLocDrv* pL=TheDrives[i];
+		__KTRACE_OPT(KLOCDRV,Kern::Printf("CloseMediaDrivers aborting for extension media %08X", this));
+		return;
+		}
+
+
+	TDriveIterator driveIter;
+	for (TLocDrv* pL = driveIter.NextDrive(); pL != NULL; pL = driveIter.NextDrive())
+		{
 		if (pL && pL->iPrimaryMedia==this)
 			{
-			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d",i));
-			OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS2, "Drive=%d", i );
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d",driveIter.Index()));
+			OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_CLOSEMEDIADRIVERS2, "Drive=%d", driveIter.Index());
 			if (aMedia == NULL || pL->iMedia == aMedia)
 				{
 				pL->iMedia=NULL;
 				}
 			}
 		}
-	for (i=iLastMediaId; i>=iMediaId; i--)
+	for (TInt i=iLastMediaId; i>=iMediaId; i--)
 		{
 		DMedia* pM=TheMedia[i];
 		if (aMedia == NULL || pM == aMedia)
@@ -2865,7 +3116,7 @@
 		if (pM->iDriver)
 			{
 #ifdef __DEMAND_PAGING__
-			if (DataPagingDfcQ(this))
+			if (DataPagingMedia(this))
 				{
 				__KTRACE_OPT(KLOCDRV,Kern::Printf("DoPartitionInfoComplete(%d) Close Media Driver aborted for data paging media %08X", this));
 				OstTraceDef1(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE2, "Close Media Driver for data paging media 0x%08x", this);
@@ -2931,10 +3182,10 @@
 	TInt id=iMediaId;	// start with primary media
 	TInt partitionsOnThisMedia=PartitionCount();
 	TInt partition=0;
-	TInt j;
-	for (j=0; j<KMaxLocalDrives; j++)
+
+	TDriveIterator driveIter;
+	for (TLocDrv* pD = driveIter.NextDrive(); pD != NULL; pD = driveIter.NextDrive())
 		{
-		TLocDrv* pD=TheDrives[j];
 		if (pD && pD->iPrimaryMedia==this)
 			{
 			if (totalPartitions==0)
@@ -2948,9 +3199,8 @@
 				partition=0;
 				partitionsOnThisMedia=TheMedia[id]->PartitionCount();
 				}
-			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d = Media %d Partition %d",j,id,partition));
-			OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE5, "Local Drive=%d; iMediaId=%d; partition=%d", j, id, partition );
-			
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d = Media %d Partition %d",driveIter.Index(),id,partition));
+			OstTraceExt3( TRACE_INTERNALS, DPRIMARYMEDIABASE_DOPARTITIONINFOCOMPLETE5, "Local Drive=%d; iMediaId=%d; partition=%d", driveIter.Index(), id, partition );
 			pD->iMedia=TheMedia[id];
 			pD->iPartitionNumber=partition;
 			memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
@@ -3216,10 +3466,10 @@
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_SETCLOSED_EXIT, this );
 	}
 
-void DPrimaryMediaBase::NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv)
+void DPrimaryMediaBase::NotifyClients(TNotifyType aNotifyType, TLocDrv* aLocDrv)
 
 //
-// Notify all clients of a media change or power-down event
+// Notify all clients of a media change or media present event
 //
 	{
 	OstTraceFunctionEntryExt( DPRIMARYMEDIABASE_NOTIFYCLIENTS_ENTRY, this );
@@ -3227,11 +3477,23 @@
 	SDblQueLink* pL=iConnectionQ.iA.iNext;
 	while (pL!=&iConnectionQ.iA)
 		{
-		DLocalDrive* pD=_LOFF(pL,DLocalDrive,iLink);
+		// Get pointer to TCallBackLink
+		TCallBackLink* pCallBackLink = _LOFF(pL,TCallBackLink,iLink);
+
+		// The link is embedded in either a TLocDrv or a  DLocalDrive object;
+		// find out which one it is and then get TLocDrv pointer from that
+		__ASSERT_DEBUG(pCallBackLink->iObjectType == TCallBackLink::EDLocalDriveObject || pCallBackLink->iObjectType == TCallBackLink::ETLocDrvObject, LOCM_FAULT());
+		TLocDrv* locDrv;
+		if (pCallBackLink->iObjectType == TCallBackLink::EDLocalDriveObject)
+			locDrv = ((DLocalDrive*) _LOFF(pCallBackLink,DLocalDrive, iMediaChangeObserver))->iDrive;
+		else
+			locDrv = ((TLocDrv*) _LOFF(pCallBackLink,TLocDrv, iMediaChangeObserver))->iNextDrive;
+
 		// Issue the notification if the caller wants to notify all drives (aLocDrv == NULL) or 
 		// the specified drive matches this one
-		if (aLocDrv == NULL || aLocDrv == pD->iDrive)
-			pD->NotifyChange(*this, aMediaChange);
+		if (aLocDrv == NULL || aLocDrv == locDrv)
+			pCallBackLink->CallBack(aNotifyType);
+
 		pL=pL->iNext;
 		}
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYCLIENTS_EXIT, this );
@@ -3249,32 +3511,13 @@
 
 	OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_MEDIACHANGE, DPRIMARYMEDIABASE_NOTIFYMEDIACHANGE, "iMediaId=%d; iState=%d", iMediaId, iState );
 	
-	TInt state=iState;
-
-	__ASSERT_DEBUG(iBody, LOCM_FAULT());
-
-#ifdef __DEMAND_PAGING__
-	iBody->iMediaChanges++;
-
-	// As data paging media never close, need to ensure the media driver cancels
-	// any requests it owns as the stack may be powered down by DPBusPrimaryMedia::ForceMediaChange().
-	// DMediaDriver::NotifyPowerDown() should do this
-	if(DataPagingDfcQ(this))
-		NotifyPowerDown();
-#endif
-
-	// complete any outstanding requests with KErrNotReady
-	// and any force media change requests with KErrNone
-	SetClosed(KErrNotReady);
-
-	// close all media drivers on this device
-	if (state>=EOpening)
-		{
-		CloseMediaDrivers();
-		}
+	// This should only be called in the context of the media thread
+	__ASSERT_ALWAYS(NKern::CurrentThread() == iDfcQ->iThread, LOCM_FAULT());
+
+	MediaChange();
 
 	// notify all connections that media change has occurred
-	NotifyClients(ETrue);
+	NotifyClients(EMediaChange);
 
 	// complete any force media change requests
 	iWaitMedChg.CompleteAll(KErrNone);
@@ -3343,8 +3586,6 @@
 		CloseMediaDrivers();
 		SetClosed(KErrNotReady);
 		}
-
-	NotifyClients(EFalse);
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYPOWERDOWN_EXIT, this );
 	}
 
@@ -3414,17 +3655,56 @@
 		}
 	CloseMediaDrivers();
 	SetClosed(KErrNotReady);
-	NotifyClients(EFalse);
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYEMERGENCYPOWERDOWN_EXIT, this );
 	}
 
+
+/**
+Called by NotifyMediaPresent() and NotifyMediaChange() to ensure the media is in the correct state
+*/
+void DPrimaryMediaBase::MediaChange()
+	{
+	// Media has been inserted, so we need to cancel any outstanding requests and 
+	// ensure that the partition info is read again
+	TInt state = iState;
+
+	__ASSERT_DEBUG(iBody, LOCM_FAULT());
+
+#ifdef __DEMAND_PAGING__
+	iBody->iMediaChanges++;
+
+	// As data paging media never close, need to ensure the media driver cancels
+	// any requests it owns as the stack may be powered down by DPBusPrimaryMedia::ForceMediaChange().
+	// DMediaDriver::NotifyPowerDown() should do this
+	if (DataPagingMedia(this))
+		NotifyPowerDown();
+#endif
+
+	// complete any outstanding requests with KErrNotReady
+	// and any force media change requests with KErrNone
+	SetClosed(KErrNotReady);
+
+	// close all media drivers on this device
+	if (state>=EOpening)
+		{
+		CloseMediaDrivers();
+		}
+	}
+
 EXPORT_C void DPrimaryMediaBase::NotifyMediaPresent()
 /**
 Notifies clients of a media change by calling NotifyClients ( ) function to indicate that media is present.
 */
 	{
 	OstTraceFunctionEntry1( DPRIMARYMEDIABASE_NOTIFYMEDIAPRESENT_ENTRY, this );
-	NotifyClients(ETrue);
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyMediaPresent state %d",iMediaId,iState));
+
+	// This should only be called in the context of the media thread
+	__ASSERT_ALWAYS(NKern::CurrentThread() == iDfcQ->iThread, LOCM_FAULT());
+
+	MediaChange();
+
+	NotifyClients(EMediaPresent);
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYMEDIAPRESENT_EXIT, this );
 	}
 
@@ -3575,10 +3855,10 @@
 		TInt id=iMediaId;	// start with primary media
 		TInt partitionsOnThisMedia=PartitionCount();
 		TInt partition=0;
-		TInt j;
-		for (j=0; j<KMaxLocalDrives; j++)
+		
+		TDriveIterator driveIter;
+		for (TLocDrv* pD = driveIter.NextDrive(); pD != NULL; pD = driveIter.NextDrive())
 			{
-			TLocDrv* pD=TheDrives[j];
 			if (pD && pD->iPrimaryMedia==this)
 				{
 				if (totalPartitions==0)
@@ -3939,7 +4219,7 @@
 	TInt retVal = KErrGeneral;
 	for (TInt i=0; retVal != KErrNone && i < KPageInRetries; i++)
 		{
-		m.Flags() = TLocDrvRequest::EPaging;
+		m.Flags() = TLocDrvRequest::EKernelBuffer | TLocDrvRequest::EPaging;
 		TLocDrv* pL=NULL;
 		if(aDrvNumber == EDriveRomPaging)					// ROM paging
 			{
@@ -3978,7 +4258,7 @@
 			m.Id() = DMediaPagingDevice::ECodePageInRequest;
 			m.Flags() |= TLocDrvRequest::ECodePaging;
 			pL=TheDrives[aDrvNumber];
-			__ASSERT_DEBUG(pL&&(pL->iPrimaryMedia==iPrimaryMedia),LOCM_FAULT());	// valid drive number?
+			__ASSERT_DEBUG(pL && TDriveIterator::GetDrive(aDrvNumber, iPrimaryMedia) ,LOCM_FAULT());	// valid drive number?
 			m.Drive()=pL;
 #ifdef __DEMAND_PAGING_BENCHMARKS__
 			__e32_atomic_add_ord32(&iMediaPagingInfo.iCodePageInCount, (TUint) 1);
@@ -4101,7 +4381,7 @@
 	TInt retVal = KErrGeneral;
 	for (TInt i=0; retVal != KErrNone && i < KPageOutRetries; i++)
 		{
-		m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging | (aBackground ? TLocDrvRequest::EBackgroundPaging : 0);
+		m.Flags() = TLocDrvRequest::EKernelBuffer | TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging | (aBackground ? TLocDrvRequest::EBackgroundPaging : 0);
 
 		m.Id() = DLocalDrive::EWrite;
 		m.Drive() = TheDrives[iDataPagingDriveNumber];
@@ -4197,7 +4477,7 @@
 	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
 
 
-	m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging;
+	m.Flags() = TLocDrvRequest::EKernelBuffer | TLocDrvRequest::EPaging  | TLocDrvRequest::EDataPaging;
 	m.Id() = DLocalDrive::EDeleteNotify;
 	m.Drive() = TheDrives[iDataPagingDriveNumber];
 
@@ -4230,7 +4510,6 @@
 	}
 
 
-
 EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset)
 	{
 	OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITETOPAGEHANDLER_ENTRY, this );
@@ -4418,6 +4697,28 @@
 	OstTraceFunctionExit1( DMEDIADRIVER_SETTOTALSIZEINBYTES_EXIT, this );
 	}
 
+/**
+For non NAND devices, i.e. devices which don't set TLocalDriveCapsV4::iNumOfBlocks,
+set iSectorSizeInBytes, iNumberOfSectors & iNumPagesPerBlock appropriately to allow 
+TLocalDriveCapsV4::MediaSizeInBytes() to correctly return the media size
+
+Media drivers should call this when they receive a DLocalDrive::ECaps request
+*/
+EXPORT_C void DMediaDriver::SetTotalSizeInBytes(TLocalDriveCapsV4& aCaps)
+	{
+	if (aCaps.iNumOfBlocks == 0)
+		{
+		aCaps.iSectorSizeInBytes = 512;
+		aCaps.iNumPagesPerBlock = 1;	// ...to ensure compatibility with NAND semantics
+		Int64 numberOfSectors = iTotalSizeInBytes >> 9;
+		while (I64HIGH(numberOfSectors) > 0)
+			{
+			aCaps.iNumPagesPerBlock<<= 1;
+			numberOfSectors>>= 1;
+			}
+		aCaps.iNumberOfSectors = I64LOW(numberOfSectors);
+		}
+	}
 
 
 
@@ -4649,37 +4950,25 @@
 	// Create TLocDrv / DMedia objects to handle a media device
 	__KTRACE_OPT(KBOOT,Kern::Printf("RegisterMediaDevice %lS dev=%1d #drives=%d 1st=%d PM=%08x #media=%d",&aName,aDevice,aDriveCount,*aDriveList,aPrimaryMedia,aNumMedia));
 	OstTraceExt5( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE1, "aDevice=%d; aDriveCount=%d; aDriveList=%d; aPrimaryMedia=0x%08x; aNumMedia=%d", (TInt) aDevice, (TInt) aDriveCount, (TInt) *aDriveList, (TUint) aPrimaryMedia, (TInt) aNumMedia );
-	
-	const TInt* p=aDriveList;
-	TInt i;
-	TInt r=0;
+
 	if (UsedMedia+aNumMedia>KMaxLocalDrives)
 	    {
 		OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT1, "< KErrInUse");
 		return KErrInUse;
-	    }
-	for (i=0; i<aDriveCount; ++i)
-		{
-		TInt drv = *p++;
-		// -1 means not used; this is to enable Dual-slot MMC support 
-		if (drv == -1)
-			continue;
-		__KTRACE_OPT(KBOOT,Kern::Printf("Registering drive %d", drv));
-		OstTrace1( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE2, "Registering drive=%d", drv );
-		if (TheDrives[drv])
-			{
-			__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d already in use", drv));
-			OstTrace1( TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT2, "< Drive %d already in use; KErrInUse", drv);
-			return KErrInUse;
-			}
 		}
+
+	// make a local copy of the name
 	HBuf* pN=HBuf::New(aName);
 	if (!pN)
 	    {
         OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT3, "< KErrNoMemory");
 		return KErrNoMemory;
-	    }
-	TInt lastMedia=UsedMedia+aNumMedia-1;
+		}
+
+	// Register the primary media and any secondary media
+	TInt lastMedia = UsedMedia+aNumMedia-1;
+	TInt i;
+	TInt r=0;
 	for (i=UsedMedia; i<=lastMedia; ++i)
 		{
 		if (i==UsedMedia)
@@ -4700,29 +4989,88 @@
 			return r;
 		    }
 		}
-
 	__KTRACE_OPT(KBOOT,Kern::Printf("FirstMedia %d LastMedia %d",UsedMedia,lastMedia));
 	OstTraceExt2( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE4, "FirstMedia=%d; LastMedia=%d", UsedMedia, lastMedia );
 	UsedMedia+=aNumMedia;
-	p=aDriveList;
+
+	if (__IS_EXTENSION(aDevice))
+		aPrimaryMedia->iBody->iMediaExtension = ETrue;
+
+	// Register the drives
+	const TInt* p=aDriveList;
 	for (i=0; i<aDriveCount; ++i)
 		{
-		TInt drv=*p++;
+		TInt drv = *p++;
+		// -1 means not used; this is to enable Dual-slot MMC support 
 		if (drv == -1)
 			continue;
-		TLocDrv* pL=new TLocDrv(drv);
-		if (!pL)
-		    {
+
+		__KTRACE_OPT(KBOOT,Kern::Printf("Registering drive %d", drv));
+		if (!__IS_EXTENSION(aDevice) && TheDrives[drv])
+			{
+			__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d already in use", drv));
+			return KErrInUse;
+			}
+		else if (__IS_EXTENSION(aDevice) && !TheDrives[drv])
+			{
+			__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d not initialized", drv));
+			return KErrNotReady;
+			}
+
+		TLocDrv* pNewDrive = new TLocDrv(drv);
+		if (!pNewDrive)
+			{
             OstTrace0(TRACE_FLOW, LOCDRV_REGISTERMEDIADEVICE_EXIT6, "< KErrNoMemory");
 			return KErrNoMemory;
-		    }
-		TheDrives[drv]=pL;
-		DriveNames[drv]=pN;
-		pL->iPrimaryMedia=aPrimaryMedia;
-		__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d: TLocDrv @ %08x",drv,pL));
-		OstTraceExt2( TRACE_INTERNALS, LOCDRV_REGISTERMEDIADEVICE5, "Drive=%d; TLocDrv 0x%08x;", (TInt) drv, (TUint) pL );
+			}
+
+
+		TLocDrv* pOldDrive = TheDrives[drv];
+		aPrimaryMedia->iBody->iRegisteredDriveMask|= (0x1 << drv);
+		pNewDrive->iNextDrive = pOldDrive;
+
+		TheDrives[drv] = pNewDrive;
+		DriveNames[drv] = pN;
+		pNewDrive->iPrimaryMedia = aPrimaryMedia;
+
+
+		if (pOldDrive)
+			{
+			TInt r = pOldDrive->iPrimaryMedia->Connect(pNewDrive);
+			if (r != KErrNone)
+				return r;
+
+#ifdef __DEMAND_PAGING__
+			// If we've hooked a drive letter which is being used for ROM paging by a media driver
+			// which does not report the ROM partition, then we need to change iFirstLocalDriveNumber
+			// so that ROM page-in requests go directly to that driver
+			DMediaPagingDevice* oldPagingDevice = pOldDrive->iPrimaryMedia->iBody->iPagingDevice;
+			if (oldPagingDevice && 
+				(oldPagingDevice->iType & DPagingDevice::ERom) &&
+				oldPagingDevice->iRomPagingDriveNumber == KErrNotFound && 
+				oldPagingDevice->iFirstLocalDriveNumber == drv)
+				{
+				__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("TRACE: hooking ROM paging device with no defined ROM partition"));
+				TInt n;
+				for (n=0; n<KMaxLocalDrives; ++n)
+					{
+					if(TheDrives[n] && TheDrives[n]->iPrimaryMedia == pOldDrive->iPrimaryMedia)
+						{
+						__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("TRACE: Changing iFirstLocalDriveNumber from %d to %d", oldPagingDevice->iFirstLocalDriveNumber, n));
+						oldPagingDevice->iFirstLocalDriveNumber = n;
+						break;
+						}
+					}
+				__ASSERT_ALWAYS(n < KMaxLocalDrives, LOCM_FAULT());
+				}
+#endif
+
+			}
+
+		__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d: TLocDrv @ %08x",drv,pNewDrive));
 		}
 
+
 	OstTraceFunctionExit0( LOCDRV_REGISTERMEDIADEVICE_EXIT7 );
 	return KErrNone;
 	}
@@ -4807,11 +5155,12 @@
 EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* aPrimaryMedia, const TInt* aPagingDriveList, TInt aDriveCount, TUint aPagingType, TInt aReadShift, TUint aNumPages)
 	{
 	OstTraceFunctionEntry0( LOCDRV_REGISTERPAGINGDEVICE_ENTRY );
+//	SETDEBUGFLAG(KLOCDPAGING);
 	
 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf(">RegisterPagingDevice: paging type=%d PM=0x%x read shift=%d",aPagingType,aPrimaryMedia,aReadShift));
 	OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE1, "aPagingType=%d; aPrimaryMedia=0x%x; aReadShift=%d", (TInt) aPagingType, (TUint) aPrimaryMedia, (TInt) aReadShift);
 	
-	TInt i;
+	TInt i = 0;
 
 	if(!aPagingType || (aPagingType&~(DPagingDevice::ERom | DPagingDevice::ECode | DPagingDevice::EData)))
 		{
@@ -4821,20 +5170,23 @@
 		}
 
 
-
-	for(i=0; i<KMaxLocalDrives; i++)
+	// Check for duplicate drives
+	if (!aPrimaryMedia->iBody->iMediaExtension)
 		{
-		if (ThePagingDevices[i] == NULL)
-			continue;
-		if ((ThePagingDevices[i]->iType&DPagingDevice::ERom) &&	(aPagingType & DPagingDevice::ERom))
+		for(i=0; i<KMaxLocalDrives; i++)
 			{
-			aPagingType&=~DPagingDevice::ERom;		// already have a ROM paging device
-			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has ROM pager on locdrv no %d",i));
-			}
-		if ((ThePagingDevices[i]->iType&DPagingDevice::EData) && (aPagingType & DPagingDevice::EData))
-			{
-			aPagingType&=~DPagingDevice::EData;		// already have a Data paging device
-			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has Data pager on locdrv no %d",i));
+			if (ThePagingDevices[i] == NULL)
+				continue;
+			if ((ThePagingDevices[i]->iType&DPagingDevice::ERom) &&	(aPagingType & DPagingDevice::ERom))
+				{
+				aPagingType&=~DPagingDevice::ERom;		// already have a ROM paging device
+				__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has ROM pager on locdrv no %d",i));
+				}
+			if ((ThePagingDevices[i]->iType&DPagingDevice::EData) && (aPagingType & DPagingDevice::EData))
+				{
+				aPagingType&=~DPagingDevice::EData;		// already have a Data paging device
+				__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has Data pager on locdrv no %d",i));
+				}
 			}
 		}
 
@@ -4915,12 +5267,16 @@
 	
 	// Send an ECaps message to wake up the media driver & ensure all partitions are 
 	// reported, then search for paged-data or paged-ROM partitions
+	// NB: older media drivers supporting ROM and/or code paging only may not have started their DFC queues, 
+	// so for these media drivers, use the first local drive supported for ROM-pagin-in  requests and
+	// assume the media driver itself will adjust the request position internally to match the ROM partition
+	// @see DMediaPagingDevice::Read()
 	if ((aPagingType & DPagingDevice::EData) ||
 		(aPagingType & DPagingDevice::ERom && aPrimaryMedia->iDfcQ && aPrimaryMedia->iMsgQ.iReady))
 		{
 		// the message queue must have been started already (by the media driver calling iMsgQ.Receive())
-		// otherwise we can't send the DLocalDrive::EQueryDevice request
-		if (aPrimaryMedia->iDfcQ && !aPrimaryMedia->iMsgQ.iReady)
+		// otherwise we can't send the DLocalDrive::ECaps request
+		if (!aPrimaryMedia->iDfcQ || !aPrimaryMedia->iMsgQ.iReady)
 			{
 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: Message queue not started"));
 			OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT8, "< RegisterPagingDevice: Message queue not started; KErrNotReady");
@@ -4955,7 +5311,7 @@
 
 		if (r != KErrNone)
 		    {
-            OstTrace1(TRACE_FLOW, LOCRV_REGISTERPAGINGDEVICE_EXIT9, "< Caps::retval=%d - return KErrNotSupported",r);
+            OstTrace1(TRACE_FLOW, LOCRV_REGISTERPAGINGDEVICE_EXIT9, "< retval=%d",r);
             // Media driver failure; media maybe recoverable after boot.
             // Can't register any page drives so return not supported.
 			return KErrNotSupported;
@@ -4967,20 +5323,25 @@
 			drive = TheDrives[i];
 			if(drive && drive->iPrimaryMedia == aPrimaryMedia)
 				{
-				__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("RegisterPagingDevice: local drive %d, partition type %x size %x", i, drive->iPartitionType, I64LOW(drive->iPartitionLen)));
+				__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("RegisterPagingDevice: local drive %d, partition type %x base %lx size %lx name %lS", i, drive->iPartitionType, drive->iPartitionBaseAddr, drive->iPartitionLen, DriveNames[i] ? DriveNames[i] : &KNullDesC8));
 				// ROM partition ?
-				if ((romPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypeROM))
+				if ((romPagingDriveNumber == KErrNotFound) && 
+					(drive->iPartitionType == KPartitionTypeROM) &&
+					(aPagingType & DPagingDevice::ERom))
 					{
 					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found ROM partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
 					OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE5, "Found ROM partition on local drive=%d; size=0x%x", (TInt) i, (TUint) I64LOW(drive->iPartitionLen));
 					romPagingDriveNumber = i;
 					}
 			    // swap partition ?
-				else if ((dataPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypePagedData))
+				else if ((dataPagingDriveNumber == KErrNotFound) && 
+					(drive->iPartitionType == KPartitionTypePagedData) &&
+					(aPagingType & DPagingDevice::EData))
 					{
 					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found swap partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
 					OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, LOCDRV_REGISTERPAGINGDEVICE6, "Found SWAP partition on local drive=%d; size=0x%x", (TInt) i, (TUint) I64LOW(drive->iPartitionLen) );			
 					dataPagingDriveNumber = i;
+					TheDataPagingDrive = drive;
 					swapSize = drive->iPartitionLen >> aReadShift;
 					}
 				}
@@ -5006,6 +5367,9 @@
 		}
 
 	pagingDevice->iType = aPagingType;
+	if (aPrimaryMedia->iBody->iMediaExtension)
+		pagingDevice->iType|= DPagingDevice::EMediaExtension;
+
 	pagingDevice->iReadUnitShift = aReadShift;
 
 	pagingDevice->iFirstLocalDriveNumber = firstLocalDriveNumber;
@@ -5016,12 +5380,13 @@
 
 #ifdef __DEBUG_DEMAND_PAGING__
 	Kern::Printf("PagingDevice :");
-	Kern::Printf("iType 0x%x\n", pagingDevice->iType);
-	Kern::Printf("iReadUnitShift 0x%x\n", pagingDevice->iReadUnitShift);
-	Kern::Printf("iFirstLocalDriveNumber 0x%x\n", pagingDevice->iFirstLocalDriveNumber);
-	Kern::Printf("iRomPagingDriveNumber 0x%x\n", pagingDevice->iRomPagingDriveNumber);
-	Kern::Printf("iDataPagingDriveNumber 0x%x\n", pagingDevice->iDataPagingDriveNumber);
-	Kern::Printf("iSwapSize 0x%x\n", pagingDevice->iSwapSize);
+	Kern::Printf("Name %lS", firstLocalDriveNumber >= 0 && DriveNames[firstLocalDriveNumber] ? DriveNames[firstLocalDriveNumber] : &KNullDesC8);
+	Kern::Printf("iType 0x%x", pagingDevice->iType);
+	Kern::Printf("iReadUnitShift 0x%x", pagingDevice->iReadUnitShift);
+	Kern::Printf("iFirstLocalDriveNumber 0x%x", pagingDevice->iFirstLocalDriveNumber);
+	Kern::Printf("iRomPagingDriveNumber 0x%x", pagingDevice->iRomPagingDriveNumber);
+	Kern::Printf("iDataPagingDriveNumber 0x%x", pagingDevice->iDataPagingDriveNumber);
+	Kern::Printf("iSwapSize 0x%x", pagingDevice->iSwapSize);
 #endif
 
 
@@ -5042,24 +5407,38 @@
 	if(aPagingType & DPagingDevice::ECode)
 		{
 		for (i=0; i<aDriveCount; ++i)
-			pagingDevice->iDrivesSupported|=(0x1<<aPagingDriveList[i]);
+			pagingDevice->iDrivesSupported |= (0x1<<aPagingDriveList[i]);
 		}
 	pagingDevice->iName = DeviceName[aPagingType];
 
+	// If ThePinObjectAllocator has already been created with a smaller number of pages,
+	// delete it & then re-create it
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: ThePinObjectAllocator %x", ThePinObjectAllocator));
+	if (ThePinObjectAllocator && ThePinObjectAllocator->iFragmentGranularity < Kern::RoundToPageSize(1) * aNumPages)
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: Recreating ThePinObjectAllocator..."));
+		delete ThePinObjectAllocator;
+		ThePinObjectAllocator = NULL;
+		}
+
+
+	TInt r;
 	if (ThePinObjectAllocator == NULL)
-		ThePinObjectAllocator = new DPinObjectAllocator();
-	if(!ThePinObjectAllocator)
 		{
-		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create ThePinObjectAllocator"));
-		OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT11, "RegisterPagingDevice: could not create ThePinObjectAllocator; KErrNoMemory");
-		return KErrNoMemory;
-		}
-	TInt r = ThePinObjectAllocator->Construct(KDynamicPagingLockCount, aNumPages);
-	if (r != KErrNone)
-		{
-		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not construct ThePinObjectAllocator"));
-		OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT12, "< RegisterPagingDevice: could not construct ThePinObjectAllocator; retval=%d",r);
-		return r;
+		ThePinObjectAllocator = new DPinObjectAllocator();
+		if(!ThePinObjectAllocator)
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create ThePinObjectAllocator"));
+			OstTrace0(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT11, "RegisterPagingDevice: could not create ThePinObjectAllocator; KErrNoMemory");
+			return KErrNoMemory;
+			}
+		r = ThePinObjectAllocator->Construct(KDynamicPagingLockCount, aNumPages);
+		if (r != KErrNone)
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not construct ThePinObjectAllocator"));
+			OstTrace1(TRACE_FLOW, LOVDRV_REGISTERPAGINGDEVICE_EXIT12, "< RegisterPagingDevice: could not construct ThePinObjectAllocator; retval=%d",r);
+			return r;
+			}
 		}
 
 
@@ -5089,7 +5468,14 @@
 		for (i=0; i<aDriveCount; ++i)
 			{
 			TLocDrv* pD=TheDrives[*p++];
-			pD->iPagingDrv=1;
+			pD->iPagingDrv = 1;
+			// mark all attached drives as pageable too - this is really 
+			// only to avoid hitting an ASSERT in DMediaDriver::Complete()
+			while (pD->iNextDrive)
+				{
+				pD->iNextDrive->iPagingDrv = 1;
+				pD = pD->iNextDrive;
+				}
 			}
 		}
 
@@ -5133,6 +5519,7 @@
 
 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("< RegisterPagingDevice"));
 	OstTraceFunctionExit0( LOCDRV_REGISTERPAGINGDEVICE_EXIT14 );
+//	CLRDEBUGFLAG(KLOCDPAGING);
 	return KErrNone;
 	}
 
@@ -5208,6 +5595,7 @@
 		TLocDrv* pL=TheDrives[i];
 		if (pL)
 			{
+			pL = TDriveIterator::GetPhysicalDrive(TheDrives[i]);
 			++drives;
 			TInt sockNum;
 			DPrimaryMediaBase* pM=pL->iPrimaryMedia;
@@ -5347,11 +5735,7 @@
 #if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
 		case EMediaHalGetROMConcurrencyInfo:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ERom);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5363,11 +5747,7 @@
 			}
 		case EMediaHalGetCodeConcurrencyInfo:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ECode);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5379,11 +5759,7 @@
 			}
 		case EMediaHalGetDataConcurrencyInfo:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::EData);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5395,17 +5771,20 @@
 			}
 		case EMediaHalResetConcurrencyInfo:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
-			if(!device)
-				break;
 			TUint index=(TInt)a2;
 			if(index>EMediaPagingStatsCode)
 				break;
-			ResetConcurrencyStats(device, (TMediaPagingStats)index);
+
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ERom);
+			if (device)
+				ResetConcurrencyStats(device, (TMediaPagingStats)index);
+			device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ECode);
+			if (device)
+				ResetConcurrencyStats(device, (TMediaPagingStats)index);
+			device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::EData);
+			if (device)
+				ResetConcurrencyStats(device, (TMediaPagingStats)index);
+
 			r=KErrNone;
 			break;
 			}
@@ -5413,11 +5792,7 @@
 #if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
 		case EMediaHalGetROMPagingBenchmark:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ERom);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5429,11 +5804,7 @@
 			}		
 		case EMediaHalGetCodePagingBenchmark:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ECode);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5445,11 +5816,7 @@
 			}	
 		case EMediaHalGetDataInPagingBenchmark:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::EData);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5461,11 +5828,7 @@
 			}		
 		case EMediaHalGetDataOutPagingBenchmark:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::EData);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5477,27 +5840,26 @@
 			}		
 		case EMediaHalResetPagingBenchmark:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
-			if(!device)
-				break;
 			TUint index=(TInt)a2;
 			if(index>EMediaPagingStatsCode)
 				break;
-			ResetBenchmarkStats(device, (TMediaPagingStats)index);
+
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ERom);
+			if (device)
+				ResetBenchmarkStats(device, (TMediaPagingStats)index);
+			device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::ECode);
+			if (device)
+				ResetBenchmarkStats(device, (TMediaPagingStats)index);
+			device = TDriveIterator::PagingDevice((TInt)a1, DPagingDevice::EData);
+			if (device)
+				ResetBenchmarkStats(device, (TMediaPagingStats)index);
+
 			r=KErrNone;
 			break;
 			}
 		case EMediaHalGetPagingInfo:
 			{
-			TInt drvNo=(TInt)a1;
-			TLocDrv* drv=TheDrives[drvNo];
-			if(!drv)
-				break;
-			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			DMediaPagingDevice* device = TDriveIterator::PagingDevice((TInt)a1, (DPagingDevice::TType) 0xFF);
 			if(!device)
 				break;
 			NKern::FMWait(&device->iInstrumentationLock);
@@ -5737,6 +6099,309 @@
 
 
 /******************************************************************************
+ DMediaDriverExtension base class
+ ******************************************************************************/
+
+EXPORT_C DMediaDriverExtension::DMediaDriverExtension(TInt aMediaId) :
+	DMediaDriver(aMediaId)
+	{
+	}
+
+/**
+*/
+EXPORT_C DMediaDriverExtension::~DMediaDriverExtension()
+	{
+	}
+
+/**
+Closes the media driver.
+
+This default implementation simply deletes this DMediaDriverExtension object.
+
+Media drivers can provide their own implementation, which gives them
+the opportunity to clean up resources before closure; for example,
+cancelling a DFC.
+Any replacement function must call this base class function as
+the last instruction. 
+*/
+EXPORT_C void DMediaDriverExtension::Close()
+	{
+	DMediaDriver::Close();
+	}
+
+/**
+DoDrivePartitionInfo()
+
+Fills out the passed TPartitionInfo object with information from the attached drives
+*/
+EXPORT_C TInt DMediaDriverExtension::DoDrivePartitionInfo(TPartitionInfo& aInfo)
+	{
+	memclr(&aInfo, sizeof(aInfo));
+	aInfo.iPartitionCount = 0;
+	aInfo.iMediaSizeInBytes = 0;
+
+	TDriveIterator driveIter;
+	for (TLocDrv* drv = driveIter.NextDrive(); drv != NULL; drv = driveIter.NextDrive())
+		{
+		if (drv && drv->iPrimaryMedia == iPrimaryMedia)
+			{
+			TLocDrv* attachedDrive = drv->iNextDrive;
+			__ASSERT_DEBUG(attachedDrive, LOCM_FAULT());
+			TLocDrvRequest m;
+			memclr(&m, sizeof(m));
+
+			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
+			capsBuf.SetMax();
+			capsBuf.FillZ();
+			m.Drive() = attachedDrive;
+			m.Id() = DLocalDrive::ECaps;
+			m.RemoteDes() = (TAny*)capsBuf.Ptr();
+			m.Length() = KMaxLocalDriveCapsLength;
+			TInt r = attachedDrive->iPrimaryMedia->Request(m);
+
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("DMediaDriverExtension::PartitionInfo(ECaps: i %d: r %d ", driveIter.Index(), r));
+			
+			// NB The ECaps call might legitimately fail if one of the attached drives is removable
+			// If this happens, just ignore & proceed to the next attached drive
+			if (r == KErrNone)
+				{
+				aInfo.iEntry[aInfo.iPartitionCount] = *attachedDrive;
+				// Set the media size to be that of the largest attached media
+				// This is only needed to ensure that the test in TLocDrvRequest::CheckAndAdjustForPartition()
+				// with the ELocDrvWholeMedia flag set succeeds: A further check on whether a request's
+				// position & length are outside the media will be made when its is delievered  to the attached media....
+				aInfo.iMediaSizeInBytes = Max(
+					aInfo.iMediaSizeInBytes, 
+					((TLocalDriveCapsV4*) capsBuf.Ptr())->MediaSizeInBytes());
+				}
+
+
+			aInfo.iPartitionCount++;
+			}
+		}
+
+	return KErrNone;
+	}
+
+/**
+ForwardRequest() - 
+
+forwards the request onto the next attached drive in the chain
+*/
+EXPORT_C TInt DMediaDriverExtension::ForwardRequest(TLocDrvRequest& aRequest)
+	{
+	TLocDrv* drive = aRequest.Drive();
+	TLocDrv* attachedDrive = drive->iNextDrive;
+	__ASSERT_DEBUG(attachedDrive, LOCM_FAULT());
+	aRequest.Drive() = attachedDrive;
+
+
+	TInt r = attachedDrive->iPrimaryMedia->HandleMediaNotPresent(aRequest);
+	if (r != KErrNone)
+		{
+		return r;
+		}
+	
+	aRequest.Forward(&attachedDrive->iPrimaryMedia->iMsgQ, EFalse);
+	return KErrNone;
+	}
+
+
+TInt DMediaDriverExtension::SendRequest(TInt aReqId, TBool aPagingRequest, TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen)
+	{
+	__ASSERT_DEBUG(aLen > 0, LOCM_FAULT());
+
+	// Ensure this is a legitimate attached drive registered using LocDrv::RegisterMediaDevice()
+	if (!(iPrimaryMedia->iBody->iRegisteredDriveMask & (0x1 << aDriveNumber)))
+		return KErrArgument;
+
+	TLocDrv* drive = TDriveIterator::GetDrive(aDriveNumber, iPrimaryMedia);
+	__ASSERT_DEBUG(drive, LOCM_FAULT());
+	TLocDrv* attachedDrive = drive->iNextDrive;
+	__ASSERT_DEBUG(attachedDrive, LOCM_FAULT());
+
+	TLocDrvRequest request;
+	memclr(&request, sizeof(request));
+
+	request.Drive() = attachedDrive;
+	request.Id() = aReqId;
+	request.Length() = aLen;
+	request.RemoteDes() = (TAny*) aData;
+	request.Pos() = aPos;
+	request.Flags() = TLocDrvRequest::EKernelBuffer | TLocDrvRequest::EAdjusted;
+
+#ifdef __DEMAND_PAGING__
+	if (aPagingRequest)
+		{
+		request.Flags()|= TLocDrvRequest::EPaging;
+		// If the buffer is page aligned, use SendToMainQueueDfcAndBlock() as this 
+		// is more efficient if the attached drive use DMA.
+		const TInt KPageSizeMask = 4096-1;
+		if (aData & KPageSizeMask)
+			{
+			return attachedDrive->iPrimaryMedia->SendReceive(request, aData);
+			}
+		else
+			{
+			attachedDrive->iPrimaryMedia->iBody->iPagingDevice->SendToMainQueueDfcAndBlock(&request);
+			return 0;
+			}
+		}
+#else
+	aPagingRequest;
+#endif
+
+	return attachedDrive->iPrimaryMedia->SendReceive(request, aData);
+	}
+
+
+/**
+Read() - 
+
+reads data from the next attached drive in the chain
+
+N.B. The position is assumed to be already adjusted i.e. relative to the start of the
+media, not the partition
+*/
+EXPORT_C TInt DMediaDriverExtension::Read(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen)
+	{
+	return SendRequest(DLocalDrive::ERead, EFalse, aDriveNumber, aPos, aData, aLen);
+	}
+
+/**
+Write() - 
+
+writes data to the next attached drive in the chain
+
+N.B. The position is assumed to be already adjusted i.e. relative to the start of the
+media, not the partition
+*/
+EXPORT_C TInt DMediaDriverExtension::Write(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen)
+	{
+	return SendRequest(DLocalDrive::EWrite, EFalse, aDriveNumber, aPos, aData, aLen);
+	}
+
+
+#ifdef __DEMAND_PAGING__
+/**
+ReadPaged() - 
+
+Sends a paging read request to the specified attached drive
+
+N.B. The position is assumed to be already adjusted i.e. relative to the start of the
+media, not the partition
+*/
+EXPORT_C TInt DMediaDriverExtension::ReadPaged(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen)
+	{
+	return SendRequest(DLocalDrive::ERead, ETrue, aDriveNumber, aPos, aData, aLen);
+	}
+
+/**
+WritePaged() - 
+
+Send a paging write request to the specified attached drive
+
+N.B. The position is assumed to be already adjusted i.e. relative to the start of the
+media, not the partition
+*/
+EXPORT_C TInt DMediaDriverExtension::WritePaged(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen)
+	{
+	return SendRequest(DLocalDrive::EWrite, ETrue, aDriveNumber, aPos, aData, aLen);
+	}
+#endif	// __DEMAND_PAGING__
+
+
+
+/**
+Caps() - 
+
+gets the caps from the next attached drive in the chain
+
+N.B. The position is assumed to be already adjusted i.e. relative to the start of the
+media, not the partition
+*/
+EXPORT_C TInt DMediaDriverExtension::Caps(TInt aDriveNumber, TDes8& aCaps)
+	{
+	// Ensure this is a legitimate attached drive registered using LocDrv::RegisterMediaDevice()
+	if (!(iPrimaryMedia->iBody->iRegisteredDriveMask & (0x1 << aDriveNumber)))
+		return KErrArgument;
+
+	TLocDrv* drive = TDriveIterator::GetDrive(aDriveNumber, iPrimaryMedia);
+	__ASSERT_DEBUG(drive, LOCM_FAULT());
+	TLocDrv* attachedDrive = drive->iNextDrive;
+	__ASSERT_DEBUG(attachedDrive, LOCM_FAULT());
+
+	TLocDrvRequest request;
+	memclr(&request, sizeof(request));
+
+	request.Drive() = attachedDrive;
+	request.Id() = DLocalDrive::ECaps;
+	request.Length() = aCaps.Length();
+	request.RemoteDes() = (TAny*) aCaps.Ptr();
+
+	return request.SendReceive(&attachedDrive->iPrimaryMedia->iMsgQ);
+	}
+
+
+
+EXPORT_C void DMediaDriverExtension::NotifyPowerDown()
+	{
+	}
+
+EXPORT_C void DMediaDriverExtension::NotifyEmergencyPowerDown()
+	{
+	}
+
+
+/**
+Returns ETrue if this media - or any media which this TLocDrv is attached to - is busy
+*/
+EXPORT_C TBool DMediaDriverExtension::MediaBusy(TInt aDriveNumber)
+	{
+	for (TLocDrv* drive = TDriveIterator::GetDrive(aDriveNumber, iPrimaryMedia); 
+		drive; 
+		drive = drive->iNextDrive)
+		{
+		DPrimaryMediaBase* primaryMedia = drive->iPrimaryMedia;
+		__ASSERT_DEBUG(primaryMedia, LOCM_FAULT());
+
+		if ((primaryMedia->iMsgQ.iMessage && primaryMedia->iMsgQ.iMessage->iState != TMessageBase::EFree) || 
+			!primaryMedia->iMsgQ.iQ.IsEmpty() ||
+			primaryMedia->iBody->iMediaChangeDfc.Queued() ||
+			primaryMedia->iBody->iMediaPresentDfc.Queued())
+			return ETrue;
+
+#ifdef __DEMAND_PAGING__
+		DMediaPagingDevice* pagingDevice = iPrimaryMedia->iBody->iPagingDevice;
+		if (pagingDevice)
+			{
+			if ((pagingDevice->iMainQ.iMessage && pagingDevice->iMainQ.iMessage->iState != TMessageBase::EFree) || 
+				!pagingDevice->iMainQ.iQ.IsEmpty())
+			return ETrue;
+			}
+#endif
+		}
+
+	return EFalse;
+	}
+
+
+TCallBackLink::TCallBackLink()
+	{
+	memclr(this, sizeof(this));
+	}
+
+TCallBackLink::TCallBackLink(TInt (*aFunction)(TAny* aPtr, TInt aParam),TAny* aPtr, TObjectType aObjectType) : 
+	iFunction(aFunction), iPtr(aPtr), iObjectType(aObjectType)
+	{
+	}
+
+TInt TCallBackLink::CallBack(TInt aParam) const
+	{
+	return (*iFunction)(iPtr, aParam);
+	}
+
+/******************************************************************************
  Entry point
  ******************************************************************************/
 DECLARE_STANDARD_EXTENSION()
@@ -5745,6 +6410,7 @@
 
 	// install the HAL function
 	TInt r=Kern::AddHalEntry(EHalGroupMedia,MediaHalFunction,NULL);
+
 #ifdef __DEMAND_PAGING__
 	if (r==KErrNone)
 		{
@@ -5757,6 +6423,7 @@
 		__KTRACE_OPT(KBOOT,Kern::Printf("Installing LocDrv device in kernel returned %d",r));
 		}
 #endif // __DEMAND_PAGING__
+
 	return r;
 	}
 
--- a/kernel/eka/drivers/medata/pccd_ata.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/medata/pccd_ata.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -1785,6 +1785,7 @@
 	aInfo.iFileSystemId=KDriveFileSysFAT;
 	aInfo.iHiddenSectors=iHiddenSectors;
 	aInfo.iBlockSize=KAtaSectorSize;
+	SetTotalSizeInBytes(aInfo);
 	return KErrCompletion;	// synchronous completion
 	}
 
--- a/kernel/eka/drivers/medint/iram.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/medint/iram.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -200,6 +200,7 @@
 	caps.iEraseBlockSize=TInternalRamDrive::MaxSize();	// overload for RAM drive to avoid
 														// F32 depending on memory model
 	caps.iBlockSize=1;
+	SetTotalSizeInBytes(caps);
 	return KErrNone;									
 	}
 
--- a/kernel/eka/drivers/medlfs/flash_media.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/medlfs/flash_media.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -163,10 +163,11 @@
 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DMediaDriverFlash::Request %d",id));
 	if (id==DLocalDrive::ECaps)
 		{
-  		TLocalDriveCapsV2& c=*(TLocalDriveCapsV2*)m.RemoteDes();
+  		TLocalDriveCapsV4& c=*(TLocalDriveCapsV4*)m.RemoteDes();
 		r=Caps(c);
 		c.iSize=m.Drive()->iPartitionLen;
 		c.iPartitionType=m.Drive()->iPartitionType;
+		SetTotalSizeInBytes(c);
 		return r;
 		}
 	switch (id)
--- a/kernel/eka/drivers/medmmc/medmmc.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/drivers/medmmc/medmmc.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -797,17 +797,8 @@
 		}
 	else
 		{
-#if defined(__DEMAND_PAGING__) && !defined(__WINS__)
-		if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
-			{
-			r = iCurrentReq->WriteToPageHandler(NULL, 0, 0);
-			}
-		else
-#endif	// __DEMAND_PAGING__
-			{
-			TPtrC8 zeroDes(NULL, 0);
-			r = iCurrentReq->WriteRemote(&zeroDes,0);
-			}
+		TPtrC8 zeroDes(NULL, 0);
+		r = iCurrentReq->WriteRemote(&zeroDes,0);
 		}
 
 	// error occurred or read all from cache so complete immediately
@@ -2957,12 +2948,7 @@
 	TUint usrOfst = I64LOW(iReqCur - iReqStart);
 
 	OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY1, "Begin writing user data" );
-#if defined(__DEMAND_PAGING__) && !defined(__WINS__)
-	if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
-		r=iCurrentReq->WriteToPageHandler((TUint8 *)(&extrView[0]), len, usrOfst);
-	else
-#endif	// __DEMAND_PAGING__
-		r = iCurrentReq->WriteRemote(&extrView,usrOfst);
+	r = iCurrentReq->WriteRemote(&extrView,usrOfst);
 	
 	OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY2, "End writing user data" );
 
@@ -2973,19 +2959,10 @@
 TInt DMmcMediaDriverFlash::ReadDataFromUser(TDes8& aDes, TInt aOffset)
 	{
 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_READDATAFROMUSER_ENTRY ,"DMmcMediaDriverFlash::ReadDataFromUser;aOffset=%d;this=%x", aOffset, (TUint) this);
-	TInt r = KErrNotSupported;
-#ifndef __WINS__
-	if (DMediaPagingDevice::PageOutRequest(*iCurrentReq))
-	    {
-		r = iCurrentReq->ReadFromPageHandler((TAny*) aDes.Ptr(), aDes.MaxLength(), aOffset);
-		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT1, this, r );
-		return r;
-	    }
-	else
-#endif // #ifndef __WINS__
-		r = iCurrentReq->ReadRemote(&aDes, aOffset);
-	
-	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT2, this, r );
+
+	TInt r = iCurrentReq->ReadRemote(&aDes, aOffset);
+
+	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT1, this, r );
 	return r;
 	}
 
@@ -3698,6 +3675,7 @@
 		c.iSize = drive.iPartitionLen;
 		c.iPartitionType = drive.iPartitionType;	
 		c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift);
+		SetTotalSizeInBytes(c);
 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT1, this, r );
 		return r;
 		}
--- a/kernel/eka/eabi/elocdu.def	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/eabi/elocdu.def	Fri Apr 23 22:20:31 2010 +0100
@@ -64,4 +64,23 @@
 	_ZTI10DDmaHelper @ 63 NONAME ; #<TI>#
 	_ZTV10DDmaHelper @ 64 NONAME ; #<VT>#
 	_ZN14TLocDrvRequest19ReadFromPageHandlerEPvii @ 65 NONAME
+	_ZN21DMediaDriverExtension14ForwardRequestER14TLocDrvRequest @ 66 NONAME
+	_ZN21DMediaDriverExtension15NotifyPowerDownEv @ 67 NONAME
+	_ZN21DMediaDriverExtension20DoDrivePartitionInfoER14TPartitionInfo @ 68 NONAME
+	_ZN21DMediaDriverExtension24NotifyEmergencyPowerDownEv @ 69 NONAME
+	_ZN21DMediaDriverExtension4CapsEiR5TDes8 @ 70 NONAME
+	_ZN21DMediaDriverExtension4ReadEixmj @ 71 NONAME
+	_ZN21DMediaDriverExtension5CloseEv @ 72 NONAME
+	_ZN21DMediaDriverExtension5WriteEixmj @ 73 NONAME
+	_ZN21DMediaDriverExtension9MediaBusyEi @ 74 NONAME
+	_ZN21DMediaDriverExtensionC2Ei @ 75 NONAME
+	_ZN21DMediaDriverExtensionD0Ev @ 76 NONAME
+	_ZN21DMediaDriverExtensionD1Ev @ 77 NONAME
+	_ZN21DMediaDriverExtensionD2Ev @ 78 NONAME
+	_ZTI21DMediaDriverExtension @ 79 NONAME
+	_ZTV21DMediaDriverExtension @ 80 NONAME
+	_ZN12DMediaDriver19SetTotalSizeInBytesER17TLocalDriveCapsV4 @ 81 NONAME
+	_ZN21DMediaDriverExtension10WritePagedEixmj @ 82 NONAME
+	_ZN21DMediaDriverExtension9ReadPagedEixmj @ 83 NONAME
+	_ZN11DLocalDrive4CapsEiR5TDes8 @ 84 NONAME
 
--- a/kernel/eka/include/d32locd.h	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/include/d32locd.h	Fri Apr 23 22:20:31 2010 +0100
@@ -36,17 +36,22 @@
 enum TMediaDevice { EFixedMedia0, EFixedMedia1, EFixedMedia2, EFixedMedia3,
 					EFixedMedia4, EFixedMedia5, EFixedMedia6, EFixedMedia7,
 					ERemovableMedia0, ERemovableMedia1, ERemovableMedia2, ERemovableMedia3,
-					EInvalidMedia
+					EInvalidMedia,
+					EMediaExtension0, EMediaExtension1, EMediaExtension2, EMediaExtension3,
+					EMediaExtension4, EMediaExtension5, EMediaExtension6, EMediaExtension7,
 				};
 
 #define __IS_REMOVABLE(aDevice) (aDevice>=ERemovableMedia0 && aDevice<=ERemovableMedia3)
 #define __IS_FIXED(aDevice) ((TUint)aDevice<=EFixedMedia7)
+#define __IS_EXTENSION(aDevice) (aDevice>=EMediaExtension0 && aDevice<=EMediaExtension7)
+
 #define MEDIA_DEVICE_IRAM EFixedMedia0
 #define MEDIA_DEVICE_LFFS EFixedMedia1
 #define MEDIA_DEVICE_NAND EFixedMedia2
 #define MEDIA_DEVICE_MMC ERemovableMedia0
 #define MEDIA_DEVICE_PCCARD ERemovableMedia1
 #define MEDIA_DEVICE_CSA ERemovableMedia2
+#define MEDIA_DEVICE_NFE EMediaExtension0
 
 typedef signed int TSocket;
 
@@ -506,6 +511,16 @@
 	};
 typedef TPckgBuf<TPageDeviceInfo> TPageDeviceInfoBuf;
 
+class TLocalDriveFinaliseInfo
+/**
+@internalTechnology
+*/
+	{
+public:
+	TInt iMode;		// @see RFs::TFinaliseDrvMode
+	};
+typedef TPckgBuf<TLocalDriveFinaliseInfo> TLocalDriveFinaliseInfoBuf;
+
 class RLocalDrive : public RBusLogicalChannel
 /**
 Interface class to local media
@@ -553,6 +568,7 @@
 		ELocDrvWholeMedia				= 0x40000000	/**< Set to access whole media, rather than partition */
 		};
 
+	// @see TBusLocalDrive::QueryDevice()
 	enum TQueryDevice
 		{ 
 		// Symbian publishedPartner range
@@ -567,7 +583,14 @@
 		EQueryLicenseeFirst					= 0x8000,
 		EQueryLicenseeLast					= 0xBFFF,
 		
+		// Finalize Drive - called as a result of a call to RFs::FinaliseDrives()
+		EQueryFinaliseDrive					= EQuerySymbianPublishedPartnerFirst + 0,	// @internalTechnology
+
 		EQueryPageDeviceInfo = EQuerySymbianTestFirst,	/**< @see TPageDeviceInfo */
+		
+		// NFE test driver
+		EQuerySymbianNfeTestFirst = EQuerySymbianTestFirst+0x10,
+		EQuerySymbianNfeTestEnd = EQuerySymbianTestFirst+0x1F,
 		};
 public:
 	inline TVersion VersionRequired() const;
--- a/kernel/eka/include/drivers/locmedia.h	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/include/drivers/locmedia.h	Fri Apr 23 22:20:31 2010 +0100
@@ -166,6 +166,46 @@
 class TLocDrvRequest;
 class DPrimaryMediaBase;
 
+/* 
+TCallBackLink
+
+@internalComponent
+
+Internal class which allows a list of callbacks to be linked together.
+*/
+
+NONSHARABLE_CLASS(TCallBackLink)
+	{
+public:
+	enum TObjectType
+		{
+		EDLocalDriveObject, // object containing this TCallBackLink is a DLocalDrive
+		ETLocDrvObject,		// object containing this TCallBackLink is a TLocDrv
+		};
+
+public:
+	TCallBackLink();
+	TCallBackLink(TInt (*aFunction)(TAny* aPtr, TInt aParam),TAny* aPtr, TObjectType aObjectType);
+	TInt CallBack(TInt aParam) const;
+public:
+	/**
+	A pointer to the callback function.
+	*/
+	TInt (*iFunction)(TAny* aPtr, TInt aParam);
+	
+	
+	/**
+	A pointer that is passed to the callback function when
+	the function is called.
+	*/
+	TAny* iPtr;
+
+	TObjectType iObjectType;
+
+	SDblQueLink iLink;
+	};
+
+
 /**
 @publishedPartner
 @released
@@ -275,19 +315,22 @@
 		Query device 
 		*/
 		EQueryDevice=32,
-
 		};
 public:
 	DLocalDrive(); 
 	~DLocalDrive();
-public:
+
 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); /**< @internalComponent */
 	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);                      /**< @internalComponent */
-public:
-	void NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange);
-public:
+
+	void NotifyChange();
+
 	inline void Deque();                 /**< @internalComponent */
 
+	static TInt MediaChangeCallback(TAny* aLocalDrive, TInt aNotifyType);	/**< @internalComponent */
+
+	IMPORT_C static TInt Caps(TInt aDriveNumber, TDes8& aCaps);
+
 private:
 #ifdef __DEMAND_PAGING__
 	TInt LockMountInfo(DPrimaryMediaBase& aPrimaryMedia, TLocDrvRequest& aReq);
@@ -296,10 +339,10 @@
 	TInt ReadPasswordData(TLocDrvRequest& aReq, TLocalDrivePasswordData& aPswData, TMediaPassword& aOldPasswd, TMediaPassword& aNewPasswd);
 
 public:
-	TLocDrv* iDrive;							/**< @internalComponent */
-	SDblQueLink iLink;							/**< @internalComponent */
+	TLocDrv* iDrive;									/**< @internalComponent */
+	TCallBackLink iMediaChangeObserver;					/**< @internalComponent */
 	TClientDataRequest<TBool>* iNotifyChangeRequest;	/**< @internalComponent */
-	TLocalDriveCleanup iCleanup;				 /**< @internalComponent */
+	TLocalDriveCleanup iCleanup;						/**< @internalComponent */
 	};
 
 /**
@@ -341,7 +384,7 @@
 		ECodePaging=0x20,			// a code paging request
 		EDataPaging=0x40,			// a data paging request
 		ETClientBuffer=0x80,		// RemoteDes() points to a TClientBuffer
-		EKernelBuffer=0x100,		// RemoteDes() points to a kernel-side buffer
+		EKernelBuffer=0x100,		// RemoteDes() points to a kernel-side buffer : set for all paging requests and media extension requests
 		};
 public:
     
@@ -493,7 +536,7 @@
 @internalComponent
 */
 inline void DLocalDrive::Deque()
-	{ iLink.Deque(); }
+	{ iMediaChangeObserver.iLink.Deque(); }
 
 
 
@@ -647,6 +690,7 @@
 	inline TInt Connect(DLocalDrive* aLocalDrive);
 	inline void Disconnect(DLocalDrive* aLocalDrive);
 	inline TInt Request(TLocDrvRequest& aRequest);
+	static TInt MediaChangeCallback(TAny* aLocDrv, TInt aNotifyType);
 public:
 	TInt iDriveNumber;
 	DMedia* iMedia;
@@ -661,6 +705,14 @@
 	TUint8 iSpare3;
 #endif
 	DDmaHelper* iDmaHelper;
+
+	// Media extension stuff:
+
+	/** ptr to the next TLocDrv object in the chain. Null if not a media extension */
+	TLocDrv* iNextDrive;
+
+	/** media change callback - called when the next media in the chain has a media change */
+	TCallBackLink iMediaChangeObserver;
 	};
 
 /**
@@ -827,7 +879,7 @@
 
 public:
 	IMPORT_C DPrimaryMediaBase();
-public:
+
 	// provided by implementation
 	IMPORT_C virtual TInt Create(TMediaDevice aDevice, TInt aMediaId, TInt aLastMediaId);
 	IMPORT_C virtual TInt Connect(DLocalDrive* aLocalDrive);
@@ -841,7 +893,7 @@
 	IMPORT_C virtual void DeltaCurrentConsumption(TInt aCurrent);
 	IMPORT_C virtual void DefaultDriveCaps(TLocalDriveCapsV2& aCaps);
 	IMPORT_C virtual TBool IsRemovableDevice(TInt& aSocketNum);
-public:
+
 	// used by implementation
 	IMPORT_C void NotifyMediaChange();
 	IMPORT_C void NotifyPowerDown();
@@ -849,7 +901,7 @@
 	IMPORT_C void NotifyPsuFault(TInt anError);
 	IMPORT_C void NotifyMediaPresent();
 	IMPORT_C void PowerUpComplete(TInt anError);
-public:
+
 	IMPORT_C virtual void HandleMsg(TLocDrvRequest& aRequest);
 	IMPORT_C virtual TInt DoRequest(TLocDrvRequest& aRequest);
 	TInt OpenMediaDriver();
@@ -862,7 +914,10 @@
 	void CompleteRequest(TLocDrvRequest& aMsg, TInt aResult);
 	IMPORT_C void RunDeferred();
 	void SetClosed(TInt anError);
-	void NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv=NULL);
+	
+	enum TNotifyType {EMediaChange, EMediaPresent};
+	void NotifyClients(TNotifyType aNotifyType, TLocDrv* aLocDrv=NULL);
+
 	TInt InCritical();
 	void EndInCritical();
 	void UpdatePartitionInfo();
@@ -882,6 +937,13 @@
 	void RequestCountDec();
 #endif
 
+	// called by LocDrv::RegisterMediaDevice() for media extensions
+	TInt Connect(TLocDrv* aLocDrv);
+
+	void MediaChange();
+	TInt HandleMediaNotPresent(TLocDrvRequest& aReq);
+
+
 public:
 	TInt iLastMediaId;					/**< @internalComponent */
 	TMessageQue iMsgQ;
@@ -1148,6 +1210,7 @@
 	virtual void NotifyEmergencyPowerDown()=0;
 public:
 	IMPORT_C void SetTotalSizeInBytes(Int64 aTotalSizeInBytes, TLocDrv* aLocDrv=NULL);
+	IMPORT_C void SetTotalSizeInBytes(TLocalDriveCapsV4& aCaps);
 	IMPORT_C Int64 TotalSizeInBytes();
 	IMPORT_C void SetCurrentConsumption(TInt aValue);
 	IMPORT_C TInt InCritical();
@@ -1165,6 +1228,74 @@
 	};
 
 
+/**
+@internalTechnology
+@prototype
+
+An abstract base class for media driver 'extensions' within the local media subsystem
+*/
+class DMediaDriverExtension : public DMediaDriver
+	{
+public:
+	IMPORT_C DMediaDriverExtension(TInt aMediaId);
+	IMPORT_C virtual ~DMediaDriverExtension();
+	IMPORT_C virtual void Close();
+
+	virtual TInt Request(TLocDrvRequest& aRequest) = 0;
+	
+	virtual TInt PartitionInfo(TPartitionInfo &anInfo) = 0;
+
+	IMPORT_C virtual void NotifyPowerDown();
+
+	IMPORT_C virtual void NotifyEmergencyPowerDown();
+
+	/**
+	Retrieve partition info from all the attached drives
+	*/
+	IMPORT_C TInt DoDrivePartitionInfo(TPartitionInfo &anInfo);
+	/**
+	Forward a request to the next attached drive
+	*/
+	IMPORT_C TInt ForwardRequest(TLocDrvRequest& aRequest);
+
+	/**
+	Read from the specified attached drive
+	*/
+	IMPORT_C TInt Read(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen);
+
+	/**
+	Write to the specified attached drive
+	*/
+	IMPORT_C TInt Write(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen);
+
+	/**
+	Get the Caps from the specified attached drive
+	*/
+	IMPORT_C TInt Caps(TInt aDriveNumber, TDes8& aCaps);
+
+	/**
+	Return whether the media is busy i.e. if it has any pending requests or DFCs
+	*/
+	IMPORT_C TBool MediaBusy(TInt aDriveNumber);
+
+#ifdef __DEMAND_PAGING__
+	/**
+	Send a paging read request to the specified attached drive
+	*/
+	IMPORT_C TInt ReadPaged(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen);
+
+	/**
+	Send a paging write request to the specified attached drive
+	*/
+	IMPORT_C TInt WritePaged(TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen);
+#endif
+
+private:
+	TInt SendRequest(TInt aReqId, TBool aPagingRequest, TInt aDriveNumber, TInt64 aPos, TLinAddr aData, TUint aLen);
+
+	};
+
+
 
 
 /**
--- a/kernel/eka/include/e32ver.h	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/include/e32ver.h	Fri Apr 23 22:20:31 2010 +0100
@@ -28,7 +28,7 @@
 
 const TInt KE32MajorVersionNumber=2;
 const TInt KE32MinorVersionNumber=0;
-const TInt KE32BuildVersionNumber=3064;
+const TInt KE32BuildVersionNumber=3066;
 
 const TInt KMachineConfigurationMajorVersionNumber=1;
 const TInt KMachineConfigurationMinorVersionNumber=0;
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -64,7 +64,7 @@
 	*/
 	static DCodePagedMemoryManager TheManager;
 
-	friend DPagingDevice* CodePagingDevice(TInt aDiveNum);
+	friend DPagingDevice* CodePagingDevice(TInt aDriveNum);
 	};
 
 
@@ -131,6 +131,8 @@
 			{
 			TRACEB(("DCodePagedMemoryManager::InstallPagingDevice drive=%d",i));
 			TAny* null = 0;
+			if(aDevice->iType & DPagingDevice::EMediaExtension)
+				__e32_atomic_store_ord_ptr(&iDevice[i], null);
 			if(!__e32_atomic_cas_ord_ptr(&iDevice[i], &null, aDevice)) // set iDevice[i]=aDevice if it was originally 0
 				{
 				// paging device already registered...
@@ -207,11 +209,11 @@
 
 TInt DCodePagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry)
 	{
-	if(aPageInfo->IsDirty()==false)
+	if(!aPageInfo->IsDirty())
 		return KErrNone;
 
 	// shouldn't be asked to clean a page which is writable...
-	__NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false);
+	__NK_ASSERT_DEBUG(!aPageInfo->IsWritable());
 
 	// Note, memory may have been modified by the CodeModifier class.
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -656,6 +656,15 @@
 		}
 
 	// Store the device, blocking any other devices from installing.
+	// unless the device is a media extension device
+	if(aDevice->iType & DPagingDevice::EMediaExtension)
+		{
+		delete iSwapManager;
+		iSwapManager = NULL;
+		TAny* null = 0;
+		__e32_atomic_store_ord_ptr(&iDevice, null);
+		}
+
 	if (!NKern::CompareAndSwap((TAny*&)iDevice, (TAny*)NULL, (TAny*)aDevice))
 		{// Data paging device already installed.
 		__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("**** Attempt to install more than one data paging device !!!!!!!! ****"));
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -502,6 +502,8 @@
 		}
 
 	TAny* null = 0;
+	if(aDevice->iType & DPagingDevice::EMediaExtension)
+		__e32_atomic_store_ord_ptr(&iDevice, null);
 	if(!__e32_atomic_cas_ord_ptr(&iDevice, &null, aDevice)) // set iDevice=aDevice if it was originally 0
 		{
 		// ROM paging device already registered...
@@ -969,6 +971,11 @@
 		MmuLock::Lock();
 		SPageInfo::FromPhysAddr(iNewPage)->SetShadow(aIndex,aMemory->PageInfoFlags());
 		MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize);
+		++Epoc::KernelMiscPages;
+#endif
 		}
 
 	RamAllocLock::Unlock();
@@ -992,6 +999,11 @@
 		{
 		RamAllocLock::Lock();
 		TheMmu.FreeRam(&iNewPage, 1, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize);
+		--Epoc::KernelMiscPages;
+#endif
 		RamAllocLock::Unlock();
 		}
 	if(IsAttached())
--- a/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -651,6 +651,17 @@
 	}
 
 
+TInt MmuBase::FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes)
+	{
+	TUint zonePages;
+	TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, aZoneBase, zonePages);
+	if (r != KErrNone)
+		return r;
+	aZoneBytes = zonePages << KPageShift;
+	return MmuBase::FreePhysicalRam(aZoneBase, aZoneBytes);
+	}
+
+
 TInt MmuBase::ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize)
 	{
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(%08x,%x)",aPhysAddr,aSize));
@@ -1263,14 +1274,14 @@
 #endif
 
 #ifdef BTRACE_RAM_ALLOCATOR
-	// Must check for -1 as that is the default value of aCategroy for
+	// Must check for -1 as that is the default value of aCategory for
 	// BTrace::Prime() which is intended to prime all categories that are 
 	// currently enabled via a single invocation of BTrace::Prime().
 	if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1)
 		{
 		NKern::ThreadEnterCS();
 		Mmu::Wait();
-		Mmu::Get().iRamPageAllocator->SendInitialBtraceLogs();
+		Mmu::Get().iRamPageAllocator->DoBTracePrime();
 		Mmu::Signal();
 		NKern::ThreadLeaveCS();
 		}
@@ -2051,6 +2062,45 @@
 
 
 /**
+Free a RAM zone which was previously allocated by one of these methods:
+Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or 
+TRamDefragRequest::ClaimRamZone().
+
+All of the pages in the RAM zone must be allocated and only via one of the methods 
+listed above, otherwise a system panic will occur.
+
+@param	aZoneId			The ID of the RAM zone to free.
+@return	KErrNone 		If the operation was successful.
+		KErrArgument 	If a RAM zone with ID aZoneId was not found.
+
+@pre Calling thread must be in a critical section.
+@pre Interrupts must be enabled.
+@pre Kernel must be unlocked.
+@pre No fast mutex can be held.
+@pre Call in a thread context.
+@pre Can be used in a device driver.
+*/
+EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId)
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone");
+	MmuBase& m = *MmuBase::TheMmu;
+	MmuBase::Wait();
+	TPhysAddr zoneBase;
+	TUint zoneBytes;
+	TInt r = m.FreeRamZone(aZoneId, zoneBase, zoneBytes);
+#ifdef BTRACE_KERNEL_MEMORY
+	if (r == KErrNone)
+		{
+		BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, zoneBytes, zoneBase);
+		Epoc::DriverAllocdPhysRam -= zoneBytes;
+		}
+#endif
+	MmuBase::Signal();
+	return r;
+	}
+
+
+/**
 Translate a virtual address to the corresponding physical address.
 
 @param	aLinAddr	The virtual address to be translated.
@@ -3244,7 +3294,7 @@
 	{
 	NKern::LockSystem();
 	SPagingDevice* device = &iPagingDevices[aId];
-	if(device->iInstalled)
+	if((device->iInstalled) && !(aDevice->iType & DPagingDevice::EMediaExtension))
 		{
 		__KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("**** Attempt to install more than one ROM paging device !!!!!!!! ****"));
 		//Panic(EDeviceAlreadyExists);
--- a/kernel/eka/release.txt	Fri Apr 23 22:14:19 2010 +0100
+++ b/kernel/eka/release.txt	Fri Apr 23 22:20:31 2010 +0100
@@ -1,3 +1,23 @@
+Version 2.00.3066
+=================
+(Made by vfebvre 15/04/2010)
+
+1.	migubarr
+	1.	REQ 415-7212 NFE drive encryption on Demand Paging-enabled device
+		PackageReleaseID=453228 FeatureReleaseID=447937
+
+
+Version 2.00.3065
+=================
+(Made by vfebvre 15/04/2010)
+
+1.	ahiron
+	1.	DEF145202: E32TEST T_IIC test failure investigation (KERN-EXEC 17) 
+
+2.	vfebvre
+	1.	MINOR_CHANGE Temporarily disable crash-prone test T_SOUND2 until it is fixed (DEF144934)
+
+
 Version 2.00.3064
 =================
 (Made by vfebvre 14/04/2010)
--- a/kerneltest/e32test/iic/t_iic.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/e32test/iic/t_iic.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -1522,6 +1522,8 @@
 	gChanSlaveI2c.Close();
 	
 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
+// Not safe to assume that heap clean-up has completed for the channels just closed, so insert a delay.(DEF145202)
+	User::After(20 * 1000);
 	__KHEAP_MARKEND;
 
 	gTest.Next(_L("Free kernel-side proxy IIC client"));
@@ -1598,6 +1600,8 @@
 	gChanSlaveI2c.Close();
 
 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
+// Not safe to assume that heap clean-up has completed for the channels just closed, so insert a delay.(DEF145202)
+	User::After(20 * 1000);
 	__KHEAP_MARKEND;
 
 	gTest.Next(_L("Free kernel-side proxy IIC client"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mediaext/d_nfe.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -0,0 +1,1779 @@
+// Copyright (c) 1995-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:
+// e32test\mediext\d_nfe.cpp
+// 
+//
+
+#include <drivers/locmedia.h>
+#include <platform.h>
+#include <variantmediadef.h>
+#include "nfe.h"
+
+#if defined(_DEBUG)
+	#define TRACE_ENABLED
+#else
+#endif
+
+#if defined(TRACE_ENABLED)
+#define __KTRACE_PRINT(p) {p;}
+#else
+#define __KTRACE_PRINT(p)
+#endif
+
+
+
+
+// Variant parameters for test Media Extension Driver
+
+
+const TInt KNfeThreadPriority = 24;	        // same as file server
+const TInt KNfeDiskOpReady = 100;       //100%
+//const TInt KNfeDiskOpStart = 0;         //0%
+
+_LIT(KPddName, "Media.NFE");
+#define NFE_DRIVENAME "NFE"
+#define NFE_NUMMEDIA 1
+
+// Define the array of local drives which we're attaching to
+__ASSERT_COMPILE(sizeof(TNfeDeviceInfo) <= 256);	// KMaxQueryDeviceLength
+
+// Define the array of local code-paging drives which we're attaching to
+#ifdef __DEMAND_PAGING__
+	__ASSERT_COMPILE(NFE_PAGEDRIVECOUNT <= TNfeDeviceInfo::ENfeMaxPartitionEntries);
+	__ASSERT_COMPILE(NFE_DRIVECOUNT >= NFE_PAGEDRIVECOUNT);
+	#define	SECTOR_SHIFT 9
+#endif	// #ifdef __DEMAND_PAGING__
+
+
+
+
+class DPrimaryMediaExt : public DPrimaryMediaBase
+	{
+public:
+	DPrimaryMediaExt(TInt aInstance);
+public:
+	TInt iInstance;
+	TDfcQue iNfeDfcQ;
+	};
+
+
+
+// Get the number of drives in the drive array belonging to this instance 
+TInt DriveCount(TInt aInstance)
+	{
+	static const TInt NfeInstanceDriveCounts[NFE_INSTANCE_COUNT]={NFE_INSTANCE_DRIVE_COUNTS};
+	return NfeInstanceDriveCounts[aInstance];
+	}
+
+// Get a pointer to the first drive in the drive array belonging to this instance 
+const TInt* DriveList(TInt aInstance)
+	{
+	static const TInt NfeDriveNumbers[NFE_DRIVECOUNT]={NFE_DRIVELIST};
+	TInt driveListOffset = 0;
+	for (TInt n=0; n<aInstance; n++)
+		driveListOffset+= DriveCount(n);
+	return  NfeDriveNumbers + driveListOffset;
+	}
+
+const TInt* DriveLetterList(TInt aInstance)
+	{
+	static const TInt NfeDriveLetters[NFE_DRIVECOUNT]={NFE_DRIVELETTERLIST};
+	TInt driveListOffset = 0;
+	for (TInt n=0; n<aInstance; n++)
+		driveListOffset+= DriveCount(n);
+	return  NfeDriveLetters + driveListOffset;
+	}
+
+TInt DriveLetter(TInt aIndex)
+	{
+	static const TInt NfeDriveLetters[NFE_DRIVECOUNT]={NFE_DRIVELETTERLIST};
+	return NfeDriveLetters[aIndex];
+	}
+
+TChar DriveLetterToAscii(TInt aDriveLetter)
+	{
+	return aDriveLetter >= 0 && aDriveLetter <= 25 ? aDriveLetter +'A' : '?';
+	}
+
+#ifdef __DEMAND_PAGING__
+	// Get the number of drives in the paged drive array belonging to this instance 
+	TInt PageDriveCount(TInt aInstance)
+		{
+	#if NFE_PAGEDRIVECOUNT > 0
+		static const TInt NfeInstancePageDriveCounts[NFE_INSTANCE_COUNT]={NFE_INSTANCE_PAGEDRIVE_COUNTS};
+		return NfeInstancePageDriveCounts[aInstance];
+	#else
+		return 0;
+	#endif
+		}
+
+	// Get a pointer to the first drive in the paged drive array belonging to this instance 
+	const TInt* PageDriveList(TInt aInstance)
+		{
+	#if NFE_PAGEDRIVECOUNT > 0
+		static const TInt NfePageDriveNumbers[NFE_PAGEDRIVECOUNT]={NFE_PAGEDRIVELIST};
+		TInt driveListOffset = 0;
+		for (TInt n=0; n<aInstance; n++)
+			driveListOffset+= PageDriveCount(n);
+		return  NfePageDriveNumbers + driveListOffset;
+	#else
+		return NULL;
+	#endif
+		}
+
+	// Get the number of paging type belonging to this instance 
+	TInt PagingType(TInt aInstance)
+		{
+	#if NFE_PAGEDRIVECOUNT > 0
+		static const TInt NfeInstancePagingType[NFE_INSTANCE_COUNT]={NFE_INSTANCE_PAGING_TYPE};
+		return NfeInstancePagingType[aInstance];
+	#else
+		return 0;
+	#endif
+		}
+
+	// get the instance of the swap drive
+	TInt SwapInstance()
+		{
+		for (TInt i=0; i<NFE_INSTANCE_COUNT; i++)
+			if (PagingType(i) & DPagingDevice::EData)
+				return i;
+		return KErrNotFound;
+		}
+#endif	// #ifdef __DEMAND_PAGING__
+
+
+const char* DriveStatus(TNfeDiskStatus aStatus)
+	{
+	const char* KNfeUnmounted = "Unmounted";
+	const char* KNfeDecrypted = "Decrypted";
+	const char* KNfeDecrypting = "Decrypting";
+	const char* KNfeEncrypted = "Encrypted";
+	const char* KNfeEncrypting = "Encrypting";
+	const char* KNfeWiping = "Wiping";
+	const char* KNfeCorrupted = "Corrupted";
+	const char* KNfeUnrecognised = "Unrecognised";
+
+	switch(aStatus)
+		{
+		case ENfeUnmounted:
+			return KNfeUnmounted;
+		case ENfeDecrypted:
+			return KNfeDecrypted;
+		case ENfeDecrypting:
+			return KNfeDecrypting;
+		case ENfeEncrypted:
+			return KNfeEncrypted;
+		case ENfeEncrypting:
+			return KNfeEncrypting;
+		case ENfeWiping:
+			return KNfeWiping;
+		case ENfeCorrupted:
+			return KNfeCorrupted;
+		default:
+			return KNfeUnrecognised;
+
+		}
+	}
+
+
+DPrimaryMediaExt::DPrimaryMediaExt(TInt aInstance) : iInstance(aInstance)
+	{
+	}
+
+
+#define NFE_FAULT()	Kern::Fault("NFEMEDIA",__LINE__)
+
+// disk encryption/decryption/wiping is only performed after the following period of inactivity
+// NB USB Mass Storage tends to 'poll' the media driver by sending ECaps every second or so, so we need
+// to ensure this timeout period is significantly less to ensure the timer DFC thread gets a chance to run...
+const TInt KNotBusyInterval = 200;		// 200 mS
+
+
+
+class DPhysicalDeviceMediaNFE : public DPhysicalDevice
+	{
+public:
+	DPhysicalDeviceMediaNFE();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Info(TInt aFunction, TAny* a1);
+	};
+								
+
+class DMediaDriverNFE : public DMediaDriverExtension
+	{
+public:
+	class TPropertyObserver
+		{
+	public:
+		void Close();
+		static void PropertySubsCompleteFn(TAny* aPtr, TInt aReason);
+	public:
+		TInt iDriveIndex;
+		DMediaDriverNFE* iMediaExt;
+		RPropertyRef iProperty;
+		TPropertySubsRequest* iPropertySubsRequest;
+		TDfc* iPropertyDfc;	// N.B. subscription call backs don't occur in our thread context, hence the need for this DFC
+		TInt iValue;
+		};
+
+public:
+	 DMediaDriverNFE(TInt aMediaId);
+	~DMediaDriverNFE();
+
+	// replacing pure virtual
+	virtual TInt Request(TLocDrvRequest& aRequest);
+	virtual TInt PartitionInfo(TPartitionInfo &anInfo);
+
+	TInt DoCreate(TInt aMediaId);
+	void Close();
+
+	TNfeDriveInfo*  GetSwapDrive();
+
+private:
+	TInt HandleRead(TLocDrvRequest& aRequest);
+	TInt HandleWrite(TLocDrvRequest& aRequest);
+	TInt HandleFormat(TLocDrvRequest& aRequest);
+	TInt HandleCaps(TLocDrvRequest& aReq);
+
+
+	void EncryptBuffer(TDes8& aBuffer);
+	void DecryptBuffer(TDes8& aBuffer);
+
+	inline TUint8 EncryptByte(TUint8 aByte) {return (TUint8) (aByte ^ 0xDD);}
+	inline TUint8 DecryptByte(TUint8 aByte) {return (TUint8) (aByte ^ 0xDD);}
+	inline TInt DriveIndex(TInt aDriveNum) {return iDriveNumToIndex[aDriveNum];}
+
+	static void IdleTimerCallBack(TAny* aMediaDriver);
+	static void TimerDfcFunction(TAny* aMediaDriver);
+
+	// Publish & Subscribe stuff - used to listen to requests from UI 
+	static void FromUiPropertyDfcFunction(TAny* aObserver);
+	void FromUiPropertyDfc(TPropertyObserver& aObserver);
+
+	// Publish & Subscribe stuff - used to listen to status setting from other NFE drives
+	static void StatusToUiPropertyDfcFunction(TAny* aObserver);
+	void StatusToUiPropertyDfc(TPropertyObserver& aObserver);
+
+	void StartEncrypting();
+	void StartDecrypting();
+
+	TInt HandleDiskContent();	// called from idle timer DFC
+
+	TNfeDriveInfo* NextDrive();
+	
+	TBool AdjustRequest(TNfeDriveInfo*& aDriveInfo, TInt64& aCurrentPos, TInt64& aCurrentLen);
+
+	void SetStatus(TNfeDriveInfo& aDi, TNfeDiskStatus aStatus);
+
+	TBool ValidBootSector(TUint8* aBuffer);
+	TUint32 VolumeId(TUint8* aBuffer);
+	void CheckBootSector(TNfeDriveInfo &aDriveInfo);
+	TInt WriteEncryptionStatusToBootSector(TNfeDriveInfo &aDi, TBool aFinalised = EFalse);
+
+private:
+	TInt iInstance;		// media drive instance
+
+	// A local buffer use for encryting / decrypting
+	// For paging requests we need this to be page aligned, so allocate enough to cater for 
+	// the worst case of up to 4K being wasted at the start of the buffer and the end
+	enum {KSectorSize = 512, KPageSize = 4096, KBufSize = 65536};
+	TUint8 iNonPageAlignedBuffer[KBufSize + KPageSize*2];
+	// a pointer to the start of the first page in iNonPageAlignedBuffer
+	TUint8* iBuffer;
+
+	
+	// Idle timer & DFC for kicking an encryption pass
+	NTimer iIdleTimer;
+	TDfc iTimerDfc;
+
+	TInt iDriveIndex;								// index of local drive number currently being encrypted
+	TInt iDriveNumToIndex[KMaxPartitionEntries];	// maps drive numbers to index
+
+	TBool iBusy;
+
+	const TInt* iDriveList;	// pointer into the drives in NFE_DRIVELIST belonging to this media driver
+	const TInt* iDriveLetterList;	// pointer into the drive letter in NFE_DRIVELETTERLIST belonging to this media driver
+
+	// Publish & subscribe stuff which handles drive command notification events from the UI
+	TPropertyObserver iFromUiPropertyObserver[NFE_DRIVECOUNT];
+
+	// Publish & subscribe stuff which handles drive status notification events from the other NFE drives
+	TPropertyObserver iStatusToUiPropertyObserver[NFE_DRIVECOUNT];
+
+	TBool iDriveFinalised;
+
+public:
+	// Partition information etc for drives this driver is attached to
+	TNfeDeviceInfo iInfo;
+	};
+
+
+
+class TBootSectorStatus
+	{
+public:
+	TUint8 iFatBootSectorData[128];
+	
+	enum {ENfeBootSectorSignature = 0x2045464E};	// 'NFE '
+	TUint32 iSignature;
+
+	TNfeDiskStatus iStatus;
+	TBool iFinalised;
+	TInt64 iEncryptEndPos;	// position of the last encrypted byte +1. Only written when device is powered down
+	};
+
+
+DPhysicalDeviceMediaNFE::DPhysicalDeviceMediaNFE()
+	{
+	__KTRACE_PRINT(Kern::Printf(": DPhysicalDeviceMediaNFE::DPhysicalDeviceMediaNFE()"));
+	iUnitsMask=0x1;
+	iVersion=TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+	}
+
+/**
+Install the Internal NFE PDD.
+*/
+TInt DPhysicalDeviceMediaNFE::Install()
+	{
+	__KTRACE_PRINT(Kern::Printf(": TInt DPhysicalDeviceMediaNFE::Install()"));
+
+	return SetName(&KPddName);
+	}
+
+void DPhysicalDeviceMediaNFE::GetCaps(TDes8& /*aDes*/) const
+	{
+	}
+
+/**
+Create an NFE media driver.
+*/
+TInt DPhysicalDeviceMediaNFE::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /* anInfo */,const TVersion &aVer)
+	{
+	__KTRACE_PRINT(Kern::Printf(": DPhysicalDeviceMediaNFE::Create()"));
+
+	if (!Kern::QueryVersionSupported(iVersion,aVer))
+		return KErrNotSupported;
+
+	TInt r=KErrNoMemory;
+
+	DMediaDriverNFE* pD = new DMediaDriverNFE(aMediaId);
+	aChannel=pD;
+	if (pD)
+		r=pD->DoCreate(aMediaId);
+
+	if (r == KErrNone)
+		pD->OpenMediaDriverComplete(KErrNone);
+
+	return r;
+	}
+
+TInt DPhysicalDeviceMediaNFE::Validate(TInt aDeviceType, const TDesC8* /*anInfo*/, const TVersion& aVer)
+	{
+	TInt r;
+	if (!Kern::QueryVersionSupported(iVersion,aVer))
+		r = KErrNotSupported;
+	else if (aDeviceType == MEDIA_DEVICE_NFE)
+		return r = KErrNone;
+	else
+		r = KErrNotSupported;
+
+//	__KTRACE_PRINT(Kern::Printf("DPhysicalDeviceMediaNFE::Validate() aDeviceType %d NfeDeviceType %d r %d", aDeviceType, MEDIA_DEVICE_NFE, r));
+	return r;
+	}
+
+TInt DPhysicalDeviceMediaNFE::Info(TInt aFunction, TAny*)
+//
+// Return the priority of this media driver
+//
+	{
+//	__KTRACE_PRINT(Kern::Printf(": DPhysicalDeviceMediaNFE::Info()"));
+
+	if (aFunction==EPriority)
+		return KMediaDriverPriorityNormal;
+
+	if (aFunction==EMediaDriverPersistent)
+		return KErrNone;
+
+	return KErrNotSupported;
+	}
+
+DMediaDriverNFE::DMediaDriverNFE(TInt aMediaId) :
+	DMediaDriverExtension(aMediaId),
+	iInstance(((DPrimaryMediaExt*) iPrimaryMedia)->iInstance),
+	iIdleTimer(IdleTimerCallBack,this),
+	iTimerDfc(TimerDfcFunction,this,2),
+	iDriveList (DriveList(iInstance)),
+	iDriveLetterList (DriveLetterList(iInstance))
+	{
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DMediaDriverNFE()", iInstance));
+	iInfo.iDriveCount = DriveCount(iInstance);
+
+	__ASSERT_ALWAYS(Kern::RoundToPageSize(1) == KPageSize, NFE_FAULT());
+
+	// Align the buffer to a page boundary to improve efficiency for paging requests
+	iBuffer = &iNonPageAlignedBuffer[0];
+	iBuffer = (TUint8*) ((((TUint32) &iNonPageAlignedBuffer[0]) + KPageSize-1) & ~(KPageSize-1));
+	}
+
+DMediaDriverNFE::~DMediaDriverNFE()
+//
+// Destructor.
+//
+	{
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::~DMediaDriverNFE()", iInstance));
+
+	TInt i;
+	for (i=0; i<TNfeDeviceInfo::ENfeMaxPartitionEntries; i++)
+		{
+		RPropertyRef* property = (RPropertyRef*) iInfo.iDrives[i].iStatusToUiProperty;
+		if (property)
+			{
+			property->Delete();
+			delete property;
+			}
+		property = (RPropertyRef*) iInfo.iDrives[i].iToUiProperty;
+		if (property)
+			{
+			property->Delete();
+			delete property;
+			}
+		property = (RPropertyRef*) iInfo.iDrives[i].iProgressToUiProperty;
+		if (property)
+			{
+			property->Delete();
+			delete property;
+			}
+		}
+
+	for (i=0; i<NFE_DRIVECOUNT; i++)
+		{
+		iFromUiPropertyObserver[i].Close();
+		iStatusToUiPropertyObserver[i].Close();
+		}
+	}
+
+
+TInt CreateKey(RPropertyRef*& aProperty, TUint aKey)
+	{
+	aProperty = new RPropertyRef;
+	if (aProperty == NULL)
+		return KErrNoMemory;
+	TInt r = aProperty->Attach(KNfeUID, aKey);
+	if (r != KErrNone)
+		return r;
+
+    static _LIT_SECURITY_POLICY_PASS(KPassPolicy);
+	r = aProperty->Define( RProperty::EInt, KPassPolicy, KPassPolicy );
+	if (r != KErrNone && r != KErrAlreadyExists)
+		return r;
+	return KErrNone;
+	}
+
+TInt DMediaDriverNFE::DoCreate(TInt /*aMediaId*/)
+//
+// Create the media driver.
+//
+	{
+	__KTRACE_PRINT(Kern::Printf("NFE%d: TInt DMediaDriverNFE::DoCreate()", iInstance));
+
+	// Associate the idle timer DFC with our thread
+	iTimerDfc.SetDfcQ(iPrimaryMedia->iDfcQ);
+
+	// Publish & Subscribe stuff - used to initiate an encryption pass from the test app
+	static _LIT_SECURITY_POLICY_PASS(KPassPolicy);
+	TInt r;
+	TInt i;
+
+	TInt swapInstance = KErrNotFound;
+#if defined (__DEMAND_PAGING__)
+	swapInstance = SwapInstance();
+#endif
+
+	// **************************************************************************************
+	// Set up P&S publishers so we can publish the status for our drives
+	// **************************************************************************************
+	__KTRACE_PRINT(Kern::Printf("NFE%d: Setting up StatusToUi, ToUi, ProgressToUi P&S publisher & FromUi P&S observer", iInstance));
+
+	for (i = 0; i<DriveCount(iInstance); i++)
+		{
+		__KTRACE_PRINT(Kern::Printf("NFE%d:drive index %d", iInstance, i));
+		TInt driveLetter = iDriveLetterList[i];
+		__KTRACE_PRINT(Kern::Printf("NFE%d:drive letter %c", iInstance, (TInt) DriveLetterToAscii(driveLetter)));
+
+		// no point setting up P&S for the swap drive
+		if (driveLetter == -1)
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: i %d, Skipping P&S for swap partition", iInstance, i));
+			continue;
+			}
+
+		r = CreateKey((RPropertyRef*&) iInfo.iDrives[i].iStatusToUiProperty, NFE_KEY(driveLetter, KNfeStatusToUiKey));
+		if (r != KErrNone)
+			return r;
+
+		r = CreateKey((RPropertyRef*&) iInfo.iDrives[i].iToUiProperty, NFE_KEY(driveLetter, KNfeToUiKey));
+		if (r != KErrNone)
+			return r;
+
+		r = CreateKey((RPropertyRef*&) iInfo.iDrives[i].iProgressToUiProperty, NFE_KEY(driveLetter, KNfeProgressToUiKey));
+		if (r != KErrNone)
+			return r;
+
+		TPropertyObserver& observer = iFromUiPropertyObserver[i];
+		observer.iDriveIndex = i;
+		observer.iMediaExt = this;
+		observer.iPropertySubsRequest = new TPropertySubsRequest(TPropertyObserver::PropertySubsCompleteFn, &observer);
+		if (observer.iPropertySubsRequest == NULL)
+			return KErrNoMemory;
+
+		observer.iPropertyDfc = new TDfc(FromUiPropertyDfcFunction,&observer,iPrimaryMedia->iDfcQ,2);
+		if (observer.iPropertyDfc == NULL)
+			return KErrNoMemory;
+		
+		r = observer.iProperty.Attach(KNfeUID, NFE_KEY(driveLetter, KNfeToThreadKey));
+		if (r != KErrNone)
+			return r;
+		r = observer.iProperty.Define(
+			RProperty::EInt,
+			KPassPolicy, 
+			KPassPolicy);
+		if (r != KErrNone && r != KErrAlreadyExists)
+			return r;
+
+		r = observer.iProperty.Subscribe(*observer.iPropertySubsRequest);
+		if (r != KErrNone)
+			return r;
+		}
+
+	// **************************************************************************************
+	// If this instance owns the swap partition,
+	// set up P&S listeners so we can get status notification events from the other drives
+	// **************************************************************************************
+	__KTRACE_PRINT(Kern::Printf("NFE%d: Setting up StatusToUi P&S observer", iInstance));
+
+	for (i = 0; i < (iInstance == swapInstance ? NFE_DRIVECOUNT : -1); i++)
+		{
+		__KTRACE_PRINT(Kern::Printf("NFE%d:drive index %d", iInstance, i));
+		__KTRACE_PRINT(Kern::Printf("NFE%d:drive letter %c", iInstance, (TInt) DriveLetterToAscii(DriveLetter(i))));
+
+		// no point setting up P&S for the swap drive
+		if (DriveLetter(i) == -1)
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: i %d, Skipping StatusToUi P&S observer for swap partition", iInstance, i));
+			continue;
+			}
+
+		__KTRACE_PRINT(Kern::Printf("NFE%d: i %d, Setting up StatusToUi P&S observer for drive %c", iInstance, i, (TInt) DriveLetterToAscii(DriveLetter(i))));
+		TPropertyObserver& observer = iStatusToUiPropertyObserver[i];
+		observer.iDriveIndex = i;
+		observer.iMediaExt = this;
+		observer.iPropertySubsRequest = new TPropertySubsRequest(TPropertyObserver::PropertySubsCompleteFn, &observer);
+		if (observer.iPropertySubsRequest == NULL)
+			return KErrNoMemory;
+
+		observer.iPropertyDfc = new TDfc(StatusToUiPropertyDfcFunction,&observer,iPrimaryMedia->iDfcQ,2);
+		if (observer.iPropertyDfc == NULL)
+			return KErrNoMemory;
+		
+		r = observer.iProperty.Attach(KNfeUID, NFE_KEY(DriveLetter(i), KNfeStatusToUiKey));
+		if (r != KErrNone)
+			return r;
+		r = observer.iProperty.Define(
+			RProperty::EInt,
+			KPassPolicy, 
+			KPassPolicy);
+		if (r != KErrNone && r != KErrAlreadyExists)
+			return r;
+
+		r = observer.iProperty.Subscribe(*observer.iPropertySubsRequest);
+		if (r != KErrNone)
+			return r;
+		}
+
+	return(KErrNone);
+	}
+
+void DMediaDriverNFE::TPropertyObserver::Close()
+	{
+	iProperty.Close();
+	delete iPropertyDfc;
+	iPropertyDfc = NULL;
+	delete iPropertySubsRequest;
+	iPropertySubsRequest = NULL;
+	}
+
+void DMediaDriverNFE::TPropertyObserver::PropertySubsCompleteFn(TAny* aPtr, TInt /*aReason*/)
+	{
+	TPropertyObserver* self = (TPropertyObserver*) aPtr;
+	// Queue a DFC to ensure we're running in the correct thread
+	self->iPropertyDfc->Enque();
+	}
+
+void DMediaDriverNFE::FromUiPropertyDfcFunction(TAny* aObserver)
+	{
+	TPropertyObserver& observer = *(TPropertyObserver*) aObserver;
+	observer.iMediaExt->FromUiPropertyDfc(observer);
+	}
+
+void DMediaDriverNFE::FromUiPropertyDfc(TPropertyObserver& aObserver)
+	{
+    // Get the value of request from the UI
+    TInt err = aObserver.iProperty.Get(aObserver.iValue);
+
+	TInt r = aObserver.iProperty.Subscribe(*aObserver.iPropertySubsRequest);
+	__ASSERT_ALWAYS(r == KErrNone, NFE_FAULT());
+
+	TInt driveLetter = iDriveLetterList[aObserver.iDriveIndex];
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::FromUiPropertyDfc() cmd %d driveLetter %c", 
+		iInstance, aObserver.iValue, (TInt) DriveLetterToAscii(driveLetter)));
+
+	// is this our drive letter ?
+	TInt driveCount = DriveCount(iInstance);
+	TNfeDriveInfo* driveInfo = NULL;
+
+	for (TInt i=0; i<driveCount; i++)
+		{
+		TInt myDriveLetter = iDriveLetterList[i];
+
+		__KTRACE_PRINT(Kern::Printf("NFE%d: Comparing drive %c with myDrive %c", iInstance, (TInt) DriveLetterToAscii(driveLetter), (TInt) DriveLetterToAscii(myDriveLetter)));
+
+		if (myDriveLetter == driveLetter)
+			{
+			TInt driveNumber = iDriveList[i];
+			driveInfo = &iInfo.iDrives[iDriveNumToIndex[driveNumber]];
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Drive Match found driveNumber %d", iInstance, driveInfo->iLocalDriveNum));
+
+			__ASSERT_ALWAYS(driveInfo->iProgressToUiProperty, NFE_FAULT());
+			((RPropertyRef*) (driveInfo->iProgressToUiProperty))->Set(0); 
+			// Wake up the possibly waiting client, whether or not the request
+			// was successfull.
+			((RPropertyRef*) (driveInfo->iToUiProperty))->Set( err ); // Return value ignored
+			break;
+			}
+		}
+
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: err %d aObserver.iValue %d swap %x swap state %d", iInstance, err, aObserver.iValue, GetSwapDrive(), GetSwapDrive() ? GetSwapDrive()->Status() : -1));
+
+	if (err == KErrNone && aObserver.iValue == ENfeEncryptDisk && driveInfo != NULL)
+		{
+		if (driveInfo->Status() == ENfeDecrypted)
+			{
+			SetStatus(*driveInfo, ENfeEncrypting);
+			StartEncrypting();
+			}
+		}
+	if (err == KErrNone && aObserver.iValue == ENfeDecryptDisk && driveInfo != NULL)
+		{
+		if (driveInfo->Status() == ENfeEncrypted)
+			{
+			SetStatus(*driveInfo, ENfeDecrypting);
+			StartDecrypting();
+			}
+		}
+	}
+
+
+void DMediaDriverNFE::StatusToUiPropertyDfcFunction(TAny* aObserver)
+	{
+	TPropertyObserver& observer = *(TPropertyObserver*) aObserver;
+	observer.iMediaExt->StatusToUiPropertyDfc(observer);
+	}
+
+void DMediaDriverNFE::StatusToUiPropertyDfc(TPropertyObserver& aObserver)
+	{
+    // Get the value of request from the UI
+    TInt err = aObserver.iProperty.Get(aObserver.iValue);
+
+	TInt r = aObserver.iProperty.Subscribe(*aObserver.iPropertySubsRequest);
+	__ASSERT_ALWAYS(r == KErrNone, NFE_FAULT());
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::StatusToUiPropertyDfc() status %d driveLetter %c", 
+		iInstance, aObserver.iValue, DriveLetter(aObserver.iDriveIndex) >=0 ? DriveLetter(aObserver.iDriveIndex)+'A' : '?'));
+
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: err %d aObserver.iValue %d swap %x swap state %d", iInstance, err, aObserver.iValue, GetSwapDrive(), GetSwapDrive() ? GetSwapDrive()->Status() : -1));
+
+	if (err == KErrNone && (aObserver.iValue == ENfeEncrypted || aObserver.iValue == ENfeEncrypting))
+		{
+		// If any drive is being or is already encrypted then we have to encrypt the swap partition...
+		TNfeDriveInfo* diSwap = GetSwapDrive();
+		if (diSwap != NULL && diSwap->Status() == ENfeDecrypted)
+			{
+			SetStatus(*diSwap, ENfeEncrypting);
+			StartEncrypting();
+			}
+		}
+	}
+
+
+void DMediaDriverNFE::Close()
+	{
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::Close()", iInstance));
+	DMediaDriverExtension::Close();
+	}
+
+
+void DMediaDriverNFE::SetStatus(TNfeDriveInfo& aDi, TNfeDiskStatus aStatus)
+	{
+	if (aStatus != aDi.Status())
+		{
+		aDi.SetStatus(aStatus);
+		__KTRACE_PRINT(Kern::Printf("NFE%d: SetStatus = %s", iInstance, DriveStatus(aDi.Status())));
+		}
+	}
+
+void TNfeDriveInfo::SetStatus(TNfeDiskStatus aStatus)
+    {
+	iStatus = aStatus;
+	if (IsUDADrive())
+		{
+		// Update the status pub&sub variable for UI
+		__ASSERT_ALWAYS(iStatusToUiProperty, NFE_FAULT());
+		((RPropertyRef*) iStatusToUiProperty)->Set(aStatus);
+		}
+	}
+
+
+
+
+TInt DMediaDriverNFE::Request(TLocDrvRequest& aReq)
+	{
+//	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DoRequest() : Req %d drv %d flags %x pos %lx len %lx", iInstance, reqId, aReq.Drive()->iDriveNumber, aReq.Flags(), aReq.Pos(), aReq.Length()));
+
+	TInt r = KErrNotSupported;
+
+	TInt reqId = aReq.Id();
+    TNfeDriveInfo& di = iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)];
+
+	switch (reqId)
+		{
+#if defined(__DEMAND_PAGING__)
+		case DMediaPagingDevice::ERomPageInRequest:
+			BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_NFE,&aReq);
+			r=HandleRead(aReq);
+			break;
+
+		case DMediaPagingDevice::ECodePageInRequest:
+			BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_NFE,&aReq);
+			r=HandleRead(aReq);
+			break;
+
+#endif	// __DEMAND_PAGING__
+
+		case DLocalDrive::ERead:
+			r=HandleRead(aReq);
+			break;
+
+		case DLocalDrive::EWrite:
+			WriteEncryptionStatusToBootSector(di, EFalse);	// a write to the drive clears the finalised state
+			r=HandleWrite(aReq);
+			break;
+
+		case DLocalDrive::ECaps:
+			r = HandleCaps(aReq);
+			break;
+
+		case DLocalDrive::EFormat:
+			r = HandleFormat(aReq);
+			break;
+
+		// API used by T_NFE to query state etc.
+		case DLocalDrive::EQueryDevice:
+			switch((TInt) aReq.iArg[0])
+				{
+				case EQueryNfeDeviceInfo:
+					{
+					TNfeDeviceInfo& deviceInfo = *(TNfeDeviceInfo*) aReq.RemoteDes();
+					iInfo.iMediaSizeInBytes = iTotalSizeInBytes;
+					deviceInfo = iInfo;
+
+					r = KErrCompletion;
+					break;
+					}
+				case RLocalDrive::EQueryFinaliseDrive:
+					{
+//					TLocalDriveFinaliseInfo& finaliseInfo = *(TLocalDriveFinaliseInfo*) aReq.RemoteDes();
+//					__KTRACE_PRINT(Kern::Printf("NFE%d: EQueryFinaliseDrive iMode %d", iInstance, finaliseInfo.iMode));
+
+					// write to boot sector to indicate that the drive has ben finalised
+					WriteEncryptionStatusToBootSector(di, ETrue);
+					}
+				default:
+					r = KErrNotSupported;
+					break;
+				}
+			break;
+
+		default:
+			r = ForwardRequest(aReq);
+			break;
+		}
+
+//	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::DoRequest() : ret: %d", iInstance, r));
+
+	if (!di.iDriveFinalised && iBusy)
+		{
+		// Restart the idle timer after processing a request 
+		iIdleTimer.Cancel();
+		iTimerDfc.Cancel();
+		iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval));
+		}
+
+	return r;
+	}
+
+/**
+PartitionInfo()
+
+    Reads the partition information from the attached drive(s). 
+    Note: this method is also called when a removable card is removed, so can  
+    be used to detect a memory card insertions/removals. Assumes the swap 
+    partition is encrypted if any encrypted FAT drives are found
+*/
+TInt DMediaDriverNFE::PartitionInfo(TPartitionInfo& aInfo)
+	{
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DMediaDriverNFE::PartitionInfo()", iInstance));
+
+	TInt r = DoDrivePartitionInfo(aInfo);
+	__KTRACE_PRINT(Kern::Printf("NFE%d: DoDrivePartitionInfo() r %d", iInstance, r));
+	if (r != KErrNone)
+		return r;
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: *** Slave drives partition info ***", iInstance));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: iMediaSizeInBytes %lx", iInstance, aInfo.iMediaSizeInBytes));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: iPartitionCount %d", iInstance, aInfo.iPartitionCount));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: ", iInstance));
+
+	TInt i;
+
+	__ASSERT_DEBUG(aInfo.iPartitionCount <= TNfeDeviceInfo::ENfeMaxPartitionEntries, NFE_FAULT());
+	for (i=0; i<aInfo.iPartitionCount; i++)
+		{
+		TInt driveNum = iDriveList[i];
+		iDriveNumToIndex[driveNum] = i;
+
+		TNfeDriveInfo& di = iInfo.iDrives[i];
+
+		di.iDriveFinalised = EFalse;	// a remount clears the finalised state
+
+		// Make a copy of the TPartitionEntry
+		di.iEntry = aInfo.iEntry[i];
+
+
+		// save the local drive number
+		di.iLocalDriveNum = driveNum;
+		di.iDriveLetter = iDriveLetterList[i];
+
+		__KTRACE_PRINT(Kern::Printf("NFE%d: DriveNum %d", iInstance, driveNum));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: DriveLetter %c", iInstance, (TInt) DriveLetterToAscii(di.iDriveLetter)));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: iPartitionBaseAddr %lX", iInstance, di.iEntry.iPartitionBaseAddr));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: iPartitionLen %lx", iInstance, di.iEntry.iPartitionLen));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: iPartitionType %x", iInstance, di.iEntry.iPartitionType));
+		
+
+		// If the drive was removed, reset it's state
+		if (di.iEntry.iPartitionType == KPartitionTypeEmpty)
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Empty Partition, setting state to ENfeUnmounted", iInstance));
+			SetStatus(di, ENfeUnmounted);
+			}
+
+		// Is this an unencrypted FAT partition ?
+		if (di.IsUDADrive())
+			{
+			r = Read(di.iLocalDriveNum, di.iEntry.iPartitionBaseAddr, (TLinAddr) iBuffer, KSectorSize);
+			if (r != KErrNone)
+				return r;
+			CheckBootSector(di);
+			}
+		
+
+		__KTRACE_PRINT(Kern::Printf("NFE%d: status = %s", iInstance, DriveStatus(di.Status())));
+
+		__KTRACE_PRINT(Kern::Printf("NFE%d: iEncryptStartPos %lX", iInstance, di.iEncryptStartPos));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: iEncryptEndPos %lX", iInstance, di.iEncryptEndPos));
+		__KTRACE_PRINT(Kern::Printf("NFE%d: ", iInstance));
+		}
+
+
+
+#ifdef COMPOSITE_DRIVES
+	// Accumulate the sizes of consecutive FAT drives & report the accumulated size back in the first FAT partition
+	for (i=0; i<aInfo.iPartitionCount; i++)
+		{
+		aInfo.iEntry[i] = iInfo.iDrives[i].iEntry;
+
+		if (iInfo.iDrives[i].IsUDADrive())
+			{
+			aInfo.iEntry[i].iPartitionLen = 0;
+			for (TInt j=i; j<aInfo.iPartitionCount; j++)
+				{
+				if (iInfo.iDrives[j].IsUDADrive())
+					{
+					aInfo.iEntry[i].iPartitionLen+= iInfo.iDrives[j].iEntry.iPartitionLen;
+					}
+				}
+			iInfo.iDrives[i].iCompositeSize = aInfo.iEntry[i].iPartitionLen;
+			i = j;
+			}
+		}
+#endif
+
+
+	SetTotalSizeInBytes(aInfo.iMediaSizeInBytes);
+
+
+	return KErrCompletion;	// synchronous completion
+	}
+
+/**
+HandleCaps() - 
+
+Return the Caps for a particular drive
+
+Queries the caps from the attached drive, ORs in appropriate paging flags & returns
+*/
+TInt DMediaDriverNFE::HandleCaps(TLocDrvRequest& aReq)
+	{
+	// Get caps from slave drive
+	// NB if we didn't want to alter anything then we could just call ForwardRequest(aReq);
+	TBuf8<sizeof(TLocalDriveCapsV6)> slaveCapsBuf;
+	TLocalDriveCapsV6& slaveCaps = *(TLocalDriveCapsV6*) slaveCapsBuf.Ptr();
+	slaveCapsBuf.SetMax();
+	slaveCapsBuf.FillZ();
+	TInt r = Caps(aReq.Drive()->iDriveNumber, slaveCapsBuf);
+	if (r != KErrNone)
+		return r;
+
+#ifdef COMPOSITE_DRIVES
+	TInt driveNum = aReq.Drive()->iDriveNumber;
+	TInt driveIndex = DriveIndex(driveNum);
+	if (iInfo.iDrives[driveIndex].iCompositeSize)
+		slaveCaps.iSize = iInfo.iDrives[driveIndex].iCompositeSize;
+#endif
+
+	// copy slave caps to returned caps
+	TLocalDriveCapsV6& caps = *(TLocalDriveCapsV6*)aReq.RemoteDes();		
+	caps = slaveCaps;
+
+	// set the paging flags
+#ifdef __DEMAND_PAGING__
+	TLocDrv& drive = *aReq.Drive();
+	if (drive.iPrimaryMedia->iPagingMedia)
+		caps.iMediaAtt|=KMediaAttPageable;
+	if (drive.iPagingDrv)
+		caps.iDriveAtt|=KDriveAttPageable;
+#endif // __DEMAND_PAGING__
+
+	return KErrCompletion;
+	}
+
+
+/**
+AdjustRequest() - 
+
+Adjusts position & length if a request crosses these boundaries:
+- the start of the partition (if RLocalDrive::ELocDrvWholeMedia set)
+- the current encrytion point (iEncryptEndPos) N.B. this will point to the end of the partition 
+  if the drive is fully encrypted
+
+For composite drives, it also adjusts the position, length & drive number as appropriate to cater for 
+crossing partition boundaries
+
+returns ETrue if buffer needs encrypting/decrypting
+*/
+
+TBool DMediaDriverNFE::AdjustRequest(TNfeDriveInfo*& aDriveInfo, TInt64& aCurrentPos, TInt64& aCurrentLen)
+	{
+#ifdef COMPOSITE_DRIVES
+	while (aCurrentPos >= aDriveInfo->iEntry.iPartitionLen)
+		{
+		aCurrentPos-= aDriveInfo->iEntry.iPartitionLen;
+		aDriveInfo++;
+		}
+	if (aCurrentPos + aCurrentLen > aDriveInfo->iEntry.iPartitionLen)
+		aCurrentLen = aDriveInfo->iEntry.iPartitionLen - aCurrentPos;
+#endif
+
+	// do we need to encrypt/decrypt this buffer ?
+	TBool encodeBuffer = EFalse;
+	
+	if ((aDriveInfo->Status() == ENfeEncrypted) || aDriveInfo->Status() == ENfeEncrypting)
+		{
+//		__ASSERT_DEBUG(aDriveInfo->iEncryptEndPos <= aDriveInfo->iEntry.iPartitionBaseAddr + aDriveInfo->iEntry.iPartitionLen, NFE_FAULT());
+
+		if (aCurrentPos < aDriveInfo->iEncryptStartPos)
+			{
+			aCurrentLen = Min(aCurrentLen, aDriveInfo->iEncryptStartPos - aCurrentPos);
+			encodeBuffer = EFalse;
+			}
+		else if (aCurrentPos < aDriveInfo->iEncryptEndPos)
+			{
+			aCurrentLen = Min(aCurrentLen, aDriveInfo->iEncryptEndPos - aCurrentPos);
+			encodeBuffer = ETrue;
+			}
+		else
+			{
+			encodeBuffer = EFalse;
+			}
+		}
+
+	return encodeBuffer;
+	}
+
+
+TInt DMediaDriverNFE::HandleRead(TLocDrvRequest& aReq)
+	{
+	TInt r = KErrNone;
+	TInt64 currentPos = aReq.Pos();
+	TInt64 remainingLength = aReq.Length();
+	TInt desPos = 0;
+	TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)];
+
+//	__KTRACE_PRINT(Kern::Printf("NFE%d: HandleRead pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status()));
+
+
+	di->iReadRequestCount++;
+
+	if (aReq.Flags() & TLocDrvRequest::ECodePaging)
+		di->iCodePagingRequesCount++;
+	if (aReq.Flags() & TLocDrvRequest::EDataPaging)
+		di->iDataPagingReadRequestCount++;
+
+	
+	// just forward the request if the drive is not encrypted
+	if (di->Status() == ENfeDecrypted)
+		return ForwardRequest(aReq);
+
+	
+	while(remainingLength)
+		{
+		TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize);
+
+		TBool decryptBuffer = AdjustRequest(di, currentPos, currentLength);
+
+		// Read from attached drive
+#ifdef __DEMAND_PAGING__
+		if (DMediaPagingDevice::PagingRequest(aReq))
+			r = ReadPaged(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength));
+		else
+#endif
+		r = Read(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength));
+		if(r != KErrNone)
+			break;
+
+		TPtr8 des(iBuffer, I64LOW(currentLength), I64LOW(currentLength));
+
+		// decrypt buffer
+		if (decryptBuffer)
+			DecryptBuffer(des);
+
+		//  write back to user
+		r = aReq.WriteRemote(&des, desPos);
+		if(r != KErrNone)
+			break;
+
+		remainingLength-= currentLength;
+		currentPos+= currentLength;
+		desPos+= I64LOW(currentLength);
+		}
+
+	return r == KErrNone ? KErrCompletion : r;
+	}
+
+TInt DMediaDriverNFE::HandleWrite(TLocDrvRequest& aReq)
+	{
+	TInt r = KErrNone;
+	TInt64 currentPos =  aReq.Pos();
+	TInt64 remainingLength = aReq.Length();
+	TInt desPos = 0;
+	TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)];
+
+//	__KTRACE_PRINT(Kern::Printf("NFE%d: HandleWrite pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status()));
+
+
+	di->iWriteRequestCount++;
+	if (aReq.Flags() & TLocDrvRequest::EDataPaging)
+		di->iDataPagingWriteRequestCount++;
+	
+
+	// just forward the request if the drive is not encrypted
+	if (di->Status() == ENfeDecrypted)
+		return ForwardRequest(aReq);
+
+	while(remainingLength)
+		{
+		TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize);
+
+		TBool encryptBuffer = AdjustRequest(di, currentPos, currentLength);
+
+		// read from user
+		TPtr8 des(iBuffer,0,I64LOW(currentLength));
+		r = aReq.ReadRemote(&des, desPos);
+		if(r != KErrNone)
+			break;
+		
+		// get the length of data read from the user in case user's
+		// descriptor is shorter than advertised
+		currentLength = des.Length();
+		if (currentLength == 0)
+			break;
+
+		// writing to sector zero ?
+		if (currentPos >= di->iEntry.iPartitionBaseAddr && 
+			currentPos < di->iEntry.iPartitionBaseAddr + KSectorSize && 
+			di->IsUDADrive())
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Write to sector #0 detected", iInstance));
+
+
+			TUint8* bootSector = iBuffer;
+			TUint8 bootSectorBuffer[KSectorSize];
+			// writing partial sector ?
+			if (currentPos > di->iEntry.iPartitionBaseAddr || currentLength < KSectorSize)
+				{
+				bootSector = bootSectorBuffer;
+				r = Read(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) bootSector, KSectorSize);
+				if(r != KErrNone)
+					break;
+				TInt64 readLen = KSectorSize;
+				TBool encryptBuffer = AdjustRequest(di, di->iEntry.iPartitionBaseAddr, readLen);
+				if (encryptBuffer)
+					{
+					TPtr8 des(bootSectorBuffer,KSectorSize,KSectorSize);
+					DecryptBuffer(des);
+					}
+				TInt sectorOffset = (TInt) (currentPos - di->iEntry.iPartitionBaseAddr);
+				TInt64 copyLen = currentLength;
+				if (copyLen > KSectorSize-sectorOffset)
+					copyLen = KSectorSize-sectorOffset;
+				memcpy(bootSectorBuffer+sectorOffset, iBuffer, (TInt) copyLen);
+				}
+
+			if ((di->Status() == ENfeUnmounted || di->Status() == ENfeCorrupted) && 
+				ValidBootSector(bootSector))
+				{
+				__KTRACE_PRINT(Kern::Printf("NFE%d: Setting status to ENfeDecrypted", iInstance ));
+				di->SetStatus(ENfeDecrypted);
+				}
+			di->iUniqueID = VolumeId(bootSector);		// update the Volume ID
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Setting Volume ID to %08X", iInstance, di->iUniqueID ));
+			TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer;
+			if (di->Status() == ENfeEncrypting || di->Status() == ENfeDecrypting)
+				{
+				__KTRACE_PRINT(Kern::Printf("NFE%d: Adding NFE status record to boot sector", iInstance ));
+				bootSectorStatus->iSignature = TBootSectorStatus::ENfeBootSectorSignature;
+				bootSectorStatus->iEncryptEndPos = di->iEncryptEndPos;
+				bootSectorStatus->iStatus = di->Status();
+				bootSectorStatus->iFinalised = EFalse;
+				}
+			}
+
+		// encrypt the buffer
+		if (encryptBuffer)
+			EncryptBuffer(des);
+
+		// write the data to the attached drive
+#ifdef __DEMAND_PAGING__
+		if (DMediaPagingDevice::PagingRequest(aReq))
+			r = WritePaged(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength));
+		else
+#endif
+		r = Write(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength));
+		if(r != KErrNone)
+			break;
+
+		remainingLength-= currentLength;
+		currentPos+= currentLength;
+		desPos+= I64LOW(currentLength);
+		}
+
+	return r == KErrNone ? KErrCompletion : r;
+	}
+
+TInt DMediaDriverNFE::HandleFormat(TLocDrvRequest& aReq)
+	{
+	TInt r = KErrNone;
+	TInt64 currentPos =  aReq.Pos();
+	TInt64 remainingLength = aReq.Length();
+	TNfeDriveInfo* di = &iInfo.iDrives[DriveIndex(aReq.Drive()->iDriveNumber)];
+
+//	__KTRACE_PRINT(Kern::Printf("NFE%d: HandleFormat pos %lx len %lx status %d", iInstance, currentPos, remainingLength, di->Status()));
+
+
+	// just forward the request if the drive is not encrypted
+	if (di->Status() == ENfeDecrypted)
+		return ForwardRequest(aReq);
+
+	// otherwise create a buffer containing NULLs, encrypt it and write that to the attached drive
+	while(remainingLength && r == KErrNone)
+		{
+		TInt64 currentLength = (remainingLength <= KBufSize ? remainingLength : KBufSize);
+
+		TBool encryptBuffer = AdjustRequest(di, currentPos, currentLength);
+
+		memclr(iBuffer, KBufSize);
+		TPtr8 des(iBuffer,KBufSize,KBufSize);
+
+		if (encryptBuffer)
+			EncryptBuffer(des);
+		
+		r = Write(di->iLocalDriveNum, currentPos, (TLinAddr) iBuffer, I64LOW(currentLength));
+		if(r != KErrNone)
+			break;
+
+		remainingLength-= currentLength;
+		currentPos+= currentLength;
+		}
+
+	return r == KErrNone ? KErrCompletion : r;
+	}
+
+
+void DMediaDriverNFE::EncryptBuffer(TDes8& aBuffer)
+	{
+	TInt len = aBuffer.Length();
+	for(TInt i=0; i<len; i++)
+		aBuffer[i] = EncryptByte(aBuffer[i]);
+	}
+
+void DMediaDriverNFE::DecryptBuffer(TDes8& aBuffer)
+	{
+	TInt len = aBuffer.Length();
+	for(TInt i=0; i<len; i++)
+		aBuffer[i] = DecryptByte(aBuffer[i]);
+	}
+
+
+TNfeDriveInfo* DMediaDriverNFE::GetSwapDrive()
+	{
+	for (TInt i=0; i<iInfo.iDriveCount; i++)
+		{
+		TNfeDriveInfo& di = iInfo.iDrives[i];
+		if (di.iEntry.iPartitionType == KPartitionTypePagedData)
+			{
+			return &di;
+			}
+		}
+	return NULL;	// swap drive not found
+	}
+
+/**
+Get the first/next drive to encrypt 
+*/
+
+TNfeDriveInfo* DMediaDriverNFE::NextDrive()
+	{
+	for (iDriveIndex = 0; iDriveIndex<iInfo.iDriveCount; iDriveIndex++)
+		{
+		TNfeDriveInfo& di = iInfo.iDrives[iDriveIndex];
+		TNfeDiskStatus status = iInfo.iDrives[iDriveIndex].Status();
+		if (status == ENfeEncrypting || status == ENfeDecrypting)
+			{
+			di.iEncryptStartPos = di.iEncryptEndPos = di.iEntry.iPartitionBaseAddr;
+
+			// write to boot sector to indicate we are encrypting/decrypting this drive
+			WriteEncryptionStatusToBootSector(di);
+
+			return &di;
+			}
+		}
+	__KTRACE_PRINT(Kern::Printf("NFE%d: Finished encrypting / decrypting", iInstance));
+	iBusy = EFalse;
+	return NULL;
+	}
+
+
+/** 
+Finds the first unencrypted drive & kicks off the idle timer - 
+when this expires the encryption of the drive will start
+*/
+void DMediaDriverNFE::StartEncrypting()
+	{
+	// start encrypting if not already doing so
+	if (!iBusy)
+		{
+		iBusy = ETrue;
+		TNfeDriveInfo* di = NextDrive();
+		if (di)
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Start encrypting drive %d...", iInstance, iInfo.iDrives[iDriveIndex].iLocalDriveNum));
+			iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval));
+			}
+		}
+	}
+
+/** 
+Finds the first unencrypted drive & kicks off the idle timer - 
+when this expires the encryption of the drive will start
+*/
+void DMediaDriverNFE::StartDecrypting()
+	{
+	// start encrypting if not already doing so
+	if (!iBusy)
+		{
+		iBusy = ETrue;
+		TNfeDriveInfo* di = NextDrive();
+		if (di)
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Start decrypting drive %d...", iInstance, iInfo.iDrives[iDriveIndex].iLocalDriveNum));
+			iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval));
+			}
+		}
+	}
+
+/**
+Idle timer callback
+Kicks off a DFC to ensure we are running in the correct thread
+*/
+void DMediaDriverNFE::IdleTimerCallBack(TAny* aMediaDriver)
+	{
+	((DMediaDriverNFE*)aMediaDriver)->iTimerDfc.Add();
+	}
+
+/**
+Idle timer DFC
+*/
+void DMediaDriverNFE::TimerDfcFunction(TAny* aMediaDriver)
+	{
+	((DMediaDriverNFE*) aMediaDriver)->HandleDiskContent();
+	}
+
+
+TBool DMediaDriverNFE::ValidBootSector(TUint8* aBuffer)
+	{
+	if (aBuffer[0] == 0xEB || aBuffer[0] == 0xE9)
+		return ETrue;
+	else
+		return EFalse;
+	}
+
+
+TUint32 DMediaDriverNFE::VolumeId(TUint8* aBuffer)
+	{
+	TUint16 rootDirEntries;
+	TUint32 uniqueID;   
+    memcpy(&rootDirEntries,&aBuffer[17], 2);	// 17   TUint16 iRootDirEntries
+	TBool fat32 = rootDirEntries == 0;
+	TInt pos = fat32 ? 67 : 39;		// get position of VolumeID
+	memcpy(&uniqueID,&aBuffer[pos],4);
+	return uniqueID;
+	}
+
+void DMediaDriverNFE::CheckBootSector(TNfeDriveInfo &aDi)
+	{
+	TNfeDiskStatus  fatBootSectorStatus = ENfeDecrypted;
+
+	// Try to determine whether the FAT boot sector is encypted
+	if (ValidBootSector(iBuffer))
+		{
+		fatBootSectorStatus = ENfeDecrypted;
+		__KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is decrypted", iInstance));
+		}
+	else
+		{
+		TPtr8 des(iBuffer, KSectorSize, KSectorSize);
+		DecryptBuffer(des);
+		if (ValidBootSector(iBuffer))
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is encrypted", iInstance));
+			fatBootSectorStatus = ENfeEncrypted;
+			}
+		else
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: FAT Boot sector is corrupted", iInstance));
+			fatBootSectorStatus = ENfeCorrupted;
+			}
+		}
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: fatBootSectorStatus %d", iInstance, fatBootSectorStatus));
+
+	// Find out whether the volume has changed
+	TUint32 uniqueID = VolumeId(iBuffer);   
+	TBool volumeChanged = uniqueID != aDi.iUniqueID;
+	__KTRACE_PRINT(Kern::Printf("NFE%d: Old Volume ID %08X", iInstance, aDi.iUniqueID));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: New Volume ID %08X", iInstance, uniqueID));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: volumeChanged %d", iInstance, volumeChanged));
+	aDi.iUniqueID = uniqueID;
+
+
+
+	TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer;
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iSignature %08X", iInstance, bootSectorStatus->iSignature));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iStatus %d", iInstance, bootSectorStatus->iStatus));
+	__KTRACE_PRINT(Kern::Printf("NFE%d: CheckBootSector, iEncryptEndPos %lx", iInstance, bootSectorStatus->iEncryptEndPos));
+
+
+	/*
+	If there IS NFE info in the boot sector, restore the encryption settings - 
+	unless the 'finalised' flag is clear which indicates that the media was removed or power was lost
+	while encrypting the device...
+
+	If there is no NFE info in the boot sector and there has been a volume change, then we can decide  
+	whether the drive is encrypted/decrypted/corrupt by examining the boot sector
+	*/
+	if (volumeChanged && 
+		fatBootSectorStatus != ENfeCorrupted &&
+		bootSectorStatus->iSignature == TBootSectorStatus::ENfeBootSectorSignature &&
+		!bootSectorStatus->iFinalised)
+		{
+		SetStatus(aDi, ENfeCorrupted);
+		}
+	else if (volumeChanged && 
+		fatBootSectorStatus != ENfeCorrupted &&
+		bootSectorStatus->iFinalised &&
+		bootSectorStatus->iSignature == TBootSectorStatus::ENfeBootSectorSignature &&
+		(bootSectorStatus->iStatus == ENfeDecrypting || bootSectorStatus->iStatus == ENfeEncrypting))
+		{
+		SetStatus(aDi, bootSectorStatus->iStatus);
+		aDi.iEncryptEndPos = bootSectorStatus->iEncryptEndPos;
+
+		// write to boot sector to indicate we are no longer finalised
+		WriteEncryptionStatusToBootSector(aDi, EFalse);	
+
+		iBusy = ETrue;
+		}
+	else if (volumeChanged || aDi.Status() == ENfeUnmounted)
+		{
+		SetStatus(aDi, fatBootSectorStatus);
+		if (aDi.Status() == ENfeEncrypted)
+			{
+			aDi.iEncryptStartPos = aDi.iEntry.iPartitionBaseAddr;
+			aDi.iEncryptEndPos = aDi.iEntry.iPartitionBaseAddr + aDi.iEntry.iPartitionLen;
+			}
+		}
+	}
+
+
+TInt DMediaDriverNFE::WriteEncryptionStatusToBootSector(TNfeDriveInfo &aDi, TBool aFinalised)
+	{
+	if (!aDi.IsUDADrive())
+		return KErrNone;
+
+	if (aDi.iDriveFinalised == aFinalised)
+		return KErrNone;
+
+	TNfeDiskStatus status = aDi.Status();
+
+	TInt64 currentPos = aDi.iEntry.iPartitionBaseAddr;
+	TInt64 currentLen = KSectorSize;
+	TNfeDriveInfo* di = &aDi;
+	TBool encodeBuffer = EFalse;
+
+	if (status == ENfeEncrypting || status == ENfeEncrypted || status == ENfeDecrypting)
+		encodeBuffer = AdjustRequest(di, currentPos, currentLen);
+
+
+	TInt r = Read(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) iBuffer, KSectorSize);
+	if (r != KErrNone)
+		return r;
+	TPtr8 des(iBuffer, I64LOW(currentLen), I64LOW(currentLen));
+
+	if (encodeBuffer)
+		DecryptBuffer(des);
+
+
+	TBootSectorStatus* bootSectorStatus = (TBootSectorStatus*) iBuffer;
+
+	if (status == ENfeEncrypting || status == ENfeDecrypting)
+		{
+		bootSectorStatus->iSignature = TBootSectorStatus::ENfeBootSectorSignature;
+		bootSectorStatus->iEncryptEndPos = di->iEncryptEndPos;
+		bootSectorStatus->iStatus = status;
+		bootSectorStatus->iFinalised = aFinalised;
+		}
+	else
+		{
+		bootSectorStatus->iSignature = 0;
+		bootSectorStatus->iEncryptEndPos = 0;
+		bootSectorStatus->iStatus = ENfeUnmounted;
+		bootSectorStatus->iFinalised = EFalse;
+		}
+
+	if (encodeBuffer)
+		EncryptBuffer(des);
+
+
+	r = Write(di->iLocalDriveNum, di->iEntry.iPartitionBaseAddr, (TLinAddr) iBuffer, KSectorSize);
+	return r;
+	}
+
+
+/**
+HandleDiskContent - 
+
+Called from Idle timer DFC
+
+Starts encrypting the current drive (iDrives[iDriveIndex]) from the current encryption position (iEncryptEndPos)
+*/
+TInt DMediaDriverNFE::HandleDiskContent()
+	{
+	TNfeDriveInfo* di = &iInfo.iDrives[iDriveIndex];
+
+	__KTRACE_PRINT(Kern::Printf("NFE%d: Starting to encrypt Drive %d at pos %lx", iInstance, di->iLocalDriveNum, di->iEncryptEndPos));
+
+	if (di->iDriveFinalised)
+		{
+	    __KTRACE_PRINT(Kern::Printf("HandleDiskContent aborting as drive has been finalised", iInstance));
+		return KErrNone;
+		}
+
+//	TInt KBackgroundPriority = 7;						//*test*
+//	Kern::SetThreadPriority(KBackgroundPriority);		//*test*
+
+	TInt r = KErrNone;
+	for (;;)
+		{
+		// If we've finished encryting this drive, change the state and move on to the next drive
+		if (r != KErrNone || di->iEncryptEndPos >= di->iEntry.iPartitionBaseAddr + di->iEntry.iPartitionLen)
+			{
+			if (di->Status() == ENfeEncrypting)
+				{
+				__KTRACE_PRINT(Kern::Printf("NFE%d: Finished encrypting Drive %d r %d", iInstance, di->iLocalDriveNum, r));
+				SetStatus(*di,  r == KErrNone ? ENfeEncrypted : ENfeCorrupted);
+				}
+			if (di->Status() == ENfeDecrypting)
+				{
+				__KTRACE_PRINT(Kern::Printf("NFE%d: Finished decrypting Drive %d r %d", iInstance, di->iLocalDriveNum, r));
+				SetStatus(*di,  r == KErrNone ? ENfeDecrypted : ENfeCorrupted);
+				}
+			
+			// write to boot sector to indicate we have finished encrypting/decrypting this drive
+			r = WriteEncryptionStatusToBootSector(*di);
+
+			di = NextDrive();
+			if (di == NULL)
+				{
+				r = KErrCompletion;
+				break;
+				}
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Starting to encrypt Drive %d", iInstance, iInfo.iDrives[iDriveIndex].iLocalDriveNum));
+			}
+
+		// If this media or any of the attached media are busy, stop encrypting & wait for the next idle timeout
+		if (MediaBusy(di->iLocalDriveNum))
+			{
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Media is busy !!!", iInstance));
+			r = KErrNone;	// goto sleep & wait for another timer event
+			break;
+			}
+
+		TInt64& pos = di->iEncryptEndPos;
+		TInt64 partitionEnd = di->iEntry.iPartitionBaseAddr + di->iEntry.iPartitionLen;
+		TInt len = (TInt) Min (partitionEnd - pos, KBufSize);
+
+#if defined(TRACE_ENABLED)
+		// print position every 1/16 of the partition size
+		TInt64 printPos = Max((di->iEntry.iPartitionLen >> 4) & ~(KBufSize-1), KBufSize);
+		if (((di->iEncryptEndPos - di->iEncryptStartPos)% printPos) == 0) 
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Encrypting drive %d from %lx to %lx end %lx", iInstance, di->iLocalDriveNum, pos, pos + len, partitionEnd));
+#endif
+//		__KTRACE_PRINT(Kern::Printf("NFE%d: Encrypting drive %d from %lx to %lx end %lx", iInstance, di->iLocalDriveNum, pos, pos + len, partitionEnd));
+
+
+		// Read a buffer, encrypt it, and then write it back
+		// retry in case of media change
+		const TInt KRetries = 5;
+		r = KErrNotReady;
+		for (TInt i=0; r == KErrNotReady && i < KRetries; i++)
+			{
+			r = Read(di->iLocalDriveNum, pos, (TLinAddr) iBuffer, len);
+			if (r != KErrNone)
+				continue;
+
+			TPtr8 des(iBuffer,len,len);
+			if (di->Status() == ENfeEncrypting)
+				EncryptBuffer(des);
+			else
+				DecryptBuffer(des);
+			
+			r = Write(di->iLocalDriveNum, pos, (TLinAddr) iBuffer, len);
+			}
+
+		if (r == KErrNone)
+			pos+= len;
+
+		if (di->iProgressToUiProperty)	// no iProgressToUiProperty for swap drive
+			{
+			TInt progress = (TInt) (KNfeDiskOpReady * (pos - di->iEntry.iPartitionBaseAddr) / di->iEntry.iPartitionLen);
+//			__KTRACE_PRINT(Kern::Printf("NFE%d: Progess %d ", progress));
+			((RPropertyRef*) (di->iProgressToUiProperty))->Set( progress ); // Return value ignored
+			}
+		}
+	
+	__KTRACE_PRINT(Kern::Printf("NFE%d: HandleDiskContent returned %d", iInstance, r));
+
+	// If not completed, start the idle timer & try again later
+	if (r != KErrCompletion)
+		iIdleTimer.OneShot(NKern::TimerTicks(KNotBusyInterval));
+
+//	Kern::SetThreadPriority(KNfeThreadPriority);	//*test*
+	
+	return r;
+	}
+
+
+
+DECLARE_EXTENSION_PDD()
+	{
+	__KTRACE_PRINT(Kern::Printf("DECLARE_EXTENSION_PDD()"));
+	return new DPhysicalDeviceMediaNFE;
+	}
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	__KTRACE_PRINT(Kern::Printf("DECLARE_STANDARD_EXTENSION()"));
+
+
+	// Create the media driver factory object and register this with the kernel
+	__KTRACE_PRINT(Kern::Printf("Creating NFE PDD"));
+	DPhysicalDeviceMediaNFE* device = new DPhysicalDeviceMediaNFE;
+	if (device == NULL)
+		return KErrNoMemory;
+	TInt r = Kern::InstallPhysicalDevice(device);
+	__KTRACE_PRINT(Kern::Printf("Installing NFE PDD in extension init - name %s r:%d", NFE_DRIVENAME, r));
+	if (r != KErrNone)
+		return r;
+
+	TInt swapInstance = KErrNotFound;
+#if defined (__DEMAND_PAGING__)
+	swapInstance = SwapInstance();
+#endif
+
+	DPrimaryMediaExt* primaryMedia[NFE_INSTANCE_COUNT];
+	TInt instance;
+
+	for (instance=0; instance<NFE_INSTANCE_COUNT; instance++)
+		{
+		// Register this media device & define which drives we want to attach to.
+		// These drives must already be registered with the local media subsystem
+		// i.e. this media's kernel extension must be defined AFTER any attached
+		// media's kernel extension in the appropriate .IBY file
+		__KTRACE_PRINT(Kern::Printf("NFE%d: Creating NFE primary media", instance));
+		DPrimaryMediaExt* pM = new DPrimaryMediaExt(instance);
+		if (pM == NULL)
+			return KErrNoMemory;
+		primaryMedia[instance] = pM;
+
+		_LIT(KMediaThreadName,"NfeThread?");
+		HBuf* pMediaThreadName = HBuf::New(KMediaThreadName);
+		(*pMediaThreadName)[9] = (TUint8) ('0' + (TUint8) instance);
+
+		TInt r = Kern::DfcQInit(&pM->iNfeDfcQ,KNfeThreadPriority,pMediaThreadName);
+		if (r != KErrNone)
+			return r;
+
+#ifdef CPU_AFFINITY_ANY
+		NKern::ThreadSetCpuAffinity((NThread*)(pM->iNfeDfcQ.iThread), KCpuAffinityAny);
+#endif
+		
+
+		pM->iDfcQ = &pM->iNfeDfcQ;
+		pM->iMsgQ.Receive();
+
+
+		const TInt* driveList = DriveList(instance);
+		TInt driveCount = DriveCount(instance);
+
+		TBuf<4> driveName(_L("NFE?"));
+		driveName[3] = (TUint8) ('0' + (TUint8) instance);
+
+		
+		r = LocDrv::RegisterMediaDevice(
+			MEDIA_DEVICE_NFE, 
+			driveCount, driveList,
+			pM, NFE_NUMMEDIA, driveName);
+		if (r != KErrNone)
+			return r;
+
+
+#if defined (__DEMAND_PAGING__)
+		if (PagingType(instance))
+			{
+			// Define which of the drives we have already attached to have code or data paging enabled 
+			const TInt* pageDriveList = PageDriveList(instance);
+			TInt pageDriveCount = PageDriveCount(instance);
+
+			r = LocDrv::RegisterPagingDevice(pM,pageDriveList,pageDriveCount,PagingType(instance),SECTOR_SHIFT,NFE_NUM_PAGES);
+			__KTRACE_PRINT(Kern::Printf("NFE%d: Installing NFE PagingDevice in extension init - r:%d", pM->iInstance, r));
+			// Ignore error if demand paging not supported by kernel
+			if (r == KErrNotSupported)
+				r = KErrNone;
+			if (r != KErrNone)
+				return r;
+			}
+
+
+#endif	// __NAND_DEMAND_PAGING__
+
+		/*
+		If there is a swap partition we need to make sure all instances have their PartitionInfo() called
+		so that we can flag the swap partition as 'encrypted' if there are any encrypted drives at all
+		*/
+		if (swapInstance != KErrNotFound)
+			{
+			TBuf8<sizeof(TLocalDriveCapsV6)> capsBuf;
+			capsBuf.SetMax();
+			capsBuf.FillZ();
+			DLocalDrive::Caps(driveList[0], capsBuf);
+			}
+		}
+		
+
+	// If we encounter an encrypted drive belonging to ANY NFE instance, then assume the swap partition is 
+	// encrypted too. We need to do this because the swap partition has no equivalent of the boot sector
+	if (swapInstance != KErrNotFound)
+		{
+		__KTRACE_PRINT(Kern::Printf("NFE: Searching for encrypted drives to determine whether swap partition should be encrypted..."));
+		TBool encryptedDriveFound = EFalse;
+		TNfeDriveInfo* swapDriveInfo = NULL;
+		for (instance=0; instance<NFE_INSTANCE_COUNT; instance++)
+			{
+			DPrimaryMediaExt* pM = primaryMedia[instance];
+			DMediaDriverNFE* mediaDriver = (DMediaDriverNFE*) pM->iDriver;
+			__ASSERT_ALWAYS(mediaDriver, NFE_FAULT());
+
+			if (swapDriveInfo == NULL)
+				swapDriveInfo = mediaDriver->GetSwapDrive();
+
+			for (TInt i=0; i<mediaDriver->iInfo.iDriveCount; i++)
+				{
+				TNfeDriveInfo& di = mediaDriver->iInfo.iDrives[i];
+				__KTRACE_PRINT(Kern::Printf("NFE%d: Testing drive %d DriveLetter %c status %s", 
+					instance, di.iLocalDriveNum, (TInt) DriveLetterToAscii(di.iDriveLetter), DriveStatus(di.Status()) ));
+				if (di.Status() == ENfeEncrypted || di.Status() == ENfeEncrypting)
+					encryptedDriveFound = ETrue;
+				}
+			}
+		if (swapDriveInfo)
+			{
+			swapDriveInfo->SetStatus(encryptedDriveFound ? ENfeEncrypted : ENfeDecrypted);
+			swapDriveInfo->iEncryptEndPos = swapDriveInfo->iEntry.iPartitionBaseAddr + swapDriveInfo->iEntry.iPartitionLen;
+
+			__KTRACE_PRINT(Kern::Printf("NFE: Setting swap partition state to %s...", DriveStatus(swapDriveInfo->Status())));
+			}
+		}
+
+
+	return r;
+	}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mediaext/nfe.h	Fri Apr 23 22:20:31 2010 +0100
@@ -0,0 +1,163 @@
+// Copyright (c) 1995-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:
+// e32test\mediext\nfe.h
+// 
+//
+
+#ifndef __NFE_H__
+#define __NFE_H__
+
+#include <d32locd.h>
+
+
+
+// The following is stolen from the genuine NDE driver interface from nfe_interface.h
+// >>>>>nfe_interface.h
+enum TNfeCommands
+    {
+    ENfeDiskStatus   = 0, // No longer used, preserved for SC/BC.
+    ENfeEncryptDisk  = 1,
+    ENfeDecryptDisk  = 2,
+    ENfeWipeDisk     = 3,
+    // Debug commands below, enabled only in RnD compiled extension
+    ENfePause        = 128,
+    ENfeContinue     = 129,
+    };
+
+enum TNfeDiskStatus
+    {
+    ENfeUnmounted  = 0,
+    ENfeDecrypted  = 8,
+    ENfeDecrypting = 9,
+    ENfeEncrypted  = 10,
+    ENfeEncrypting = 11,
+    ENfeWiping     = 12,
+    ENfeCorrupted  = 13,
+    };
+
+
+
+// The keys under the KNfeUID category are generated by combining the constants
+// below with drive number by using the NFE_KEY macro below.
+const TUint KNfeToThreadKey     = 1;
+const TUint KNfeToUiKey         = 2;
+const TUint KNfeToExtKey        = 3; // No longer used, preserved for SC/BC.
+const TUint KNfeProgressToUiKey = 4;
+const TUint KNfeStatusToUiKey   = 5; // Replaces ENfeDiskStatus command.
+
+//- Macros ------------------------------------------------------------------
+// Calculates pub&sub key for given drive and id. Top 8 bits are used for the
+// drives. Bottom 8 bits are used for the ids. The rest of the bits are
+// reserved and use zero value. The key layout:
+//          dddddddd0000000000000000kkkkkkkk
+//          ^bit 31                        ^bit 0
+#define NFE_KEY(drive, id) (((drive) << 24) | (0xFF & (id)))
+// <<<<nfe_interface.h 
+
+
+
+
+// copy of TPartitionEntry from locmedia.h
+#ifndef __KERNEL_MODE__
+class TPartitionEntry
+	{
+public:
+	Int64 iPartitionBaseAddr;
+	Int64 iPartitionLen;
+	TUint16 iBootIndicator;
+	TUint16 iPartitionType;
+	};
+#endif
+
+enum
+	{
+	EQueryNfeDeviceInfo = RLocalDrive::EQuerySymbianNfeTestFirst+0,
+	};
+
+class TNfeDriveInfo
+	{
+public:
+	inline TBool IsUDADrive() 
+		{return PartitionIsFAT(iEntry.iPartitionType) || PartitionIsFAT32(iEntry.iPartitionType); }
+
+#ifdef __KERNEL_MODE__
+	void SetStatus(TNfeDiskStatus aStatus);
+#endif
+	inline TNfeDiskStatus Status() { return iStatus; }
+
+private:
+	TNfeDiskStatus iStatus;			// @see TNfeDiskStatus
+
+public:
+	TInt iLocalDriveNum;
+	TInt iDriveLetter;
+	TPartitionEntry iEntry;
+	Int64 iCompositeSize;
+
+	/** 
+	position of first encrypted byte - normally the same as 
+	iEntry.iPartitionBaseAddr unless the MBR has been changed
+	*/
+	TInt64 iEncryptStartPos;
+
+	/** 
+	position of the last encrypted byte +1 - normally the same as 
+	iEntry.iPartitionBaseAddr+iEntry.iPartitionLen if the drive is fully
+	encrypted
+	*/
+	TInt64 iEncryptEndPos;
+
+	TInt iReadRequestCount;
+	TInt iWriteRequestCount;
+	TInt iCodePagingRequesCount;
+	TInt iDataPagingReadRequestCount;
+	TInt iDataPagingWriteRequestCount;
+
+	TAny* iStatusToUiProperty;
+	TAny* iToUiProperty;
+	TAny* iProgressToUiProperty;
+	TUint32 iUniqueID;		// FAT volume ID
+	TBool iDriveFinalised;
+	};
+
+/**
+NFE media details - for testing purposes only
+This is a structure used to communicate NFE-related information
+from the NFE media driver to a test application
+
+@internalTechnology
+@prototype
+*/
+class TNfeDeviceInfo
+	{
+public:
+	enum {ENfeMaxPartitionEntries = 2};
+	TNfeDriveInfo iDrives[ENfeMaxPartitionEntries];
+
+	TInt iDriveCount;
+
+	TInt64 iMediaSizeInBytes;
+	};
+
+typedef TPckgBuf<TNfeDeviceInfo> TNfeDeviceInfoBuf;
+
+
+// Publish & Subscribe is used to initiate an encryption pass - to emulate the behaviour of the genuine NFE UI & driver
+//const TUid KNfeUID = TUid::Uid(0xA000E7C5);	// UID of NFE test mdia driver (D_NFE.MMP)
+const TUid KNfeUID = {0x100039e3};
+
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mediaext/t_nfe.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -0,0 +1,406 @@
+// Copyright (c) 1995-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:
+// e32test\mediext\t_nfe.cpp
+// 
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <e32test.h>
+#include <f32file.h>
+
+
+RTest test(_L("t_nfe"));
+
+#include <d32locd.h>
+#include <e32property.h>
+#include "nfe.h"
+
+
+TBusLocalDrive Drive;
+TBool TheWaitFlag = EFalse;				// wait for drive to be encrypted before exiting test
+TBool TheFinaliseDriveFlag = EFalse;
+TBool TheDisplayStatusFlag = EFalse;	// display drive status and then exit (i.e. don't encrypt)
+TBool TheEncryptDriveFlag = ETrue;
+
+TInt FindNfeDrive(TInt aDriveNum)
+/** 
+Find the next NFE drive 
+
+@return		Local drive identifier.
+*/
+	{
+	TInt drive = KErrNotFound;
+	
+//	test.Printf(_L("Searching for NFE drive:\n"));
+	
+	for (TInt i = aDriveNum; i < KMaxLocalDrives && drive < 0; ++i)
+		{
+		RLocalDrive	d;
+		TBool		change = EFalse;
+		
+		if(d.Connect(i, change) == KErrNone)
+			{
+//			test.Printf(_L("Connected to local drive %d\n"), i);
+			TLocalDriveCapsV4			dc;
+			TPckg<TLocalDriveCapsV4>	capsPack(dc);
+			capsPack.FillZ();
+			
+			if(d.Caps(capsPack) != KErrNone)
+				continue;
+			if (dc.iType == EMediaNANDFlash || dc.iType == EMediaHardDisk)
+				{
+				TNfeDeviceInfo nfeDeviceInfo;
+				TPtr8 nfeDeviceInfoBuf((TUint8*) &nfeDeviceInfo, sizeof(nfeDeviceInfo));
+				nfeDeviceInfoBuf.FillZ();
+
+				TInt r = d.QueryDevice((RLocalDrive::TQueryDevice) EQueryNfeDeviceInfo, nfeDeviceInfoBuf);
+
+//				test.Printf(_L("EQueryNfeDeviceInfo on local drive %d returned %d\n"), i, r);
+				if (r == KErrNone)
+					{
+					test.Printf(_L("\nFound NFE on local drive %d\n"), i);
+					drive = i;
+					}
+				}
+			d.Close();
+			}
+		}
+	return drive;
+	}
+
+
+
+const TDesC* DriveStatus(TNfeDiskStatus aStatus)
+	{
+	_LIT(KNfeUnmounted, "Unmounted");
+	_LIT(KNfeDecrypted, "Decrypted");
+	_LIT(KNfeDecrypting, "Decrypting");
+	_LIT(KNfeEncrypted, "Encrypted");
+	_LIT(KNfeEncrypting, "Encrypting");
+	_LIT(KNfeWiping, "Wiping");
+	_LIT(KNfeCorrupted, "Corrupted");
+	_LIT(KNfeUnrecognised, "Unrecognised");
+
+	switch(aStatus)
+		{
+		case ENfeUnmounted:
+			return &KNfeUnmounted;
+		case ENfeDecrypted:
+			return &KNfeDecrypted;
+		case ENfeDecrypting:
+			return &KNfeDecrypting;
+		case ENfeEncrypted:
+			return &KNfeEncrypted;
+		case ENfeEncrypting:
+			return &KNfeEncrypting;
+		case ENfeWiping:
+			return &KNfeWiping;
+		case ENfeCorrupted:
+			return &KNfeCorrupted;
+		default:
+			return &KNfeUnrecognised;
+
+		}
+	}
+
+TInt DriveStatus(TInt aNfeDrive, TNfeDiskStatus& aStatus, TInt &aProgress)
+	{
+	TInt r = RProperty::Get(
+		KNfeUID, 
+		NFE_KEY(aNfeDrive, KNfeStatusToUiKey),
+		*(TInt*) &aStatus); 
+	if (r != KErrNone)
+		return r;
+	r = RProperty::Get(
+		KNfeUID, 
+		NFE_KEY(aNfeDrive, KNfeProgressToUiKey),
+		*(TInt*) &aProgress); 
+	return r;
+	}
+
+void DisplayNfeDeviceInfo(TInt aNfeDrive, TNfeDeviceInfo& aDeviceInfo)
+	{
+	test.Printf(_L("Stats: \n"));
+
+	RLocalDrive	d;
+	TBool change = EFalse;
+	TInt r = d.Connect(aNfeDrive, change);
+	test (r == KErrNone);
+		
+	TPtr8 nfeDeviceInfoBuf((TUint8*) &aDeviceInfo, sizeof(aDeviceInfo));
+	nfeDeviceInfoBuf.FillZ();
+	r = d.QueryDevice((RLocalDrive::TQueryDevice) EQueryNfeDeviceInfo, nfeDeviceInfoBuf);
+	test (r == KErrNone || r == KErrNotSupported);
+
+	d.Close();
+
+	test.Printf(_L("iDriveCount %d\n"), aDeviceInfo.iDriveCount);
+	test.Printf(_L("iMediaSizeInBytes %lx\n"), aDeviceInfo.iMediaSizeInBytes);
+
+	for (TInt i=0; i<aDeviceInfo.iDriveCount; i++)
+		{
+		TNfeDriveInfo& di = aDeviceInfo.iDrives[i];
+
+		test.Printf(_L("*** drive index %d ***\n"), i);
+		test.Printf(_L("iLocalDriveNum %x\n"), di.iLocalDriveNum);
+		test.Printf(_L("iDriveLetter %c\n"), di.iDriveLetter >= 0 && di.iDriveLetter <= 25 ? di.iDriveLetter +'A' : '?');
+		test.Printf(_L("iState %d\n"), di.Status());
+
+		test.Printf(_L("State = %S\n"), DriveStatus(di.Status()));
+
+		test.Printf(_L("iEncryptStartPos %lx\n"), di.iEncryptStartPos);
+		test.Printf(_L("iEncryptEndPos %lx\n"), di.iEncryptEndPos);
+		test.Printf(_L("iPartitionBaseAddr %lx\n"), di.iEntry.iPartitionBaseAddr);
+		test.Printf(_L("iPartitionLen %lx\n"), di.iEntry.iPartitionLen);
+		test.Printf(_L("iPartitionType %x\n"), di.iEntry.iPartitionType);
+		
+		test.Printf(_L("iReadRequestCount %d\n"), di.iReadRequestCount);
+		test.Printf(_L("iWriteRequestCount %d\n"), di.iWriteRequestCount);
+		test.Printf(_L("iCodePagingRequesCount %d\n"), di.iCodePagingRequesCount);
+		test.Printf(_L("iDataPagingReadRequestCount %d\n"), di.iDataPagingReadRequestCount);
+		test.Printf(_L("iDataPagingWriteRequestCount %d\n"), di.iDataPagingWriteRequestCount);
+		test.Printf(_L("iUniqueID %08X\n"), di.iUniqueID);
+		}
+	}
+
+void EncryptDrive(TInt aNfeDrive)
+	{
+	// subscribe to cmd acknowledgement property - KNfeToUiKey
+    RProperty propToUi;
+    test.Printf(_L("Attaching ToUi property")); 
+    TInt r = propToUi.Attach(KNfeUID,NFE_KEY(aNfeDrive,KNfeToUiKey));
+    test.Printf(_L("Attaching returned %d"), r);    
+	if (r != KErrNone)
+		return;
+
+
+    TRequestStatus status;
+    propToUi.Subscribe( status );
+    
+
+	// Issue command
+	test.Printf(_L("Encrypting drive %c...\n"), aNfeDrive+'A');
+	r = RProperty::Set(
+		KNfeUID, 
+		NFE_KEY(aNfeDrive, KNfeToThreadKey),
+		ENfeEncryptDisk); 
+	test.Printf(_L("Encrypting drive %c, r %d\n"), aNfeDrive+'A', r);
+	test (r == KErrNone);
+
+	// wait for ack
+	User::WaitForRequest( status );
+    r = status.Int();
+    test.Printf(_L("cmd status %d"), r);    
+	test (r == KErrNone);
+	}
+
+void DecryptDrive(TInt aNfeDrive)
+	{
+	// subscribe to cmd acknowledgement property - KNfeToUiKey
+    RProperty propToUi;
+    test.Printf(_L("Attaching ToUi property")); 
+    TInt r = propToUi.Attach(KNfeUID,NFE_KEY(aNfeDrive,KNfeToUiKey));
+    test.Printf(_L("Attaching returned %d"), r);    
+	if (r != KErrNone)
+		return;
+
+
+    TRequestStatus status;
+    propToUi.Subscribe( status );
+    
+
+	// Issue command
+	test.Printf(_L("Decrypting drive %c...\n"), aNfeDrive+'A');
+	r = RProperty::Set(
+		KNfeUID, 
+		NFE_KEY(aNfeDrive, KNfeToThreadKey),
+		ENfeDecryptDisk); 
+	test.Printf(_L("Decrypting drive %c, r %d\n"), aNfeDrive+'A', r);
+	test (r == KErrNone);
+
+	// wait for ack
+	User::WaitForRequest( status );
+    r = status.Int();
+    test.Printf(_L("cmd status %d"), r);    
+	test (r == KErrNone);
+	}
+
+void WaitForFinish(TInt aNfeDrive, TBool aEncrypt)
+	{
+	TNfeDiskStatus diskStatus = ENfeCorrupted;
+	TInt progress = 0;
+
+	TInt r = DriveStatus(aNfeDrive, diskStatus, progress);
+	test (r == KErrNone);
+	
+	// Poll progress status.
+    while (diskStatus != (aEncrypt ? ENfeEncrypted : ENfeDecrypted ))
+        {
+		r = DriveStatus(aNfeDrive, diskStatus, progress);
+		test (r == KErrNone);
+		test.Printf(_L("Drive %c, r %d progress %3u%% status %S\n"), aNfeDrive+'A', r, progress, DriveStatus((TNfeDiskStatus) diskStatus));
+
+
+		if (TheFinaliseDriveFlag && progress > 10)
+			{
+			TheFinaliseDriveFlag = EFalse;
+			RFs fs;
+			TInt r = fs.Connect();
+			test_KErrNone(r);
+
+			r = fs.FinaliseDrive(aNfeDrive, RFs::EFinal_RW);
+			test_KErrNone(r);
+			return;
+			}
+
+		User::After( 1000 * 500 );
+        }
+	test.Printf( _L("\nFinished\n") );
+	}
+
+//
+// E32Main
+//
+
+TInt ParseCommandArguments()
+	{
+    TInt tokenCount = 0;
+	TChar driveToTest = 'C';;
+
+	TBuf<0x100> cmd;
+	User::CommandLine(cmd);
+	TLex lex(cmd);
+	
+    for (TPtrC token=lex.NextToken(); token.Length() != 0;token.Set(lex.NextToken()))
+		{
+        tokenCount++;
+		// Get the drive letter
+		if (tokenCount == 1)
+			{
+			TChar ch = token[0];
+			if (ch.IsAlpha())
+				{
+				if(token.Length() > 0)		
+					{
+					driveToTest=token[0];
+					driveToTest.UpperCase();
+					}
+				}
+			RDebug::Print(_L("drive=%C"), (TUint) driveToTest);
+			continue;
+			}
+
+		else if (token.CompareF(_L("-d")) == 0)
+			{
+			TheEncryptDriveFlag = EFalse;
+			}
+		else if (token.CompareF(_L("-e")) == 0)
+			{
+			TheEncryptDriveFlag = ETrue;
+			}
+		else if (token.CompareF(_L("-f")) == 0)
+			{
+			TheFinaliseDriveFlag = ETrue;
+			}
+		else if (token.CompareF(_L("-w")) == 0)
+			{
+			TheWaitFlag = ETrue;
+			}
+		else if (token.CompareF(_L("-s")) == 0)
+			{
+			TheDisplayStatusFlag = ETrue;
+			}
+		}
+
+	return driveToTest;
+	}
+
+TInt E32Main()
+	{
+	test.Title();
+	test.Start(_L("NFE tests"));
+
+	RFs fs;
+
+	TInt r = fs.Connect();
+	test_KErrNone(r);
+
+	TChar driveToTest = ParseCommandArguments();
+
+	TInt drive;
+	r = fs.CharToDrive(driveToTest,drive);
+	test_KErrNone(r);
+
+
+	TVolumeInfo volumeInfo;
+	r = fs.Volume(volumeInfo, drive);
+	test(r == KErrNone);
+
+
+
+	TNfeDiskStatus diskStatus = ENfeCorrupted;
+	TInt progress = 0;
+
+	r = DriveStatus(drive, diskStatus, progress);
+	test.Printf(_L("drive %c diskStatus %S, progress %d r %d\n"), drive+'A', DriveStatus(diskStatus), progress, r);
+
+	if (TheDisplayStatusFlag)
+		{
+		test.Printf(_L("*** press any key ***"));
+		test.Getch();
+		test.End();
+		test.Close();
+		return 0;
+		}
+
+	if (r == KErrNone && diskStatus == ENfeDecrypted && TheEncryptDriveFlag)
+		{
+		test.Next(_L("Encrypting NFE drive"));
+		EncryptDrive(drive);
+		r = DriveStatus(drive, diskStatus, progress);
+		test.Printf(_L("drive %c diskStatus %S, progress %d r %d\n"), drive+'A', DriveStatus(diskStatus), progress, r);
+		}
+
+	if (r == KErrNone && diskStatus == ENfeEncrypted && !TheEncryptDriveFlag)
+		{
+		test.Next(_L("Decrypting NFE drive"));
+		DecryptDrive(drive);
+		r = DriveStatus(drive, diskStatus, progress);
+		test.Printf(_L("drive %c diskStatus %S, progress %d r %d\n"), drive+'A', DriveStatus(diskStatus), progress, r);
+		}
+
+
+	if (r == KErrNone && TheWaitFlag)
+		{
+		test.Next(_L("Waiting for finish"));
+		WaitForFinish(drive, TheEncryptDriveFlag);
+		}
+
+
+	for(TInt nfeDrive = FindNfeDrive(0); nfeDrive != KErrNotFound; nfeDrive = FindNfeDrive(++nfeDrive))
+		{
+		TNfeDeviceInfo deviceInfo;
+		DisplayNfeDeviceInfo(nfeDrive, deviceInfo);
+		}
+
+	fs.Close();
+
+	test.End();
+	test.Close();
+
+	return 0;
+	}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mediaext/t_nfe.mmp	Fri Apr 23 22:20:31 2010 +0100
@@ -0,0 +1,33 @@
+// Copyright (c) 1995-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:
+// e32test/group/t_nfe.mmp
+// 
+//
+
+target			t_nfe.exe
+targettype		exe
+
+capability		All
+
+sourcepath		../mediaext
+source			t_nfe.cpp
+
+library			euser.lib efsrv.lib
+
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+
+
+
+
+SMPSAFE
--- a/kerneltest/e32test/multimedia/t_sound2.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/e32test/multimedia/t_sound2.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -2379,6 +2379,10 @@
 	Test.Title();
 
 	Test.Start(_L("Load"));
+	// --- TEMPORARILY DISABLING T_SOUND2
+	Test.Printf(_L("T_SOUND2 DISABLED UNTIL DEF144934 IS FIXED\n"));
+	CHECK(0);
+	// --- TEMPORARILY DISABLING T_SOUND2
 	if (Load()==KErrNotFound)
 		{
 		Test.Printf(_L("Shared chunk sound driver not supported - test skipped\r\n"));
--- a/kerneltest/f32test/demandpaging/t_nandpaging.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/demandpaging/t_nandpaging.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -28,6 +28,7 @@
 //! @SYMTestPriority        High
 //! @SYMTestStatus          Implemented
 
+#define __E32TEST_EXTENSION__
 #include <e32test.h>
 RTest test(_L("T_NANDPAGING"));
 
@@ -38,6 +39,7 @@
 #include <f32dbg.h>
 #include "testdefs.h"
 #include <hal.h>
+#include "nfe.h"
 
 
 TInt DriveNumber=-1;   // Parameter - Which drive?  -1 = autodetect.
@@ -544,9 +546,53 @@
 		return;
 		}
 		
+	// If the NFE test media driver extension is present, ALL the drive is encrypted;
+	// this means that there will be very few free blocks in the free block reservoir: this effectively 
+	// disables background garbage collection and all block erasing needs to happen on the fly...
+	TNfeDeviceInfo nfeDeviceinfo;
+	TPtr8 nfeDeviceInfoBuf((TUint8*) &nfeDeviceinfo, sizeof(nfeDeviceinfo));
+	nfeDeviceInfoBuf.FillZ();
+	TInt r = Drive.QueryDevice((RLocalDrive::TQueryDevice) EQueryNfeDeviceInfo, nfeDeviceInfoBuf);
+/*
+	if (r == KErrNone)
+		{
+		test.Printf(_L("NFE device detected, aborting garbage collection test for now\n"));
+		return;
+		}
+*/
+	// Create some free blocks by creating a huge file and then deleting it....
+	if (r == KErrNone)
+		{
+		test.Printf(_L("NFE device detected\n"));
+		RFile file;
+
+		TBuf<256> tempFileName = _L("?:\\f32-tst\\");
+		tempFileName[0] = 'A'+DriveNumber;
+
+		r = TheFs.MkDirAll(tempFileName);
+		test(r==KErrNone || r== KErrAlreadyExists);
+
+		tempFileName+= _L("TEMP.TXT");
+
+		r = file.Replace(TheFs, tempFileName, EFileWrite);
+		test_KErrNone(r);
+		
+		for (TInt fileSize = KMaxTInt; fileSize > 0; fileSize >>= 1)
+			{
+			r = file.SetSize(fileSize);
+			test.Printf(_L("Setting file size to %d, r %d\n"), fileSize, r);
+			if (r == KErrNone)
+				break;
+			}
+		file.Close();
+		r = TheFs.Delete(tempFileName);
+		test_KErrNone(r);
+		}
+
+
+
 	TInt timeout;
 	TInt writesNeeded=100;
-	TInt r = KErrNone;
 	RFile tempFile;
 	TInt i;
 	TInt ii;
@@ -593,6 +639,7 @@
 	 	
 	for (ii=0; ii<MaxDeferLoops; ii++)  // Repeat the test, 'MaxDeferLoops' number of times.  This can be set on cammand line.
 		{
+		writesNeeded=100;
 		timeout=20;
 		do  // while ((pageGarbageCount==0) && (timeout>0));
 			// ie, while garbage collection hasn't happened, or timed out
--- a/kerneltest/f32test/filesystem/fat/t_scn32dr1.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/filesystem/fat/t_scn32dr1.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -11,9 +11,11 @@
 // Contributors:
 //
 // Description:
-// f32test\scndrv\t_scn32dr1.cpp
+// f32test\filesystem\fat\t_scn32dr1.cpp
+// Tests that ScanDrive fixes known errors to a Rugged FAT drive
 //
-//
+
+#define __E32TEST_EXTENSION__
 
 #include <f32file.h>
 #include <e32test.h>
@@ -262,10 +264,10 @@
         {
         pos += BootSector.ReservedSectors() * BootSector.BytesPerSector();
         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-        test(r==KErrNone);
+        test_KErrNone(r);
         TPtr8 buf(&data[0], 4);
         r=TheRawDisk.Read(pos, buf);
-        test(r==KErrNone);
+        test_KErrNone(r);
         TheRawDisk.Close();
         }
 
@@ -290,7 +292,7 @@
     return val;
     }
 
-LOCAL_C void WriteFat(TInt aFatIndex,TInt aValue,const TUint8* aFat)
+LOCAL_C void WriteToFatBuf(TInt aFatIndex,TInt aValue,const TUint8* aFat)
 //
 // Write a value to both fats starting at aFat
 //
@@ -344,7 +346,7 @@
     {
 
     TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     if(!BootSector.IsValid())
         {
@@ -580,6 +582,18 @@
     aName.SetLength(i);
     }
 
+TDes& MakePrintable(TDes& aDes)
+	{
+	TInt len = aDes.Length();
+
+	for (TInt i=0; i<len; i++)
+		{
+		if ((TUint8) aDes[i] < 0x20)
+			aDes[i] = '?';
+		}
+	return aDes;
+	}
+
 GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
 //
 // Dump a single directory entry to the log.  Return false if it was end of
@@ -603,9 +617,9 @@
         ExtractNameString(name, aEntry);
         TInt ord = aEntry[0];
         if (ord & KDirLastLongEntry)
-            RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
+            RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &MakePrintable(name), ord & ~KDirLastLongEntry);
         else
-            RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
+            RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &MakePrintable(name), ord & ~KDirLastLongEntry);
         }
     else if (!IsValidDirEntry(d))
         {
@@ -618,7 +632,7 @@
         TBuf<11> name;
         name.Copy(d->Name());
         RDebug::Print(_L("%5d: '%S'   %S  start %-5d size %d"),
-                      aNum, &name, DirAttributes(d->Attributes()), d->StartCluster(), d->Size());
+                      aNum, &MakePrintable(name), DirAttributes(d->Attributes()), d->StartCluster(), d->Size());
         }
     return ETrue;
     }
@@ -696,12 +710,12 @@
     if (aStart < 2 && gDiskType != EFat32)
         {
         HBufC8* buf=HBufC8::New(BootSector.RootDirEntries() * KSizeOfFatDirEntry);
-        test(buf != NULL);
+        test_NotNull(buf);
         TPtr8 ptr=buf->Des();
         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-        test(r==KErrNone);
+        test_KErrNone(r);
         r=TheRawDisk.Read(gRootDirStart, ptr);
-        test(r==KErrNone);
+        test_KErrNone(r);
         TheRawDisk.Close();
         DumpRootDir(buf->Ptr());
         delete(buf);
@@ -712,12 +726,12 @@
         if (GetFatEntry(cluster, aFat) != 0)
             {
             HBufC8* buf=HBufC8::New(gBytesPerCluster);
-            test(buf!=NULL);
+            test_NotNull(buf);
             TPtr8 ptr=buf->Des();
             TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-            test(r==KErrNone);
+            test_KErrNone(r);
             r=TheRawDisk.Read(ClusterToByte(cluster), ptr);
-            test(r==KErrNone);
+            test_KErrNone(r);
             TheRawDisk.Close();
             RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
             DumpDirCluster(ptr.Ptr());
@@ -786,12 +800,12 @@
 //
     {
     HBufC8* buf=HBufC8::New(gBytesPerCluster*2);
-    test(buf!=NULL);
+    test_NotNull(buf);
     TPtr8 ptr=buf->Des();
     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheRawDisk.Read(ClusterToByte(aCluster), ptr);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TheRawDisk.Close();
     RDebug::Print(_L("Cluster %d @ 0x%08X:"), aCluster, ClusterToByte(aCluster));
     TFatDirEntry* d = (TFatDirEntry*)ptr.Ptr() + aEntry;
@@ -829,7 +843,7 @@
     nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue);
 #endif
 
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     }
 
@@ -847,7 +861,7 @@
         num[0] = TText(aDepth % 26 + 'A');
         aDir+=num;
         r=TheFs.MkDir(aDir);
-        test(r==KErrNone);
+        test_KErrNone(r);
         }
     }
 
@@ -860,7 +874,7 @@
     while(aDepth--)
         {
         r=TheFs.RmDir(aDir);
-        test(r==KErrNone);
+        test_KErrNone(r);
         aDir.SetLength(aDir.Length()-2);
         }
     }
@@ -877,7 +891,7 @@
     aDir2=aDir1;
     aDir2+=_L("a\\");
     TInt r=TheFs.MkDir(aDir2);
-    test(r==KErrNone);
+    test_KErrNone(r);
     // create dir with depth of 126 directories - one short of max depth
     CreateDeepDir(aDir1,101);
     // create dir with depth of 90
@@ -891,7 +905,7 @@
     {
     DeleteDeepDir(aDir2,64);
     TInt r=TheFs.RmDir(aDir2);
-    test(r==KErrNone);
+    test_KErrNone(r);
     aDir2.SetLength(aDir2.Length()-2);
     DeleteDeepDir(aDir1,102);
     DeleteDeepDir(aDir1,24);
@@ -925,7 +939,7 @@
         aLong[len+1] = TText(count%26 + 'A');
         count++;
         TInt r=temp.Create(TheFs,aLong,EFileShareAny);
-        test(r==KErrNone);
+        test_KErrNone(r);
         temp.Close();
         }
     }
@@ -944,7 +958,7 @@
         aLong[len+1] = TText(count%26 + 'A');
         count++;
         TInt r=TheFs.Delete(aLong);
-        test(r==KErrNone || r==KErrNotFound);
+        test_Value(r, r==KErrNone || r==KErrNotFound);
         }
     }
 
@@ -966,7 +980,7 @@
         name[2]=(TUint16)(count/26%26+'a');
         name[3]=(TUint16)(count%26+'a');
         r=TheFs.Delete(name);
-        test(r==KErrNone || r==KErrNotFound);
+        test_Value(r, r==KErrNone || r==KErrNotFound);
         ++count;
         }
     }
@@ -990,7 +1004,7 @@
         name[2]=(TUint16)(count/26%26+'a');
         name[3]=(TUint16)(count%26+'a');
         r=f.Create(TheFs, name, EFileWrite);
-        test(r==KErrNone);
+        test_KErrNone(r);
         f.Close();
         ++count;
         }
@@ -1012,7 +1026,7 @@
         dir[1]=(TUint16)(count/26+'a');
         dir[2]=(TUint16)(count%26+'a');
         r=TheFs.MkDir(dir);
-        test(r==KErrNone);
+        test_KErrNone(r);
         entriesSoFar+=2;
         ++count;
         }
@@ -1032,7 +1046,7 @@
         dir[1]=TUint16(count/26+'a');
         dir[2]=TUint16(count%26+'a');
         r=TheFs.RmDir(dir);
-        test(r==KErrNone);
+        test_KErrNone(r);
         entriesSoFar-=2;
         ++count;
         }
@@ -1045,27 +1059,27 @@
     {
     test.Next(_L("Delete Directory Structure"));
     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\almostfull\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     TInt entriesNeeded=(gEntriesPerCluster-2) / 2;  //7*2entries + . + .. = full sector
     for (TInt i = 0; i < entriesNeeded; i++)
         {
         TFileName file=_L("\\scndrv\\dir2\\full\\__a");
         file.AppendNum(i);
         r=TheFs.Delete(file);
-        test(r==KErrNone||r==KErrNotFound);
+        test_Value(r, r==KErrNone||r==KErrNotFound);
         }
     r=TheFs.RmDir(_L("\\scndrv\\dir2\\full\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheFs.RmDir(_L("\\scndrv\\dir2\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     TFileName veryLongName=(_L("\\scndrv\\dir1\\"));
     MakeVeryLongName(veryLongName);
     r=TheFs.Delete(veryLongName);
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheFs.RmDir(_L("\\scndrv\\dir1\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheFs.RmDir(_L("\\scndrv\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     }
 
 LOCAL_C void CreateDirectoryStructure()
@@ -1076,34 +1090,34 @@
     test.Next(_L("Create Directory Structure"));
     // cluster 3 (root dir is cluster 2)
     TInt r=TheFs.MkDir(_L("\\scndrv\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 4
     r=TheFs.MkDir(_L("\\scndrv\\dir1\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     TFileName veryLongName=(_L("\\scndrv\\dir1\\"));
     MakeVeryLongName(veryLongName);
     RFile f;
     // cluster 5
     r=f.Create(TheFs,veryLongName,EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=f.SetSize(512);
-    test(r==KErrNone);
+    test_KErrNone(r);
     f.Close();
     // cluster 6
     r=TheFs.MkDir(_L("\\scndrv\\dir2\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 7
     r=TheFs.MkDir(_L("\\scndrv\\dir2\\full\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 8
     r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 9
     r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 10
     r=TheFs.MkDir(_L("\\scndrv\\dir2\\almostfull\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // cluster 11-17
     TInt entriesNeeded=(gEntriesPerCluster-2) / 2;  //7*2entries + . + .. = full sector
     for (TInt i = 0; i < entriesNeeded; i++)
@@ -1112,11 +1126,11 @@
         file.AppendNum(i);
         LastInFull = file;
         r=f.Create(TheFs,file,EFileShareAny);
-        test(r==KErrNone);
+        test_KErrNone(r);
         if (i < 7)
             {
             r=f.SetSize(512);
-            test(r==KErrNone);
+            test_KErrNone(r);
             }
         f.Close();
         }
@@ -1132,14 +1146,14 @@
     file1.AppendNum(1);
     file2.AppendNum(2);
     r=f.Create(TheFs,file1,EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=f.SetSize(512);
-    test(r==KErrNone);
+    test_KErrNone(r);
     f.Close();
     r=f.Create(TheFs,file2,EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=f.SetSize(512);
-    test(r==KErrNone);
+    test_KErrNone(r);
     f.Close();
     }
 
@@ -1165,16 +1179,16 @@
         // contains aOffset
         ExtBufLen = 2 * gBytesPerCluster;
         ExtBufPtr = HBufC8::New(ExtBufLen);
-        test(ExtBufPtr != NULL);
+        test_NotNull(ExtBufPtr);
         // read the clusters in
         ExtBufAdd = aOffset - aOffset % gBytesPerCluster;
         TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2;
         RDebug::Print(_L("Extension buffer for cluster %d allocated"), clust);
         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-        test(r==KErrNone);
+        test_KErrNone(r);
         TPtr8 des(ExtBufPtr->Des());
         r=TheRawDisk.Read(gRootDirStart + ExtBufAdd, des);
-        test(r==KErrNone);
+        test_KErrNone(r);
         TheRawDisk.Close();
         }
     // convert to offset in the extension buffer
@@ -1209,10 +1223,10 @@
 // reads directory section of disk into buffer
 //
     {
-    test(aCluster != 1);
+    test_Value(aCluster, aCluster != 1);
 
     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     if (aCluster == -1) // all clusters ?
         {
@@ -1233,7 +1247,7 @@
         r=TheRawDisk.Read(gRootDirStart + pos, dirPtr);
         }
 
-    test(r==KErrNone);
+    test_KErrNone(r);
     TheRawDisk.Close();
     }
 
@@ -1243,21 +1257,21 @@
 //
     {
     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheRawDisk.Read(gFatStartBytes, aFatBuf);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TheRawDisk.Close();
     }
 
-LOCAL_C void WriteDirDisk(TDes8& aDirBuf, TInt aCluster = -1)
+LOCAL_C void WriteDirEntryToDisk(TDes8& aDirBuf, TInt aCluster = -1)
 //
-// writes dir buffer to disk
+// writes dir entry buffer to disk
 //
     {
-    test(aCluster != 1);
+	test_Value(aCluster, aCluster != 1);
 
     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     if (aCluster == -1)
         {
@@ -1278,29 +1292,29 @@
         r=TheRawDisk.Write(gRootDirStart + pos, dirPtr);
         }
 
-    test(r==KErrNone);
+    test_KErrNone(r);
     if (ExtBufPtr)
         {
         TPtr8 des(ExtBufPtr->Des());
         r=TheRawDisk.Write(gRootDirStart + ExtBufAdd, des);
-        test(r==KErrNone);
+        test_KErrNone(r);
         }
     TheRawDisk.Close();
     }
 
-LOCAL_C void WriteFatDisk(TDes8& aFatBuf, TInt aStart=0)
+LOCAL_C void WriteFatToDisk(TDes8& aFatBuf, TInt aStart=0)
 //
 // writes fat buffer to disk
 //
     {
     TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     TInt fatCount=BootSector.NumberOfFats() - aStart;
     TInt pos = gFatStartBytes + aStart * gFatSizeSectors*BootSector.BytesPerSector();
     while(fatCount--)
         {
         r=TheRawDisk.Write(pos, aFatBuf);
-        test(r==KErrNone);
+        test_KErrNone(r);
         pos += gFatSizeSectors*BootSector.BytesPerSector();
         }
     TheRawDisk.Close();
@@ -1357,15 +1371,15 @@
         gFatTestEntries = KMaxFatSize;
     gFatTestSize = PosInBytes(gFatTestEntries);
     FatBufPtr=HBufC8::New(gFatTestSize);
-    test(FatBufPtr!=NULL);
+    test_NotNull(FatBufPtr);
     DirBufPtr=HBufC8::New(DirBufferSize());
-    test(DirBufPtr!=NULL);
+    test_NotNull(DirBufPtr);
 
     // Buffers for reading from disk
     FatDiskPtr=HBufC8::New(gFatTestSize);
-    test(FatDiskPtr!=NULL);
+    test_NotNull(FatDiskPtr);
     DirDiskPtr=HBufC8::New(DirBufferSize());
-    test(DirDiskPtr!=NULL);
+    test_NotNull(DirDiskPtr);
     }
 
 LOCAL_C TBool IsSameAsDrive(const TDes8& aFatBuf,const TDes8& aDirBuf)
@@ -1452,12 +1466,12 @@
     else if (ExtBufPtr)
         {
         HBufC8* extPtr = HBufC8::New(ExtBufLen);
-        test(extPtr != NULL);
+        test_NotNull(extPtr);
         TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-        test(r==KErrNone);
+        test_KErrNone(r);
         TPtr8 des(extPtr->Des());
         r=TheRawDisk.Read(ExtBufAdd+gRootDirStart, des);
-        test(r==KErrNone);
+        test_KErrNone(r);
         TheRawDisk.Close();
         TInt i = FindUnMatch(ExtBufPtr->Ptr(), extPtr->Ptr(), ExtBufLen);
         if (i >= 0)
@@ -1506,7 +1520,7 @@
     if(aAddEOfDir)
         WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry);
     TPtr8 dirBuf=DirBufPtr->Des();
-    WriteDirDisk(dirBuf);
+    WriteDirEntryToDisk(dirBuf);
     }
 
 LOCAL_C TBool TestPartialEntry(TEntryInfo aEntry)
@@ -1516,7 +1530,7 @@
     {
     test.Next(_L("TestPartialEntry"));
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     WriteDelete(aEntry.iBytePos,aEntry.iLength);
 
     TPtr8 fatBuf=FatBufPtr->Des();
@@ -1539,7 +1553,7 @@
     if(aAddEOfDir)
         WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry);
     TPtr8 dirBuf=DirBufPtr->Des();
-    WriteDirDisk(dirBuf);
+    WriteDirEntryToDisk(dirBuf);
     }
 
 LOCAL_C TBool TestMatchingEntry(TEntryInfo aToDelete)
@@ -1550,7 +1564,7 @@
     test.Next(_L("TestMatchingEntries"));
     WriteDelete(aToDelete.iBytePos,aToDelete.iLength);
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     TPtr8 fatBuf=FatBufPtr->Des();
     TPtr8 dirBuf=DirBufPtr->Des();
@@ -1574,8 +1588,8 @@
     CDir* dirs;
     // check no entries in the root directory
     TInt r=TheFs.GetDir(KRoot,KEntryAttMaskSupported,ESortNone,dirs);
-    test(r==KErrNone);
-    test(dirs->Count()==0);
+    test_KErrNone(r);
+    test_Equal(0,dirs->Count());
     delete(dirs);
     dirs=NULL;
 
@@ -1593,13 +1607,13 @@
 
     RFile file;
     r=file.Replace(TheFs,TestFileName,EFileShareExclusive);
-    test(r==KErrNone);
+    test_KErrNone(r);
     file.Close();
 
     // get short name
     TFileName shortName;
     r=TheFs.GetShortName(TestFileName,shortName);
-    test(r==KErrNone);
+    test_KErrNone(r);
     test(shortName==KOrigShortName);
 
     // must be first entry in root, modify to read like
@@ -1608,26 +1622,26 @@
     TInt bytePos=ClusterEntryToBytes(0,1);
     RRawDisk raw;
     r=raw.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     TBuf8<1> buf(1);
 
     //-- change 2nd character in the short name (Fat DOS entry)
     buf[0]=(TUint8)'\xC4';
     r=raw.Write(gRootDirStart+bytePos+1,buf);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     //-- fix the fiddled short name checksum in the corresponding VFat entry
     bytePos=ClusterEntryToBytes(0,0);
     buf[0]=(TUint8)0x2f;
     r=raw.Write(gRootDirStart+bytePos+13,buf);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     // retrieve short name from media.
     // Note: do not use RFs::GetShortName() as its behaviours are code page dependent.
     bytePos=ClusterEntryToBytes(0,1);
     TBuf8<11> shortNameBuf8;
     r=raw.Read(gRootDirStart+bytePos,shortNameBuf8);
-    test(r==KErrNone);
+    test_KErrNone(r);
     shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8);
     shortName.Copy(shortNameBuf8);
     raw.Close();
@@ -1638,15 +1652,15 @@
     //TheFs.SetDebugRegister(KFSYS);
     r=TheFs.ScanDrive(gSessionPath);
     TheFs.SetDebugRegister(0);
-    test(r==KErrNone);
+    test_KErrNone(r);
     DumpData(NULL, 0, 20);
 
     // retrieve short name from media.
     r=raw.Open(TheFs,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     bytePos=ClusterEntryToBytes(0,1);
     r=raw.Read(gRootDirStart+bytePos,shortNameBuf8);
-    test(r==KErrNone);
+    test_KErrNone(r);
     shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8);
     shortName.Copy(shortNameBuf8);
     raw.Close();
@@ -1655,7 +1669,7 @@
 
     // delete file
     r=TheFs.Delete(TestFileName);
-    test(r==KErrNone);
+    test_KErrNone(r);
     }
 
 LOCAL_C void TestMountAndScan()
@@ -1668,46 +1682,47 @@
 
     test.Next(_L("TestMountAndScan"));
     HBufC8* newFat=HBufC8::New(gFatTestSize);
-    test(newFat!=NULL);
+    test_NotNull(newFat);
     TPtr8 fat=newFat->Des();
     TPtr8 origFat=FatBufPtr->Des();
     TPtr8 origDir=DirBufPtr->Des();
 
     // set cluster of \scndrv\dir1\ to a hanging cluster
     ReadFatDisk(fat);
-    WriteFat(gClusterDir1ext,35,fat.Ptr());
-    WriteFat(35,36,fat.Ptr());
-    WriteFatDisk(fat);
+    WriteToFatBuf(gClusterDir1ext,35,fat.Ptr());
+    WriteToFatBuf(35,36,fat.Ptr());
+    WriteFatToDisk(fat);
     // set the default path to something other than the current drive
     TFileName fsName;
     TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     TFileName origDefPath, newDefPath;
     r=TheFs.SessionPath(origDefPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     newDefPath=origDefPath;
     newDefPath[0]=(TText)'z';
     r=TheFs.SetSessionPath(newDefPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0);
     if (r == KErrNone)
         {
         primaryExtensionExists = ETrue;
         }
     r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     // mount file system and check scandrive corrects error
     TBool isMount;
     if (primaryExtensionExists)
         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
     else
         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
-    test(isMount && r==KErrNone);
+    test(isMount);
+    test_KErrNone(r);
     TBool res=IsSameAsDrive(origFat,origDir);
     test(res);
 
     r=TheFs.SetSessionPath(origDefPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     delete newFat;
     }
 
@@ -1721,14 +1736,14 @@
     TBool primaryExtensionExists = EFalse;
     TFileName fsName;
     TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
     r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0);
     if (r == KErrNone)
         {
         primaryExtensionExists = ETrue;
         }
     r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A');
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     // RFs::MountFileSystemAndScan twice consecutively
     // first time
@@ -1737,15 +1752,37 @@
         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
     else
         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
-    test(isMount && r==KErrNone);
+    test(isMount);
+    test_KErrNone(r);
     // and a second time
     if (primaryExtensionExists)
         r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount);
     else
         r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount);
-    test(!isMount && r==KErrAccessDenied);
+    test(!isMount);
+    test_Equal(KErrAccessDenied,r);
     }
 
+
+static void CreateContiguousClusterChain(TUint32 aStartIndex, TUint32 aEndIndex, const TUint8* aFatPtr, TBool aMarkEoc)
+/*
+ * Creates a contiguous cluster chain in the FAT buffer.
+ * 
+ * @param	aStartIndex	The first cluster index of the chain
+ * 			aEndIndex	The last cluster index of the chain 
+ * 			aFatPtr		FAT table buffer pointer
+ * 			aMarkEoc	If ETrue, aEndIndex will be marked as EOC, else it will be a hanging cluster chain
+ */
+	{
+	// Write cluster chain
+    for(TUint i=aStartIndex; i<aEndIndex; ++i)
+        WriteToFatBuf(i, i+1, aFatPtr);
+    // Mark EOC if needed
+    if (aMarkEoc)
+    	WriteToFatBuf(aEndIndex, gEndOfChain, aFatPtr);
+	}
+
+
 LOCAL_C void DoHangingClusters()
 //
 // Tests that scandrive removes hanging clusters
@@ -1753,42 +1790,42 @@
     {
     test.Next(_L("Check Hanging clusters"));
     HBufC8* newFat=HBufC8::New(gFatTestSize);
-    test(newFat!=NULL);
+    test_NotNull(newFat);
     TPtr8 fat=newFat->Des();
     TPtr8 origFat=FatBufPtr->Des();
     TPtr8 origDir=DirBufPtr->Des();
 
-    // set cluster of \scndrv\dir1\ to a hanging cluster
+    // Set cluster of \scndrv\dir1\ to hanging cluster chain
     test.Start(_L("Test hanging cluster in \\scndrv\\dir1\\"));
     ReadFatDisk(fat);
-    WriteFat(gClusterDir1ext,35,fat.Ptr());
-    WriteFat(35,36,fat.Ptr());
-    WriteFatDisk(fat);
+    WriteToFatBuf(gClusterDir1ext,35,fat.Ptr());
+    WriteToFatBuf(35,36,fat.Ptr());
+    WriteFatToDisk(fat); // gClusterDir1ext->35->36
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TBool res=IsSameAsDrive(origFat,origDir);
     test(res);
 
-    // set  cluster chain of first entry of \scndrv\dir1\ to
+    // Set cluster chain of first entry of \scndrv\dir1\ to
     // larger size than file size
     test.Next(_L("Test hanging cluster in first entry"));
     ReadFatDisk(fat);
-    WriteFat(gClusterDir1ext,39,fat.Ptr());
-    WriteFat(39,500,fat.Ptr());
-    WriteFat(500,gEndOfChain,fat.Ptr());
-    WriteFatDisk(fat);
+    WriteToFatBuf(gClusterDir1ext,39,fat.Ptr());
+    WriteToFatBuf(39,500,fat.Ptr());
+    CreateContiguousClusterChain(500, 505, fat.Ptr(), ETrue);
+    WriteFatToDisk(fat); // gClusterDir1ext->39->500->501->502->503->504->505->EOC
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(origFat,origDir);
     test(res);
 
-    // set cluster of \scndrv\ to a hanging cluster
+    // Set cluster of \scndrv\ to a hanging cluster
     test.Next(_L("Test hanging cluster of \\scndrv\\"));
     ReadFatDisk(fat);
-    WriteFat(gClusterScnDrv,511,fat.Ptr());
-    WriteFatDisk(fat);
+    WriteToFatBuf(gClusterScnDrv,511,fat.Ptr());
+    WriteFatToDisk(fat); // gClusterScnDrv->511
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(origFat,origDir);
     test(res);
 
@@ -1803,7 +1840,7 @@
     {
     test.Next(_L("Check lost clusters"));
     HBufC8* newFat=HBufC8::New(gFatTestSize);
-    test(newFat!=NULL);
+    test_NotNull(newFat);
     TPtr8 fat=newFat->Des();
     TPtr8 origFat=FatBufPtr->Des();
     TPtr8 origDir=DirBufPtr->Des();
@@ -1813,12 +1850,10 @@
     // write cluster chain
     test.Start(_L("Test removal of lost cluster chain"));
     ReadFatDisk(fat);
-    for(TInt i=25;i<35;++i)
-        WriteFat(i,i+1,fat.Ptr());
-    WriteFat(35,gEndOfChain,fat.Ptr());
-    WriteFatDisk(fat);
+    CreateContiguousClusterChain(25, 35, fat.Ptr(), ETrue);
+    WriteFatToDisk(fat); // 25->26->27->28->29->30->31->32->33->34->35->EOC
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TBool res=IsSameAsDrive(origFat,origDir);
     test(res);
 
@@ -1829,17 +1864,17 @@
         TInt off = j*BootSector.BytesPerSector()+j*7%512;
         fat[off]=1;
         }
-    WriteFatDisk(fat);
+    WriteFatToDisk(fat);
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(origFat,origDir);
     test(res);
 
     // write semi-random changes to second fat
     test.Next(_L("Test semi-random changes to second fat"));
-    WriteFatDisk(fat, 1);
+    WriteFatToDisk(fat, 1);
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(origFat,origDir);
     test(res);
 
@@ -1847,6 +1882,74 @@
     test.End();
     }
 
+
+static void DoHangingAndLostClusters()
+/*
+ * Tests that ScanDrive fixes MULTIPLE hanging clusters and removes lost clusters.
+ * It creates multiple hanging and lost cluster chains in the FAT table and
+ * expects ScanDrive to fix them all.
+ */
+	{
+	test.Start(_L("Check multiple hanging and lost cluster chains"));
+	HBufC8* newFat = HBufC8::New(gFatTestSize);
+	test_NotNull(newFat);
+	TPtr8 fat = newFat->Des();
+	TPtr8 origFat = FatBufPtr->Des();
+	TPtr8 origDir = DirBufPtr->Des();
+	ReadFatDisk(origFat);
+	ReadDirDisk(origDir);
+
+	test.Printf(_L("Create multiple hanging cluster chains\n"));
+	ReadFatDisk(fat);
+	// Set hanging cluster for the file in \scndrv\dir1
+	// gClusterDir1ext+1->25->26->27->28->29->30->31->32->33->34->35
+	WriteToFatBuf(gClusterDir1ext+1, 25, fat.Ptr());
+	CreateContiguousClusterChain(25, 35, fat.Ptr(), EFalse);
+	// Set hanging cluster for the first file in \scndrv\dir2
+	// gClusterDir2_AFull+1->249->250->53->54->55->EOC
+	WriteToFatBuf(gClusterDir2_AFull+1, 249, fat.Ptr());
+	WriteToFatBuf(249, 250, fat.Ptr());
+	WriteToFatBuf(250, 53, fat.Ptr());
+	CreateContiguousClusterChain(53, 55, fat.Ptr(), ETrue);
+	// Set hanging cluster for the fourth file in \scndrv\dir2
+	// gClusterDir2_AFull+4->59->60->61->62->63
+	WriteToFatBuf(gClusterDir2_AFull+4, 59, fat.Ptr());
+	CreateContiguousClusterChain(59, 63, fat.Ptr(), EFalse);
+	// Set hanging cluster for the second file in \scndrv\dir2
+	// gClusterDir2_AFull+2->67->68->69->EOC
+	WriteToFatBuf(gClusterDir2_AFull+2, 67, fat.Ptr());
+	CreateContiguousClusterChain(67, 69, fat.Ptr(), ETrue);
+
+	test.Printf(_L("Create multiple lost clusters\n"));
+	// Create 1st lost cluster chain (clusters 36-45)
+	CreateContiguousClusterChain(36, 45, fat.Ptr(), ETrue);
+	// Create 2nd lost cluster chain (clusters 246-248,56-58)
+	CreateContiguousClusterChain(246, 248, fat.Ptr(), EFalse);
+	WriteToFatBuf(248, 56, fat.Ptr());
+	CreateContiguousClusterChain(56, 58, fat.Ptr(), ETrue);
+	// Create 3rd lost cluster chain (clusters 251-253,564-566, with hanging end)
+	CreateContiguousClusterChain(251, 253, fat.Ptr(), EFalse);
+	WriteToFatBuf(253, 564, fat.Ptr());
+	CreateContiguousClusterChain(564, 566, fat.Ptr(), EFalse);
+	
+	// Flush all FAT changes to the media
+	WriteFatToDisk(fat);
+
+	test.Next(_L("Test ScanDrive fixes multiple hanging and lost cluster chains"));
+	TInt r = TheFs.CheckDisk(gSessionPath);	// CheckDisk should detect an error
+	test_Value(r, r != KErrNone);
+	r = TheFs.ScanDrive(gSessionPath);		// ScanDrive should find the errors and fix them
+	test_KErrNone(r);
+	r = TheFs.CheckDisk(gSessionPath);
+	test_KErrNone(r);
+	TBool res = IsSameAsDrive(origFat, origDir);
+	test(res);
+
+	delete newFat;
+	test.End();
+	}
+
+
 LOCAL_C void DoPartEntries()
 //
 // Tests that scandrive detects/corrects partial entries
@@ -1860,9 +1963,9 @@
     TPtr8 dirBuf=DirBufPtr->Des();
 
     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
-    test(r==KErrNone || r==KErrNotFound || KErrPathNotFound);
+    test_Value(r, r==KErrNone || r==KErrNotFound || r==KErrPathNotFound);
     r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
-    test(r==KErrNone || r==KErrNotFound || KErrPathNotFound);
+    test_Value(r, r==KErrNone || r==KErrNotFound || r==KErrPathNotFound);
 
     if (BootSector.RootDirEntries() != 0)
         {
@@ -1871,7 +1974,7 @@
         test.Next(_L("Partial entry at end of rootdir"));
         FillUpRootDir(2);
         r=temp.Create(TheFs,_L("\\temp"),EFileShareAny);
-        test(r==KErrNone);
+        test_KErrNone(r);
         temp.Close();
         ReadDirDisk(dirBuf);
         ReadFatDisk(fatBuf);
@@ -1891,7 +1994,7 @@
     CreatePartialEntry(partial2,3,EFalse);
     // entry has been allocated a cluster which scandrive should delete along with partial entry
     if (last > 0)
-        WriteFat(last,0,fatBuf.Ptr());
+        WriteToFatBuf(last,0,fatBuf.Ptr());
     res=TestPartialEntry(partial2);
     test(res);
 
@@ -1899,26 +2002,26 @@
     test.Next(_L("Test directory reclaim"));
     last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-2);
     WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2));
-    WriteDirDisk(dirBuf);
+    WriteDirEntryToDisk(dirBuf);
     TInt entry = GetFatEntry(gClusterDir2_Full, fatBuf.Ptr());
-    WriteFat(gClusterDir2_Full,gEndOfChain,fatBuf.Ptr());
+    WriteToFatBuf(gClusterDir2_Full,gEndOfChain,fatBuf.Ptr());
     while (entry && (entry & gEndOfChain) != gEndOfChain)
         {
         TInt next = GetFatEntry(entry, fatBuf.Ptr());
-        WriteFat(entry,0,fatBuf.Ptr());
+        WriteToFatBuf(entry,0,fatBuf.Ptr());
         entry = next;
         }
     if (last > 0)
-        WriteFat(last,0,fatBuf.Ptr());
+        WriteToFatBuf(last,0,fatBuf.Ptr());
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(fatBuf,dirBuf);
     test(res);
 
     // use last entry of first cluster in \scndrv\dir2\full\ 
     test.Next(_L("Partial entry at end of subdir"));
     r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     temp.Close();
     ReadDirDisk(dirBuf);
     ReadFatDisk(fatBuf);
@@ -1931,12 +2034,12 @@
     test.Next(_L("Partial entry preceeding end-of-dir marker"));
     last = GetStartCluster(gClusterDir2_AFull,14);
     if (last > 0)
-        WriteFat(last,0,fatBuf.Ptr());
+        WriteToFatBuf(last,0,fatBuf.Ptr());
     last = GetStartCluster(gClusterDir2_AFull,8);
     if (last > 0)
-        WriteFat(last,0,fatBuf.Ptr());
+        WriteToFatBuf(last,0,fatBuf.Ptr());
     WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_AFull,14));
-    WriteDirDisk(dirBuf);
+    WriteDirEntryToDisk(dirBuf);
     TEntryInfo partial4(ClusterEntryToBytes(gClusterDir2_AFull,8),6);
     CreatePartialEntry(partial4,4,EFalse);
     res=TestPartialEntry(partial4);
@@ -1952,14 +2055,14 @@
 	// create entry in \scndrv\dir2\almostfull\ 
 //	test.Next(_L("Partial entry with invalid dos name"));
 //	r=temp.Create(TheFs,_L("\\scndrv\\dir2\\almostfull\\Dodgy file name"),EFileShareAny);
-//	test(r==KErrNone);
+//	test_KErrNone(r);
 //	temp.Close();
 //	ReadDirDisk(dirBuf);
 //	TInt dosStart=ClusterEntryToBytes(gClusterDir2_AFull,4);
 //	dirBuf[dosStart+4]=0x1;
 //	WriteDirDisk(dirBuf);
 //	r=TheFs.ScanDrive(gSessionPath);
-//	test(r==KErrNone);
+//	test_KErrNone(r);
 //	WriteDelete(dosStart-2*32,3);
 //	res=IsSameAsDrive(fatBuf,dirBuf);
 //	test(res);
@@ -1971,26 +2074,26 @@
         last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-1);
         WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2));
         WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-1));
-        WriteDirDisk(dirBuf);
+        WriteDirEntryToDisk(dirBuf);
         TFileName longFile=_L("\\scndrv\\dir2\\full\\");
         MakeVeryLongName(longFile);
         r=temp.Create(TheFs,longFile,EFileShareAny);
-        test(r==KErrNone);
+        test_KErrNone(r);
         temp.Close();
         ReadDirDisk(dirBuf);
-        WriteFat(gClusterDir2_Full,gClusterDir2_SD3E,fatBuf.Ptr());
-        WriteFat(gClusterDir2_SD3E,gClusterDir2_SD23E,fatBuf.Ptr());
-        WriteFat(gClusterDir2_SD23E,gEndOfChain,fatBuf.Ptr());
+        WriteToFatBuf(gClusterDir2_Full,gClusterDir2_SD3E,fatBuf.Ptr());
+        WriteToFatBuf(gClusterDir2_SD3E,gClusterDir2_SD23E,fatBuf.Ptr());
+        WriteToFatBuf(gClusterDir2_SD23E,gEndOfChain,fatBuf.Ptr());
         if (last > 0)
-            WriteFat(last,0,fatBuf.Ptr());
+            WriteToFatBuf(last,0,fatBuf.Ptr());
         TEntryInfo partial5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19);
         CreatePartialEntry(partial5,7,EFalse);
         res=TestPartialEntry(partial5);
         test(res);
         r=TheFs.Delete(longFile);
-        test(r==KErrNone || r==KErrNotFound);
+        test_Value(r, r==KErrNone || r==KErrNotFound);
         r=TheFs.Delete(_L("\\temp"));
-        test(r==KErrNone || r==KErrNotFound);
+        test_Value(r, r==KErrNone || r==KErrNotFound);
         }
     ReadDirDisk(dirBuf);
 
@@ -2040,16 +2143,16 @@
     test.Next(_L("matching entries in same subdir"));
     // delete entries to allow contiguous clusters in \scndrv\dir2\full directory
     TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     // ensure directory is expanded
     RFile temp;
     r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     temp.Close();
     r=TheFs.Delete(_L("\\scndrv\\dir2\\full\\temp"));
-    test(r==KErrNone);
+    test_KErrNone(r);
     ReadDirDisk(dirBuf);
     ReadFatDisk(fatBuf);
     TEntryInfo from4(ClusterEntryToBytes(gClusterDir2_Full,4),2);
@@ -2062,14 +2165,14 @@
     test.Next(_L("matching entries in diff dirs + new cluster"));
     // delete last entry in directory
     r=TheFs.Delete(LastInFull);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TFileName veryLongName=_L("\\scndrv\\dir2\\full\\");
     MakeVeryLongName(veryLongName);
     r=temp.Create(TheFs,veryLongName,EFileShareAny);
-    test(r==KErrNone);
+    test_KErrNone(r);
     temp.Close();
     r=TheFs.Delete(veryLongName);
-    test(r==KErrNone);
+    test_KErrNone(r);
     ReadDirDisk(dirBuf);
     ReadFatDisk(fatBuf);
     TEntryInfo from5(ClusterEntryToBytes(gClusterDir1,2),19);
@@ -2099,7 +2202,7 @@
     ReadFatDisk(fatBuf);
     // run scandisk and compare
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     TBool res=IsSameAsDrive(fatBuf,dirBuf);
     test(res);
     // Create a entry with matching start cluster and check fixed up
@@ -2126,7 +2229,7 @@
     ReadFatDisk(fatBuf);
 
     TInt r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     TBool res=IsSameAsDrive(fatBuf,dirBuf);
     test(res);
@@ -2219,9 +2322,9 @@
             name.AppendNumFixedWidth(i+totalFilesCreated, EHex, 3);
             RFile f;
             r = f.Create(TheFs, name, EFileShareAny);
-            test(r == KErrNone);
+            test_KErrNone(r);
             r = f.Write(buf);
-            test(r == KErrNone);
+            test_KErrNone(r);
             f.Close();
             }
 
@@ -2254,7 +2357,7 @@
 
             }
 
-        WriteDirDisk(dirBuf, cluster);
+        WriteDirEntryToDisk(dirBuf, cluster);
         totalFilesCreated += filesThisTime;
         test.Printf(_L("   created %d entries\n"), totalFilesCreated);
         }
@@ -2266,7 +2369,7 @@
 
     test.Printf(_L("Running ScanDrive\n"), filesThisTime);
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     TBool res=IsSameAsDrive(fatBuf,dirBuf);
     test(res);
@@ -2278,17 +2381,17 @@
         name.Append(_L("tempfile."));
         name.AppendNumFixedWidth(i, EHex, 3);
         r = TheFs.Delete(name);
-        test(r == KErrNone);
+        test_KErrNone(r);
         }
 
     ReadDirDisk(dirBuf);
     ReadFatDisk(fatBuf);
     WriteEndOfDir(ClusterEntryToBytes(cluster, startEntry));
-    WriteDirDisk(dirBuf);
+    WriteDirEntryToDisk(dirBuf);
 
     test.Printf(_L("Running ScanDrive\n"), filesThisTime);
     r=TheFs.ScanDrive(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
     res=IsSameAsDrive(fatBuf,dirBuf);
     test(res);
     }
@@ -2329,6 +2432,7 @@
     DoPartEntries();
     DoLostClusters();
     DoHangingClusters();
+    DoHangingAndLostClusters();
     TestMountAndScan();
     TestConsecutiveMountAndScans();
     DeleteDirectoryStructure();
@@ -2350,7 +2454,7 @@
     {
     TInt r;
     r = TheFs.CharToDrive(gSessionPath[0], gDriveNumber);
-    test( KErrNone == r );
+    test_KErrNone(r);
 
 
     //-- set up console output
@@ -2368,7 +2472,7 @@
     // check this is not the internal ram drive
     TVolumeInfo v;
     r=TheFs.Volume(v);
-    test(r==KErrNone);
+    test_KErrNone(r);
     if(v.iDrive.iMediaAtt&KMediaAttVariableSize)
         {
         test.Printf(_L("Error: Internal ram drive not tested\n"));
@@ -2376,7 +2480,7 @@
         }
 
     r=TheFs.SetSessionPath(gSessionPath);
-    test(r==KErrNone);
+    test_KErrNone(r);
 
     DoTests();
 
--- a/kerneltest/f32test/filesystem/fat/t_tscan32.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/filesystem/fat/t_tscan32.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -11,9 +11,10 @@
 // Contributors:
 //
 // Description:
-// f32test\scndrv\t_tscan32.cpp
+// f32test\filesystem\fat\t_tscan32.cpp
 // 
-//
+
+#define __E32TEST_EXTENSION__
 
 #include <f32file.h>
 #include <e32test.h>
@@ -36,9 +37,9 @@
 
 #ifdef _DEBUG
 GLREF_D RTest test;
-GLDEF_D TInt TheFunctionNumber;
-GLDEF_D TInt TheOpNumber;
-GLDEF_D TInt TheFailCount;
+GLDEF_D TInt TheFunctionNumber;	// Indicates which test to run
+GLDEF_D TInt TheOpNumber;		// Indicates which file operation to be tested
+GLDEF_D TInt TheFailCount;		
 GLDEF_D TBool IsReset;
 GLDEF_D TFileName TestExeName=_L("?:\\T_SCANDR.EXE"); //Renaming it to fit in one root dir entry.
 GLDEF_D TFileName LogFileName=_L("?:\\T_SCANDR.LOG"); //Renaming it to fit in one root dir entry.
@@ -56,8 +57,8 @@
 const TInt KDirAttrLongMask  = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
 const TInt KDirLastLongEntry = 0x40;
 
-GLDEF_D TInt WriteFailValue;
-
+GLDEF_D TInt WriteFailValue;	// Indicates what error should return from a write failure
+								// Value assigned in t_scn32dr2 and t_scn32dr3
 LOCAL_C TFatBootSector BootSector;	
 LOCAL_D RRawDisk TheRawDisk;
 
@@ -79,7 +80,13 @@
 LOCAL_D HBufC8* gFatBuf  = NULL;
 LOCAL_D TInt    gFatAddr = -1;
 
-enum TFatChain {EChainStd,EChainAlternate,EChainBackwards,EChainForwards};
+enum TFatChain
+	{
+	EChainStd,			// Cluster chain grows contiguously
+	EChainAlternate,	// Cluster chain grows forward but not contiguously
+	EChainBackwards,	// Cluster chain first goes backwards(up to 3.5kb for fat16 file) and then forwards
+	EChainForwards		// Cluster chain first goes forward (upto 3.5kb for fat16 file) and then backwards
+	};
 
 LOCAL_C TBool IsInternalRam()
 //
@@ -88,7 +95,7 @@
 	{
 	TVolumeInfo v;
 	TInt r=TheFs.Volume(v,gSessionPath[0]-'A');
-	test(r==KErrNone);
+	test_KErrNone(r);
 	return(v.iDrive.iMediaAtt&KMediaAttVariableSize);
 	}
 
@@ -102,10 +109,10 @@
 	TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive|EFileWrite);
 	if(r!=KErrNone)
 		test.Printf(_L("error=%d\n"),r);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TInt size;
 	r=log.Size(size);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TBuf8<16> buf;
 	buf.SetLength(4);
 	buf[0]=(TUint8)TheFunctionNumber;
@@ -113,7 +120,7 @@
 	buf[2]=(TUint8)TheFailCount;
 	buf[3]='\n';
 	r=log.Write(size,buf,buf.Length());
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test.Printf(_L("Written func=%d,op=%d,fail=%d\n"),TheFunctionNumber,TheOpNumber,TheFailCount);
 	log.Close();
 	}
@@ -141,8 +148,8 @@
 	TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive);
 	if(r!=KErrNone)
 		test.Printf(_L("error in ReadLogFile()=%d\n"),r);
-	test(r==KErrNone);
-	test(r==KErrNone);
+	test_KErrNone(r);
+	
 	TInt fileSize;
 	r=log.Size(fileSize);
 	if(fileSize==0)
@@ -187,7 +194,7 @@
 */
 static void DoZeroFillMedia(TInt64 aStartPos, TInt64 aEndPos, RRawDisk& aWriter)
 {
-    test(aStartPos >=0 && aEndPos >=0 && aStartPos < aEndPos);
+	test(aStartPos >=0 && aEndPos >=0 && aStartPos < aEndPos);
     
     if(aStartPos == aEndPos)
         return;
@@ -198,7 +205,7 @@
     const TUint32 KBufSz=65536*2; //-- buffer with zeroes
     
     nRes = buf.CreateMax(KBufSz);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     buf.FillZ();
 
@@ -209,7 +216,7 @@
     
         TPtrC8 ptr(buf.Ptr(), bytesToWrite);
         nRes = aWriter.Write(aStartPos, ptr);
-        test(nRes == KErrNone || nRes == KErrDiskFull);
+        test_Value(nRes, nRes == KErrNone || nRes == KErrDiskFull);
 
         aStartPos+=bytesToWrite;
         rem-=bytesToWrite;
@@ -227,7 +234,7 @@
 	{
 
 	TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	TUint32 startPos = gDataStartBytes;
 	if (gDiskType == EFat32)
@@ -269,7 +276,7 @@
 	{
 	
     TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     if(!BootSector.IsValid())
         {
@@ -323,7 +330,7 @@
 	if (!gFatBuf)
 		{
 		gFatBuf=HBufC8::New(gBytesPerCluster);
-		test(gFatBuf!=NULL);
+		test_NotNull(gFatBuf);
 		gFatAddr = -1;
 		}
 
@@ -339,10 +346,10 @@
 		if (gFatAddr < 0 || pos < gFatAddr || pos >= gFatAddr + gBytesPerCluster)
 			{
 			TPtr8 ptr=gFatBuf->Des();
-		TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-			test(r==KErrNone);
+			TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
+			test_KErrNone(r);
 			r=TheRawDisk.Read(pos, ptr);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			TheRawDisk.Close();
 			gFatAddr = pos;
 			}
@@ -550,6 +557,18 @@
 	aName.SetLength(i);
 	}
 
+TDes& MakePrintable(TDes& aDes)
+	{
+	TInt len = aDes.Length();
+
+	for (TInt i=0; i<len; i++)
+		{
+		if ((TUint8) aDes[i] < 0x20)
+			aDes[i] = '?';
+		}
+	return aDes;
+	}
+
 GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
 // 
 // Dump a single directory entry to the log.  Return false if it was end of
@@ -569,9 +588,9 @@
 		ExtractNameString(name, aEntry);
 		TInt ord = aEntry[0];
 		if (ord & KDirLastLongEntry)
-			RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
+			RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &MakePrintable(name), ord & ~KDirLastLongEntry);
 		else
-			RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
+			RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &MakePrintable(name), ord & ~KDirLastLongEntry);
 		}
 	else if (!IsValidDirEntry(d))
 		return EFalse;
@@ -580,7 +599,7 @@
 		TBuf<11> name;
 		name.Copy(d->Name());
 		RDebug::Print(_L("%5d: '%S'  %S  cluster %d"),
-					  aNum, &name, DirAttributes(d->Attributes()), d->StartCluster());
+					  aNum, &MakePrintable(name), DirAttributes(d->Attributes()), d->StartCluster());
 		}
 	return ETrue;
 	}
@@ -619,12 +638,12 @@
 		if (GetFatEntry(cluster, aFat) != 0)
 			{
 			HBufC8* buf=HBufC8::New(gBytesPerCluster);
-			test(buf!=NULL);
+			test_NotNull(buf);
 			TPtr8 ptr=buf->Des();
 			TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
-			test(r==KErrNone);
+			test_KErrNone(r);
 			r=TheRawDisk.Read(ClusterToByte(cluster), ptr);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			TheRawDisk.Close();
 			RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
 			DumpDirCluster(ptr.Ptr());
@@ -708,7 +727,7 @@
 		dir[1]=TUint16(count/26+'a');
 		dir[2]=TUint16(count%26+'a');
 		r=TheFs.MkDir(dir);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		entriesSoFar+=2;
 		++count;
 		}
@@ -733,7 +752,7 @@
 		dir[1]=TUint16(count/26+'a');
 		dir[2]=TUint16(count%26+'a');
 		r=TheFs.RmDir(dir);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		entriesSoFar-=2;
 		++count;
 		}
@@ -755,7 +774,7 @@
 	{
 	TEntry entry;
 	TInt r=TheFs.Entry(aName,entry);
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	return(r==KErrNone?(TBool)ETrue:(TBool)EFalse);
 	}
 
@@ -794,7 +813,7 @@
 //
 	{
 	TInt r=TheFs.Entry(aName,aEntry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	}
 
 LOCAL_C TBool IsSameEntryDetails(TEntry aOldEntry,TEntry aNewEntry)
@@ -817,9 +836,9 @@
 	TInt size1,size2;
 	size1=size2=0;
 	TInt r=file1.Create(TheFs,aNameOne,EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file2.Create(TheFs,aNameTwo,EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	// one entry for file1 for every 40 entries for file2
 	// if file 1 subseqently deleted then 7 entries available
 	// in that fat sector - ~3.5kb file size - for fat16
@@ -831,15 +850,15 @@
 			{
 			size1+=gBytesPerCluster;
 			r=file1.SetSize(size1);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			first=EFalse;
 			--entries;
 			}
 		else
 			{
 			size2+=gBytesPerCluster*ratio;
-			r=file1.SetSize(size1);
-			test(r==KErrNone);
+			r=file2.SetSize(size2);
+			test_KErrNone(r);
 			first=ETrue;
 			entries-=ratio;
 			}
@@ -892,7 +911,7 @@
 		TFileName fullName(aName);
 		fullName.Append(fn);
 		TInt r = TheFs.Delete(fullName);
-		test(r == KErrNone);
+		test_KErrNone(r);
 		entry += 1 + (fn.Length() + 12) / 13;
 		}
 	RDebug::Print(_L("CleanDirectory(%S, %d)"), &aName, aClusters);
@@ -927,7 +946,7 @@
 		fullName.Append(fn);
 		RFile file;
 		TInt r = file.Create(TheFs,fullName,EFileShareAny);
-		test(r == KErrNone);
+		test_KErrNone(r);
 		file.Close();
 		entry += 1 + (fn.Length() + 12) / 13;
 		}
@@ -942,7 +961,7 @@
 //
 	{
 	TInt r=TheFs.Delete(_L("\\fat\\file2"));
-	test(r==KErrNone||KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	if(aIsDir)
 		return(TheFs.RmDir(aName));
 	else
@@ -956,7 +975,7 @@
 //
 	{
 	TInt r=DeleteAlternateEntry(aName,aIsDir);
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	RFile file;
 	if(aIsDir)
 		{
@@ -970,17 +989,17 @@
 		if(r!=KErrNone)
 			return(r);
 		r=file.SetSize(1); //ensure file allocated a start cluster
-		test(r==KErrNone);
+		test_KErrNone(r);
 		}
 	CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
 	r=TheFs.Delete(_L("\\fat\\file1"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	if(aIsDir)
 		ExpandDirectory(aName,aSize);
 	else
 		{
 		r=file.SetSize(aSize);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		file.Close();
 		}
 	return(KErrNone);
@@ -992,11 +1011,11 @@
 //
 	{
 	TInt r=TheFs.Delete(_L("\\fat\\file2"));
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	r=TheFs.Delete(_L("\\fat\\file4"));
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	r=TheFs.Delete(_L("\\fat\\file5"));
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	if(aIsDir)
 		r=TheFs.RmDir(aName);
 	else
@@ -1011,16 +1030,16 @@
 //	
 	{
 	TInt r=DeleteForwardEntry(aName,aIsDir);
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	RFile file1,file2,entry;
 	r=file1.Create(TheFs,_L("\\fat\\file1"),EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file1.SetSize(EntriesPerFatSector()*gBytesPerCluster);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file2.Create(TheFs,_L("\\fat\\file2"),EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file2.SetSize(EntriesPerFatSector()*gBytesPerCluster);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	if(aIsDir)
 		{
 		r=TheFs.MkDir(aName);
@@ -1033,27 +1052,27 @@
 		if(r!=KErrNone)
 			return(r);
 		r=entry.SetSize(1);	// ensure entry has start cluster allocated
-		test(r==KErrNone);
+		test_KErrNone(r);
 		}
 	CreateAlternate(_L("\\fat\\file3"),_L("\\fat\\file4"));
 	RFile file5;
 	r=file5.Create(TheFs,_L("\\fat\\file5"),EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file5.SetSize(EntriesPerFatSector()*gBytesPerCluster*2);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	file1.Close();
 	file2.Close();
 	file5.Close();
 	r=TheFs.Delete(_L("\\fat\\file1"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.Delete(_L("\\fat\\file3"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	if(aIsDir)
 		ExpandDirectory(aName,aSize);
 	else
 		{
 		r=entry.SetSize(aSize);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		entry.Close();
 		}
 	return(KErrNone);
@@ -1065,9 +1084,9 @@
 //
 	{
 	TInt r=TheFs.Delete(_L("\\fat\\file2"));
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	r=TheFs.Delete(_L("\\fat\\file3"));
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	if(aIsDir)
 		r=TheFs.RmDir(aName);
 	else
@@ -1082,7 +1101,7 @@
 //
 	{
 	TInt r=DeleteBackwardEntry(aName,aIsDir);
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
 	RFile entry;
 	if(aIsDir)
@@ -1097,22 +1116,22 @@
 		if(r!=KErrNone)
 			return(r);
 		r=entry.SetSize(1);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		}
 	RFile file3;
 	r=file3.Create(TheFs,_L("\\fat\\file3"),EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file3.SetSize(EntriesPerFatSector()*gBytesPerCluster);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.Delete(_L("\\fat\\file1"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	file3.Close();
 	if(aIsDir)
 		ExpandDirectory(aName,aSize);
 	else
 		{
 		r=entry.SetSize(aSize);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		entry.Close();
 		}
 	return(KErrNone);	
@@ -1135,7 +1154,7 @@
 //
 	{
 	TInt r=DeleteStdEntry(aName,aIsDir);
-	test(r==KErrNone||r==KErrNotFound);
+	test_Value(r, r==KErrNone||r==KErrNotFound);
 	if(aIsDir)
 		{
 		r=TheFs.MkDir(aName);
@@ -1150,12 +1169,12 @@
 		if(r==KErrNone)
 			{
 			r=file.SetSize(aSize);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			}
 		else if(r==KErrAlreadyExists)
 			{
 			TInt res =file.Open(TheFs,aName,EFileShareAny);
-			test(res==KErrNone);
+			test_KErrNone(res);
 			}
 		else
 			return(r);
@@ -1206,28 +1225,28 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aName,EFalse,aChain,aFileSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.Delete(aName);
 		if(r==KErrNone)
 			break;
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(!EntryExists(aName));
 	++TheOpNumber;
 	TheFailCount=0;
@@ -1262,18 +1281,18 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aName,ETrue,aChain,aDirSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.RmDir(aName);
 		if(r==KErrNone)
 			break;
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
 		RDebug::Print(_L("%6d: ScanDrive = %d"), __LINE__, r);
 		if (r != KErrNone)
@@ -1282,16 +1301,16 @@
 			DumpFat();
 			DumpData(NULL, 0, 200);
 		}
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
 		RDebug::Print(_L("%6d: CheckDisk = %d"), __LINE__, r);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(!EntryExists(aName));
 	++TheOpNumber;
 	TheFailCount=0;
@@ -1309,31 +1328,31 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=DeleteEntry(aName,ETrue,EChainStd);
-		test(r==KErrNone||r==KErrNotFound);
+		test_Value(r, r==KErrNone||r==KErrNotFound);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.MkDir(aName);
 		if(r==KErrNone)
 			break;
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aName));
 	r=DeleteEntry(aName,ETrue,EChainStd);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1351,9 +1370,9 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aOldName,aIsDir,aChain,aSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		r=DeleteEntry(aNewName,aIsDir,aChain);
-		test(r==KErrNone||r==KErrNotFound);
+		test_Value(r, r==KErrNone||r==KErrNotFound);
 		GetEntryDetails(aOldName,oldEntryInfo);
 		if(IsReset)
 			{
@@ -1361,34 +1380,29 @@
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.Rename(aOldName,aNewName);
 		if(r==KErrNone)
 			break;
-		if(r!=WriteFailValue)
-			{
-			test.Printf(_L("r=%d\n"),r);
-			test(EFalse);
-			}
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		// no start cluster if aSize==0
 		if(aSize!=0)
 			test(OneEntryExists(aOldName,aNewName));
 		++failCount;
 		}
 	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aNewName) && !EntryExists(aOldName));
 	GetEntryDetails(aNewName,newEntryInfo);
 	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
 	r=DeleteEntry(aNewName,aIsDir,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1410,16 +1424,16 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		if(aBothExist)
 			{
 			r=CreateEntry(aNewName,EFalse,aChain,aFileSize);
-			test(r==KErrNone||r==KErrAlreadyExists);
+			test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 			}
 		else
 			{
 			r=DeleteEntry(aNewName,EFalse,aChain);
-			test(r==KErrNone||r==KErrNotFound);
+			test_Value(r, r==KErrNone||r==KErrNotFound);
 			}
 		GetEntryDetails(aOldName,oldEntryInfo);
 		if(IsReset)
@@ -1428,15 +1442,15 @@
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.Replace(aOldName,aNewName);
 		if(r==KErrNone)
 			break;
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		if(!aBothExist && aFileSize!=0)
 			test(OneEntryExists(aOldName,aNewName));
 		else if(aBothExist)
@@ -1444,14 +1458,14 @@
 		++failCount;
 		}
 	r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aNewName) && !EntryExists(aOldName));
 	GetEntryDetails(aNewName,newEntryInfo);
 	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
 	r=DeleteEntry(aNewName,EFalse,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1468,35 +1482,35 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=DeleteEntry(aName,EFalse,EChainStd);
-		test(r==KErrNone||r==KErrNotFound);
+		test_Value(r, r==KErrNone||r==KErrNotFound);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		RFile file;
 		r=file.Create(TheFs,aName,EFileShareAny);
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aName));
 	r=DeleteEntry(aName,EFalse,EChainStd);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1519,28 +1533,28 @@
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		RFile file;
  		r=file.Temp(TheFs,aPath,temp,EFileShareAny);
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
 		test(r==WriteFailValue);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(temp));
 	r=DeleteEntry(temp,EFalse,EChainStd);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1558,9 +1572,9 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		r=DeleteEntry(aNewName,EFalse,aChain);
-		test(r==KErrNone||r==KErrNotFound);
+		test_Value(r, r==KErrNone||r==KErrNotFound);
 		GetEntryDetails(aOldName,oldEntryInfo);
 		if(IsReset)
 			{
@@ -1569,34 +1583,34 @@
 			}
 		RFile file;
 		r=file.Open(TheFs,aOldName,EFileShareExclusive|EFileWrite);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=file.Rename(aNewName);
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		file.Close();
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		if(aFileSize)
 			test(OneEntryExists(aOldName,aNewName));
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aNewName) && !EntryExists(aOldName));
 	GetEntryDetails(aNewName,newEntryInfo);
 	test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
 	r=DeleteEntry(aNewName,EFalse,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheOpNumber;
 	TheFailCount=0;
 	}
@@ -1615,12 +1629,12 @@
 		if(aAlreadyExists)
 			{
 			r=CreateEntry(aName,EFalse,aChain,aFileSize);
-			test(r==KErrNone||r==KErrAlreadyExists);
+			test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 			}
 		else
 			{
 			r=DeleteEntry(aName,EFalse,aChain);
-			test(r==KErrNone||r==KErrNotFound);
+			test_Value(r, r==KErrNone||r==KErrNotFound);
 			}
 		if(IsReset)
 			{
@@ -1628,28 +1642,28 @@
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		RFile file;
 		r=file.Replace(TheFs,aName,EFileShareAny);
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(EntryExists(aName));
 	r=DeleteEntry(aName,EFalse,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	if(!aAlreadyExists)
 		{
 		++TheOpNumber;
@@ -1675,54 +1689,54 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aName,EFalse,aChain,aOldFileSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		RFile file;
 		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=file.SetSize(aNewFileSize);
 		// close the file before testing the return value!
 		file.Close();
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
 		file.Close();
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		TInt size;
 		r=file.Size(size);
-		test(r==KErrNone);
-		test(size==aNewFileSize||size==aOldFileSize);
+		test_KErrNone(r);
+		test_Value(size, size==aNewFileSize||size==aOldFileSize);
 		file.Close();
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	RFile file;
 	r=file.Open(TheFs,aName,EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TInt fileSize;
 	r=file.Size(fileSize);
-	test(r==KErrNone);
-	test(aNewFileSize==fileSize);
+	test_KErrNone(r);
+	test_Equal(aNewFileSize,fileSize);
 	file.Close();
 	r=DeleteEntry(aName,EFalse,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	++TheFunctionNumber;
 	TheFailCount=0;
 	}
@@ -1739,7 +1753,7 @@
 	TInt newSize=(aFileSize>=aPos+aLength)?aFileSize:aPos+aLength;
 	HBufC8* desPtr;
 	desPtr=HBufC8::New(aLength);
-	test(desPtr!=NULL);
+	test_NotNull(desPtr);
 	TPtr8 des=desPtr->Des();
 	des.SetLength(aLength);
 	InitialiseWriteBuffer(des);
@@ -1747,64 +1761,64 @@
 		{
 		test.Printf(_L("failCount=%d\n"),failCount);
 		r=CreateEntry(aName,EFalse,aChain,aFileSize);
-		test(r==KErrNone||r==KErrAlreadyExists);
+		test_Value(r, r==KErrNone||r==KErrAlreadyExists);
 		if(IsReset)
 			{
 			++TheFailCount;
 			WriteLogFile();
 			}
 		r=SetWriteFailOn(failCount);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		RFile file;
 		r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=file.Write(aPos,des,aLength);
 		if(r==KErrNone)
 			{
 			r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
-			test(r==KErrNone);
+			test_KErrNone(r);
 			file.Close();
 			break;
 			}
-		test(r==WriteFailValue);
+		test_Equal(WriteFailValue,r);
 		file.Close();
 		r=TheFs.ScanDrive(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=TheFs.CheckDisk(gSessionPath);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		file.Open(TheFs,aName,EFileShareAny);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		TInt fileSize;
 		r=file.Size(fileSize);
 		// with fair scheduling enabled it's possible for the file 
 		// size to grow even if the write appears to have failed...
-//		test(fileSize==aFileSize||fileSize==newSize);
-		test(fileSize>=aFileSize && fileSize <= newSize);
+//		test_Value(fileSize, fileSize==aFileSize||fileSize==newSize);
+		test_Value(fileSize, fileSize>=aFileSize && fileSize <= newSize);
 
 		file.Close();
 		++failCount;
 		}
 	r=TheFs.CheckDisk(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	RFile file;
 	r=file.Open(TheFs,aName,EFileShareAny);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TInt fileSize;
 	r=file.Size(fileSize);
-	test(r==KErrNone);
-	test(newSize==fileSize);
+	test_KErrNone(r);
+	test_Equal(newSize,fileSize);
 	HBufC8* desPtr2;
 	desPtr2=HBufC8::New(aLength);
-	test(desPtr2!=NULL);
+	test_NotNull(desPtr2);
 	TPtr8 des2=desPtr2->Des();
 	des2.SetLength(aLength);
 	r=file.Read(aPos,des2,des2.Length());
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=des2.Compare(des);
-	test(r==0);
+	test_KErrNone(r);
 	file.Close();
 	r=DeleteEntry(aName,EFalse,aChain);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	delete desPtr;
 	delete desPtr2;
 	++TheFunctionNumber;
@@ -1973,7 +1987,7 @@
 	ClearDiskData();
 
 	r=TheFs.SetSessionPath(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	switch(TheFunctionNumber)
 		{
@@ -1981,15 +1995,15 @@
 		case(1):{
 				TestOperation1();
 				r=TheFs.MkDir(_L("\\fat\\"));
-				test(r==KErrNone);
+				test_KErrNone(r);
 				r=TheFs.MkDir(_L("\\test\\"));
-				test(r==KErrNone);
+				test_KErrNone(r);
 				r=TheFs.MkDir(_L("\\ANother\\"));
-				test(r==KErrNone);
+				test_KErrNone(r);
 				r=TheFs.MkDir(_L("\\test\\subdir1\\"));
-				test(r==KErrNone);
+				test_KErrNone(r);
 				r=TheFs.MkDir(_L("\\test\\subdir2\\"));
-				test(r==KErrNone);}
+				test_KErrNone(r);}
 		case(2):{
 				TestOperation2();
 				// add some filler files
@@ -2037,15 +2051,15 @@
 	DeleteEntry(_L("\\test\\subdir1\\FillerTwo"),EFalse,EChainStd);
 	DeleteEntry(_L("\\test\\subdir1\\FillerOne"),EFalse,EChainStd);
 	r=TheFs.RmDir(_L("\\test\\subdir2\\"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.RmDir(_L("\\test\\subdir1\\"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.RmDir(_L("\\ANother\\"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.RmDir(_L("\\test\\"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.RmDir(_L("\\fat\\"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	if (gFatBuf)
 		{
 		delete gFatBuf;
--- a/kerneltest/f32test/group/bld.inf	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/group/bld.inf	Fri Apr 23 22:20:31 2010 +0100
@@ -31,6 +31,8 @@
 ../../../userlibandfileserver/fileserver/inc/runtests.h                         /epoc32/include/
 
 PRJ_TESTMMPFILES
+../../e32test/mediaext/t_nfe
+
 // These tests must be run early on so they do not time out on LFFS disks.
 
 #ifdef WINS
@@ -259,6 +261,7 @@
 t_plugin_v2beta.mmp
 
 t_localtime 
+
 #ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
 t_file64bit manual
 fhserver64bit       support
--- a/kerneltest/f32test/group/t_nandpaging.mmp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/group/t_nandpaging.mmp	Fri Apr 23 22:20:31 2010 +0100
@@ -17,6 +17,7 @@
 
 TARGET			t_nandpaging.exe
 TARGETTYPE		EXE
+userinclude		../../e32test/mediaext
 SOURCEPATH		../demandpaging
 SOURCE			t_nandpaging.cpp
 LIBRARY			euser.lib efsrv.lib hal.lib
--- a/kerneltest/f32test/group/wintest.bat	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/group/wintest.bat	Fri Apr 23 22:20:31 2010 +0100
@@ -175,6 +175,7 @@
 	echo FlashResumeTime 0 >>%EPOCROOT%epoc32\data\epoc.ini
 	echo FlashWriteTime 0 >>%EPOCROOT%epoc32\data\epoc.ini
 	echo NandDriverType=XSR >>%EPOCROOT%epoc32\data\epoc.ini
+	echo MediaExtensionDriver=?medtestnfe.pdd >>%EPOCROOT%epoc32\data\epoc.ini
 	if exist %BASEPATH%e32\rombuild\platsec.settings (
 		type %BASEPATH%e32\rombuild\platsec.settings >>%EPOCROOT%epoc32\data\epoc.ini
 	) else (
--- a/kerneltest/f32test/server/t_misc.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/kerneltest/f32test/server/t_misc.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -15,10 +15,16 @@
 // 
 //
 
+#define __E32TEST_EXTENSION__
 #include <f32file.h>
 #include <e32test.h>
 #include "t_server.h"
 
+// If there is an NFE media driver present, then because of the way EDeleteNotify requests work,
+// the data retrieved from a deleted file will not be a buffer full of zero's, but instead a buffer
+// full of decrypted zero's
+#define __NFE_MEDIA_DRIVER_PRESENT__
+
 #ifdef __VC32__
     // Solve compilation problem caused by non-English locale
     #pragma setlocale("english")
@@ -26,6 +32,8 @@
 
 GLDEF_D RTest test(_L("T_MISC"));
 
+const TUint KBufLength = 0x100;
+
 LOCAL_C void Test1()
 //
 // Open, write to and read from a file
@@ -34,19 +42,19 @@
 
 	test.Next(_L("Open, write to and read from a file"));
 	TInt r=TheFs.SetSessionPath(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	RFile file;
 	r=file.Create(TheFs,_L("Hello.Wld"),EFileWrite);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=file.Write(_L8("Hello World"),11);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	file.Close();
 
 	r=file.Open(TheFs,_L("Hello.Wld"),EFileRead);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TBuf8<256> buf;
 	r=file.Read(buf);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(buf==_L8("Hello World"));
 	file.Close();
 	}
@@ -59,17 +67,17 @@
 
 	test.Next(_L("Open and read from a file"));
 	TInt r=TheFs.SetSessionPath(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	RFile file;
 	r=file.Open(TheFs,_L("Hello.Wld"),EFileRead);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TBuf8<256> buf;
 	r=file.Read(buf);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(buf==_L8("Hello World"));
 	file.Close();
 	r=TheFs.Delete(_L("HELLO.WLD"));
-	test(r==KErrNone);
+	test_KErrNone(r);
 	}
 
 LOCAL_C void Test3()
@@ -80,25 +88,25 @@
 
 	test.Next(_L("Create nested directories"));
 	TInt r=TheFs.SetSessionPath(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TheFs.ResourceCountMarkStart();
 //
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\A.B"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\RIGHT\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 //
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\ONE\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\TWO\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\THREE\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\TWO\\BOTTOM\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 //
 	r=TheFs.MkDirAll(_L("\\F32-TST\\RIGHT\\TOP\\MID\\BOT\\"));
-	test(r==KErrNone || r==KErrAlreadyExists);
+	test_Value(r, r == KErrNone || r==KErrAlreadyExists);
 	}
 
 LOCAL_C void Test4()
@@ -109,58 +117,58 @@
 
 	test.Next(_L("Test returned error values"));
 	TInt r=TheFs.SetSessionPath(gSessionPath);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TheFs.ResourceCountMarkStart();
 //
 	r=TheFs.MkDir(_L("\\"));
-	test(r==KErrAlreadyExists);
+	test_Value(r, r == KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\LEFT"));
-	test(r==KErrAlreadyExists);
+	test_Value(r, r == KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\"));
-	test(r==KErrAlreadyExists);
+	test_Value(r, r == KErrAlreadyExists);
 	r=TheFs.MkDir(_L("\\F32-TST\\LEFT\\..\\NEWDIR\\"));
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	r=TheFs.MkDir(_L("\\F32-TST\\NEWDIR\\SUBDIR\\"));
-	test(r==KErrPathNotFound);
+	test_Value(r, r == KErrPathNotFound);
 //
 	r=TheFs.RmDir(_L("\\"));
-	test(r==KErrInUse);
+	test_Value(r, r == KErrInUse);
 	r=TheFs.RmDir(_L("\\PROG"));
-	test(r==KErrInUse);
+	test_Value(r, r == KErrInUse);
 	r=TheFs.RmDir(_L("\\F32-TST\\"));
-	test(r==KErrInUse);
+	test_Value(r, r == KErrInUse);
 
 
 	RDir dir;
 	r=dir.Open(TheFs,_L("V:\\asdf"),KEntryAttNormal);
-	test(r==KErrNone || r==KErrNotReady || r==KErrNotFound);
+	test_Value(r, r == KErrNone || r==KErrNotReady || r==KErrNotFound);
 	if (r==KErrNone)
 		dir.Close();
 	r=dir.Open(TheFs,_L("L:\\asdf"),KEntryAttNormal);
-	test(r==KErrNone || r==KErrNotReady || r==KErrNotFound);
+	test_Value(r, r == KErrNone || r==KErrNotReady || r==KErrNotFound);
 	dir.Close();
 //
 	TEntry entry;
 	r=TheFs.Entry(_L("z:\\NOTEXiSTS\\file.txt"),entry);
-	test(r==KErrPathNotFound);
+	test_Value(r, r == KErrPathNotFound);
 	r=TheFs.Entry(_L("z:\\NOTEXiSTS\\"),entry);
-	test(r==KErrNotFound);
+	test_Value(r, r == KErrNotFound);
 	r=TheFs.Entry(_L("z:\\SYSTEM\\"),entry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.Entry(PlatSec::ConfigSetting(PlatSec::EPlatSecEnforceSysBin)?_L("z:\\SYS\\BIN\\ESHELL.EXE"):_L("z:\\SYSTEM\\BIN\\ESHELL.EXE"),entry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	r=dir.Open(TheFs,_L("\\*"),NULL);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	TEntry dirEntry;
 	r=dir.Read(dirEntry);
-	test(r==KErrNone || r==KErrEof);
+	test_Value(r, r == KErrNone || r==KErrEof);
 	if (r==KErrNone)
 		test.Printf(_L("%S\n"),&dirEntry.iName);
 	dir.Close();
 
 	r=dir.Open(TheFs,_L("A:\\*"),NULL);
-	test(r==KErrNotReady || r==KErrNone);
+	test_Value(r, r == KErrNotReady || r==KErrNone);
 	dir.Close();
 	}
 
@@ -181,13 +189,13 @@
 		{
 		RFile f;
 		r=f.Open(TheFs,KTFileCpp,EFileRead);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=f.Seek(ESeekAddress,pos);
 		TText8* ptrPos=*(TText8**)&pos;
-		test(r==KErrNone);
+		test_KErrNone(r);
 		TBuf8<1024> readBuf;
 		r=f.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		TPtrC8 memBuf(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -195,10 +203,10 @@
 		ptrPos+=9913;
 		pos=9913;
 		r=f.Seek(ESeekStart,pos);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		readBuf.SetLength(0);
 		r=f.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		memBuf.Set(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -207,16 +215,16 @@
 		pos=10;
 		r=f2.Open(TheFs,KTFsrvCpp,EFileRead);
 
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=f2.Seek(ESeekAddress,pos);
 		ptrPos=*(TText8**)&pos;
-		test(r==KErrNone);
+		test_KErrNone(r);
 		readBuf.SetLength(0);
 		pos=10;
 		r=f2.Seek(ESeekStart,pos);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=f2.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		memBuf.Set(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -224,10 +232,10 @@
 		ptrPos+=2445;
 		pos=10+2445;
 		r=f2.Seek(ESeekStart,pos);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		readBuf.SetLength(0);
 		r=f2.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		memBuf.Set(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -235,13 +243,13 @@
 		pos=0;
 		r=f.Seek(ESeekAddress,pos);
 		ptrPos=*(TText8**)&pos;
-		test(r==KErrNone);
+		test_KErrNone(r);
 		readBuf.SetLength(0);
 		pos=0;
 		r=f.Seek(ESeekStart,pos);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		r=f.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		memBuf.Set(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -249,10 +257,10 @@
 		ptrPos+=5245;
 		pos=5245;
 		r=f.Seek(ESeekStart,pos);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		readBuf.SetLength(0);
 		r=f.Read(readBuf);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		test(readBuf.Length()==readBuf.MaxLength());
 		memBuf.Set(ptrPos,readBuf.Length());
 		test(memBuf==readBuf);
@@ -271,14 +279,14 @@
 
 	RFile f;
 	TInt r=f.Replace(TheFs,_L("Z:\\Test\\T_Fsrv.Cpp"),EFileRead);
-	test(r==KErrAccessDenied);
+	test_Value(r, r == KErrAccessDenied);
 	r=f.Create(TheFs,_L("Z:\\Test\\newT_Fsrv.Cpp"),EFileRead);
-	test(r==KErrAccessDenied);
+	test_Value(r, r == KErrAccessDenied);
 	r=f.Open(TheFs,_L("Z:\\Test\\T_Fsrv.Cpp"),EFileRead);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	f.Close();
 	r=f.Open(TheFs,_L("Z:\\Test\\T_Fsrv.Cpp"),EFileRead|EFileWrite);
-	test(r==KErrAccessDenied);
+	test_Value(r, r == KErrAccessDenied);
 	}
 
 LOCAL_C void Test7()
@@ -295,7 +303,7 @@
 
 	TEntry entry;
 	TInt r=TheFs.Entry(file1,entry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(entry.iType==uid1);
 
 	TUidType uid2(TUid::Uid(4),TUid::Uid(5),TUid::Uid(6));
@@ -303,19 +311,19 @@
 	TPtrC8 uidData((TUint8*)&checkedUid,sizeof(TCheckedUid));
 	RFile f;
 	r=f.Open(TheFs,file1,EFileRead|EFileWrite);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=f.Write(uidData);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r = f.Flush();
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	r=TheFs.Entry(file1,entry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(entry.iType==uid2);
 
 	f.Close();
 	r=TheFs.Entry(file1,entry);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(entry.iType==uid2);
 	}
 
@@ -538,7 +546,7 @@
 
 	CFileMan* fMan=CFileMan::NewL(TheFs);
 	TInt r=fMan->Copy(_L("Z:\\TEST\\T_FILE.CPP"),_L("C:\\T_FILE.CPP"));
-	test(r==KErrNone || r==KErrAccessDenied);
+	test_Value(r, r == KErrNone || r==KErrAccessDenied);
 	delete fMan;
 	TUint8* addr=TheFs.IsFileInRom(_L("C:\\ESHELL.EXE"));
 	test(addr==NULL);
@@ -567,7 +575,7 @@
 	for(i=0;i<KMaxDrives;i++)
 		{
 		TInt r=TheFs.GetDriveName(i,driveName);
-		test(r==KErrNone);
+		test_KErrNone(r);
 		if (driveName.Length())
 			test.Printf(_L("Default name of %c: == %S\n"),'A'+i,&driveName);
 		}
@@ -577,32 +585,32 @@
 	TBuf<64> drive17=_L("Flibble");
 	TBuf<64> drive25=_L("RAMDRIVE");
 	TInt r=TheFs.SetDriveName(0,drive0);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(4,drive4);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(17,drive17);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(25,drive25);
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	r=TheFs.GetDriveName(0,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive0);
 	r=TheFs.GetDriveName(4,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive4);
 	r=TheFs.GetDriveName(17,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive17);
 	r=TheFs.GetDriveName(25,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive25);
 
 	drive0=_L("askdjflsdfourewoqiuroiuaksjdvx,cvsdhwjhjhalsjhfshfkjhslj");
 	r=TheFs.SetDriveName(0,drive0);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.GetDriveName(0,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive0);
 
 //	Test with illegal characters in drive name
@@ -612,13 +620,13 @@
 	drive25=_L("RAMD//RIVE");
 
 	r=TheFs.SetDriveName(0,drive0);
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	r=TheFs.SetDriveName(4,drive4);
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	r=TheFs.SetDriveName(17,drive17);
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	r=TheFs.SetDriveName(25,drive25);
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 
 //	Test that it is OK to set the name to no characters
 
@@ -628,25 +636,25 @@
 	drive25=_L("");
 
 	r=TheFs.SetDriveName(0,drive0);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(4,drive4);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(17,drive17);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.SetDriveName(25,drive25);
-	test(r==KErrNone);
+	test_KErrNone(r);
 
 	r=TheFs.GetDriveName(0,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive0);
 	r=TheFs.GetDriveName(4,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive4);
 	r=TheFs.GetDriveName(17,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive17);
 	r=TheFs.GetDriveName(25,driveName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	test(driveName==drive25);
 
 
@@ -662,11 +670,11 @@
 	TVolumeInfo vol;
 	TInt r=TheFs.Volume(vol);
 	test.Printf(_L("VolumeName = %S\n"),&vol.iName);
-	test(r==KErrNone);
+	test_KErrNone(r);
 	r=TheFs.RmDir(_L("\\asdfasdf.\\"));
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	r=TheFs.MkDir(_L("\\asdfasdf.\\"));
-	test(r==KErrBadName);
+	test_Value(r, r == KErrBadName);
 	}
 
 LOCAL_C void Test12()
@@ -697,23 +705,23 @@
 	test.Next(_L("Test RFs::Volume"));
 	TVolumeInfo vol;
 	TInt r=TheFs.Volume(vol,EDriveB);
-	test(r==KErrNotReady || r==KErrNone || KErrPathNotFound);
+	test_Value(r, r == KErrNotReady || r==KErrNone || r == KErrPathNotFound);
 	test.Printf(_L("RFs::Volume EDriveB returned %d\n"),r);
 
 	r=TheFs.Volume(vol,EDriveC);
-	test(r==KErrNotReady || r==KErrNone || KErrPathNotFound);
+	test_Value(r, r == KErrNotReady || r==KErrNone || r == KErrPathNotFound);
 	test.Printf(_L("RFs::Volume EDriveC returned %d\n"),r);
 
 	r=TheFs.Volume(vol,EDriveD);
-	test(r==KErrNotReady || r==KErrNone || KErrPathNotFound);
+	test_Value(r, r == KErrNotReady || r==KErrNone || r == KErrPathNotFound);
 	test.Printf(_L("RFs::Volume EDriveD returned %d\n"),r);
 
 	r=TheFs.Volume(vol,EDriveE);
-	test(r==KErrNotReady || r==KErrNone || KErrPathNotFound);
+	test_Value(r, r == KErrNotReady || r==KErrNone || r == KErrPathNotFound);
 	test.Printf(_L("RFs::Volume EDriveE returned %d\n"),r);
 
 	r=TheFs.Volume(vol,EDriveF);
-	test(r==KErrNotReady || r==KErrNone || KErrPathNotFound);
+	test_Value(r, r == KErrNotReady || r==KErrNone || r == KErrPathNotFound);
 	test.Printf(_L("RFs::Volume EDriveF returned %d\n"),r);
 	}
 
@@ -722,7 +730,9 @@
 TInt    CreateStuffedFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize);
 TInt    CreateEmptyFile(RFs& aFs, const TDesC& aFileName, TUint aFileSize);
 TBool   CheckFileContents(RFs& aFs, const TDesC& aFileName);
+#ifndef __NFE_MEDIA_DRIVER_PRESENT__
 TBool   CheckBufferContents(const TDesC8& aBuffer, TUint aPrintBaseAddr=0);
+#endif
 
 /**
 Testing unallocated data initialization vulnerability in RFile
@@ -740,7 +750,7 @@
 
 	//-- 1. get drives list
 	nRes=TheFs.DriveList(driveList);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
 	//-- 2. walk through all drives, performing the test only on suitable ones
 	for (TInt drvNum=0; drvNum<KMaxDrives; ++drvNum)
@@ -826,15 +836,17 @@
 
     //-- 1. create an empty file
     nRes = CreateEmptyFile(TheFs, fileName, KFileSize);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
+#ifndef __NFE_MEDIA_DRIVER_PRESENT__	// can't easily check for illegitimate information if drive is encrypted
     //-- 1.1  check that this file doesn't contain illegitimate information.
     nRes = CheckFileContents(TheFs, fileName);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
+#endif
 
     //-- 1.2 delete the empty file
     nRes = TheFs.Delete(fileName);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     //==============================
     //== Scenario 2.
@@ -847,18 +859,18 @@
 
     //-- 2. create file filled with some data pattern
     nRes = CreateStuffedFile(TheFs, fileName, KFileSize);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     //-- 2.1 delete this file
     TheFs.Delete(fileName);
 
     //-- 2.1 create an empty file on the place of just deleted one (hopefully)
     nRes = CreateEmptyFile(TheFs, fileName, KFileSize);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     //-- 2.2  check that this file doesn't contain illegitimate information.
     nRes = CheckFileContents(TheFs, fileName);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     //-- 2.3 delete this file
     TheFs.Delete(fileName);
@@ -1162,11 +1174,11 @@
 	test.Next(_L("Test RFs::GetMediaSerialNumber"));	
     TInt theDrive;
     TInt r = TheFs.CharToDrive(gDriveToTest,theDrive);
-    test(r == KErrNone);
+    test_KErrNone(r);
     TMediaSerialNumber serNum;
     r = TheFs.GetMediaSerialNumber(serNum, theDrive);
 	if (r) test.Printf(_L("RFs::GetMediaSerialNumber returned error %d"), r);
-    test(r == KErrNotSupported || r == KErrNotReady || r == KErrNone);
+    test_Value(r, r == KErrNotSupported || r == KErrNotReady || r == KErrNone);
     if (r == KErrNotSupported)
         {
         test.Printf(_L("MediaSerialNumber: Not Supported\n"));
@@ -1238,7 +1250,6 @@
     RFile   file;
 
 	//-- create a buffer with some data
-	const TUint KBufLength = 0x100;
 	TBuf8<KBufLength> buffer;
 	buffer.SetLength(KBufLength);
 
@@ -1289,13 +1300,12 @@
 	TInt    nRes = KErrNone;
     RFile   file;
 
-	const TInt KBufLength = 0x100;
 	TBuf8<KBufLength> buffer;
     buffer.SetLength(0);
 
     //-- open the file
     nRes = file.Open(aFs, aFileName, EFileRead);
-    test(nRes == KErrNone);
+    test_KErrNone(nRes);
 
     //-- check file contents
     TUint nFilePos=0;
@@ -1303,7 +1313,7 @@
     {
         //-- read data from the file into the buffer
         nRes = file.Read(buffer);
-        test(nRes == KErrNone);
+        test_KErrNone(nRes);
 
         if(buffer.Length() == 0)
         {
@@ -1311,6 +1321,18 @@
             break; //EOF
         }
 
+#ifdef __NFE_MEDIA_DRIVER_PRESENT__
+		// check the buffer doesn't contain the same pattern written to it by CreateStuffedFile()
+		TUint i;
+		for(i = 0; i < KBufLength; i++)
+			if (buffer[i] != static_cast<TUint8> (i))
+				break;
+		if (i == KBufLength)
+			{
+            nRes = KErrCorrupt; //-- indicate that the read buffer contains illegitimate information
+            break; //-- comment this out if you need a full dump of the file
+			}
+#else
         //-- check if the buffer contains only allowed data (RAM page initialisation data, etc. e.g. 0x00, 0xff, 0x03, 0xcc)
         if(!CheckBufferContents(buffer, nFilePos))
         {
@@ -1318,6 +1340,7 @@
             nRes = KErrCorrupt; //-- indicate that the read buffer contains illegitimate information
             break; //-- comment this out if you need a full dump of the file
         }
+#endif
 
         nFilePos+=buffer.Length();
     }
--- a/userlibandfileserver/fileserver/group/release.txt	Fri Apr 23 22:14:19 2010 +0100
+++ b/userlibandfileserver/fileserver/group/release.txt	Fri Apr 23 22:20:31 2010 +0100
@@ -1,3 +1,12 @@
+Version 2.00.3031
+=================
+(Made by vfebvre 15/04/2010)
+
+1.	migubarr
+	1.	REQ 415-7212 NFE drive encryption on Demand Paging-enabled device, kernelhwsrv/MCL
+		PackageReleaseID=453228 FeatureReleaseID=447937
+
+
 Version 2.00.3030
 =================
 (Made by vfebvre 14/04/2010)
--- a/userlibandfileserver/fileserver/inc/f32ver.h	Fri Apr 23 22:14:19 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32ver.h	Fri Apr 23 22:20:31 2010 +0100
@@ -58,6 +58,6 @@
 
 @see TVersion
 */
-const TInt KF32BuildVersionNumber=3030;
+const TInt KF32BuildVersionNumber=3031;
 //
 #endif
--- a/userlibandfileserver/fileserver/sfile/sf_drv.cpp	Fri Apr 23 22:14:19 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_drv.cpp	Fri Apr 23 22:20:31 2010 +0100
@@ -233,7 +233,7 @@
 
 	if (iReason==KErrNone && CurrentMount().LockStatus() > 0)
 	    {
-    	//-- this meand that the mount has drive access objetcs opened (RFormat or RRawDisk)
+    	//-- this means that the mount has drive access objects opened (RFormat or RRawDisk)
         __PRINT1(_L("TDrive::CheckMount() Mount is locked! LockStaus:%d"), CurrentMount().LockStatus());
         return KErrInUse;
 	    }	
@@ -547,6 +547,19 @@
 	TRAP(r,CurrentMount().FinaliseMountL(aOperation, aParam1, aParam2));
 	TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFinaliseMount2Ret, EF32TraceUidFileSys, r);
 	
+	// Pass FinaliseDrive notification down to media driver
+	TInt driveNumber = DriveNumber();
+	if (LocalDrives::IsValidDriveMapping(driveNumber) && !LocalDrives::IsProxyDrive(driveNumber))
+		{
+		TBusLocalDrive& drv = LocalDrives::GetLocalDrive(driveNumber);
+
+		TLocalDriveFinaliseInfoBuf finaliseBuf;
+		finaliseBuf().iMode = aOperation;
+
+		// notify local drive, ignore the error
+		drv.QueryDevice(RLocalDrive::EQueryFinaliseDrive, finaliseBuf);	
+		}
+
     return r;
 	}
 
@@ -815,7 +828,7 @@
 // Check that the sharing rules are obeyed.
 //
 	{
-
+	// Check the correct share modes are passed in
 	switch (aReqShare)
 		{
 	case EFileShareExclusive:
@@ -824,47 +837,46 @@
 	case EFileShareReadersOrWriters:
 		break;
 	default:
-		return(KErrArgument);
+		return KErrArgument;
 		}
+	
+	// Check the share mode of the file
 	switch (aFile.iShare)
 		{
 	case EFileShareExclusive:
-		return(KErrInUse);
+		return KErrInUse;
 
 	case EFileShareReadersOnly:
 	case EFileShareAny:
 		if (aReqShare != aFile.iShare && aReqShare != EFileShareReadersOrWriters)
-			return(KErrInUse);
+		    {
+            return KErrInUse;
+		    }
 		break;
 
 	case EFileShareReadersOrWriters:
-		if (aReqShare==EFileShareExclusive)
-			return(KErrInUse);
+		if (aReqShare == EFileShareExclusive)
+		    {
+            return KErrInUse;
+		    }
 		//
-		// If the file is currently open as EFileShareReadersOrWriters then
+		// If the file is currently opened as EFileShareReadersOrWriters then
 		// promote the share to the requested share mode.
+		// 
+		// If the requested share is EFileShareReadersOnly, verify that no
+		// other share has the file opened for writing.
 		//
-		// If the requested share is EFileShareReadersOnly, verfiy that no
-		// other share has the file open for writing.
-		//
-
 		if (aReqShare == EFileShareReadersOnly)
 			{
-			FileShares->Lock();
-			TInt count = FileShares->Count();
-			while(count--)
+			TDblQueIter<CFileShare> fileShareIter(aFile.FileShareList());
+			CFileShare* pFileShare;
+			while ((pFileShare = fileShareIter++) != NULL)
 				{
-				CFileShare* share = (CFileShare*)(*FileShares)[count];
-				if (&share->File() == &aFile)
+				if(pFileShare->iMode & EFileWrite)
 					{
-					if(share->iMode & EFileWrite)
-						{
-						FileShares->Unlock();
-						return KErrInUse;
-						}
+					return KErrInUse;
 					}
 				}
-			FileShares->Unlock();
 			}
 		break;
     
@@ -872,7 +884,8 @@
 		Fault(EDrvIllegalShareValue);
         break;
 		}
-	return(KErrNone);
+
+	return KErrNone;
 	}
 
 void TDrive::DriveInfo(TDriveInfo& anInfo)
@@ -1332,88 +1345,90 @@
 	if ((aMode & EDeleteOnClose) && (anOpen!=EFileCreate))
 		User::Leave(KErrArgument);
 
-	CFileCB* pF=LocateFile(aName);
+	CFileCB* pFile=LocateFile(aName);
 	CFileCache* pFileCache = NULL;
-	TBool openFile=EFalse;
-	if (pF!=NULL)
+	TBool openFile=EFalse;	// True if file is being opened for the first time
+	if (pFile!=NULL)		// File is already opened on the drive
 		{
-		if (pF->iShare==EFileShareReadersOnly && (aMode&EFileWrite)!=0)
+		if (pFile->iShare==EFileShareReadersOnly && (aMode&EFileWrite))
 			User::Leave(KErrInUse);
 		if (anOpen==EFileCreate)
 			User::Leave(KErrAlreadyExists);
-		TInt r=ValidateShare(*pF,share);
+		TInt r=ValidateShare(*pFile,share);
 		if (r!=KErrNone)
 			User::Leave(r);
-		if ((r=pF->Open())!=KErrNone)
+		if ((r=pFile->Open())!=KErrNone)
 			User::Leave(r);
-		aFileCB=pF;
-		pFileCache = pF->FileCache();
+		
+		aFileCB=pFile;
+		pFileCache = pFile->FileCache();
 		}
 	else
 		{
 		TRACE2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFileL, EF32TraceUidFileSys, &FSys(), DriveNumber());
 
         //-- construct CFileCB object, belonging to the corresponding mount
-        pF = aFileCB = CurrentMount().NewFileL();
-
-		TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFileLRet, EF32TraceUidFileSys, r, pF);
+        pFile = aFileCB = CurrentMount().NewFileL();
+
+		TRACERET2(UTF::EBorder, UTraceModuleFileSys::ECFileSystemNewFileLRet, EF32TraceUidFileSys, r, pFile);
 		TDrive* createdDrive=!aRequest->SubstedDrive() ? this : aRequest->SubstedDrive();
 
     	HBufC* fileName = CreateFileNameL(aName);
 
-        pF->InitL(this, createdDrive, fileName);
-
-
-		pF->iShare = share;
+        pFile->InitL(this, createdDrive, fileName);
+
+		pFile->iShare = share;
+		pFile->SetSequentialMode(aMode & EFileSequential);
 		openFile=ETrue;
-		CurrentMount().iMountQ.AddLast(*pF);
-		Files->AddL(pF,ETrue);
+		CurrentMount().iMountQ.AddLast(*pFile);
+		Files->AddL(pFile,ETrue);
+		__PRINT1(_L("TDrive::FileOpenL - CFileCB->IsSequentialMode = %d"), pFile->IsSequentialMode());
 		}
 	
-    CFileShare* pS=aFileShare=new(ELeave) CFileShare(pF);
+    CFileShare* pFileShare=aFileShare=new(ELeave) CFileShare(pFile);
 
 	// We need to call CFileCB::PromoteShare immediately after the CFileShare 
 	// instance is created since the destructor calls CFileCB::DemoteShare()
 	// which checks the share count is non-zero
-	pS->iMode=aMode;
-	pF->PromoteShare(pS);
-
-	pS->InitL();
+	pFileShare->iMode=aMode;
+	pFile->PromoteShare(pFileShare);
+
+	pFileShare->InitL();
 	aFileCB=NULL; 
-	FileShares->AddL(pS,ETrue);
-	aHandle=aRequest->Session()->Handles().AddL(pS,ETrue);
+	FileShares->AddL(pFileShare,ETrue);
+	aHandle=aRequest->Session()->Handles().AddL(pFileShare,ETrue);
 
 
 	if (openFile)
 		{
-		TRACEMULT5(UTF::EBorder, UTraceModuleFileSys::ECMountCBFileOpenL, EF32TraceUidFileSys, DriveNumber(), aName, aMode, (TUint) anOpen, (TUint) pF);
-		CurrentMount().FileOpenL(aName,aMode,anOpen,pF);
+		TRACEMULT5(UTF::EBorder, UTraceModuleFileSys::ECMountCBFileOpenL, EF32TraceUidFileSys, DriveNumber(), aName, aMode, (TUint) anOpen, (TUint) pFile);
+		CurrentMount().FileOpenL(aName,aMode,anOpen,pFile);
 		TRACE1(UTF::EBorder, UTraceModuleFileSys::ECMountCBFileOpenLRet, EF32TraceUidFileSys, KErrNone);
 
 		// Delete on close may now be safely flagged if required.
 		// The file did not exist on the media prior to the
 		// CMountCB::FileOpenL() call for the case of a create.
 		if ((aMode & EDeleteOnClose) && (anOpen==EFileCreate))
-			pF->SetDeleteOnClose();
-
-		TBool localBufferSuppport = (CurrentMount().LocalBufferSupport(pF) == KErrNone)?(TBool)ETrue:(TBool)EFalse;
-		pF->SetLocalBufferSupport(localBufferSuppport);
+			pFile->SetDeleteOnClose();
+
+		TBool localBufferSuppport = (CurrentMount().LocalBufferSupport(pFile) == KErrNone)?(TBool)ETrue:(TBool)EFalse;
+		pFile->SetLocalBufferSupport(localBufferSuppport);
 		if (localBufferSuppport)
 			{
-			// if file exists on closed queue resurrect it or discard it,
+			// If file exists on closed queue resurrect it or discard it,
 			// depending on the file open mode
 			pFileCache = LocateClosedFile(aName, anOpen == EFileOpen?(TBool)ETrue:(TBool)EFalse);
 			if (pFileCache)
 				{
-				pFileCache = pFileCache->ReNewL(*pS);	// NB may return NULL if caching not enabled
+				pFileCache = pFileCache->ReNewL(*pFileShare);	// NB may return NULL if caching not enabled
 				}
 			else
 				{
-				pFileCache = CFileCache::NewL(*pS);		// NB may return NULL if caching not enabled
+				pFileCache = CFileCache::NewL(*pFileShare);		// NB may return NULL if caching not enabled
 				}
 			if (pFileCache)
-				// set the cached size to be the same as the uncached size
-				pF->SetCachedSize64(pF->Size64());
+				// Set the cached size to be the same as the uncached size
+				pFile->SetCachedSize64(pFile->Size64());
 			}
 		else
 			{
@@ -1421,9 +1436,9 @@
 			}
 		}
 
-	// initialize share mode flags
+	// Initialize share mode flags
 	if (pFileCache != NULL)
-		pFileCache->Init(*pS);
+		pFileCache->Init(*pFileShare);
 	}
 
 TInt TDrive::FileOpen(CFsRequest* aRequest,TInt& aHandle,const TDesC& aName,TUint aMode,TFileOpen anOpen)
@@ -1435,7 +1450,7 @@
 	CFileCB* pF=NULL;
 	CFileShare* pS=NULL;
 	aHandle=0;
-	TRAPD(r,FileOpenL(aRequest,aHandle,aName,aMode,anOpen,pF,pS))
+	TRAPD(r,FileOpenL(aRequest,aHandle,aName,aMode,anOpen,pF,pS));
 
 	// Allow files > 2GB-1 to be opened only if EFileBigFile is specified in iMode
 	if (r == KErrNone && pS && ((TUint64)pS->File().Size64() > KMaxLegacyFileSize) && (!(pS->IsFileModeBig())))