Revision: 201033 RCL_3
authorDremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 19 Aug 2010 11:14:22 +0300
branchRCL_3
changeset 42 a179b74831c9
parent 41 0ffb4e86fcc9
child 43 c1f20ce4abcf
Revision: 201033 Kit: 201033
kernel/eka/bmarm/elocdu.def
kernel/eka/bwins/elocdu.def
kernel/eka/bx86/elocdu.def
kernel/eka/drivers/locmedia/locmedia.cpp
kernel/eka/drivers/medata/pccd_ata.cpp
kernel/eka/drivers/media/base_e32_drivers_media.mrp
kernel/eka/drivers/media/bld.inf
kernel/eka/drivers/medint/iram.cpp
kernel/eka/drivers/medlfs/flash_media.cpp
kernel/eka/drivers/medmmc/medmmc.cpp
kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp
kernel/eka/drivers/sdapc/d_sdapc.cpp
kernel/eka/drivers/sdapc/d_sdapc.h
kernel/eka/drivers/sdapc/d_sdapc.mmp
kernel/eka/drivers/sdapc/traces/OstTraceDefinitions.h
kernel/eka/eabi/elocdu.def
kernel/eka/include/d32locd.h
kernel/eka/include/drivers/locmedia.h
kernel/eka/include/drivers/sdcard.h
kernel/eka/include/drivers/sdcard.inl
kernel/eka/include/e32ver.h
kernel/eka/include/kernel/kernel.h
kernel/eka/kernel/sprocess.cpp
kernel/eka/kernel/sutils.cpp
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/demandpaging/t_svrpinning.cpp
kerneltest/e32test/group/bld.inf
kerneltest/e32test/group/sdapctest.mmp
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/mmu/t_alias_remove.cpp
kerneltest/e32test/mmu/t_shadow.cpp
kerneltest/e32test/pccd/sdapctest.cpp
kerneltest/e32test/power/t_domain.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_dspace.cpp
kerneltest/f32test/server/t_file.cpp
kerneltest/f32test/server/t_fman.cpp
kerneltest/f32test/server/t_misc.cpp
kerneltest/f32test/server/t_rcache.cpp
kerneltest/f32test/server/t_sysbin.cpp
userlibandfileserver/domainmgr/src/domaincli.cpp
userlibandfileserver/fileserver/bmarm/efileu.def
userlibandfileserver/fileserver/bwins/efileu.def
userlibandfileserver/fileserver/bx86/efileu.def
userlibandfileserver/fileserver/eabi/efileu.def
userlibandfileserver/fileserver/etshell/ts_com.cpp
userlibandfileserver/fileserver/etshell/ts_edshl.cpp
userlibandfileserver/fileserver/etshell/ts_std.h
userlibandfileserver/fileserver/group/release.txt
userlibandfileserver/fileserver/inc/f32fsys.h
userlibandfileserver/fileserver/inc/f32ver.h
userlibandfileserver/fileserver/sfat/sl_cache.cpp
userlibandfileserver/fileserver/sfat/sl_fatcache.cpp
userlibandfileserver/fileserver/sfat/sl_leafdir_cache.cpp
userlibandfileserver/fileserver/sfat32/fat_table32.cpp
userlibandfileserver/fileserver/sfat32/inc/fat_table32.h
userlibandfileserver/fileserver/sfat32/inc/sl_std.h
userlibandfileserver/fileserver/sfat32/inc/sl_std.inl
userlibandfileserver/fileserver/sfat32/ram_fat_table32.cpp
userlibandfileserver/fileserver/sfat32/sl_cache.cpp
userlibandfileserver/fileserver/sfat32/sl_disk.cpp
userlibandfileserver/fileserver/sfat32/sl_disk.h
userlibandfileserver/fileserver/sfat32/sl_drv.cpp
userlibandfileserver/fileserver/sfat32/sl_fatcache.cpp
userlibandfileserver/fileserver/sfat32/sl_file.cpp
userlibandfileserver/fileserver/sfat32/sl_leafdir_cache.cpp
userlibandfileserver/fileserver/sfat32/sl_mnt.cpp
userlibandfileserver/fileserver/sfat32/sl_mnt32.cpp
userlibandfileserver/fileserver/sfile/sf_debug.cpp
userlibandfileserver/fileserver/sfile/sf_drv.cpp
userlibandfileserver/fileserver/sfile/sf_file.cpp
userlibandfileserver/fileserver/sfile/sf_memory_client.cpp
userlibandfileserver/fileserver/sfile/sf_plugin.h
userlibandfileserver/fileserver/sfile/sf_pool.cpp
userlibandfileserver/fileserver/sfile/sf_request.cpp
userlibandfileserver/fileserver/sfile/sf_std.h
userlibandfileserver/fileserver/sfile/sf_std.inl
userlibandfileserver/fileserver/swins/elocal.cpp
--- a/kernel/eka/bmarm/elocdu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/bmarm/elocdu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/bwins/elocdu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/bx86/elocdu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -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/locmedia.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/locmedia/locmedia.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -29,7 +29,6 @@
 #include "locmediaTraces.h"
 #endif
 
-
 #if defined(_DEBUG) && defined(__DEMAND_PAGING__)
 //#define __DEBUG_DEMAND_PAGING__
 #endif
@@ -71,6 +70,9 @@
 class DPrimaryMediaBase::DBody : public DBase
 	{
 public:
+	DBody(DPrimaryMediaBase& aPrimaryMediaBase);
+public:
+	DPrimaryMediaBase& iPrimaryMediaBase;	// ptr to parent
 	TInt iPhysDevIndex;
 	TInt iRequestCount;
 #ifdef __DEMAND_PAGING__
@@ -79,12 +81,24 @@
 	TInt iPageSizeLog2;        // LOG2 of page size (i.e. 4096 -> 12)
 	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;
@@ -93,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
@@ -105,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
 	{
@@ -158,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)
@@ -193,7 +227,7 @@
 	    }
 
 
-	SVirtualPinContainer* iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
+	iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
 	if (iVirtualPinContainers == NULL)
 	    {
 		OstTraceFunctionExitExt( DPINOBJECTALLOCATOR_CONSTRUCT_EXIT3, this, KErrNoMemory );
@@ -260,6 +294,99 @@
 
 #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;
 	}
@@ -493,42 +621,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();
@@ -597,7 +689,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;	
@@ -640,7 +736,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;
 
@@ -878,11 +978,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);
@@ -1037,7 +1141,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;
@@ -1069,50 +1173,52 @@
 	}
 #endif	// __DEMAND_PAGING__
 
-void DLocalDrive::NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange)
-	{
-    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)
+void DLocalDrive::NotifyChange()
+	{
+    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()
 	{
 	}
@@ -1131,6 +1237,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
  ********************************************/
@@ -1159,6 +1292,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();
@@ -1298,6 +1439,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)
@@ -1307,12 +1456,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;
 	}
 
@@ -1445,7 +1594,7 @@
 			break;
 		case DLocalDrive::EReduce:
 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Reduce request %lx@%lx",Length(),Pos()));
-			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION3, "Reduce request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()), (TUint) I64LOW(Length()), (TUint) I64HIGH(Pos()), (TUint) I64LOW(Pos()) );
+			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION3, "Reduce request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()), (TUint) I64LOW(Length()), (TUint) I64HIGH (Pos()), (TUint) I64LOW (Pos()) );
 			if (Pos()+Length()>d.iPartitionLen)
 				r = KErrArgument;
 			else
@@ -1453,7 +1602,7 @@
 			break;
 		case DLocalDrive::EFormat:
 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Format request %lx@%lx",Length(),Pos()));
-			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION4, "Format request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()),(TUint) I64LOW(Length()), (TUint) I64HIGH(Pos()), (TUint) I64LOW(Pos()) );
+			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION4, "Format request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()),(TUint) I64LOW(Length()), (TUint) I64HIGH (Pos()), (TUint) I64LOW (Pos()) );
 			if (!(DriverFlags() & RLocalDrive::ELocDrvWholeMedia))
 				{
 				if (Pos()>d.iPartitionLen)
@@ -1481,7 +1630,7 @@
 //		    Otherwise the media driver adjust it internally
 		case DMediaPagingDevice::ECodePageInRequest:
 			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Adjusted Paging read request %lx@%lx",Length(),Pos()));
-			OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, TLOCDRVREQUESTCHECKANDADJUSTFORPARTITION5, "Adjusted Paging read request length=%x:%x; position=%x%:%x", (TUint) I64HIGH(Length()), (TUint) I64LOW(Length()),  (TUint) I64HIGH(Pos()), (TUint) I64LOW(Pos()));
+			OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, TLOCDRVREQUESTCHECKANDADJUSTFORPARTITION5, "Adjusted Paging read request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()), (TUint) I64LOW(Length()),  (TUint) I64HIGH(Pos()), (TUint) I64LOW(Pos()));
 			if (Pos()+Length()>d.iPartitionLen)
 			    {
 				r = KErrArgument;
@@ -1494,10 +1643,10 @@
 		
 		default:	// read or write or fragment
 			__KTRACE_OPT(KLOCDRV,Kern::Printf("R/W request %lx@%lx",Length(),Pos()));
-			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION6, "Read/Write request length=%x:%x; position=%x:%x", (TUint) I64HIGH(Length()), (TUint) I64LOW(Length()), (TUint) I64HIGH(Pos()), (TUint) I64LOW(Pos()));
+			OstTraceExt4( TRACE_INTERNALS, TLOCDRVREQUEST_CHECKANDADJUSTFORPARTITION6, "Read/Write request length=%x:%x; position=%x:%x", (TUint)I64HIGH (Length()), (TUint)I64LOW (Length()), (TUint) I64HIGH (Pos()), (TUint) I64LOW (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;
@@ -1527,9 +1676,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.
  
@@ -1596,6 +1758,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
@@ -1635,15 +1817,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);
@@ -1706,7 +1891,7 @@
 	
 	NKern::LockSystem();
 	TBool first=iConnectionQ.IsEmpty();
-	iConnectionQ.Add(&aLocalDrive->iLink);
+	iConnectionQ.Add(&aLocalDrive->iMediaChangeObserver.iLink);
 	NKern::UnlockSystem();
 	if (first)
 		{
@@ -1774,6 +1959,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 .
@@ -1794,7 +2025,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()));
@@ -1804,18 +2035,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
@@ -2261,7 +2487,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;
@@ -2285,6 +2511,30 @@
 			{
 			TUint flags = (TUint) m.Pos();
 
+#ifdef __DEMAND_PAGING__
+			// if this is a paging media (ROM,code or data), turn off the KMediaRemountForceMediaChange flag 
+			// as this normally results in a call to DPBusSocket::ForceMediaChange() which effectively disables 
+			// the media for a small time period - which would be disasterous if a paging request arrived
+			if (iBody->iPagingDevice)
+				flags&= ~KMediaRemountForceMediaChange;
+#endif
+
+			// 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));
@@ -2515,18 +2765,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;
@@ -2553,7 +2803,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();
 			}
@@ -2639,9 +2889,10 @@
 			}
 		else
 #endif
-
-		CompleteRequest(m, s);
-		OstTraceDefExt3( OST_TRACE_CATEGORY_RND, TRACE_INTERNALS, DPRIMARYMEDIABASE_DOREQUEST_RETURN, "Return req Id=%d; Remote Thread=0x%x; retval=%d", (TInt) m.Id(), (TUint) m.RemoteThread(), (TInt) s);
+			{
+			CompleteRequest(m, s);
+			OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_INTERNALS, DPRIMARYMEDIABASE_DOREQUEST_RETURN, "Return Remote Thread=0x%x; retval=%d", (TUint) m.RemoteThread(), (TInt) s);
+			}
 		}
 
 	iCurrentReq=NULL;
@@ -2697,7 +2948,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);
@@ -2705,21 +2956,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)
@@ -2876,7 +3136,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);
@@ -2942,10 +3202,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)
@@ -2959,9 +3219,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));
@@ -3227,10 +3486,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 );
@@ -3238,11 +3497,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 );
@@ -3260,32 +3531,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);
@@ -3354,8 +3606,6 @@
 		CloseMediaDrivers();
 		SetClosed(KErrNotReady);
 		}
-
-	NotifyClients(EFalse);
 	OstTraceFunctionExit1( DPRIMARYMEDIABASE_NOTIFYPOWERDOWN_EXIT, this );
 	}
 
@@ -3425,17 +3675,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 );
 	}
 
@@ -3586,10 +3875,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)
@@ -3626,15 +3915,19 @@
 void DPrimaryMediaBase::RequestCountInc()
 	{
 	__ASSERT_DEBUG(iBody, LOCM_FAULT());
-	TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) 1);
-//Kern::Printf("RCINC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
-	
-	OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTINC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
-	
-	if (oldVal == 0 && iBody->iPagingDevice)
+	if (iBody->iPagingDevice)
 		{
-//Kern::Printf("RCINC: NotifyBusy()");
-		iBody->iPagingDevice->NotifyBusy();
+		NFastMutex* lock = iBody->iPagingDevice->NotificationLock();
+		NKern::FMWait(lock);
+		TInt oldVal = iBody->iRequestCount++;
+		//Kern::Printf("RCINC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
+		OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTINC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
+		if (oldVal == 0)
+			{
+			//Kern::Printf("RCINC: NotifyBusy()");
+			iBody->iPagingDevice->NotifyBusy();
+			}
+		NKern::FMSignal(lock);
 		}
 	}
 
@@ -3646,17 +3939,21 @@
 void DPrimaryMediaBase::RequestCountDec()
 	{
 	__ASSERT_DEBUG(iBody, LOCM_FAULT());
-	TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) -1);
-//Kern::Printf("RCDEC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
-	
-	OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTDEC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
-	
-	if (oldVal == 1 && iBody->iPagingDevice)
+	if (iBody->iPagingDevice)
 		{
-//Kern::Printf("RCDEC: NotifyIdle()");
-		iBody->iPagingDevice->NotifyIdle();
+		NFastMutex* lock = iBody->iPagingDevice->NotificationLock();
+		NKern::FMWait(lock);
+		TInt oldVal = iBody->iRequestCount--;
+		//Kern::Printf("RCDEC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
+		OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_DEMANDPAGING, DPRIMARYMEDIABASE_REQUESTCOUNTDEC, "new count=%d; old count=%d", iBody->iRequestCount, oldVal );
+		if (oldVal == 1)
+			{
+			//Kern::Printf("RCDEC: NotifyIdle()");
+			iBody->iPagingDevice->NotifyIdle();
+			}		
+		NKern::FMSignal(lock);
+		__ASSERT_DEBUG(iBody->iRequestCount >= 0, LOCM_FAULT());
 		}
-	__ASSERT_DEBUG(iBody->iRequestCount >= 0, LOCM_FAULT());
 	}
 #endif	// __DEMAND_PAGING__
 
@@ -3957,7 +4254,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
 			{
@@ -3996,7 +4293,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);
@@ -4134,7 +4431,8 @@
 	TInt retVal = KErrGeneral;
 	for (TInt i=0; retVal != KErrNone && i < KPageOutRetries; i++)
 		{
-		m.Flags() = TLocDrvRequest::EPaging | 
+		m.Flags() = TLocDrvRequest::EKernelBuffer |
+					TLocDrvRequest::EPaging | 
                     TLocDrvRequest::EDataPaging | 
                     (aBackground ? TLocDrvRequest::EBackgroundPaging : 0) |
                     (aPhysAddr ? TLocDrvRequest::EPhysAddrOnly : 0);
@@ -4235,7 +4533,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];
 
@@ -4268,7 +4566,6 @@
 	}
 
 
-
 EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset)
 	{
 	OstTraceFunctionEntry1( TLOCDRVREQUEST_WRITETOPAGEHANDLER_ENTRY, this );
@@ -4456,6 +4753,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);
+		}
+	}
 
 
 
@@ -4685,39 +5004,27 @@
 	{
 	OstTraceFunctionEntry0( LOCDRV_REGISTERMEDIADEVICE_ENTRY );
 	// 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));
+	__KTRACE_OPT(KBOOT,Kern::Printf("RegisterMediaDevice %S 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)
@@ -4738,29 +5045,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;
 	}
@@ -4845,11 +5211,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)))
 		{
@@ -4858,19 +5225,24 @@
 		return KErrArgument;
 		}
 
-	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));
+				}
 			}
 		}
 
@@ -4953,12 +5325,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");
@@ -4993,7 +5369,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;
@@ -5001,6 +5377,8 @@
 
 		TLocalDriveCapsV6& caps = *(TLocalDriveCapsV6*)capsBuf.Ptr();
 		blockSize = caps.iBlockSize;
+		__ASSERT_DEBUG(blockSize,LOCM_FAULT());
+		__ASSERT_DEBUG(__e32_bit_count_32(blockSize)==1,LOCM_FAULT());
 		
 		TLocDrv* drive;
 		for (i=0; i<KMaxLocalDrives; ++i)
@@ -5008,20 +5386,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 %S", 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;
 					
 			        // Mark Paging Device capable of utilising physical addresss only accesses
@@ -5051,7 +5434,9 @@
 		}
 
 	pagingDevice->iType = aPagingType;
-	pagingDevice->iFlags = flags;
+	if (aPrimaryMedia->iBody->iMediaExtension)
+		pagingDevice->iType|= DPagingDevice::EMediaExtension;
+
 	pagingDevice->iReadUnitShift = aReadShift;
 
 	pagingDevice->iFirstLocalDriveNumber = firstLocalDriveNumber;
@@ -5064,13 +5449,14 @@
 
 #ifdef __DEBUG_DEMAND_PAGING__
 	Kern::Printf("PagingDevice :");
-	Kern::Printf("iType 0x%x\n", pagingDevice->iType);
+	Kern::Printf("Name %S", firstLocalDriveNumber >= 0 && DriveNames[firstLocalDriveNumber] ? DriveNames[firstLocalDriveNumber] : &KNullDesC8);
+	Kern::Printf("iType 0x%x", pagingDevice->iType);
 	Kern::Printf("iFlags 0x%x\n", pagingDevice->iFlags);
-	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("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);
 	Kern::Printf("iPreferredWriteShift 0x%x\n", pagingDevice->iPreferredWriteShift);
 #endif
 
@@ -5092,24 +5478,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;
+			}
 		}
 
 
@@ -5139,7 +5539,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;
+				}
 			}
 		}
 
@@ -5183,6 +5590,7 @@
 
 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("< RegisterPagingDevice"));
 	OstTraceFunctionExit0( LOCDRV_REGISTERPAGINGDEVICE_EXIT14 );
+//	CLRDEBUGFLAG(KLOCDPAGING);
 	return KErrNone;
 	}
 
@@ -5258,6 +5666,7 @@
 		TLocDrv* pL=TheDrives[i];
 		if (pL)
 			{
+			pL = TDriveIterator::GetPhysicalDrive(TheDrives[i]);
 			++drives;
 			TInt sockNum;
 			DPrimaryMediaBase* pM=pL->iPrimaryMedia;
@@ -5266,7 +5675,7 @@
 				if (!(sock_mask & (1<<sockNum)))
 					{
 					info.iSocketName[sockNum]=*DriveNames[i];
-					__KTRACE_OPT(KLOCDRV,Kern::Printf("Socket %d device %d name %lS", sockNum, pM->iDevice, DriveNames[i]));
+					__KTRACE_OPT(KLOCDRV,Kern::Printf("Socket %d device %d name %S", sockNum, pM->iDevice, DriveNames[i]));
 					OstTraceExt2( TRACE_INTERNALS, GETDRIVEINFO1, "Socket=%d; device=%d", sockNum, (TUint) pM->iDevice );
 					if ( (sockNum + 1) > sockets )
 						sockets = sockNum + 1;
@@ -5274,7 +5683,7 @@
 				sock_mask |= (1<<sockNum);
 				}
 			info.iDriveName[i]=*DriveNames[i];
-			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d device %d name %lS",i,pM->iDevice,DriveNames[i]));
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d device %d name %S",i,pM->iDevice,DriveNames[i]));
 			OstTraceExt2( TRACE_INTERNALS, GETDRIVEINFO2, "Drive=%d; device=%d", i, (TUint) pM->iDevice );
 			
 			info.iRegisteredDriveBitmask |= (0x01 << i);
@@ -5397,11 +5806,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);
@@ -5413,11 +5818,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);
@@ -5429,11 +5830,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);
@@ -5445,17 +5842,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;
 			}
@@ -5463,11 +5863,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);
@@ -5479,11 +5875,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);
@@ -5495,11 +5887,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);
@@ -5511,11 +5899,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);
@@ -5527,27 +5911,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);
@@ -5787,6 +6170,317 @@
 
 
 /******************************************************************************
+ 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));
+
+			// Get the Caps from the device. NB for MMC/SD we may need to retry as there may have been an earlier 
+			// EForceMediaChange request which can result in the cancellation of requests already in the queue
+			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
+			TInt i;
+			const TInt KRetries = 5;
+			TInt r = KErrNotReady;
+			for (i=0; r == KErrNotReady && i < KRetries; i++)
+				{
+				capsBuf.SetMax();
+				capsBuf.FillZ();
+				m.Drive() = attachedDrive;
+				m.Id() = DLocalDrive::ECaps;
+				m.RemoteDes() = (TAny*)capsBuf.Ptr();
+				m.Length() = KMaxLocalDriveCapsLength;
+				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()
@@ -5795,6 +6489,7 @@
 
 	// install the HAL function
 	TInt r=Kern::AddHalEntry(EHalGroupMedia,MediaHalFunction,NULL);
+
 #ifdef __DEMAND_PAGING__
 	if (r==KErrNone)
 		{
@@ -5807,6 +6502,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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/medata/pccd_ata.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1785,6 +1785,7 @@
 	aInfo.iFileSystemId=KDriveFileSysFAT;
 	aInfo.iHiddenSectors=iHiddenSectors;
 	aInfo.iBlockSize=KAtaSectorSize;
+	SetTotalSizeInBytes(aInfo);
 	return KErrCompletion;	// synchronous completion
 	}
 
--- a/kernel/eka/drivers/media/base_e32_drivers_media.mrp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/media/base_e32_drivers_media.mrp	Thu Aug 19 11:14:22 2010 +0300
@@ -10,6 +10,7 @@
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\medlfs
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\medmmc
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\mednand
+source	\sf\os\kernelhwsrv\kernel\eka\drivers\sdapc
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\pbus\pbusmedia.cpp
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\pbus\spbus.cpp
 source	\sf\os\kernelhwsrv\kernel\eka\drivers\pbus\distribution.policy.s60
--- a/kernel/eka/drivers/media/bld.inf	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/media/bld.inf	Thu Aug 19 11:14:22 2010 +0300
@@ -42,6 +42,7 @@
 ../pbus/mmc/sdcard/sdcard3c/sdio/dummyexp.h     SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/sdio/)
 ../pbus/mmc/sdcard/sdcard3c/sdio/sdiocard.h     SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/sdio/)
 ../pbus/mmc/sdcard/sdcard3c/sdio/sdiocard.inl     SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(drivers/sdio/)
+../sdapc/d_sdapc.h				SYMBIAN_OS_LAYER_PUBLIC_EXPORT_PATH(drivers/)
 
 PRJ_MMPFILES
 
@@ -59,6 +60,7 @@
 #if !defined(WINS) && !defined(GENERIC_X86)
 ../../drivers/pbus/mmc/sdcard/sdcard3c/epbussd
 ../../drivers/pbus/mmc/sdcard/sdcard3c/sdio/epbussdio
+../../drivers/sdapc/d_sdapc
 #endif
 
 // Build the folowing from variant if required.
--- a/kernel/eka/drivers/medint/iram.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/medint/iram.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/medlfs/flash_media.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/medmmc/medmmc.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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
@@ -2898,7 +2889,7 @@
 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rdc:%x,%x", iReqCur, iReqEnd));
 	OstTraceExt3( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED, "iReqCur=%x:%x; iReqEnd=0x%x", (TUint) I64HIGH(iReqCur), (TUint) I64LOW(iReqCur), (TUint) iReqEnd );
 	
-	if ( iCurrentReq->IsPhysicalAddress()
+	if ( (iCurrentReq->DriverFlags() & RLocalDrive::ELocDrvDirectIO) || iCurrentReq->IsPhysicalAddress()
 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
 	     || DMediaPagingDevice::PageInRequest(*iCurrentReq)
 #endif //DEMAND_PAGING 
@@ -2959,12 +2950,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" );
 
@@ -2975,19 +2961,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;
 	}
 
@@ -3700,6 +3677,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/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1999-2010 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"
@@ -27,9 +27,8 @@
 // ======== TSDCard ========
 
 TSDCard::TSDCard()
-:	iProtectedAreaSize(0), iPARootDirEnd(KPARootDirEndUnknown)
+:	iProtectedAreaSize(0), iPARootDirEnd(KPARootDirEndUnknown), iClientCountSD(0)
 	{
-	// empty
 	}
 
 TInt64 TSDCard::DeviceSize64() const
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/sdapc/d_sdapc.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,304 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL " http://www.eclipse.org/legal/epl-v10.html ".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+
+
+#include <kernel/kernel.h>
+#include <drivers/mmc.h>
+#include <drivers/sdcard.h>
+#include <drivers/sdio/sdio.h>
+#include <drivers/d_sdapc.h>
+
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "locmedia_ost.h"
+#ifdef __VC32__
+#pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
+#endif
+#include "d_sdapcTraces.h"
+#endif
+
+_LIT(KLddName,"D_SDAPC");
+
+const TInt KMajorVersionNumber=1;
+const TInt KMinorVersionNumber=0;
+const TInt KBuildVersionNumber=1;
+
+const TInt KSocketNumber = 0;
+const TInt KStackNumber  = 0;
+const TInt KCardNumber   = 0;
+
+// global Dfc Que
+TDynamicDfcQue* gDfcQ;
+
+class DSDAuxiliaryPowerControlFactory : public DLogicalDevice
+//
+// LDD factory
+//
+	{
+public:
+	DSDAuxiliaryPowerControlFactory();
+	~DSDAuxiliaryPowerControlFactory();
+	virtual TInt Install(); 					//overriding pure virtual
+	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
+	virtual TInt Create(DLogicalChannelBase*& aChannel); 	//overriding pure virtual
+	};
+
+
+class DSDAuxiliaryPowerControl : public DLogicalChannel
+//
+// Logical channel
+//
+	{
+public:
+	DSDAuxiliaryPowerControl();
+	virtual ~DSDAuxiliaryPowerControl();
+
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual void HandleMsg(class TMessageBase *);
+
+private:
+	static void BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2);
+	TInt PowerUpStack();
+
+private:
+	DMMCSocket* iSocketP;
+	DMMCStack*  iStackP;
+	TSDCard*  iCardP;
+    
+	DThread* iClient;
+	
+	TPBusCallBack iBusCallBack;		
+	DSemaphore* iPowerUpSemaphore;
+	TBool iInitialised;
+	};
+
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DSDAuxiliaryPowerControlFactory;
+	}
+
+DSDAuxiliaryPowerControlFactory::DSDAuxiliaryPowerControlFactory()
+//
+// Constructor
+//
+	{
+    OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROLFACTORY_DSDAUXILIARYPOWERCONTROLFACTORY, "DSDAuxiliaryPowerControlFactory::DSDAuxiliaryPowerControlFactory");
+	__KTRACE_OPT(KPBUS1, Kern::Printf(">DSDAuxiliaryPowerControlFactory::DSDAuxiliaryPowerControlFactory"));
+    iParseMask=KDeviceAllowUnit;
+	iUnitsMask=0xffffffff;
+	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+	}
+
+TInt DSDAuxiliaryPowerControlFactory::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a new DSDAuxiliaryPowerControl on this logical device
+//
+	{
+    OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROLFACTORY_CREATE, "DSDAuxiliaryPowerControlFactory::Create");
+	__KTRACE_OPT(KPBUS1, Kern::Printf(">DSDAuxiliaryPowerControlFactory::Create"));
+	aChannel=new DSDAuxiliaryPowerControl;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+const TInt KDSDAuxiliaryPowerControlApiThreadPriority = 27;
+_LIT(KDSDAuxiliaryPowerControlApiThread,"DSDAuxiliaryPowerControlApiThread");
+
+TInt DSDAuxiliaryPowerControlFactory::Install()
+//
+// Install the LDD - overriding pure virtual
+//
+	{
+	// Allocate a kernel thread to run the DFC 
+	TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDSDAuxiliaryPowerControlApiThreadPriority, KDSDAuxiliaryPowerControlApiThread);
+
+	if (r != KErrNone)
+		return r; 	
+
+	return SetName(&KLddName);
+	}
+
+void DSDAuxiliaryPowerControlFactory::GetCaps(TDes8& aDes) const
+//
+// Stub - overriding pure virtual
+//
+	{
+	}
+
+/**
+  Destructor
+*/
+DSDAuxiliaryPowerControlFactory::~DSDAuxiliaryPowerControlFactory()
+	{
+    OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROLFACTORY_DSDAUXILIARYPOWERCONTROLFACTORY_DTOR, "DSDAuxiliaryPowerControlFactory::~DSDAuxiliaryPowerControlFactory");
+	__KTRACE_OPT(KPBUS1, Kern::Printf(">DSDAuxiliaryPowerControlFactory::~DSDAuxiliaryPowerControlFactory"));
+	if (gDfcQ)
+		gDfcQ->Destroy();
+	}
+
+void DSDAuxiliaryPowerControl::BusCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2)
+	{
+	DSDAuxiliaryPowerControl* pTest = (DSDAuxiliaryPowerControl*)aPtr;
+	TPBusState busState = (TPBusState) (TInt) a1;
+	switch (aReason)
+		{
+		case TPBusCallBack::EPBusStateChange:
+			if (busState != EPBusPoweringUp)
+				Kern::SemaphoreSignal(*(pTest->iPowerUpSemaphore));
+			break;
+		}
+	}
+
+TInt DSDAuxiliaryPowerControl::PowerUpStack()
+	{
+	iBusCallBack.iFunction = BusCallBack;
+	iBusCallBack.iPtr=this;
+	iBusCallBack.SetSocket(iSocketP->iSocketNumber);
+	iBusCallBack.Add();
+	TInt r = Kern::SemaphoreCreate(iPowerUpSemaphore, _L("SDPowerUpSem"), 0);
+	if (r == KErrNone)
+		{
+		r = iSocketP->PowerUp();
+		if (r == KErrNone)
+			Kern::SemaphoreWait(*iPowerUpSemaphore);
+		}
+	return r;
+	}
+
+TInt DSDAuxiliaryPowerControl::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+//
+// Create channel
+//
+	{
+    OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_1, "DSDAuxiliaryPowerControl::DoCreate()");
+	__KTRACE_OPT(KPBUS1, Kern::Printf(">DSDAuxiliaryPowerControl::DoCreate()"));
+
+	if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
+		return KErrNotSupported;
+
+	//
+	// Obtain the appropriate card from the socket/stack
+	//
+	iSocketP = static_cast<DMMCSocket*>(DPBusSocket::SocketFromId(KSocketNumber));
+	if(iSocketP == NULL)
+		{
+        OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_2, "DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain socket");
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain socket"));
+		return KErrNoMemory;
+		}
+
+	iStackP = static_cast<DSDStack*>(iSocketP->Stack(KStackNumber));
+	if(iStackP == NULL)
+		{
+        OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_3, "DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain stack");
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain stack"));
+		return KErrNoMemory;
+		}
+
+	iCardP = static_cast<TSDCard*>(iStackP->CardP(KCardNumber));
+	if(iCardP == NULL)
+		{
+        OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_4, "DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain card");
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : Didn't obtain card"));
+		return KErrNoMemory;
+		}
+
+	SetDfcQ(gDfcQ);
+	iMsgQ.Receive();
+
+	// Make sure stack is powered up
+	TInt r = PowerUpStack();
+	if (r != KErrNone && r != KErrCompletion)
+		{
+        OstTrace1( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_5, "DSDAuxiliaryPowerControl::DoCreate() : Failed To Power up stack, r = %d", r);
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : Failed To Power up stack, r = %d", r));
+		return r;
+		}
+		
+	if(!iCardP->IsReady())
+		{
+        OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_6, "DSDAuxiliaryPowerControl::DoCreate() : Card not ready");
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : Card not ready"));
+		return KErrNotReady;
+		}
+    	
+	if(!iCardP->ClientsRegistered())
+		{		
+		iCardP->RegisterClient();
+		((DSDIOPsu*)(iSocketP->iVcc))->Lock();
+		TBool locked = ((DSDIOPsu*)(iSocketP->iVcc))->IsLocked();
+		OstTrace1( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DOCREATE_7, "DSDAuxiliaryPowerControl::DoCreate() : PSU IsLocked(), locked = %d", locked);
+		__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::DoCreate() : PSU IsLocked(), locked = %d", locked));
+		if(!locked)
+			return KErrNotReady;
+		}
+		
+	return KErrNone;
+	}
+
+DSDAuxiliaryPowerControl::DSDAuxiliaryPowerControl()
+//
+// Constructor
+//
+	{
+	iClient=&Kern::CurrentThread();
+	((DObject*)iClient)->Open();
+	}
+
+
+DSDAuxiliaryPowerControl::~DSDAuxiliaryPowerControl()
+//
+// Destructor
+//
+	{
+    OstTrace0( TRACE_FLOW, DSDAUXILIARYPOWERCONTROL_DSDAUXILIARYPOWERCONTROL_DTOR, "DSDAuxiliaryPowerControl::~DSDAuxiliaryPowerControl");
+	__KTRACE_OPT(KPBUS1, Kern::Printf("DSDAuxiliaryPowerControl::~DSDAuxiliaryPowerControl"));
+	iBusCallBack.Remove();
+
+	if (iSocketP)
+		iSocketP->ControlIO(DPBusSocket::EControlMediaState, (TAny*)DPBusSocket::EPeriphBusMediaNormal, NULL);
+
+	
+	if(iCardP->ClientsRegistered())
+		{		
+		iCardP->DeregisterClient();
+		((DSDIOPsu*)(iSocketP->iVcc))->Unlock();
+		}
+
+	iPowerUpSemaphore->Close(NULL);
+
+	Kern::SafeClose((DObject*&)iClient,NULL);
+	}
+
+void DSDAuxiliaryPowerControl::HandleMsg(TMessageBase* aMsg)
+    {
+    TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id=m.iValue;
+    
+	if (id==(TInt)ECloseMsg)
+		{
+		if (iSocketP)
+			iSocketP->ControlIO(DPBusSocket::EControlMediaState, (TAny*)DPBusSocket::EPeriphBusMediaNormal, NULL);
+
+		m.Complete(KErrNone, EFalse);
+		return;
+		}
+    else if (id==KMaxTInt)
+		{
+		// DoCancel
+		m.Complete(KErrNone,ETrue);
+		return;
+		}
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/sdapc/d_sdapc.h	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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:
+
+
+#ifndef __D_SDAPC_H__
+#define __D_SDAPC_H__
+#include <e32cmn.h>
+
+
+
+
+class TCapsTestV01
+	{
+public:
+	TVersion	iVersion;
+	};
+
+/**
+
+A user-side interface to the SD PSU auxiliary-control driver.
+
+*/
+class RSDAuxiliaryPowerControlAPI : public RBusLogicalChannel
+	{
+public:
+	enum
+		{
+		EMajorVersionNumber=1,
+		EMinorVersionNumber=0,
+		EBuildVersionNumber=1
+		};
+
+public:
+	inline void Cancel();
+	
+	inline TInt Open(TInt aSocket,const TVersion& aVer)
+		{return(DoCreate(_L("D_SDAPC"),aVer,(TInt)aSocket,NULL,NULL));}
+	
+	inline TVersion VersionRequired() const
+		{return(TVersion(EMajorVersionNumber,EMinorVersionNumber,EBuildVersionNumber));}
+	
+	};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/sdapc/d_sdapc.mmp	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL " http://www.eclipse.org/legal/epl-v10.html ".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+
+#include "kernel/kern_ext.mmh"
+
+TARGET         d_sdapc.ldd
+TARGETTYPE     LDD
+
+SOURCEPATH		.
+SOURCE		d_sdapc.cpp
+LIBRARY		epbussd.lib
+epocallowdlldata
+
+USERINCLUDE		traces
+USERINCLUDE		../../include/drivers
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+
+capability	all
+
+SMPSAFE
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/sdapc/traces/OstTraceDefinitions.h	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,21 @@
+// Copyright (c) 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:
+
+#ifndef __OSTTRACEDEFINITIONS_H__
+#define __OSTTRACEDEFINITIONS_H__
+// OST_TRACE_COMPILER_IN_USE flag has been added by Trace Compiler
+// REMOVE BEFORE CHECK-IN TO VERSION CONTROL
+//#define OST_TRACE_COMPILER_IN_USE
+#include <OpenSystemTrace.h>
+#endif
--- a/kernel/eka/eabi/elocdu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/eabi/elocdu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/d32locd.h	Thu Aug 19 11:14:22 2010 +0300
@@ -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
@@ -550,9 +565,11 @@
 	enum TReadWriteFlags
 		{
 		ELocDrvMetaData					= 0x80000000,	/**< Set if read/write request is for metadata */
-		ELocDrvWholeMedia				= 0x40000000	/**< Set to access whole media, rather than partition */
+		ELocDrvWholeMedia				= 0x40000000,	/**< Set to access whole media, rather than partition */
+		ELocDrvDirectIO					= 0x20000000
 		};
 
+	// @see TBusLocalDrive::QueryDevice()
 	enum TQueryDevice
 		{ 
 		// Symbian publishedPartner range
@@ -567,7 +584,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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/drivers/locmedia.h	Thu Aug 19 11:14:22 2010 +0300
@@ -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
 		EPhysAddrOnly=0x200,        // No virtual address is available. Data Paging requests Only. 
 		};
 public:
@@ -494,7 +537,7 @@
 @internalComponent
 */
 inline void DLocalDrive::Deque()
-	{ iLink.Deque(); }
+	{ iMediaChangeObserver.iLink.Deque(); }
 
 
 
@@ -648,6 +691,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;
@@ -662,6 +706,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;
 	};
 
 /**
@@ -828,7 +880,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);
@@ -842,7 +894,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();
@@ -850,7 +902,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();
@@ -863,7 +915,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();
@@ -883,6 +938,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;
@@ -1155,6 +1217,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();
@@ -1172,6 +1235,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/drivers/sdcard.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/drivers/sdcard.h	Thu Aug 19 11:14:22 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1999-2010 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"
@@ -82,12 +82,16 @@
 	inline TUint32 PARootDirEnd() const;
 	inline void SetPARootDirEnd(TUint32 aPARootDirEnd);
 	virtual TUint MaxTranSpeedInKilohertz() const;
+	inline void RegisterClient();
+	inline void DeregisterClient();
+	inline TBool ClientsRegistered();
 private:
 	TUint32 iProtectedAreaSize;
 	TUint32 iPARootDirEnd;
 	TUint8	iAUSize;
 	TUint8 iPad[3];
-	TUint32 iSpare[4];
+	TUint32 iClientCountSD;
+	TUint32 iSpare[3];
 	};
 
 class TSDCardArray : public TMMCardArray
--- a/kernel/eka/include/drivers/sdcard.inl	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/drivers/sdcard.inl	Thu Aug 19 11:14:22 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1999-2010 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"
@@ -44,6 +44,34 @@
 inline TUint32 TSDCard::PARootDirEnd() const			{return iPARootDirEnd;}
 inline void TSDCard::SetPARootDirEnd(TUint32 aPARootDirEnd)	{iPARootDirEnd=aPARootDirEnd;}
 
+/**
+Called when a client registers with the SD card.
+*/
+inline void TSDCard::RegisterClient()
+	{
+	__e32_atomic_add_ord32(&iClientCountSD, 1);
+	}
+
+/**
+Called when a client de-registers with the SD card.
+*/	
+inline void TSDCard::DeregisterClient()
+
+	{ 
+	__e32_atomic_add_ord32(&iClientCountSD, TUint32(-1));
+	}
+
+/**
+Returned value indicates whether or not clients have registered with the SD card.
+*/
+inline TBool TSDCard::ClientsRegistered()
+	{
+	if(iClientCountSD)
+		return ETrue;
+
+	return EFalse;
+	}
+
 // ======== TSDCardArray ========
 
 inline TSDCardArray::TSDCardArray(DSDStack* aOwningStack) : TMMCardArray(aOwningStack)
--- a/kernel/eka/include/e32ver.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/e32ver.h	Thu Aug 19 11:14:22 2010 +0300
@@ -28,7 +28,7 @@
 
 const TInt KE32MajorVersionNumber=2;
 const TInt KE32MinorVersionNumber=0;
-const TInt KE32BuildVersionNumber=2144;
+const TInt KE32BuildVersionNumber=2655;
 
 const TInt KMachineConfigurationMajorVersionNumber=1;
 const TInt KMachineConfigurationMinorVersionNumber=0;
--- a/kernel/eka/include/kernel/kernel.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/include/kernel/kernel.h	Thu Aug 19 11:14:22 2010 +0300
@@ -2782,9 +2782,10 @@
 	/** The type of device this represents. */
 	enum TType
 		{
-		ERom  = 1<<0,	/**< Paged ROM device type. */
-		ECode = 1<<1,	/**< Code paging device type. */
-		EData = 1<<2	/**< Data paging device type. */
+		ERom  = 1<<0,			/**< Paged ROM device type. */
+		ECode = 1<<1,			/**< Code paging device type. */
+		EData = 1<<2,			/**< Data paging device type. */
+		EMediaExtension = 1<<3	/**< Media extension device type. */
 		};
 
 	enum TSpecialDrives
--- a/kernel/eka/kernel/sprocess.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/kernel/sprocess.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -590,6 +590,16 @@
 		pLink=pLink->iNext;
 		if (pT!=pC)
 			{
+			// If killing pT will cause a system crash then force that to happen in the context of the
+			// current thread
+			if(pT->iFlags & KThreadFlagSystemPermanent)
+				{
+				K::Fault(K::EPermanentThreadExit);
+				}
+			if (aType != EExitKill && (pT->iFlags & KThreadFlagSystemCritical))
+				{
+				K::Fault(K::ESystemThreadPanic);
+				}
 			// Need to stop the current thread being killed as a consequence of killing pT
 			pT->iFlags &= ~(KThreadFlagProcessPermanent|KThreadFlagProcessCritical);
 			pT->Die(aType, aReason, aCategory);
--- a/kernel/eka/kernel/sutils.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/kernel/sutils.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -3489,10 +3489,19 @@
 
 void TClientRequest::EndComplete(DThread* aThread)
 	{
+	// NB: if the callback is successfully queued, the target thread may run and
+	// process it before we get back from the call to QueueUserModeCallback().
+	// In that case, 'iStatus' will be changed; and in general it is not safe to
+	// look at any element of 'this' once the callback is queued, as it may change
+	// asynchronously.  Therefore, we must cache the value of 'iStatus' beforehand
+	// and later use this saved copy to decide whether to signal the target thread.
+	T_UintPtr status = iStatus;
 	TInt r = NKern::QueueUserModeCallback(&aThread->iNThread, this);
+
 	if (r == KErrNone)
 		{
-		if (iStatus != (KClientRequestNullStatus | KClientRequestFlagInUse))
+		__NK_ASSERT_DEBUG(status & KClientRequestFlagInUse);
+		if ((status & ~KClientRequestFlagInUse) != KClientRequestNullStatus)
 			NKern::ThreadRequestSignal(&aThread->iNThread);
 		}
 	else
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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...
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -797,6 +797,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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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...
--- a/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -3242,7 +3242,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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kernel/eka/release.txt	Thu Aug 19 11:14:22 2010 +0300
@@ -1,3 +1,57 @@
+Version 2.00.2655
+=================
+(Made by fadhliM 27/07/2010)
+
+1.	vfebvre
+	1.	ou1cimx1#488886 System-critical thread being reported in MC when another permanent thread in same process fault
+
+2.	dogunjum
+	1.	ou1cimx1#479596 92: Domain Manager - Correct the usage of RArray::Append()
+
+
+Version 2.00.2654
+=================
+(Made by fadhliM 19/07/2010)
+
+1.	gcochran
+	1.	DEF144551 t_svrpinning, _P,_UP test fails with unexpected thread exit type on Vasco/TB9.2
+
+2.	martai
+	1.	ou1cimx1#494023 E32TEST T_SHADOW Fails during testMultipleReadFile()
+
+
+Version 2.00.2653
+=================
+(Made by famustaf 14/07/2010)
+
+1.	davegord
+	1.	ou1cimx1#485331 Kernel signals MTP server unexpectedly and cause it panic
+
+
+Version 2.00.2652
+=================
+(Made by famustaf 12/07/2010)
+
+1.	jcoppear
+	1.	ou1cimx1#479552 ENV E32TEST T_ALIAS_REMOVE timeout
+	
+
+Version 2.00.2651
+=================
+(Made by famustaf 12/07/2010)
+
+1.	paconway
+	1.	MINOR_CHANGE Correct EPL header for sdapctest.mmp
+
+
+Version 2.00.2650
+=================
+(Made by famustaf 07/07/2010)
+
+1.	paconway
+	1.	REQ 417-56766 MBBMS over CMMB for TD-SCDMA Gen. 2 MobileTv
+
+
 Version 2.00.2144
 =================
 (Made by vfebvre 21/06/2010)
--- a/kerneltest/e32test/demandpaging/t_svrpinning.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/e32test/demandpaging/t_svrpinning.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -72,15 +72,13 @@
 	enum TTestMode
 		{
 		EStop,
-		ETestPinAll,
-		ETestPinEven,
-		ETestPinOdd,
-		ETestPin3,
-		ETestPin2,
-		ETestPin1,
-		ETestPin0,
-		ETestPinWritable,
-		ETestUnpinWritable,
+		ETestRdPinAll,
+		ETestRdUnpin3,
+		ETestRdUnpin2,
+		ETestRdUnpin1,
+		ETestRdUnpin0,
+		ETestWrPinAll,
+		ETestWrPinNone,
 		ETestPinOOM,
 		ETestPinDefault,
 		ETestDeadServer,
@@ -156,11 +154,22 @@
 
 TInt CTestSession::CheckDesPresent(const RMessage2& aMessage, TUint aArgIndex, TBool aExpected, TBool aWrite)
 	{
+	TRequestStatus clientStat;
+	
 	if (aExpected)
+		{
 		RDebug::Printf("  Checking message argument at %d is present", aArgIndex);
+		}
 	else
+		{
 		RDebug::Printf("  Checking message argument at %d is not present", aArgIndex);
-
+		// Start watching for client thread death
+		RThread clientThread;
+		aMessage.Client(clientThread);
+		clientThread.Logon(clientStat);
+		clientThread.Close();
+		}
+		
 	// Get the length of the descriptor and verify it is as expected.
 	TInt length = aMessage.GetDesLength(aArgIndex);
 	if (length < KErrNone)
@@ -177,14 +186,9 @@
 		{// Now read the descriptor and verify that it is present or not.
 		TBuf8<5> des;
 		TInt r = aMessage.Read(aArgIndex, des);
-		TBool pass;
-		if (iClientDied)
-			pass = r == KErrDied || r == KErrBadDescriptor;
-		else
-			pass = r == (aExpected ? KErrNone : KErrBadDescriptor);
-		if (!pass)
+		if (r != (aExpected ? KErrNone : KErrBadDescriptor))
 			{
-			RDebug::Printf("  Error reading descriptor data r %d", r);
+			RDebug::Printf("  Unexpected value returned from aMessage.Read:%d", r);
 			return KErrGeneral;
 			}
 		if (r==KErrNone && (des[0] != 'a' || des[1] != 'r' || des[2] != 'g'))
@@ -207,23 +211,19 @@
 		for (TInt i = 0; i < max; i++)
 			argPtr[i] = (TUint8)aArgIndex;
 		TInt r = aMessage.Write(aArgIndex, argPtr);
-		TBool pass;
-		if (iClientDied)
-			pass = r == KErrDied || r == KErrBadDescriptor;
-		else
-			pass = r == (aExpected ? KErrNone : KErrBadDescriptor);
-		if (!pass)
+		if (r != (aExpected ? KErrNone : KErrBadDescriptor))
 			{
-			RDebug::Printf("  Error writing to the descriptor data r %d", r);
+			RDebug::Printf("  Unexpected value returned from aMessage.Write:%d", r);
 			return KErrGeneral;
 			}
 		}
 
 	if (!aExpected)
 		{// The client should have been killed as the data wasn't present.
-		if(!iClientDied)
-			User::After(500000); // allow time for client to die before next test
+		RDebug::Printf("  CheckDesPresent: Waiting for client to die");
+		User::WaitForRequest(clientStat);
 		iClientDied = ETrue;
+		RDebug::Printf("  CheckDesPresent: Client dead");
 		}
 	return KErrNone;
 	}
@@ -243,16 +243,16 @@
 	TInt r = User::SetRealtimeState(User::ERealtimeStateOn);
 	if (r != KErrNone)
 		{
-		RDebug::Printf("Error setting realtime state r = %d", r);
+		RDebug::Printf("CheckArgsPresent: Error setting realtime state r = %d", r);
 		return r;
 		}
 
 	r = CheckDesPresent(aMessage, 0, arg0Present, aWrite);
-	if (r == KErrNone)
+	if ((r == KErrNone) && !iClientDied)
 		r = CheckDesPresent(aMessage, 1, arg1Present, aWrite);
-	if (r == KErrNone)
+	if ((r == KErrNone) && !iClientDied)
 		r = CheckDesPresent(aMessage, 2, arg2Present, aWrite);
-	if (r == KErrNone)
+	if ((r == KErrNone) && !iClientDied)
 		r = CheckDesPresent(aMessage, 3, arg3Present, aWrite);
 
 	User::SetRealtimeState(User::ERealtimeStateOff);
@@ -260,7 +260,7 @@
 	return r;
 	}
 
-void CTestSession::ServiceL(const RMessage2& aMessage)
+EXPORT_C void CTestSession::ServiceL(const RMessage2& aMessage)
 //
 // Virtual message-handler
 //
@@ -272,35 +272,32 @@
 		case EStop:
 			CActiveScheduler::Stop();
 			break;
-		case ETestPinAll:
+		case ETestRdPinAll:
 			r = CheckArgsPresent(aMessage, ETrue, ETrue, ETrue, ETrue);
 			break;
-		case ETestPinOdd:
-			r = CheckArgsPresent(aMessage, EFalse, ETrue, EFalse, ETrue);
-			break;
-		case ETestPinEven:
-			r = CheckArgsPresent(aMessage, ETrue, EFalse, ETrue, EFalse);
-			break;
-		case ETestPin3:
+		case ETestRdUnpin3:
 			r = CheckArgsPresent(aMessage, ETrue, ETrue, ETrue, EFalse);
 			break;
-		case ETestPin2:
-			r = CheckArgsPresent(aMessage, ETrue, ETrue, EFalse, EFalse);
+		case ETestRdUnpin2:
+			r = CheckArgsPresent(aMessage, ETrue, ETrue, EFalse, ETrue);
 			break;
-		case ETestPin1:
-			r = CheckArgsPresent(aMessage, ETrue, EFalse, EFalse, EFalse);
+		case ETestRdUnpin1:
+			r = CheckArgsPresent(aMessage, ETrue,  EFalse,  ETrue, ETrue);
 			break;
-		case ETestPin0:
+		case ETestRdUnpin0:
+			r = CheckArgsPresent(aMessage, EFalse, ETrue, ETrue, ETrue);
+			break;
 		case ETestPinDefault:
 			r = CheckArgsPresent(aMessage, EFalse, EFalse, EFalse, EFalse);
 			break;
-		case ETestPinWritable:
+		case ETestWrPinAll:
 			r = CheckArgsPresent(aMessage, ETrue, ETrue, ETrue, ETrue, ETrue);
 			break;
-		case ETestUnpinWritable:
+		case ETestWrPinNone:
 			r = CheckArgsPresent(aMessage, EFalse, EFalse, EFalse, EFalse, ETrue);
 			break;
 		default:
+			RDebug::Printf("CTestSession::ServiceL Unsupported Function: %d", aMessage.Function());
 			r = KErrNotSupported;
 
 		}
@@ -447,39 +444,29 @@
 
 	switch((TInt)aTestMode)
 		{
-		case CTestSession::ETestPinAll:
+		case CTestSession::ETestRdPinAll:
 			test.Printf(_L("Test pinning all args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
+			r = session.PublicSendReceive(CTestSession::ETestRdPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
 			break;
 
-		case CTestSession::ETestPinOdd:
-			test.Printf(_L("Test pinning odd args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPinOdd, TIpcArgs(&arg0, &argTmpBuf, &arg2, &arg3).PinArgs(EFalse, ETrue, EFalse, ETrue));
-			break;
-
-		case CTestSession::ETestPinEven:
-			test.Printf(_L("Test pinning even args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPinEven, TIpcArgs(&arg0, &arg1, argTmp, &arg3).PinArgs(ETrue, EFalse, ETrue, EFalse));
+		case CTestSession::ETestRdUnpin3:
+			test.Printf(_L("Read Arg3 unpinned\n"));
+			r = session.PublicSendReceive(CTestSession::ETestRdUnpin3, TIpcArgs(&arg0, argTmp, &argTmpBuf, &arg3).PinArgs(ETrue, ETrue, ETrue, EFalse));
 			break;
 
-		case CTestSession::ETestPin3:
-			test.Printf(_L("Test pinning 3 args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPin3, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs(ETrue, ETrue, ETrue, EFalse));
+		case CTestSession::ETestRdUnpin2:
+			test.Printf(_L("Read Arg2 unpinned\n"));
+			r = session.PublicSendReceive(CTestSession::ETestRdUnpin2, TIpcArgs(argTmp, &arg1, &arg2, &arg3).PinArgs(ETrue, ETrue, EFalse,  ETrue));
 			break;
 
-		case CTestSession::ETestPin2:
-			test.Printf(_L("Test pinning 2 args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPin2, TIpcArgs(argTmp, &arg1, &arg2, &arg3).PinArgs(ETrue, ETrue, EFalse, EFalse));
+		case CTestSession::ETestRdUnpin1:
+			test.Printf(_L("Read Arg1 unpinned\n"));
+			r = session.PublicSendReceive(CTestSession::ETestRdUnpin1, TIpcArgs(&argTmpBuf, &arg1, &arg2, &arg3).PinArgs(ETrue, EFalse,  ETrue,  ETrue));
 			break;
 
-		case CTestSession::ETestPin1:
-			test.Printf(_L("Test pinning 1 args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPin1, TIpcArgs(&argTmpBuf, &arg1, &arg2, &arg3).PinArgs(ETrue, EFalse, EFalse, EFalse));
-			break;
-
-		case CTestSession::ETestPin0:
-			test.Printf(_L("Test pinning 0 args\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPin0, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs(EFalse, EFalse, EFalse, EFalse));
+		case CTestSession::ETestRdUnpin0:
+			test.Printf(_L("Read Arg0 unpinned\n"));
+			r = session.PublicSendReceive(CTestSession::ETestRdUnpin0, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs(EFalse, ETrue, ETrue, ETrue));
 			break;
 
 		case CTestSession::ETestPinDefault:
@@ -487,9 +474,9 @@
 			r = session.PublicSendReceive(CTestSession::ETestPinDefault, TIpcArgs(&arg0, &arg1, &arg2, argTmp));
 			break;
 
-		case CTestSession::ETestPinWritable:
+		case CTestSession::ETestWrPinAll:
 			test.Printf(_L("Test writing to pinned descriptors\n"));
-			r = session.PublicSendReceive(CTestSession::ETestPinWritable, TIpcArgs(&arg0, &arg3, &arg4, &arg5).PinArgs(ETrue, ETrue, ETrue, ETrue));
+			r = session.PublicSendReceive(CTestSession::ETestWrPinAll, TIpcArgs(&arg0, &arg3, &arg4, &arg5).PinArgs(ETrue, ETrue, ETrue, ETrue));
 			// Verify the index of each argument has been written to each descriptor.
 			{
 			TUint maxLength = arg0.MaxLength();
@@ -512,9 +499,9 @@
 			}
 			break;
 
-		case CTestSession::ETestUnpinWritable:
+		case CTestSession::ETestWrPinNone:
 			test.Printf(_L("Test writing to unpinned descriptors\n"));
-			r = session.PublicSendReceive(CTestSession::ETestUnpinWritable, TIpcArgs(&arg0, &arg3, &arg4, &arg5).PinArgs(EFalse, EFalse, EFalse, EFalse));
+			r = session.PublicSendReceive(CTestSession::ETestWrPinNone, TIpcArgs(&arg0, &arg3, &arg4, &arg5).PinArgs(EFalse, EFalse, EFalse, EFalse));
 			// Verify the index of each argument has been written to each descriptor.
 			// Unless this is a pinnning server than the thread will be panicked before we reach there.
 			{
@@ -542,7 +529,7 @@
 			test.Printf(_L("Test pinning to dead server\n"));
 			gSem.Signal();
 			gSem1.Wait();
-			r = session.PublicSendReceive(CTestSession::ETestPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
+			r = session.PublicSendReceive(CTestSession::ETestRdPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
 			break;
 
 		case CTestSession::ETestPinOOM:
@@ -554,7 +541,7 @@
 			for (i = 0; i < KMaxKernelAllocations && r == KErrNoMemory; i++)
 				{
 				__KHEAP_FAILNEXT(i);
-				r = session.PublicSendReceive(CTestSession::ETestPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
+				r = session.PublicSendReceive(CTestSession::ETestRdPinAll, TIpcArgs(&arg0, &arg1, &arg2, &arg3).PinArgs());
 				__KHEAP_RESET;
 				}
 			test.Printf(_L("SendReceive took %d tries\n"),i);
@@ -634,7 +621,7 @@
 		RSession session;
 		test_KErrNone(session.PublicCreateSession(_L("CTestServer"),5));
 		
-		for (	TUint clientTest = CTestSession::ETestPinAll; 
+		for (	TUint clientTest = CTestSession::ETestRdPinAll; 
 				clientTest <= CTestSession::ETestPinDefault && !exitFailure;
 				clientTest++)
 			{
@@ -654,8 +641,8 @@
 
 			// If all the descriptor arguments were not pinned then the client 
 			// thread should have been panicked.
-			TBool expectPanic = (clientTest == CTestSession::ETestPinAll || 
-								clientTest == CTestSession::ETestPinWritable ||
+			TBool expectPanic = (clientTest == CTestSession::ETestRdPinAll || 
+								clientTest == CTestSession::ETestWrPinAll ||
 								clientTest == CTestSession::ETestPinOOM )? 0 : 1;
 			expectPanic = !UpdateExpected(!expectPanic);
 
@@ -666,17 +653,20 @@
 				if (exitType != EExitPanic || 
 					exitReason != EIllegalFunctionForRealtimeThread ||
 					clientThread.ExitCategory() != _L("KERN-EXEC"))
-					{// Thread didn't panic as expected.
+					{
+					test.Printf(_L("Thread didn't panic as expected\n"));
 					exitFailure = ETrue;
 					}
 				}
 			else
 				{
 				if (exitType != EExitKill || exitReason != KErrNone)
-					{// Thread didn't exit gracefully as expected.
+					{
+					test.Printf(_L("Thread didn't exit gracefully as expected\n"));
 					exitFailure = ETrue;
 					}
 				}
+			test(!exitFailure);
 			CLOSE_AND_WAIT(clientThread);
 			}
 
@@ -697,7 +687,7 @@
 		User::WaitForRequest(serverStat);
 		if (serverThread.ExitType() != EExitKill)
 			{
-			test.Printf(_L("!!Server thread did something bizarre %d"), serverThread.ExitReason());
+			test.Printf(_L("!!Server thread did something bizarre %d\n"), serverThread.ExitReason());
 			}
 
 		gSem1.Signal();
@@ -710,7 +700,6 @@
 		CLOSE_AND_WAIT(gSem);
 		CLOSE_AND_WAIT(gSem1);
 		}
-	test(!exitFailure);
 
 	test.Next(_L("Test server setting pinning policy after server started"));
 	RThread serverThread;
--- a/kerneltest/e32test/group/bld.inf	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/e32test/group/bld.inf	Thu Aug 19 11:14:22 2010 +0300
@@ -1048,3 +1048,5 @@
 
 //pci tests
 t_pci
+
+sdapctest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/group/sdapctest.mmp	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 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/sdapctest.mmp
+// 
+//
+
+OPTION CW   -w off
+TARGET         sdapctest.exe
+TARGETTYPE     EXE
+SOURCEPATH     ../pccd	
+SOURCE         sdapctest.cpp
+LIBRARY        euser.lib hal.lib
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+capability	all
+
+SMPSAFE
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mediaext/d_nfe.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,1781 @@
+// 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
+#define TRACE_ENABLED	//*test*
+#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:
+			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 sure we haven't lost the swap partition
+		__ASSERT_ALWAYS(!(di.iEntry.iPartitionType == KPartitionTypePagedData && aInfo.iEntry[i].iPartitionType != KPartitionTypePagedData), NFE_FAULT());
+
+		// 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;
+
+	aDi.iDriveFinalised = aFinalised;
+
+	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	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Aug 19 11:14:22 2010 +0300
@@ -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/mmu/t_alias_remove.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/e32test/mmu/t_alias_remove.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -207,7 +207,7 @@
 		if ((fillValue & 0xf) == 1)
 			test.Printf(_L("."));
 
-		PRINTF(T_PRINTF(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue));
+		test.Printf(_L("Process ID %d start slave fill value %d\n"), aProcessId, fillValue);
 		RServer2 masterServer;
 		r = masterServer.CreateGlobal(MasterServerName);
 		test_KErrNone(r);
@@ -269,7 +269,7 @@
 				}
 			}
 		
-		PRINTF(T_PRINTF(_L("Process ID %d Wait for alias to complete\n"), aProcessId));
+		test.Printf(_L("Process ID %d Wait for alias to complete\n"), aProcessId);
 		masterMessage.Complete(KErrNone);
 		User::WaitForRequest(threadStatus);
 		TInt statusInt = threadStatus.Int();
@@ -280,7 +280,7 @@
 		test_Equal(EExitKill, readThread.ExitType());
 		readThread.Close();
 
-		PRINTF(T_PRINTF(_L("Process ID %d Wait for slave to complete\n"), aProcessId));
+		test.Printf(_L("Process ID %d Wait for slave to complete\n"), aProcessId);
 		User::WaitForRequest(slaveStatus);
 		test_Equal(EExitKill, slaveProcess.ExitType());
 		test_Equal(KErrNone, slaveProcess.ExitReason());
--- a/kerneltest/e32test/mmu/t_shadow.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/e32test/mmu/t_shadow.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -464,6 +464,11 @@
 #ifdef __WINS__
 	test.Printf(_L("Test not valid in WINS\n"));
 #else
+	// Turn off lazy dll unloading
+	RLoader l;
+	test_KErrNone(l.Connect());
+	test_KErrNone(l.CancelLazyDllUnload());
+	l.Close();
 
 	test.Start(_L("Testing ROM shadowing"));
 	Initialise();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/pccd/sdapctest.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -0,0 +1,81 @@
+// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL " http://www.eclipse.org/legal/epl-v10.html ".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+
+
+#include <drivers/d_sdapc.h>
+
+#define __E32TEST_EXTENSION__
+
+#include <e32std.h>
+#include <e32test.h>
+#include <hal.h>
+
+LOCAL_D RTest test(_L("SDAPCTEST"));
+
+
+// This test is intended to simply load and free the associated LDD,
+// since the required funcionality is contained in the channel creation method (client registration, PSU locking)
+// and destructor (deregistration and unlocking).
+// 
+// The waits are intended to allow a generous sample time for logging of KTRACE from the PSU code
+// with the driver loaded/unloaded, to verify that it is behaving as expected.
+
+GLDEF_C TInt E32Main()
+	{
+#if !defined(__WINS__)
+	test.Title();
+		
+    RSDAuxiliaryPowerControlAPI TheDriver;
+
+	test.Start(_L("SDAPCTEST - Main Test"));
+
+	// Only test on platforms with SDIO support in all ROM configurations
+	TInt machineuid;
+    HAL::Get(HAL::EMachineUid, machineuid);
+    if(machineuid != HAL::EMachineUid_OmapH2)
+	    {
+        test.Printf(_L("Test not supported on this platform\n"));
+        }
+	else
+		{
+		TInt err = KErrGeneral;
+
+	    err = User::LoadLogicalDevice(_L("D_SDAPC"));
+		test.Printf(_L("Value of err is %d\n"), err);
+		test_Value(err, err==KErrNone || err==KErrAlreadyExists);
+    	        
+		err = TheDriver.Open(0,TheDriver.VersionRequired());
+		test_KErrNone(err);
+
+		test.Printf(_L("Wait for 10 seconds with SD auxiliary power-control driver loaded...\n"));
+		User::After(10000000);
+    	        
+		TheDriver.Close();
+        		    
+		err = User::FreeLogicalDevice(_L("D_SDAPC"));
+		test.Printf(_L("Value of err is %d\n"), err);
+
+		test.Printf(_L("Wait for 10 seconds without SD auxiliary power-control driver loaded...\n"));
+
+		User::After(10000000);
+		}
+		
+	test.End();
+#else
+	test.Printf(_L("This test does not run on emulator.\n"));
+#endif
+	return(KErrNone);
+	}
+
+
--- a/kerneltest/e32test/power/t_domain.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/e32test/power/t_domain.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
 // under the terms of the License "Eclipse Public License v1.0"
@@ -806,7 +806,9 @@
 	void Perform();
 	void Release();
 	TInt TransitionNotification(MDmDomainMember& aDomainMember);
-	void TransitionRequestComplete();
+	void TransitionRequestComplete();	
+	void RunTestOnGetTransitionFailures(RArray<const TTransitionFailure>& aTransitionFailure);
+	
 	CDmTest5(TDmDomainId aPowerId, TDmDomainId aTestId, TDmDomainState aPowerState, TDmDomainState aTestState) : 
 		CActive(CActive::EPriorityStandard), 
 		iPowerDomainId(aPowerId), iTestDomainId(aTestId), iPowerState(aPowerState), iTestState(aTestState) {}
@@ -846,7 +848,28 @@
 	TInt				iTransitionsExpected;
 	};
 
-
+void CDmTest5::RunTestOnGetTransitionFailures(RArray<const TTransitionFailure>& aTransitionFailure)
+	{
+	//*************************************************
+	// Test - OOM Testing on GetTransitionFailures()
+	// Simulates heap failure in GetTransitionFailures()
+	//*************************************************
+	TInt error = 0;
+	TInt count = 0;	
+	do
+		{		
+		__UHEAP_SETFAIL(RHeap::EFailNext, ++count);
+		error = iTestDomainManager.GetTransitionFailures(aTransitionFailure);						
+		test.Printf( _L( "CDmTest5::RunTestOnGetTransitionFailures, simulating heap failure on GetTransitionFailures(), Error=%d, Run=%d\n" ), error, count );
+		}while(error == KErrNoMemory);		
+		
+	__UHEAP_RESET;
+	
+	//Actual count of heap failure as the final iteration which terminates the loop would not return KErrNoMemory 
+	--count;
+	test(count > 0);
+	test.Printf( _L( "Out of memory tests on GetTransitionFailures() succeeded at heap failure rate of %i\n" ), count );
+	}
 
 //! @SYMTestCaseID PBASE-T_DOMAIN-5
 //! @SYMTestType CT
@@ -1106,6 +1129,18 @@
 	testFailureCount = iTestDomainManager.GetTransitionFailureCount();
 	test (testFailureCount == 1);
 
+#ifdef _DEBUG
+	//***************************************************************
+	// OOM Testing: Simulates heap failure in GetTransitionFailures()
+	//***************************************************************
+	__UHEAP_MARK;
+	RArray<const TTransitionFailure> oomTestFailures;
+	RunTestOnGetTransitionFailures(oomTestFailures);
+	test(oomTestFailures.Count()==1);
+	oomTestFailures.Close();
+	__UHEAP_MARKEND;
+#endif 
+	
 	r = iTestDomainManager.GetTransitionFailures(testFailures);
 	test(r == KErrNone);
 	test(testFailureCount == testFailures.Count());
@@ -2211,7 +2246,6 @@
 		{
 		MDmTest* tests[] = 
 			{
-
 			new CDmTest1(KDmIdRoot, EPwStandby),
 			new CDmTest1(KDmIdRoot, EPwOff),
 			new CDmTest1(KDmIdRoot, EPwActive),
--- a/kerneltest/f32test/demandpaging/t_nandpaging.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/demandpaging/t_nandpaging.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -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.
@@ -509,15 +511,14 @@
 	TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart;
 	TUint size = romHeader->iPageableRomSize;
 	TUint8* addr=NULL;
-	TBool flush;
 	while (Testing)
 		{
 			PageSemaphore.Wait(); // wait for main thread to want paging.
-			flush = (PagesBeingPaged==0);
 			addr=start+((TInt64(Random())*TInt64(size))>>32);	
-			PageDoneSemaphore.Signal(); // Acknolage request.
+			PageDoneSemaphore.Signal(); // Acknowledge request.
 
 			PageMutex.Wait();
+			TBool flush = (PagesBeingPaged==0);	// Ensure only one thread is flushing the cache at a time.
 			PagesBeingPaged++;
 			PageMutex.Signal();
 
@@ -544,9 +545,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 +638,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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/filesystem/fat/t_scn32dr1.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -580,6 +580,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 +615,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 +630,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;
     }
--- a/kerneltest/f32test/filesystem/fat/t_tscan32.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/filesystem/fat/t_tscan32.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -550,6 +550,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 +581,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 +592,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;
 	}
--- a/kerneltest/f32test/group/bld.inf	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/group/bld.inf	Thu Aug 19 11:14:22 2010 +0300
@@ -31,6 +31,8 @@
 ../../../userlibandfileserver/fileserver/inc/runtests.h                         /epoc32/include/
 
 PRJ_TESTMMPFILES
+../../e32test/mediaext/t_nfe
+
 // this should ideally be run early on as it enables 'simulated lock failure mode' in the file cache for udeb builds
 t_filecache 
 
--- a/kerneltest/f32test/group/t_nandpaging.mmp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/group/t_nandpaging.mmp	Thu Aug 19 11:14:22 2010 +0300
@@ -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	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/group/wintest.bat	Thu Aug 19 11:14:22 2010 +0300
@@ -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_dspace.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_dspace.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1696,6 +1696,102 @@
 
 	}
 
+//-------------------------------------------------------------------------------------------------
+// Test the fix for:
+// ou1cimx#410349 Not getting any Notification from RFs::NotifyDiskSpace() for E and F drive when when tested multiple
+// 
+// Action: Enable a plugin to intercept RFs::Delete, and test RFs::Delet can still trigger disk space
+// notification
+//-------------------------------------------------------------------------------------------------
+
+_LIT(KPreModifierPluginFileName,"premodifier_plugin");
+_LIT(KPreModifierPluginName,"PreModifierPlugin");
+const TUint KTestFileSize = KKilo * 100;
+
+#define SAFETEST(a)				if(a != KErrNone)\
+                                        {\
+                                        TheFs.DismountPlugin(KPreModifierPluginName);\
+                                        TheFs.RemovePlugin(KPreModifierPluginName);\
+                                        test(a == KErrNone);\
+                                        }
+
+TInt PluginTestThreadFunction(TAny*)
+    {
+    RTest test(_L("PluginTestThreadFunction"));
+    RFs fs;
+    fs.Connect();
+    
+    TInt r = fs.SetSessionPath(gSessionPath);
+    test(r == KErrNone);
+    
+    RFile file;
+    r = file.Create(fs, KTestFile1, EFileShareAny|EFileWrite);
+    test(r == KErrNone);
+    r = file.SetSize(KTestFileSize);
+    test(r == KErrNone);
+    file.Close();
+      
+    User::After(5000000); // wait for 5 seconds, to ensure first notification received.
+    
+    r = fs.Delete(KTestFile1);
+    test(r == KErrNone);
+    
+    fs.Close();
+    return KErrNone;
+    }
+
+void TestDiskSpaceNotifyWithPlugin()
+    {
+    test.Next(_L("Test Disk Space Notify With Plugin"));
+      
+    TInt drive;
+    TInt r = RFs::CharToDrive(gSessionPath[0],drive);
+    SAFETEST(r);
+    Format(drive);
+    
+    r = TheFs.MkDirAll(gSessionPath);
+    SAFETEST(r);
+     
+    r = TheFs.AddPlugin(KPreModifierPluginFileName);
+    SAFETEST(r);
+
+    r = TheFs.MountPlugin(KPreModifierPluginName);
+    SAFETEST(r);
+    
+    TInt64 free = FreeDiskSpace(drive);
+    TInt64 threshold = free - KTestFileSize + 1;
+    
+    TRequestStatus status;
+    TRequestStatus statusDeath;
+    
+    TheFs.NotifyDiskSpace(threshold, drive, status);
+    
+    RThread thread;
+    r = thread.Create(_L("PluginTestThread"), PluginTestThreadFunction, KStackSize, KHeapSize, KHeapSize, NULL);
+    SAFETEST(r);
+    thread.Logon(statusDeath);
+    thread.Resume();
+    
+    User::WaitForRequest(status);
+    SAFETEST(status.Int());
+    
+    TheFs.NotifyDiskSpace(threshold, drive, status);
+    User::WaitForRequest(status);
+    SAFETEST(status.Int());
+    
+    User::WaitForRequest(statusDeath);
+    SAFETEST(statusDeath.Int());
+    thread.Close();
+    
+    r = TheFs.DismountPlugin(KPreModifierPluginName);
+    SAFETEST(r);
+
+    r = TheFs.RemovePlugin(KPreModifierPluginName);
+    SAFETEST(r);
+
+    Format(drive);
+    }
+
 GLDEF_C void CallTestsL()
 //
 // Do all tests
@@ -1752,6 +1848,7 @@
 		}
 
 	TestChangeNotification();
+	TestDiskSpaceNotifyWithPlugin();
 
 	if( LffsDrive )
 		{
--- a/kerneltest/f32test/server/t_file.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_file.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -197,6 +197,13 @@
 	r=ZFile.Open(TheFs,fn,EFileStreamText);
 	test(r==KErrNone);
 
+	// check the file on the Z: drive his read-only
+	TEntry fileAtt;
+	r=TheFs.Entry(fn,fileAtt);
+	test_KErrNone(r);
+	test((fileAtt.iAtt & KEntryAttReadOnly) == KEntryAttReadOnly);
+
+
 	test.Next(_L("Read file"));
 	TBuf8<0x100> a,b;
 	FOREVER
@@ -953,6 +960,44 @@
 	test(r==KErrNone);
 	f.Close();
 
+
+	test.Next(_L("Internal attribute can't be read"));
+
+	r=TheFs.SetAtt(fname,0,KEntryAttReadOnly);
+	test_KErrNone(r);
+
+	r=f.Open(TheFs,fname,EFileWrite);
+	test_KErrNone(r);
+
+	r=f.SetAtt(KEntryAttReadOnly, 0);	// this will set internal attribut KEntryAttModified
+	test_KErrNone(r);
+
+	// copied \sf\os\kernelhwsrv\userlibandfileserver\fileserver\inc\common.h
+	const TUint KEntryAttModified=0x20000000;	
+
+	TUint att;
+	r = f.Att(att);
+	test_KErrNone(r);
+    test.Printf(_L("att %x"), att);
+	test_Value(att & KEntryAttModified, (att & KEntryAttModified) == 0);
+
+	r=f.SetAtt(att | KEntryAttModified, 0);
+	test_KErrNone(r);
+
+	r = f.Att(att);
+	test_KErrNone(r);
+    test.Printf(_L("att %x"), att);
+	test_Value(att & KEntryAttModified, (att & KEntryAttModified) == 0);
+
+	test.Next(_L("file time is set"));
+	r = f.Modified(time);
+	test(time.Int64() != 0);
+
+    r = f.Flush(); //-- this will flush attributes to the media
+    test_KErrNone(r);
+	f.Close();
+
+
 	// Tidy up
 	r=TheFs.SetAtt(fname,0,KEntryAttReadOnly);
 	test(r==KErrNone);
--- a/kerneltest/f32test/server/t_fman.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_fman.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -600,7 +600,7 @@
 	test_KErrNone(r);
 	test(entry.iName.MatchF(_L("T_FSRV.CPP"))!=KErrNotFound);
 #if defined (__WINS__)
-	test_Equal(KEntryAttArchive, entry.iAtt);
+	test_Equal(KEntryAttArchive | KEntryAttReadOnly, entry.iAtt);
 #else
 	if (!IsTestingLFFS())
 		{
--- a/kerneltest/f32test/server/t_misc.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_misc.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -19,6 +19,11 @@
 #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 +31,8 @@
 
 GLDEF_D RTest test(_L("T_MISC"));
 
+const TUint KBufLength = 0x100;
+
 LOCAL_C void Test1()
 //
 // Open, write to and read from a file
@@ -722,7 +729,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
@@ -828,9 +837,11 @@
     nRes = CreateEmptyFile(TheFs, fileName, KFileSize);
     test(nRes == KErrNone);
 
+#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);
+#endif
 
     //-- 1.2 delete the empty file
     nRes = TheFs.Delete(fileName);
@@ -1238,7 +1249,6 @@
     RFile   file;
 
 	//-- create a buffer with some data
-	const TUint KBufLength = 0x100;
 	TBuf8<KBufLength> buffer;
 	buffer.SetLength(KBufLength);
 
@@ -1289,7 +1299,6 @@
 	TInt    nRes = KErrNone;
     RFile   file;
 
-	const TInt KBufLength = 0x100;
 	TBuf8<KBufLength> buffer;
     buffer.SetLength(0);
 
@@ -1311,6 +1320,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 +1339,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/kerneltest/f32test/server/t_rcache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_rcache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -434,7 +434,7 @@
 
 	// delete file first to ensure it's contents are not in the cache (file may be be on the closed file queue)
 	r = fs.Delete(aFile);
-	test(r == KErrNone || r == KErrNotFound);
+	test_Value(r, r == KErrNone || r == KErrNotFound);
 
 	r = aFileWrite.Replace(fs,aFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
 	test_KErrNone(r);
@@ -556,7 +556,7 @@
 	RFile file;
 
 	TInt r = fs.Connect();
-	test (r == KErrNone);
+	test_KErrNone(r);
 
 	startTime.HomeTime();
 
@@ -695,7 +695,7 @@
 #endif
 
 	r = DeleteAll(gSessionPath);
-	test(r == KErrNone || r == KErrInUse);
+	test_Value(r, r == KErrNone || r == KErrInUse);
 
 	// Simple case filling/reading the cache from different threads
 	test.Next(_L("File fits in: read sync (another thread) + read sync + read async\n"));
@@ -715,7 +715,7 @@
 
 	buf = _L("Read File");
 	r = gThread2.Create(buf,ReadFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
-	test(r == KErrNone);
+	test_KErrNone(r);
 
 	gThread2.Resume();
 	client.Wait();
@@ -737,7 +737,7 @@
 #endif
 
 	r = DeleteAll(gSessionPath);
-	test(r == KErrNone || r == KErrInUse);
+	test_Value(r, r == KErrNone || r == KErrInUse);
 
 
 	test.Next(_L("File doesn't fit in: read sync + read sync + read async\n"));
@@ -760,7 +760,7 @@
 
 
 	r = DeleteAll(gSessionPath);
-	test(r == KErrNone || r == KErrInUse);
+	test_Value(r, r == KErrNone || r == KErrInUse);
 
 
 	test.Next(_L("File doesn't fit in: read sync (another thread) + read sync + read async\n"));
@@ -780,7 +780,7 @@
 
 	buf = _L("Read Big File");
 	r = gThread2.Create(buf,ReadFileT,KDefaultStackSize,KHeapSize,KMaxHeapSize,NULL);
-	test(r == KErrNone);
+	test_KErrNone(r);
 
 	gThread2.Resume();
 	client.Wait();
@@ -802,7 +802,7 @@
 	#endif
 
 	r = DeleteAll(gSessionPath);
-	test(r == KErrNone || r == KErrInUse);
+	test_Value(r, r == KErrNone || r == KErrInUse);
 
 	test.End();
 }
@@ -823,13 +823,13 @@
 	test(res2 == KErrNone && lBufSec != NULL);
 	lBufReadPtr.Set(lBufSec->Des());
 
-	test(r == KErrNone);
+	test_KErrNone(r);
 	r = fs.SetSessionPath(gSessionPath);
 
 
 	// delete file first to ensure it's contents are not in the cache (file may be be on the closed file queue)
 	r = fs.Delete(gFirstFile);
-	test(r == KErrNone || r == KErrNotFound);
+	test_Value(r, r == KErrNone || r == KErrNotFound);
 
 	r = file.Create(fs,gFirstFile,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
 
@@ -944,7 +944,7 @@
 
 	TBuf<20> buf2 = _L("Write Two Files 2");
 	r = gThread2.Create(buf2,WriteFileT2,KDefaultStackSize*2,KHeapSize,KMaxHeapSize,NULL);
-	test(r == KErrNone);
+	test_KErrNone(r);
 
 	gThread1.Resume();
 	gThread2.Resume();
@@ -984,10 +984,10 @@
 	RTest test(_L("T_RCACHE"));
 	RFs fs;
 	TInt r = fs.Connect();
-	test(r == KErrNone);
+	test_KErrNone(r);
 
 	r = fs.SetSessionPath(gSessionPath);
-	test(r == KErrNone);
+	test_KErrNone(r);
 
 	r = WriteFile(fs, gSecondFile, gSecondFileSize, KBlockSize, gBufWritePtr, EThreadSignal);
 	test_KErrNone(r);
@@ -1069,7 +1069,7 @@
 	TPtr8 dummyPtr(NULL, 0);
 
 	TRAPD(res,dummy = HBufC8::NewL(4));
-	test(res == KErrNone && dummy != NULL);
+	test_Value(res, res== KErrNone && dummy != NULL);
 
 	dummyPtr.Set(dummy->Des());
 	FillBuffer(dummyPtr, 4, '1');
@@ -1297,7 +1297,7 @@
 	HBufC8* bigBuf = NULL;
 	const TInt KBigBifferSize = 32 * 1024;
 	TRAPD(res,bigBuf = HBufC8::NewL(KBigBifferSize));
-	test(res == KErrNone && bigBuf != NULL);
+	test_Value(res, res== KErrNone && bigBuf != NULL);
 
 	TPtr8 bigBufWritePtr(NULL, 0);
 	bigBufWritePtr.Set(bigBuf->Des());
@@ -1315,7 +1315,7 @@
 
 		// delete file first to ensure it's contents are not in the cache (file may be on the closed file queue)
 		r = TheFs.Delete(path);
-		test(r == KErrNone || r == KErrNotFound);
+		test_Value(r, r == KErrNone || r == KErrNotFound);
 
 		r = file.Create(TheFs,path,EFileShareAny|EFileWrite|EFileReadDirectIO|EFileWriteDirectIO);
 		if(r == KErrAlreadyExists)
@@ -1353,7 +1353,7 @@
 	TPtr8 bufPtr(NULL, 0);
 
 	TRAPD(res,buf = HBufC8::NewL(2));
-	test(res == KErrNone && buf != NULL);
+	test_Value(res, res== KErrNone && buf != NULL);
 	bufPtr.Set(buf->Des());
 
 	directory = gSessionPath;
@@ -1399,7 +1399,7 @@
 		// get number of items on Page Cache
 		TFileCacheStats startPageCacheStats;
 		TInt r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, startPageCacheStats);
-		test(r==KErrNone || r == KErrNotSupported);
+		test_Value(r, r == KErrNone || r == KErrNotSupported);
 		test.Printf(_L("Number of page cache lines on free list at beginning=%d\n"),startPageCacheStats.iFreeCount);
 		test.Printf(_L("Number of page cache lines on used list at beginning=%d\n"),startPageCacheStats.iUsedCount);
 		test.Printf(_L("Number of files on closed queue=%d\n"),startPageCacheStats.iFilesOnClosedQueue);
@@ -1409,7 +1409,7 @@
 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
 		// get number of items on Page Cache
 		r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, startPageCacheStats);
-		test(r==KErrNone || r == KErrNotSupported);
+		test_Value(r, r == KErrNone || r == KErrNotSupported);
 		test.Printf(_L("Number of page cache lines on free list at end=%d\n"),startPageCacheStats.iFreeCount);
 		test.Printf(_L("Number of page cache lines on used list at end=%d\n"),startPageCacheStats.iUsedCount);
 		test.Printf(_L("Number of files on closed queue=%d\n"),startPageCacheStats.iFilesOnClosedQueue);
@@ -1446,7 +1446,7 @@
 
 */
 LOCAL_C void TestReadAhead()
-{
+	{
 	TInt r = 0,tcreate;
 	RFile fileRead;
 	HBufC8* dummy = NULL;
@@ -1454,33 +1454,11 @@
 
 	TUint32 initTicks = 0;
 	TUint32 finalTicks = 0;
-	TTimeIntervalMicroSeconds timeTakenReadFirst(0);
-	TTimeIntervalMicroSeconds timeTakenReadSubsequent(0);
-
-	// On NAND/FAT and NOR/LFFS drives, due to the lack of DMA support, the read-ahead is likely to happen
-	// BEFORE control is returned to this test app - for NAND this could be fixed by adding
-	// "FileCacheReadAsync OFF" to the estart.txt file, but we can't do this on the integrator as it has no
-	// estart.txt file. Also, we can't set "FileCacheReadAsync OFF" for LFFS as it kills the LFFS background
-	// processing (!)
-	// So... it's only really worth testing on MMC.
-	_LIT(KFATName,"FAT");
-	TDriveInfo driveInfo;
-	test(TheFs.Drive(driveInfo, gDrive) == KErrNone);
-	TFileName fileSystem;
-	r = TheFs.FileSystemName(fileSystem, gDrive);
-	fileSystem.UpperCase();
-	test((r==KErrNone)||(r==KErrNotFound));
-	// ONLY test on MMC
-	if ((driveInfo.iType != EMediaHardDisk) || (fileSystem.Compare(KFATName) != 0))
-		{
-		test.Printf(_L("Skipping read-ahead testing (drive is not MMC)...\n"));
-		return;
-		}
 
 	//--Find out if the drive is sync/async at this point and print information
     TPckgBuf<TBool> drvSyncBuf;
     r = TheFs.QueryVolumeInfoExt(gDrive, EIsDriveSync, drvSyncBuf);
-    test(r == KErrNone);
+    test_KErrNone(r);
 	const TBool bDrvSync = drvSyncBuf();
     if(bDrvSync)
 		test.Printf(_L("Drive D: is synchronous\n"));
@@ -1490,7 +1468,7 @@
 	// use a fast counter as this is more accurate than using TTime
 	TInt fastCounterFreq;
 	r = HAL::Get(HAL::EFastCounterFrequency, fastCounterFreq);
-	test(r == KErrNone);
+	test_KErrNone(r);
 	test.Printf(_L("HAL::EFastCounterFrequency %d\n"), fastCounterFreq);
 
 	// Bind this thread to CPU 0. This is so that timer deltas don't drift from
@@ -1501,7 +1479,7 @@
 	const TInt KReadLen = 28 * KOneK;
 
 	TRAPD(res,dummy = HBufC8::NewL(KReadLen));
-	test(res == KErrNone && dummy != NULL);
+	test_Value(res, res== KErrNone && dummy != NULL);
 
 	dummyPtr.Set(dummy->Des());
 
@@ -1514,82 +1492,81 @@
 	r = fileRead.Open(TheFs,gFirstFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOn);
 	test_KErrNone(r);
 
-	// Read #1
-	test.Printf(_L("Issuing read #1...\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+	TFileCacheStats fileCacheStats;
+	r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, fileCacheStats);
 	test_KErrNone(r);
+	TInt totalBytesRead = fileCacheStats.iUncachedBytesRead;
+	test.Printf(_L("totalBytesRead %d\n"), totalBytesRead);
+	TInt bytesRead = 0;
+	TInt filePos = 0;
+#endif
 
-	timeTakenReadFirst = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("first read time %d \n"), I64LOW(timeTakenReadFirst.Int64()));
+	const TInt KReadCount = 6;
+	#define	PAGE_ROUND_UP(x) ((x + 4095) & (-4096))
+	TInt expectedBytesRead[KReadCount] = 
+		{
+		PAGE_ROUND_UP(KReadLen),	// read #0 from media
+		PAGE_ROUND_UP(KReadLen),	// read #1 from media
+		PAGE_ROUND_UP(KReadLen*2),	// read #2 from media, read-ahead #1 of length KReadLen
+		PAGE_ROUND_UP(KReadLen*2),	// read #3 from cache, read-ahead #2 of length KReadLen * 2
+		PAGE_ROUND_UP(KReadLen*4),	// read #4 from cache, read-ahead #3 of length KReadLen * 4
+		0,							// read #5 from cache, no read-ahead
+		};
+	TTimeIntervalMicroSeconds readTimes[KReadCount];
 
-	// Read #2
-	test.Printf(_L("Issuing read #2...\n"));
-	r = fileRead.Read(dummyPtr);
+	for (TInt n=0; n<KReadCount; n++)
+		{
+
+		initTicks = User::FastCounter();
+		r = fileRead.Read(dummyPtr);
+		finalTicks = User::FastCounter();
+		test_KErrNone(r);
 
-	// Read #3
-	test.Printf(_L("Issuing read #3......resulting in read-ahead #1\n"));
-	r = fileRead.Read(dummyPtr);
+		readTimes[n] = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
+		test.Printf(_L("%d: read time %d \n"), n, I64LOW(readTimes[n].Int64()));
 
-	// Wait for the read ahead #1 to be done - this should be approx the same size as previous read (KReadLen)
-	test.Printf(_L("Wait for read-ahead #1...\n"));
-	User::After(I64LOW(timeTakenReadFirst.Int64()) * 3 / 2);
-
+		TInt readAheadTime = I64LOW(readTimes[0].Int64()) * expectedBytesRead[n] / expectedBytesRead[0];
+		// Wait for the read ahead to be done 
+		if (n >= 2)
+			{
+			test.Printf(_L("Wait %u uS for read-ahead ...\n"), readAheadTime);
+			User::After(readAheadTime);
+			}
 
-	test.Printf(_L("Issuing read #4...resulting in read-ahead #2\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+		// check the number of bytes read from the media is as expected. i.e. including the read-ahead length
+		// Keep waiting if it's not for up to 10 seconds
+		const TInt KMaxWaitTime = 10000000;	// 10 secs
+		TInt waitTime;
+		for (waitTime=0; waitTime <KMaxWaitTime; waitTime+= readAheadTime)
+			{
+			r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, fileCacheStats);
+			test_KErrNone(r);
+			bytesRead = fileCacheStats.iUncachedBytesRead - totalBytesRead;
+			TInt bytesReadExpected = Min(gFirstFileSize - filePos, expectedBytesRead[n]);
 
-	test.Printf(_L("read time:  %d \n"), I64LOW(timeTakenReadSubsequent.Int64()));
+			test.Printf(_L("bytesRead %d, bytesReadExpected %d\n"), bytesRead, bytesReadExpected);
+
+			if (bytesRead == bytesReadExpected)
+				break;
+			User::After(readAheadTime);
+			}
+		test(waitTime < KMaxWaitTime);
+		totalBytesRead+= bytesRead;
+		filePos += bytesRead;
+#endif
 
 #if !defined(__WINS__)
-	// NB the read-ahead on LFFS occurs "synchronously" i.e. it occurs before control is returned
-	// to the caller. However it's not a good idea to mark the drive as synchronous (FileCacheReadAsync OFF)
-	// as this causes the drive thread's priority to be lowered which kills the LFFS background processing (!)
-	if (gPagedRom)
-		test.Printf(_L("Skipping timing test on paged ROM\n"));
-	else
-		test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
+		// Read #3 should be able to be satisfied entirely from the cache, so should be quicker. If it's not quicker,
+		// display a warning rather than failing, because the read-ahead might be hogging the CPU, delaying the read from the cache.
+		if (n >= 3)
+			{
+			if (readTimes[n].Int64() >= readTimes[0].Int64())
+				test.Printf(_L("WARNING: Subsequent read not faster despite read-ahead !!!\n"));
+			}
 #endif
-
-	// The read ahead #2 should now be in progress - this should be approx KReadLen * 2
-	// so this read will take result in the next read taking longer than normal (about double)
-	test.Printf(_L("Issuing read #5......resulting in read-ahead #3\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("read time:  %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
-
-
-	// this read should take a long time, so don't test
-//#if !defined(__WINS__)
-//	test(gTimeTakenReadBlockFile.Int64() < gTimeTakenBigFile.Int64());
-//#endif
-
-	// The third read should be very quick as the previous read-ahead should have already buffered the data
-	test.Printf(_L("Issuing read #6......resulting in read-ahead #4\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("read time:  %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
-
-
-#if !defined(__WINS__)
-	if (gPagedRom)
-		test.Printf(_L("Skipping timing test on paged ROM\n"));
-	else
-		test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
-#endif
-
-
+		}
 	fileRead.Close();
 
 	r = DeleteAll(gSessionPath);
@@ -1597,8 +1574,7 @@
 
 	delete dummy;
 	test.End();
-
-}
+	}
 
 /** Main tests function
 */
@@ -1609,7 +1585,7 @@
 	// turn OFF lock failure mode
 	TBool simulatelockFailureMode = EFalse;
 	TInt r = controlIo(TheFs, gDrive, KControlIoSimulateLockFailureMode, simulatelockFailureMode);
-	test (r == KErrNone);
+	test_KErrNone(r);
 #endif
 
 	TBuf16<45> dir;
@@ -1629,7 +1605,7 @@
 
 
 	TRAPD(res,gBuf = HBufC8::NewL(KBlockSize+1));
-	test(res == KErrNone && gBuf != NULL);
+	test_Value(res, res== KErrNone && gBuf != NULL);
 
 	gBufWritePtr.Set(gBuf->Des());
 	FillBuffer(gBufWritePtr, KBlockSize, 'A');
@@ -1664,7 +1640,7 @@
 	// turn lock failure mode back ON (if enabled)
 	simulatelockFailureMode = ETrue;
 	r = controlIo(TheFs, gDrive, KControlIoSimulateLockFailureMode, simulatelockFailureMode);
-	test (r == KErrNone);
+	test_KErrNone(r);
 #endif
 
 	}
--- a/kerneltest/f32test/server/t_sysbin.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/kerneltest/f32test/server/t_sysbin.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -344,6 +344,14 @@
 
 		test.End();
 
+	// All files on the emulator's Z: drive have the KEntryAttReadOnly flag set
+	// This flag will have been copied to the C: drive, so we need to remove this before calling CFileMan::RmDir()
+#ifdef __WINS__
+	r = TheFs.SetAtt(KDllCInCTest, 0, KEntryAttReadOnly);
+	test_KErrNone(r);
+#endif
+
+
 	_LIT(KCTestPath,"c:\\sysbin_test\\");
 	r = TheFileMan->RmDir(KCTestPath);
 	test_KErrNone(r);
@@ -381,6 +389,14 @@
 
 		test.End();
 
+	// All files on the emulator's Z: drive have the KEntryAttReadOnly flag set
+	// This flag will have been copied to the C: drive, so we need to remove this before calling CFileMan::RmDir()
+#ifdef __WINS__
+	r = TheFs.SetAtt(KDllDInCSysBinTest, 0, KEntryAttReadOnly);
+	test_KErrNone(r);
+#endif
+
+
 	_LIT(KCTestPath2,"c:\\sys\\bin\\test\\");
 	r = TheFileMan->RmDir(KCTestPath2);
 	test_KErrNone(r);
--- a/userlibandfileserver/domainmgr/src/domaincli.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/domainmgr/src/domaincli.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
 // under the terms of the License "Eclipse Public License v1.0"
@@ -19,6 +19,7 @@
 #include <e32base_private.h>
 #include <e32property.h>
 
+
 #include <domainmember.h>
 #include <domainmanager.h>
 #include "domainobserver.h"
@@ -380,26 +381,43 @@
 	{
 	__DM_ASSERT(Handle() != KNullHandle);
 
+	
 	aTransitionFailures.Reset();
 
 	TInt err = KErrNone;
-
+		
 	TInt failureCount = GetTransitionFailureCount();
 	if (failureCount <= 0)
 		return failureCount;
-
+	
+	// Pre-allocate array with a known size which for this case is the value in failureCount 
+	// in order to guarantee that future append operations to the array aTransitionFailures would
+	// not fail. This is assuming that the pre-allocated size is not exceeded.
+	err=aTransitionFailures.Reserve(failureCount); 
+	if (err != KErrNone)
+		return err;
+		
 	TTransitionFailure* failures = new TTransitionFailure[failureCount];
 	if(failures == NULL)
+		{		
+		aTransitionFailures.Reset();
 		return(KErrNoMemory);
+		}
+	
 	TPtr8 dataPtr(reinterpret_cast<TUint8*>(failures), failureCount * sizeof(TTransitionFailure));
 
 	TIpcArgs a(&dataPtr);
 	err = RSessionBase::SendReceive(EDmGetTransitionFailures, a);
-	
+
 	if (err == KErrNone)
 		{
-		for (TInt i=0; i<failureCount; i++)
-			aTransitionFailures.Append(failures[i]);
+		for (TInt i=0; i<failureCount; i++)	
+			{
+			err = aTransitionFailures.Append(failures[i]);		
+			//The pre-allocation made above for the array aTransitionFailures should guarantee
+			//that append operations complete succesfully.			
+			__DM_ASSERT(err == KErrNone);	
+			}
 		}
 
 	delete [] failures;
@@ -439,19 +457,34 @@
 	if (count <= 0)
 		return KErrGeneral;
 
+	// Pre-allocate array with a known size which for this case is the value in count 
+	// in order to guarantee that future append operations to the array aTransitionFailures 
+	// would not fail. This is assuming that the pre-allocated size is not exceeded.
+	TInt ret=aTransitions.Reserve(count); 
+	if (ret != KErrNone)
+		return ret;
+
 	TTransInfo* trans = new TTransInfo[count];
 	if(trans == NULL)
+		{
+		aTransitions.Reset();
 		return(KErrNoMemory);
+		}
 	
 	TPtr8 dataPtr(reinterpret_cast<TUint8*>(trans), count * sizeof(TTransInfo));
 
 	TIpcArgs a(&dataPtr);
-	TInt ret=RSessionBase::SendReceive(EDmObserverGetEvent, a);
+	ret=RSessionBase::SendReceive(EDmObserverGetEvent, a);
 	
 	if(ret==KErrNone)
 		{
 		for (TInt i=0; i<count; i++)
-			aTransitions.Append(trans[i]);
+			{
+			ret = aTransitions.Append(trans[i]);					
+			//The pre-allocation made above for the array aTransitions should guarantee
+			//that append operations complete succesfully.
+			__DM_ASSERT(ret == KErrNone);					
+			}
 		}
 	
 	delete [] trans;
--- a/userlibandfileserver/fileserver/bmarm/efileu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/bmarm/efileu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -240,4 +240,5 @@
 	DriveInfo__C11CFileSystemR10TDriveInfoi @ 239 NONAME R3UNUSED ; CFileSystem::DriveInfo(TDriveInfo &, int) const
 	GetDriveInfo__FR10TDriveInfoi @ 240 NONAME R3UNUSED ; GetDriveInfo(TDriveInfo &, int)
 	Volume__C9RFsPluginR11TVolumeInfoi @ 241 NONAME R3UNUSED ; RFsPlugin::Volume(TVolumeInfo &, int) const
+	DirectIOMode__7CFileCBRC12RMessagePtr2 @ 242 NONAME R3UNUSED ; CFileCB::DirectIOMode(RMessagePtr2 const &)
 
--- a/userlibandfileserver/fileserver/bwins/efileu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/bwins/efileu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -241,3 +241,5 @@
 	?DriveInfo@CFileSystem@@UBEXAAVTDriveInfo@@H@Z @ 240 NONAME ; void CFileSystem::DriveInfo(class TDriveInfo &, int) const
 	?GetDriveInfo@@YAXAAVTDriveInfo@@H@Z @ 241 NONAME ; void GetDriveInfo(class TDriveInfo &, int)
 	?Volume@RFsPlugin@@QBEHAAVTVolumeInfo@@H@Z @ 242 NONAME ; int RFsPlugin::Volume(class TVolumeInfo &, int) const
+	?DirectIOMode@CFileCB@@QAEHABVRMessagePtr2@@@Z @ 243 NONAME ; int CFileCB::DirectIOMode(class RMessagePtr2 const &)
+
--- a/userlibandfileserver/fileserver/bx86/efileu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/bx86/efileu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -241,3 +241,4 @@
 	?DriveInfo@CFileSystem@@UBEXAAVTDriveInfo@@H@Z @ 240 NONAME ; public: virtual void __thiscall CFileSystem::DriveInfo(class TDriveInfo &,int)const 
 	?GetDriveInfo@@YAXAAVTDriveInfo@@H@Z @ 241 NONAME ; void __cdecl GetDriveInfo(class TDriveInfo &,int)
 	?Volume@RFsPlugin@@QBEHAAVTVolumeInfo@@H@Z @ 242 NONAME ; public: int __thiscall RFsPlugin::Volume(class TVolumeInfo &,int)const 
+	?DirectIOMode@CFileCB@@QAEHABVRMessagePtr2@@@Z @ 243 NONAME ; int CFileCB::DirectIOMode(class RMessagePtr2 const &)
\ No newline at end of file
--- a/userlibandfileserver/fileserver/eabi/efileu.def	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/eabi/efileu.def	Thu Aug 19 11:14:22 2010 +0300
@@ -313,3 +313,5 @@
 	_Z12GetDriveInfoR10TDriveInfoi @ 312 NONAME
 	_ZNK11CFileSystem9DriveInfoER10TDriveInfoi @ 313 NONAME
 	_ZNK9RFsPlugin6VolumeER11TVolumeInfoi @ 314 NONAME
+	_ZN7CFileCB12DirectIOModeERK12RMessagePtr2 @ 315 NONAME
+
--- a/userlibandfileserver/fileserver/etshell/ts_com.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/etshell/ts_com.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -31,14 +31,17 @@
 #include <nkern/nk_trace.h>
 #include "filesystem_fat.h"
 
+_LIT(KCrNl, "\r\n");
+_LIT(KNl, "\n");
+
     TPtrC ptrFormatHelp=_L("Drive:[\\] [fat12|fat16|fat32] [spc:X] [rs:Y] [ft:Z] [/Q][/S][/E][/F]\nfat12 or fat16 or fat32 specifies explicit FAT type\nspc:X specifies \"X\" sectors per cluster\nrs:Y specifies \"Y\" reserved sectors\nft:Z specifies \"Z\" FAT tables (1 or 2)\n\n/q - QuickFormat, /s - SpecialFormat, /e - ForcedErase\n/f - force formatting (ignore volume being in use)");
-    TPtrC ptrMountHelp=_L("Drive:[\\]  <fsy:X> <fs:Y> [pext:Z] [/S][/U][/F][/R]\n'X' *.fsy module name, like elocal.fsy\n'Y' file system name, like 'FAT'\n'Z' optional primary extension module name\n/U - dismount FS from the drive e.g 'mount d: /u' \n/F - force mounting with dismounting existing FS \n/S - mount drive as synchronous\n/R - remount the file system ");
-
+TPtrC ptrMountHelp=_L("Drive:[\\]  <fsy:X> <fs:Y> [pext:Z] [/S][/U][/F][/R]\n'X' *.fsy module name, like elocal.fsy\n'Y' file system name, like 'FAT'\n'Z' optional primary extension module name\n/U - dismount FS from the drive e.g 'mount d: /u' \n/U /F force dismounting the FS even if there are opened files on it \n/F - force mounting with dismounting existing FS \n/S - mount drive as synchronous\n/R - remount the file system ");
+
+TBool CShell::iDbgPrint = EFalse;
 
 //	lint -e40,e30
 const TShellCommand CShell::iCommand[ENoShellCommands]=
 	{
-//	TShellCommand(_L("BLANK"),_L("Help"),_L("-?"),TShellCommand::EDSwitch,ShellFunction::BLANK),
 	TShellCommand(_L("ATTRIB"),_L("Displays or changes file attributes"),_L("[drive:][path][filename] [+R | -R] [+H |-H] [+S | -S] [+A | -A] [/p]\n\n  /p - Pause after each screen of information"), TShellCommand::EPSwitch, ShellFunction::Attrib),
 	TShellCommand(_L("CD"),_L("Change the current directory for a drive"),_L("[path] [/d]\n\n  /d - Change drive"),TShellCommand::EDSwitch,ShellFunction::Cd),
 	TShellCommand(_L("CHKDEPS"),_L("Check the dependencies of an executable or a Dll (ARM only)"),_L("[Filename.EXE] or [Filename.DLL]"),0,ShellFunction::ChkDeps),
@@ -46,7 +49,6 @@
 	TShellCommand(_L("COPY"),_L("Copy one (or more) file(s), overwriting existing one(s)"),_L("source [destination]"),TShellCommand::ESSwitch,ShellFunction::Copy),
 	TShellCommand(_L("DEL"),_L("Delete one file"),_L("[drive:][path][filename]"),TShellCommand::ESSwitch,ShellFunction::Del),
 	TShellCommand(_L("DIR"),_L("Show directory contents"),_L("[drive:][path][filename] [/p][/w]\n\n  /p - Pause after each screen of information\n  /w - Wide format"),TShellCommand::EPSwitch|TShellCommand::EWSwitch|TShellCommand::EASwitch,ShellFunction::Dir),
-//	TShellCommand(_L("EDLIN"),_L("Edit a text file"),_L("[drive:][path][filename] [/p]\n\n  /p - Pause after each screen of information"),TShellCommand::EPSwitch,ShellFunction::Edit),
     TShellCommand(_L("FORMAT"),_L("Format a disk"),ptrFormatHelp,TShellCommand::EQSwitch|TShellCommand::ESSwitch|TShellCommand::EESwitch|TShellCommand::EFSwitch,ShellFunction::Format),
     TShellCommand(_L("GOBBLE"),_L("Create a file"),_L("[filename] size [/e]\n\n /e - create an empty file, without writing any data"),TShellCommand::EESwitch,ShellFunction::Gobble),
 	TShellCommand(_L("HEXDUMP"),_L("Display the contents of a file in hexadecimal"),_L("[drive:][path][filename] [/p]\n\n  /p - Pause after each screen of information\n\n  Hit escape to exit from hexdump "),TShellCommand::EPSwitch,ShellFunction::Hexdump),
@@ -71,7 +73,7 @@
     TShellCommand(_L("DRVINFO"),_L("Print information about present drive(s) in the system"),_L("[DriveLetter:[\\]] [/p]\n/p - pause after each drive"),TShellCommand::EPSwitch,ShellFunction::DrvInfo),
 	TShellCommand(_L("SYSINFO"),_L("Print information about system features and status"),_L(""),0,ShellFunction::SysInfo),
     TShellCommand(_L("MOUNT"),_L("Mount / dismount file system on specified drive"),ptrMountHelp,TShellCommand::EUSwitch|TShellCommand::ESSwitch|TShellCommand::EFSwitch|TShellCommand::ERSwitch,ShellFunction::MountFileSystem),
-    TShellCommand(_L("ECHO"),_L("Print out the command line to the console and standard debug port."),_L("[line to print out]"),0,ShellFunction::ConsoleEcho),
+    TShellCommand(_L("ECHO"),_L("Print out the command line to the console and standard debug port."),_L("[line to print out] [/Y/N]\n /Y turn ON copying console output to debug port\n /N turn it OFF "),TShellCommand::EYSwitch|TShellCommand::ENSwitch,ShellFunction::ConsoleEcho),
 	TShellCommand(_L("RUNEXEC"),_L("Run a program in a loop"),_L("count filename[.exe] [/E/S/R]\n	/E - exit early on error\n	/S - count in seconds\n	     zero - run forever\n	/R - reset debug regs after each run"),TShellCommand::EESwitch|TShellCommand::ESSwitch|TShellCommand::ERSwitch,ShellFunction::RunExec),
 
     };
@@ -80,10 +82,9 @@
 LOCAL_C TInt pswd_DrvNbr(TDes &aPath, TInt &aDN);
 LOCAL_C TInt pswd_Password(TDes &aPath, TInt aPWNbr, TMediaPassword &aPW);
 
-_LIT(KLitNewLine,"\n");
 void CShell::NewLine()
 	{
-	TheConsole->Printf(KLitNewLine());
+	Printf(KNl);
 	}
 
 //
@@ -363,10 +364,11 @@
 	    if (nRes<0)
 		    return(nRes);
 
+	    //-- this is, actually, FAT FS specific error codes. Other file systems can report different values.
 	    switch(nRes)
 		    {
 	    case 0:
-		    CShell::TheConsole->Printf(_L("Complete - no errors\n"));
+		    CShell::TheConsole->Printf(_L("Completed - no errors found\n"));
 		    break;
 	    case 1:
 		    CShell::TheConsole->Printf(_L("Error - File cluster chain contains a bad value (<2 or >maxCluster)\n"));
@@ -494,13 +496,15 @@
 	TInt r=CShell::TheFs.CharToDrive(CShell::currentPath[0], drive);
 	if (r!=KErrNone)
 		return(r);
+	
 	if (aPath.Length()==0)
 		{
 		r=CShell::TheFs.Volume(vol, drive);
 		if (r==KErrNone)
-			CShell::TheConsole->Printf(_L("Volume = %S\n"),&vol.iName);
+			CShell::Printf(_L("Volume Label:%S\n"),&vol.iName);
 		return(r);
 		}
+	
 	r=CShell::TheFs.SetVolumeLabel(aPath, drive);
 	return(r);
 	}
@@ -578,21 +582,39 @@
 
 }
 
-
-void ShellFunction::OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches)
-//outputs content of the buffer to console according to settings passed in aSwitches
+/**
+    outputs content of the buffer to console according to settings passed in aSwitches
+    @return ETrue if the user pressed Esc key 
+*/
+TBool ShellFunction::OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches)
 	{
 	if ((aText.Count()>0)&&((aSwitches&TShellCommand::EWSwitch)!=0))
 		AlignTextIntoColumns(aText);
 
-	for (TInt i=0;i<aText.Count();i++)
-		{
-		CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),*aText[i]);
-		CShell::OutputStringToConsole(EFalse,_L("\n"));
+	TKeyCode key=EKeyNull;
+    TInt i;
+
+    for(i=0;i<aText.Count();i++)
+		{                                             
+		key = CShell::WriteBufToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),*aText[i]);
+		if(key == EKeyEscape)
+            break;
+        
+        key = CShell::WriteBufToConsole(EFalse,_L("\n"));
+		if(key == EKeyEscape)
+            break;
+
+		}
+    
+    //-- clean up string array
+    for(i=0; i<aText.Count(); i++)
+        {
 		delete aText[i];
 		}
-	//empty string array
+	
 	aText.Reset();
+
+    return (key == EKeyEscape);
 	}
 
 
@@ -602,6 +624,7 @@
 	TInt count=aDirList->Count();
 	TInt fileCount=0, dirCount=0, printCount=0;
 	TInt64 byteCount=0;
+    TBool bBreak=EFalse;
 
 	//compose an array of strings describing entries in the directory
 	for (TInt j=0;j<count;j++)
@@ -637,42 +660,76 @@
 			TPtr name=buf->Des();
 			name=entry.iName;
 
+            const TPtrC desName(entry.iName);
+            const TBool bNameCut = desName.Length() > 26;
+
+            _LIT(KDots, ">.."); //-- will be displayed if the name is longer than 26 characters
+            _LIT(KSpc,  "   ");
+			
+            
 			if (entry.IsDir())
 				{
 				dirCount++;
-				name.Format(_L(" %- 26S   <DIR>         %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
-											&entry.iName,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+				
+                name.Format(_L(" %- 26S%S<DIR>         %+02d/%+02d/%- 4d  %02d:%02d:%02d.%03d"),
+				    &desName,
+                    bNameCut ? &KDots : &KSpc,
+                    modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+				
+                //name.Format(_L(" %- 26S   <DIR>         %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
+				//							&entry.iName,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
 				}
 			else
 				{
 				TInt64 entrySize = entry.FileSize();
 				byteCount+=entrySize;
 				fileCount++;
- 				name.Format(_L(" %- 32S%+ 15Lu   %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
- 											&entry.iName,entrySize,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+
+                name.Format(_L(" %- 26S%S%-11Lu   %+02d/%+02d/%- 4d  %02d:%02d:%02d.%03d"),
+ 				    &desName,
+                    bNameCut ? &KDots : &KSpc,
+                    entrySize,
+                    modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+ 				
+                //name.Format(_L(" %- 32S%+ 15Lu   %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
+ 				//							&entry.iName,entrySize,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
 				}
 			}
 		User::LeaveIfError(aText.Append(buf ));
 		printCount++;
+		
 		//print the contents if a screen size of data is available. This will prevent huge buffer allocation.
 		if(printCount == CShell::TheConsole->ScreenSize().iHeight)
 			{
-			OutputContentsToConsole(aText,aSwitches);
+			bBreak = OutputContentsToConsole(aText,aSwitches);
 			printCount=0;
 			}
+		
 		CleanupStack::Pop();
 
+        if(bBreak)
+            break;    
 		}
+	
+    if(bBreak)
+        return; //-- the user has interrupted the listing
+
+    
 	OutputContentsToConsole(aText,aSwitches);
 
-	//output summary information
-	CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("    %d File%c\n"),fileCount,(fileCount==1)?' ':'s');
-	if (fileCount!=0)
+	//---------------------------------
+    //-- print out summary information
+	TBuf<100> buf;
+    buf.Format(_L("    %d File%c"), fileCount, (fileCount==1) ? ' ':'s');
+    if(fileCount > 0)
 		{
-		CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("  %lu byte%c\n"),byteCount,(fileCount==1)?' ':'s');
+        buf.AppendFormat(_L(", %LU bytes"), byteCount);
 		}
 
-	TBuf<50> buf;// allocate string long enough for additional information(number of directories)
+    buf.Append(KNl);
+    
+    CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0), buf);
+    
 	buf.Format(_L("    %d Director"),dirCount);
 	if (dirCount==1)
 		buf.AppendFormat(_L("y\n"));
@@ -680,6 +737,8 @@
 		buf.AppendFormat(_L("ies\n"));
 
 	CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),buf);
+
+    
 	}
 
 TInt ShellFunction::Dir(TDes& aPath,TUint aSwitches)
@@ -705,7 +764,7 @@
 	TInt r=dir.Open(TheShell->TheFs,aPath,KEntryAttMaskSupported);
 	if (r!=KErrNone)
 		{
-		CShell::TheConsole->Printf(_L("File or directory not found\n"));
+		CShell::Printf(_L("File or directory not found\n"));
 		return(KErrNone);
 		}
 
@@ -720,7 +779,7 @@
 
 	//Sets the new length of path to the position of the last path delimiter +1
 	aPath.SetLength(aPath.LocateReverse(KPathDelimiter)+1);
-	CShell::TheConsole->Printf(_L("Directory of %S\n"),&aPath);
+	CShell::Printf(_L("Directory of %S\n"),&aPath);
 
 	//allocate array to be used as an output buffer
 	RPointerArray<HBufC>* text=new(ELeave) RPointerArray<HBufC>();
@@ -738,13 +797,6 @@
 	};
 
 
-TInt ShellFunction::Edit(TDes& /*aPath*/,TUint /*aSwitches*/)
-//
-//	Dummy, used by edlin (now retired)
-//
-	{
-	return(KErrNone);
-	}
 
 
 TInt ShellFunction::Attrib(TDes& aPath,TUint aSwitches)
@@ -1003,14 +1055,14 @@
         if(aDrvInfo.iDriveAtt & KDriveAttRedirected)    aPrintBuf.Append(_L("KDriveAttRedirected,"));
         if(aDrvInfo.iDriveAtt & KDriveAttSubsted)       aPrintBuf.Append(_L("KDriveAttSubsted,"));
         if(aDrvInfo.iDriveAtt & KDriveAttInternal)      aPrintBuf.Append(_L("KDriveAttInternal,"));
-        if(aDrvInfo.iDriveAtt & KDriveAttRemovable)     aPrintBuf.Append(_L("KDriveAttRemovable"));
-
-        if(aDrvInfo.iDriveAtt & KDriveAttRemote)        aPrintBuf.Append(_L("KDriveAttRemote"));
-        if(aDrvInfo.iDriveAtt & KDriveAttTransaction)   aPrintBuf.Append(_L("KDriveAttTransaction"));
-
-        if(aDrvInfo.iDriveAtt & KDriveAttPageable)              aPrintBuf.Append(_L("KDriveAttPageable"));
-        if(aDrvInfo.iDriveAtt & KDriveAttLogicallyRemovable)    aPrintBuf.Append(_L("KDriveAttLogicallyRemovable"));
-        if(aDrvInfo.iDriveAtt & KDriveAttHidden)                aPrintBuf.Append(_L("KDriveAttHidden"));
+        if(aDrvInfo.iDriveAtt & KDriveAttRemovable)     aPrintBuf.Append(_L("KDriveAttRemovable,"));
+
+        if(aDrvInfo.iDriveAtt & KDriveAttRemote)        aPrintBuf.Append(_L("KDriveAttRemote,"));
+        if(aDrvInfo.iDriveAtt & KDriveAttTransaction)   aPrintBuf.Append(_L("KDriveAttTransaction,"));
+
+        if(aDrvInfo.iDriveAtt & KDriveAttPageable)              aPrintBuf.Append(_L("KDriveAttPageable,"));
+        if(aDrvInfo.iDriveAtt & KDriveAttLogicallyRemovable)    aPrintBuf.Append(_L("KDriveAttLogicallyRemovable,"));
+        if(aDrvInfo.iDriveAtt & KDriveAttHidden)                aPrintBuf.Append(_L("KDriveAttHidden,"));
 
         aPrintBuf.Append(_L("\n"));
     }
@@ -1032,12 +1084,12 @@
         if(aDrvInfo.iMediaAtt & KMediaAttFormattable)       aPrintBuf.Append(_L("KMediaAttFormattable,"));
         if(aDrvInfo.iMediaAtt & KMediaAttWriteProtected)    aPrintBuf.Append(_L("KMediaAttWriteProtected,"));
         if(aDrvInfo.iMediaAtt & KMediaAttLockable)          aPrintBuf.Append(_L("KMediaAttLockable,"));
-        if(aDrvInfo.iMediaAtt & KMediaAttLocked)            aPrintBuf.Append(_L("KMediaAttLocked"));
-
-        if(aDrvInfo.iMediaAtt & KMediaAttHasPassword)       aPrintBuf.Append(_L("KMediaAttHasPassword"));
-        if(aDrvInfo.iMediaAtt & KMediaAttReadWhileWrite)    aPrintBuf.Append(_L("KMediaAttReadWhileWrite"));
-        if(aDrvInfo.iMediaAtt & KMediaAttDeleteNotify)      aPrintBuf.Append(_L("KMediaAttDeleteNotify"));
-        if(aDrvInfo.iMediaAtt & KMediaAttPageable)          aPrintBuf.Append(_L("KMediaAttPageable"));
+        if(aDrvInfo.iMediaAtt & KMediaAttLocked)            aPrintBuf.Append(_L("KMediaAttLocked,"));
+
+        if(aDrvInfo.iMediaAtt & KMediaAttHasPassword)       aPrintBuf.Append(_L("KMediaAttHasPassword,"));
+        if(aDrvInfo.iMediaAtt & KMediaAttReadWhileWrite)    aPrintBuf.Append(_L("KMediaAttReadWhileWrite,"));
+        if(aDrvInfo.iMediaAtt & KMediaAttDeleteNotify)      aPrintBuf.Append(_L("KMediaAttDeleteNotify,"));
+        if(aDrvInfo.iMediaAtt & KMediaAttPageable)          aPrintBuf.Append(_L("KMediaAttPageable,"));
         
 
         aPrintBuf.Append(_L("\n"));
@@ -1053,8 +1105,8 @@
 */
 void FormatVolInfo(const TVolumeInfo& volInfo , TDes& aPrintBuf)
     {
-   	aPrintBuf.Format(_L("VolSz:%ld Free:%ld\n"),volInfo.iSize, volInfo.iFree);
-   	aPrintBuf.AppendFormat(_L("VolId:0x%x VolName:%S\n"),volInfo.iUniqueID, &volInfo.iName);
+   	aPrintBuf.Format(_L("VolSz:%ld Free:%ld"),volInfo.iSize, volInfo.iFree);
+   	aPrintBuf.AppendFormat(_L("\r\nVolId:0x%x VolName:%S\n"),volInfo.iUniqueID, &volInfo.iName);
     }
 
 //--------------------------------------------------------
@@ -1083,7 +1135,7 @@
 
     @return standard error code
 */
-TInt PrintDrvInfo(RFs& aFs, TInt aDrvNum, CConsoleBase* apConsole, TUint aFlags = EAll)
+TInt PrintDrvInfo(RFs& aFs, TInt aDrvNum, TUint aFlags = EAll)
     {
 	TInt        nRes;
 	TDriveInfo 	driveInfo;
@@ -1094,7 +1146,7 @@
 	nRes = aFs.Drive(driveInfo, aDrvNum);
 	if(nRes != KErrNone)
 		{
-		CShell::TheConsole->Printf(_L("Error: %d\n"), nRes);
+        CShell::Printf(_L("Error: %d\n"), nRes);
 		return nRes;   //-- can't get information about the drive
 		}
 
@@ -1103,10 +1155,10 @@
     const TBool bVolumeOK  = (nRes == KErrNone);
 	if(!bVolumeOK)
 	{//-- can't get information about the volume. It might be just corrupt/unformatted
-		CShell::TheConsole->Printf(_L("Error getting volume info. code: %d\n"), nRes);
+        CShell::Printf(_L("Error getting volume info. code: %d\n"), nRes);
         if(nRes == KErrCorrupt)
         {
-            CShell::TheConsole->Printf(_L("The volume might be corrupted or not formatted.\n"));
+            CShell::Printf(_L("The volume might be corrupted or not formatted.\n"));
         }
 	}
 
@@ -1115,14 +1167,14 @@
 	if(aFlags & EFSInfo)
     {
         //-- print out drive properties
-        Buf.Format(_L("\nDrive %c: No:%d"), 'A'+aDrvNum, aDrvNum);
+        Buf.Format(_L("Drive %c: No:%d"), 'A'+aDrvNum, aDrvNum);
         
         //-- find out if the drive is synchronous / asynchronous
         TPckgBuf<TBool> drvSyncBuf;
         nRes = aFs.QueryVolumeInfoExt(aDrvNum, EIsDriveSync, drvSyncBuf);
         if(nRes == KErrNone)
         {
-            Buf.AppendFormat(_L(", Sync:%d"), drvSyncBuf() ? 1:0);        
+            Buf.AppendFormat(_L(" Sync:%d"), drvSyncBuf() ? 1:0);        
         }
 
         //-- find out if drive runs a rugged FS (debug mode only)
@@ -1132,12 +1184,12 @@
         nRes=aFs.ControlIo(aDrvNum, KControlIoIsRugged, pRugged);
         if(nRes == KErrNone)
         {
-            Buf.AppendFormat(_L(", Rugged:%d"), ruggedFS ? 1:0);        
+            Buf.AppendFormat(_L(" Rugged:%d"), ruggedFS ? 1:0);        
         }
 
-        Buf.Append(_L("\n"));
-        apConsole->Printf(Buf);
-
+        CShell::Printf(KNl);
+        Buf.Append(KNl);
+        CShell::Printf(Buf);
 
 	    //-- print the FS name
 	    if(aFs.FileSystemName(Buf, aDrvNum) == KErrNone)
@@ -1157,11 +1209,10 @@
                  Buf.AppendFormat(_L(" PExt:%S"), &fsName);
             }
 
-
-            apConsole->Printf(_L("Mounted FS:%S\n"), &Buf);
-
-            //-- print out the list of supported file systems if there are more than 1
-            nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, 0+1); //-- try to get 2nd child name
+            CShell::Printf(_L("Mounted FS:%S\n"), &Buf);
+
+            //-- print out the list of supported file systems if there are more than 0
+            nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, 0); //-- try to get 1st child name
             if(nRes == KErrNone)
             {
                 Buf.Copy(_L("Supported FS: "));
@@ -1174,8 +1225,8 @@
                     Buf.AppendFormat(_L("%S, "), &fsName);
                 }
             
-                Buf.Append(_L("\n"));
-                apConsole->Printf(Buf);
+                Buf.Append(KNl);
+                CShell::Printf(Buf);
             }
 
 
@@ -1191,9 +1242,9 @@
                 if(nRes == KErrNone)
                 {
                     if(boolPckg() >0)
-                        Buf.Copy(_L("Volume: Finalised"));
+                        Buf.Copy(_L("Vol:Finalised "));
                     else
-                        Buf.Copy(_L("Volume: Not finalised"));
+                        Buf.Copy(_L("Vol:Not finalised "));
                 }
 
                 //-- print out cluster size that FS reported
@@ -1203,23 +1254,23 @@
                 {
                     if(volIoInfo.iBlockSize >= 0)
                     {
-                        Buf.AppendFormat(_L(", BlkSz:%d"), volIoInfo.iBlockSize);
+                        Buf.AppendFormat(_L("BlkSz:%d "), volIoInfo.iBlockSize);
                     }
                     
                     if(volIoInfo.iClusterSize >= 0)
                     {
-                        Buf.AppendFormat(_L(", ClSz:%d"), volIoInfo.iClusterSize);
+                        Buf.AppendFormat(_L("ClSz:%d "), volIoInfo.iClusterSize);
                     }
 
-                    Buf.AppendFormat(_L(", CacheFlags:0x%x"), volInfo.iFileCacheFlags);
+                    Buf.AppendFormat(_L("CacheFlags:0x%x "), volInfo.iFileCacheFlags);
                 
                 }
 
 
                 if(Buf.Length())
                 {
-                    Buf.Append(_L("\n"));
-                    apConsole->Printf(Buf);    
+                    Buf.Append(KNl);
+                    CShell::Printf(Buf);
                 }
 
             }
@@ -1230,22 +1281,21 @@
 	if(aFlags & EMediaTypeInfo)
     {
         FormatDrvMediaTypeInfo(driveInfo, Buf);
-	    apConsole->Printf(Buf);
-
+        CShell::Printf(Buf);
 	}
     
     //-- print drive attributes
 	if(aFlags & EDrvAttInfo)
     {
         FormatDriveAttInfo(driveInfo, Buf);
-	    apConsole->Printf(Buf);
+        CShell::Printf(Buf);
     }
 
     //-- print media attributes
 	if(aFlags & EMediaAttInfo)
     {
 	    FormatMediaAttInfo(driveInfo, Buf);
-	    apConsole->Printf(Buf);
+        CShell::Printf(Buf);
     }
 
 
@@ -1253,7 +1303,7 @@
 	if(bVolumeOK && (aFlags & EVolInfo))
     {
 	    FormatVolInfo(volInfo, Buf);
-	    apConsole->Printf(Buf);
+        CShell::Printf(Buf);
     }
 	
     return KErrNone;
@@ -1324,7 +1374,7 @@
 		nDrv = DoExtractDriveLetter(aArgs);
         if(nDrv < 0)
             {
-            CShell::TheConsole->Printf(_L("Invalid drive specifier!\n"));    
+            CShell::Printf(_L("Invalid drive specification\n"));    
             return KErrNone;
             }
 		}
@@ -1336,7 +1386,7 @@
 	nRes=TheShell->TheFs.DriveList(driveList);
 	if(nRes != KErrNone)
 		{
-		CShell::TheConsole->Printf(_L("\nError: %d"), nRes);
+        CShell::Printf(_L("\nError: %d"), nRes);
 		return nRes;
 		}
 
@@ -1344,11 +1394,11 @@
 		{//-- the drive is specified
 		if(!driveList[nDrv])
 			{
-			CShell::TheConsole->Printf(_L("Invalid drive specification\n"));
+            CShell::Printf(_L("Invalid drive specification\n"));
 			return KErrNone;
 			}
 
-		PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
+		PrintDrvInfo(TheShell->TheFs, nDrv);
 		}
 	else
 		{//-- print information about all drives in the system
@@ -1357,11 +1407,11 @@
 			if(!driveList[nDrv])
 				continue;   //-- skip unexisting drive
 
-			PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
+			PrintDrvInfo(TheShell->TheFs, nDrv);
 
 			if(aSwitches & TShellCommand::EPSwitch)
 				{//-- /p switch, pause after each drive
-				CShell::TheConsole->Printf(_L("\n--- press any key to continue or Esc to exit ---\n"));
+                CShell::Printf(_L("\n--- press any key to continue or Esc to exit ---\n"));
 
 				TKeyCode key = CShell::TheConsole->Getch();
 				if (key==EKeyEscape)
@@ -1369,7 +1419,9 @@
 				}
 			else
 				{
-				CShell::TheConsole->Printf(_L("\n----------\n"));
+				CShell::Printf(_L("\n----------\n"));
+                CShell::Printf(_L("\n--- press any key to continue or Esc to exit ---\n"));
+
 				}
 		}
 	}
@@ -1418,7 +1470,7 @@
 
 
 //-----------------------------------------------------------------------------------------------------------------------
-TInt DoDismountFS(RFs& aFs, TInt aDrvNum)
+TInt DoDismountFS(RFs& aFs, TInt aDrvNum, TBool aForceDismount)
 {
     TInt        nRes;
     TBuf<40>    fsName;
@@ -1428,6 +1480,8 @@
     if(nRes != KErrNone)
         return KErrNotFound;//-- nothing to dismount
         
+    if(!aForceDismount)    
+    {//-- gaceful attempt to dismount the FS
     nRes = aFs.DismountFileSystem(fsName, aDrvNum);
     if(nRes != KErrNone)
     {
@@ -1440,6 +1494,17 @@
     return KErrNone;
     }
 }
+    else
+    {//-- dismount by force
+        TRequestStatus rqStat;
+        aFs.NotifyDismount(aDrvNum, rqStat, EFsDismountForceDismount);  
+        User::WaitForRequest(rqStat);
+        
+        CShell::TheConsole->Printf(_L("'%S' filesystem Forcedly dismounted from drive %c:\n"), &fsName, 'A'+aDrvNum);
+
+        return rqStat.Int(); 
+    }
+}
 
 //-----------------------------------------------------------------------------------------------------------------------
 TInt DoRemountFS(RFs& aFs, TInt aDrvNum)
@@ -1483,7 +1548,7 @@
     }
 
     //-- 4. dismount the file system
-    nRes = DoDismountFS(aFs, aDrvNum);
+    nRes = DoDismountFS(aFs, aDrvNum, EFalse);
     if(nRes != KErrNone)
         return nRes;
 
@@ -1515,16 +1580,27 @@
 /**
     Mount or dismount the file system on the specified drive.
 
-    MOUNT <DriveLetter:[\]> <FSY:xxx> <FS:yyy> [PEXT:zzz] [/S] [/U]
+    MOUNT <DriveLetter:[\]> <FSY:xxx> <FS:yyy> [PEXT:zzz] [/S] [/U] [/F]
   
     xxx is the *.fsy file system plugin name, like "elocal.fsy" or "elocal"
     yyy is the file system name that the fsy module exports, like "FAT"
     zzz is the optional parameter that specifies primary extension name
 
     /u dismounts a filesystem on the specified drive; e.g. "mount d: /u"
-    /s for mounting FS specifies that the drive will be mounted as synchronous one.
-    /f for forcing mounting the FS; the previous one will be automatically dismounted
-    /r remount existing FS (dismount and mount it back)
+        additional switch /f in conjunction with /u will perform "forced unmounting" i.e. unmounting the FS 
+        even it has opened files and / or directories. E.g. "mount d: /u /f"
+
+    
+    /s for mounting FS specifies that the drive will be mounted as a synchronous one.
+        
+
+    /f for forcing mounting the FS; the previous one will be automatically dismounted. 
+        example: "mount d: /f fsy:exfat fs:exfat" this command will dismount whatever FS ic currently mounted and 
+        mount exFAT FS instead
+
+
+    
+    /r remount existing FS (dismount and mount it back); example: "mount d: /r"
 */
 TInt ShellFunction::MountFileSystem(TDes& aArgs, TUint aSwitches)
 {
@@ -1559,10 +1635,10 @@
         return nRes;
     }
     
-    //-- check if we dismounting the FS (/U switch)
+    //-- check if we dismounting the FS (/U switch).
     if(aSwitches & TShellCommand::EUSwitch)
-    {
-        nRes = DoDismountFS(fs, drvNum);
+    {//-- also take nto account "/f" switch for forced dismounting
+        nRes = DoDismountFS(fs, drvNum, (aSwitches & TShellCommand::EFSwitch));
         
         if(nRes == KErrNotFound)
         {//-- nothing to dismount
@@ -1576,7 +1652,7 @@
     //-- check if we need to forcedly dismount the existing FS (/F switch)
     if(aSwitches & TShellCommand::EFSwitch)
     {
-        nRes = DoDismountFS(fs, drvNum);
+        nRes = DoDismountFS(fs, drvNum, EFalse);
         
         if(nRes != KErrNotFound && nRes !=KErrNone)
             return nRes;
@@ -1662,7 +1738,7 @@
     }
 
 
-    PrintDrvInfo(fs, drvNum, CShell::TheConsole, EFSInfo | EVolInfo);
+    PrintDrvInfo(fs, drvNum, EFSInfo | EVolInfo);
 
     return KErrNone;
 }
@@ -1978,52 +2054,60 @@
     }
 
 //-----------------------------------------------------------------------------------------------------------------------
-
+/**
+    Hex Dump of a file
+*/
 TInt ShellFunction::Hexdump(TDes& aPath,TUint aSwitches)
 	{
 	ShellFunction::StripQuotes(aPath);
 
 	ParsePath(aPath);
+	
 	RFile64 file;
 	TInt r=file.Open(TheShell->TheFs,aPath,EFileStream);
 	if (r!=KErrNone)
 		return(r);
 
-	TInt offset=0;
+		const TInt KLineLength = 16;
+    TBuf<0x100> buf;
+    TBuf<KLineLength> asciiBuf;
+		TBuf8<KLineLength> line;
+
 	for (;;)
 		{
-		const TInt KLineLength = 16;
-
-		TBuf8<KLineLength> line;
 		r=file.Read(line);
 		if (r != KErrNone || line.Length() == 0)
 			break;
 
-		TBuf<KLineLength*3+2> hexaRep;
-		TBuf<KLineLength> asciiRep;
+		buf.Zero();
+        asciiBuf.Zero();
+		
 		for (TInt i=0; i<KLineLength; i++)
 			{
 			if (i == KLineLength/2)
 				{
-				hexaRep.Append(' ');
-				hexaRep.Append(i<line.Length() ? '|' : ' ');
+				buf.Append(' ');
+				buf.Append(i<line.Length() ? '|' : ' ');
 				}
 
-			hexaRep.Append(' ');
+            buf.Append(' ');
 
 			if (i<line.Length())
 				{
-				hexaRep.AppendNumFixedWidth(line[i], EHex, 2);
-				asciiRep.Append(TChar(line[i]).IsPrint() ? line[i] : '.');
+				buf.AppendNumFixedWidth(line[i], EHex, 2);
+				asciiBuf.Append(TChar(line[i]).IsPrint() ? line[i] : '.');
 				}
 			else
-				hexaRep.AppendFill(' ', 2);
+				buf.AppendFill(' ', 2);
 			}
 
 		_LIT(KPrompt , " Hit escape to quit hexdump or any other key to continue\n");
-		_LIT(KLineFmt, " %+07x0:%S %S\n");
-		TKeyCode key=CShell::OutputStringToConsole(KPrompt ,(aSwitches&TShellCommand::EPSwitch)!=0,KLineFmt, offset++,&hexaRep, &asciiRep);
-
+		
+        buf.Append(_L(" "));
+        buf.Append(asciiBuf);
+        buf.Append(KNl);
+
+        TKeyCode key= CShell::WriteBufToConsole((aSwitches&TShellCommand::EPSwitch)!=0, buf, KPrompt);
 		if (key==EKeyEscape)
 				break;
 		}
@@ -2127,7 +2211,7 @@
 
 
     if(!(aSwitches&TShellCommand::EESwitch))
-    {//-- fill created file with randomn data
+    {//-- fill created file with random data
 
 	    while(rem)
 	    {
@@ -2350,22 +2434,22 @@
 	TInt DisplayHelp();
 	TInt DisplayMessage(const TFullName& aName);
 	TInt DisplayCmdUnknown();
-	TInt GetAll(const TDes& aName);
-	TInt GetProcesses(const TDes& aName);
-	TInt GetThreads(const TDes& aName);
-	TInt GetChunks(const TDes& aName);
-	TInt GetServers(const TDes& aName);
+	void GetAll(const TDes& aName);
+	void GetProcesses(const TDes& aName);
+	void GetThreads(const TDes& aName);
+	void GetChunks(const TDes& aName);
+	void GetServers(const TDes& aName);
 //	TInt GetSessions(const TDes& aName);
-	TInt GetLibraries(const TDes& aName);
+	void GetLibraries(const TDes& aName);
 //	TInt GetLogicalChannels(const TDes& aName);
-	TInt GetLogicalDevices(const TDes& aName);
-	TInt GetPhysicalDevices(const TDes& aName);
-	TInt GetSemaphores(const TDes& aName);
-	TInt GetMutexes(const TDes& aName);
+	void GetLogicalDevices(const TDes& aName);
+	void GetPhysicalDevices(const TDes& aName);
+	void GetSemaphores(const TDes& aName);
+	void GetMutexes(const TDes& aName);
 private:
 	void DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription);
-	TInt Prepare(const TFullName& aName);
-	TInt Prepare(const TFullName& aName,TCallBack& aCallBack);
+	TBool Prepare(const TFullName& aName);
+	TBool Prepare(const TFullName& aName,TCallBack& aCallBack);
 	TInt Display(TFullName& aName);
 	TFullName iPrevName;
 	TCallBack iCallBack;
@@ -2407,9 +2491,8 @@
 	return KErrNone;
 	}
 
-TInt TShowProcInfo::GetAll(const TDes& aName)
+void TShowProcInfo::GetAll(const TDes& aName)
 	{
-
 	GetProcesses(aName);
 	GetThreads(aName);
 	GetChunks(aName);
@@ -2421,24 +2504,27 @@
 	GetPhysicalDevices(aName);
 	GetSemaphores(aName);
 	GetMutexes(aName);
-	return KErrNone;
+
 	}
 
-TInt TShowProcInfo::GetProcesses(const TDes& aName)
+void TShowProcInfo::GetProcesses(const TDes& aName)
 	{
 
 	TFindProcess findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("PROCESSES"));
+	
+    if(!Prepare(_L("PROCESSES")))
+       return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+
 	}
 
-TInt TShowProcInfo::GetThreads(const TDes& aName)
+void TShowProcInfo::GetThreads(const TDes& aName)
 	{
 	TInt threads=0;
 	TFindThread findHb;
@@ -2448,7 +2534,10 @@
 
 //	Modified by WR, November 1997
 	TCallBack threadCallBack(GetThreadInfo,findPtr);
-	Prepare(_L("THREADS"),threadCallBack);
+	
+    if(!Prepare(_L("THREADS"),threadCallBack))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
@@ -2460,12 +2549,12 @@
 		message.Format(_L("? No threads called %S"), &aName);
 		DisplayMessage(message);
 		}
-	return KErrNone;
-//	End of modification
+	
+    
 	}
 
 
-TInt TShowProcInfo::GetChunks(const TDes& aName)
+void TShowProcInfo::GetChunks(const TDes& aName)
 	{
 
 	TFindChunk findHb;
@@ -2473,7 +2562,10 @@
 	TFullName name;
 	TAny* namePtr=(TAny*)&name;
 	TCallBack chunkCallBack(GetChunkInfo,namePtr);
-	Prepare(_L("CHUNKS & SIZES"),chunkCallBack);
+	
+    if(!Prepare(_L("CHUNKS & SIZES"),chunkCallBack))
+        return;
+
 	TInt totalChunkSize=0;
 	TInt protectedChunks = 0;
 	while (findHb.Next(name)==KErrNone)
@@ -2500,21 +2592,23 @@
 	CShell::OutputStringToConsole(ETrue,_L("  Total Chunk Size = %dk\n"),totalChunkSize);
 	if(protectedChunks)
 		CShell::OutputStringToConsole(ETrue,_L("  %d Protected chunks not counted\n"),protectedChunks);
-	return KErrNone;
+	
+    
 	}
 
-TInt TShowProcInfo::GetServers(const TDes& aName)
+void TShowProcInfo::GetServers(const TDes& aName)
 	{
 
 	TFindServer findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("SERVERS"));
+	if(!Prepare(_L("SERVERS")))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
 	}
 
 /*	TInt TShowProcInfo::GetSessions(const TDes& aName)
@@ -2531,18 +2625,20 @@
 	return KErrNone;
 	}
 */
-TInt TShowProcInfo::GetLibraries(const TDes& aName)
+void TShowProcInfo::GetLibraries(const TDes& aName)
 	{
 
 	TFindLibrary findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("LIBRARIES"));
+	if(!Prepare(_L("LIBRARIES")))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+	
 	}
 /*
 TInt TShowProcInfo::GetLogicalChannels(const TDes& aName)
@@ -2560,59 +2656,68 @@
 	}
 */
 
-TInt TShowProcInfo::GetLogicalDevices(const TDes& aName)
+void TShowProcInfo::GetLogicalDevices(const TDes& aName)
 	{
 
 	TFindLogicalDevice findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("LOGICAL DEVICES"));
+
+	if(!Prepare(_L("LOGICAL DEVICES")))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+	
 	}
 
-TInt TShowProcInfo::GetPhysicalDevices(const TDes& aName)
+void TShowProcInfo::GetPhysicalDevices(const TDes& aName)
 	{
 
 	TFindPhysicalDevice findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("PHYSICAL DEVICES"));
+	
+    if(!Prepare(_L("PHYSICAL DEVICES")))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+	
 	}
 
-TInt TShowProcInfo::GetSemaphores(const TDes& aName)
+void TShowProcInfo::GetSemaphores(const TDes& aName)
 	{
 	TFindSemaphore findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("SEMAPHORES"));
+	if(!Prepare(_L("SEMAPHORES")))
+        return;
+
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+	
 	}
 
-TInt TShowProcInfo::GetMutexes(const TDes& aName)
+void TShowProcInfo::GetMutexes(const TDes& aName)
 	{
 
 	TFindMutex findHb;
 	findHb.Find(aName);
 	TFullName name;
-	Prepare(_L("MUTEXES"));
+	if(!Prepare(_L("MUTEXES")))
+        return;
 	while (findHb.Next(name)==KErrNone)
 		{
 		Display(name);
 		}
-	return KErrNone;
+	
 	}
 
 void TShowProcInfo::DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription)
@@ -2621,23 +2726,32 @@
 	}
 
 
-TInt TShowProcInfo::Prepare(const TFullName& aName)
+TBool TShowProcInfo::Prepare(const TFullName& aName)
 	{
 
 	iPrevName=_L("");
-	CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+	TKeyCode key = CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+    
+    if(key==EKeyEscape)
+        return EFalse;
+
 	useCallBack=EFalse;
-	return KErrNone;
+    return ETrue;
 	}
 
-TInt TShowProcInfo::Prepare(const TFullName& aName,TCallBack& aCallBack)
+TBool  TShowProcInfo::Prepare(const TFullName& aName,TCallBack& aCallBack)
 	{
-
 	iPrevName=_L("");
-	CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+	TKeyCode key = CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+
+    if(key==EKeyEscape)
+        return EFalse;
+	
+    
 	useCallBack=ETrue;
 	iCallBack=aCallBack;
-	return KErrNone;
+	
+    return ETrue;
 	}
 
 TInt TShowProcInfo::Display(TFullName& aName)
@@ -2670,7 +2784,11 @@
 		while (posA>=0)
 			{
 			TPtrC16 temp_desc=aName.Left(posA);
-			CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+temp_desc.Left(posA).Length(),&temp_desc);
+			
+            TKeyCode key = CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+temp_desc.Left(posA).Length(),&temp_desc);
+			if (key==EKeyEscape)
+			    break;
+
 			toTab+=3;
 			aName.Delete(0,posA+2);
 			posA=aName.Match(_L("*::*"));
@@ -2701,7 +2819,7 @@
 	TBool abort=EFalse;
 	TBool processSelected=EFalse;
 	TBuf<0x16> prompt=_L("ps>");
-	r=showProcInfo.GetProcesses(processPrefix);
+	showProcInfo.GetProcesses(processPrefix);
 	do
 		{
 		TBuf<0x10> command;
@@ -2763,7 +2881,7 @@
 						if (findP.Next(findName)==KErrNone)
 							{
 							r=showProcInfo.DisplayMessage(_L("command prefixes more than one process"));
-							r=showProcInfo.GetProcesses(chosenP);
+							showProcInfo.GetProcesses(chosenP);
 							}
 						else
 							{
@@ -2777,42 +2895,42 @@
 					break;
 				case 'A':
 					{
-					r=showProcInfo.GetAll(processPrefix);
+					showProcInfo.GetAll(processPrefix);
 					command.Zero();
 					}
 					break;
 				case 'P':
-					r=showProcInfo.GetProcesses(asterisk);
+					showProcInfo.GetProcesses(asterisk);
 					break;
 				case 'T':
-					r=showProcInfo.GetThreads(processPrefix);
+					showProcInfo.GetThreads(processPrefix);
 					break;
 				case 'C':
-					r=showProcInfo.GetChunks(processPrefix);
+					showProcInfo.GetChunks(processPrefix);
 					break;
 				case 'S':
-					r=showProcInfo.GetServers(processPrefix);
+					showProcInfo.GetServers(processPrefix);
 					break;
 /*				case 'I':
 					r=showProcInfo.GetSessions(processPrefix);
 					break;
 */				case 'L':
-					r=showProcInfo.GetLibraries(processPrefix);
+					showProcInfo.GetLibraries(processPrefix);
 					break;
 //				case 'G':
 //					r=showProcInfo.GetLogicalChannels(processPrefix);
 //					break;
 				case 'V':
-					r=showProcInfo.GetLogicalDevices(processPrefix);
+					showProcInfo.GetLogicalDevices(processPrefix);
 					break;
 				case 'D':
-					r=showProcInfo.GetPhysicalDevices(processPrefix);
+					showProcInfo.GetPhysicalDevices(processPrefix);
 					break;
 				case 'E':
-					r=showProcInfo.GetSemaphores(processPrefix);
+					showProcInfo.GetSemaphores(processPrefix);
 					break;
 				case 'M':
-					r=showProcInfo.GetMutexes(processPrefix);
+					showProcInfo.GetMutexes(processPrefix);
 					break;
 				default:
 					{
@@ -3116,7 +3234,6 @@
 		c=*p, *p=p[1], p[1]=c;
 	}
 
-_LIT(KLitPercentS, "%S");
 TInt ShellFunction::Type(TDes& aPath,TUint aSwitches)
 	{
 	ParsePath(aPath);
@@ -3178,7 +3295,7 @@
 			{
 			nchars=0;
 			TPtrC bufLeft=buf.Left(r+1);
-			key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &bufLeft);
+            key = CShell::WriteBufToConsole((aSwitches&TShellCommand::EPSwitch)!=0, bufLeft);
 			buf.Set(buf.Mid(r+1));
 	
     		if(key == EKeyEscape) 
@@ -3188,7 +3305,8 @@
 		nchars=buf.Length();
 		if (nchars)
 			{
-            key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &buf);
+    		key = CShell::WriteBufToConsole((aSwitches&TShellCommand::EPSwitch)!=0, buf);
+
     		if(key == EKeyEscape) 
                 goto exit;
 
@@ -3604,11 +3722,52 @@
 	return err;
 	}
 
-_LIT(KCrNl, "\r\n");
+
+
+//----------------------------------------------------------------------
+void CShell::Print(const TDesC16& aBuf)
+{
+
+    TheConsole->Write(aBuf);
+
+    if(iDbgPrint)
+    {
+        const TInt bufLen = aBuf.Length();
+        
+        if(bufLen >1 && aBuf[bufLen-1] == '\n' && aBuf[bufLen-2] != '\r')
+            {
+            RDebug::RawPrint(aBuf.Left(bufLen-1));            
+            RDebug::RawPrint(_L8("\r\n"));
+            }
+        else if(bufLen == 1 && aBuf[bufLen-1] == '\n')
+            {
+            RDebug::RawPrint(_L8("\r\n"));
+            }
+        else
+            {
+            RDebug::RawPrint(aBuf);
+            }
+    }
+
+}
+
+void CShell::Printf(TRefByValue<const TDesC16> aFmt, ...)
+{
+	TBuf<0x200> buf;
+	VA_LIST list;					
+	VA_START(list, aFmt);
+	// coverity[uninit_use_in_call]
+	buf.FormatList(aFmt, list);			
+
+    if(!buf.Length())
+        return;
+
+    Print(buf);
+}
 
 void SIPrintf(TRefByValue<const TDesC16> aFmt, ...)
 	{
-	TBuf<256> buf;
+	TBuf<0x200> buf;
 	VA_LIST list;					
 	VA_START(list, aFmt);
 	// coverity[uninit_use_in_call]
@@ -3683,7 +3842,7 @@
 		aProg.Append(_L(".EXE"));
 
 #ifdef _DEBUG
-	SIPrintf(_L("RUNEXEC: command %S, parameters %S, count %d, forever %d, issecs %d, exiterr %d"),
+	CShell::Printf(_L("RUNEXEC: command %S, parameters %S, count %d, forever %d, issecs %d, exiterr %d"),
 		&aProg, &parameters, count, forever, countIsSecs, exitOnErr); 
 #endif
 	TInt i=0;
@@ -3698,7 +3857,7 @@
 		r = newProcess.Create(aProg, parameters);
 		if (r != KErrNone)
 			{
-			SIPrintf(KRunExecFailedProcessCreate, &aProg, r);
+			CShell::Printf(KRunExecFailedProcessCreate, &aProg, r);
 			return (r);						// this is systematic - must return
 			}
 		newProcess.Logon(status);
@@ -3712,7 +3871,7 @@
 		timeCurrent.HomeTime();
 		timeTaken = timeCurrent.MicroSecondsFrom(timeStart);
 		TInt msecs = I64LOW(timeTaken.Int64() / 1000);
-		SIPrintf(KRunExecReportStatusAndTime, msecs, i+1, exitType, retcode, &exitCat);
+		CShell::Printf(KRunExecReportStatusAndTime, msecs, i+1, exitType, retcode, &exitCat);
 
 		if (resetDebugRegs)
 			{
@@ -3779,9 +3938,29 @@
 //-------------------------------------------------------------------------
 /**
     Print out the command line to the console and standard debug port.
+
+    echo [some text] [/y] [/n]
+
+		/Y : switches ON copying console output to the debug port
+		/N : switches OFF copying console output to the debug port
+
 */
-TInt ShellFunction::ConsoleEcho(TDes& aArgs, TUint /*aSwitches*/)
+TInt ShellFunction::ConsoleEcho(TDes& aArgs, TUint aSwitches)
 {
+    if(aSwitches & TShellCommand::EYSwitch)
+    {
+        CShell::SetDbgConsoleEcho(ETrue);
+    }
+    else
+    if(aSwitches & TShellCommand::ENSwitch)
+    {
+        CShell::SetDbgConsoleEcho(EFalse);
+    }
+
+    if(aArgs.Length())
     SIPrintf(aArgs);
+    
     return KErrNone;
 }
+
+
--- a/userlibandfileserver/fileserver/etshell/ts_edshl.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/etshell/ts_edshl.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -532,6 +532,17 @@
 		}
 	}
 
+
+//-------------------------------------------------------------------------
+//-- generic shell commands that don't require sophisticated processing
+
+_LIT(KCmd_Help, "HELP");    ///< displays help
+_LIT(KCmd_Cls,  "CLS");     ///< clears the screen
+_LIT(KCmd_Rem,  "REM");     ///< *.bat processing - commented out line
+_LIT(KCmd_Break,"BREAK");   ///< stops *.bat file execution
+_LIT(KCmd_Exit, "EXIT");    ///< exit the shell
+
+//-------------------------------------------------------------------------
 //////////////////////////////////////
 //CShell
 //////////////////////////////////////
@@ -728,7 +739,7 @@
 				tabCount = 0;
 				
 #if !defined(_EPOC)
-				if(commandText.CompareF(_L("EXIT")) == 0)
+				if(commandText.CompareF(KCmd_Exit) == 0)
 					{
 					exit = ETrue;
 					break;
@@ -816,6 +827,10 @@
 	CleanupStack::PopAndDestroy(fileManObserver);
 	}
 
+
+
+//-------------------------------------------------------------------------
+
 void CShell::DoCommand(TDes& aCommand)
 //
 // Evaluate the commandline and run the command or file
@@ -884,10 +899,13 @@
 		{
 		TInt r;
 		
-		if (aCommand.CompareF(_L("HELP"))==0)
+		if (aCommand.CompareF(KCmd_Help)==0)
 			PrintHelp();
-		else if (aCommand.CompareF(_L("CLS"))==0)
+		else if (aCommand.CompareF(KCmd_Cls)==0)
 			TheConsole->ClearScreen(); 
+		else if (aCommand.CompareF(KCmd_Break)==0)
+			{//-- "break" command, do nothing
+            }
 		else if (aCommand.Length()==2 && TChar(aCommand[0]).IsAlpha() && aCommand[1]==':')
 			ChangeDrive(aCommand[0]);
 		else if (aCommand.Length()!=0)
@@ -1063,10 +1081,17 @@
 			else 
 			PrintError(KErrNotFound);
 			}
-			
-		else if (readBuf.Length()<3 || readBuf.Left(3).CompareF(_L("REM"))!=0)
+		else if (readBuf.Length()<3 || readBuf.Left(3).CompareF(KCmd_Rem)!=0)
+            {
+			//-- check if it is a "break" command. stop execution in this case
+            if(readBuf.CompareF(KCmd_Break) ==0)
+                break; //-- terminate batch file execution        
+            else
 			DoCommand(readBuf);
 		}
+		}
+	
+    
 	file.Close();
 	return KErrNone;
 	}
@@ -1218,7 +1243,7 @@
 	drivePaths[drvNum]=aDrivePath;
 	}
 
-
+//----------------------------------------------------------------------
 TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch,TRefByValue<const TDesC> aFmt,... )
 //function for output of a sring to console
 //aPageSwitch flag indicates that output should be page-by-page 
@@ -1239,6 +1264,7 @@
 	return OutputStringToConsole(KPrompt,aPageSwitch,_L("%S"),&aBuf);
 	}
 
+//----------------------------------------------------------------------
 TKeyCode CShell::OutputStringToConsole(const TDesC& aNotification,TBool aPageSwitch,TRefByValue<const TDesC> aFmt,...)
 	//function for output of a string to console aPageSwitch flag indicates that output should be page-by-page 
 	//if aPageSwitch==ETrue user will be prompted with the message passed as aNotification
@@ -1251,10 +1277,8 @@
 	
 	VA_LIST list;
 	VA_START(list,aFmt);
-	
 	TBuf<0x200> aBuf;
 	//format output string using argumen list
-	
 	//coverity[uninit_use_in_call]
 	TRAP_IGNORE(aBuf.AppendFormatList(aFmt,list,&overflow)); // ignore leave in TTimeOverflowLeave::Overflow()
 	//if we are requested to wait for the user input at the end of each page, we check whether output of next piece of text will fit into the screen
@@ -1263,27 +1287,36 @@
 		key=PageSwitchDisplay(aNotification);				
 		}
 	//output current string
-	TheConsole->Write(aBuf);
+	
+	Print(aBuf);
+    
 	return key;			
 	}
 
-TKeyCode CShell::OutputStringToConsole(TBool aPageSwitch, const TDesC& aBuf)
+//----------------------------------------------------------------------
+TKeyCode CShell::WriteBufToConsole(TBool aPageSwitch, const TDesC& aBuf)
 	{
 	_LIT(KPrompt , "Press any key to continue\n");
+    return WriteBufToConsole(aPageSwitch, aBuf, KPrompt);
+	}
 	
+//----------------------------------------------------------------------
+TKeyCode CShell::WriteBufToConsole(TBool aPageSwitch, const TDesC& aBuf, const TDesC& aNotification)
+    {
     TKeyCode key=EKeyNull;	
 
 	//if we are requested to wait for the user input at the end of each page, we check whether output of next piece of text will fit into the screen
 	if (aPageSwitch)
 		{
-		key = PageSwitchDisplay(KPrompt);				
+		key = PageSwitchDisplay(aNotification);				
 		}
-	//output current string
-	TheConsole->Write(aBuf);
+
+    Print(aBuf);
 	
     return key;
 	}
 
+
 TKeyCode CShell::PageSwitchDisplay(const TDesC& aNotification)
 	{
 	//create variable to store code of the key pressed by the user
@@ -1313,3 +1346,9 @@
 		}						
 	return key;			
 	}
+
+
+
+
+
+
--- a/userlibandfileserver/fileserver/etshell/ts_std.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/etshell/ts_std.h	Thu Aug 19 11:14:22 2010 +0300
@@ -144,8 +144,16 @@
 	void SetDrivePath(const TDesC& aDes);
 	static void NewLine();
 	static TKeyCode OutputStringToConsole(TBool aPageSwitch,TRefByValue<const TDesC> aFmt,...);
-	static TKeyCode OutputStringToConsole(TBool aPageSwitch, const TDesC& aBuf);
 	static TKeyCode OutputStringToConsole(const TDesC& aNotification,TBool aPageSwitch,TRefByValue<const TDesC> aFmt,...);
+
+    static TKeyCode WriteBufToConsole(TBool aPageSwitch, const TDesC& aBuf);
+    static TKeyCode WriteBufToConsole(TBool aPageSwitch, const TDesC& aBuf, const TDesC& aNotification);
+
+
+    static void Printf(TRefByValue<const TDesC16> aFmt, ...);
+    static void Print(const TDesC16& aBuf);
+    static void SetDbgConsoleEcho(TBool aOn) {iDbgPrint = aOn;}
+
 public:
 	static CConsoleBase* TheConsole;
 	static CFileMan* TheFileMan;
@@ -166,6 +174,7 @@
 	static TInt RunBatch(TDes& aCommand);
 	static TInt RunExecutable(TDes& aCommand,TBool aWaitForCompletion);
 	static TKeyCode PageSwitchDisplay(const TDesC& aBuf);
+
 private:
 	static TBuf<KMaxFileName> currentPath;
 	static TBuf<KMaxFileName> drivePaths[KMaxDrives];
@@ -174,6 +183,9 @@
 	static CLineEdit* TheEditor;
 	friend class ShellFunction;
 	friend class CDllChecker;
+	
+    static TBool iDbgPrint; ///< if ETrue, the output from CShell::Printf is copied to the debug port
+    
 	};
 
 
@@ -266,7 +278,7 @@
 private:		
 	static TInt ShowDirectoryTree(TDes& aPath,TUint aSwitches,TDes& aTreeGraph);
 	static TBool Certain();	
-	static void OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches);
+	static TBool OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches);
 	static void OutputDirContentL(CDir* aDirList,RPointerArray<HBufC>& aText,TUint aSwitches);	
 	};
 
--- a/userlibandfileserver/fileserver/group/release.txt	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/group/release.txt	Thu Aug 19 11:14:22 2010 +0300
@@ -1,3 +1,58 @@
+Version 2.00.2505
+=================
+(Made by fadhliM 26/07/2010)
+
+1.	h14jiang
+	1.	ou1cimx1#495678 FileServer - Bad usage of RArray::Append() and RPointerArray::Append()
+
+2.	michcox
+	1.	MINOR_CHANGE 9.2 change includes from <F32Plugin.h> to <f32plugin.h> (i.e. case correction)
+
+
+Version 2.00.2504
+=================
+(Made by fadhliM 21/07/2010)
+
+1.	dlyokhin
+	1.	ou1cimx1#491761 ENV 92 : CAtaFatTable::DataPositionInBytes() Should Fail 'Gracefully' if Cluster is Invalid (Corrupted Media)
+
+
+Version 2.00.2503
+=================
+(Made by fadhliM 19/07/2010)
+
+1.	migubarr
+	1.	ou1cimx1#485027 Internal file server attribute (KEntryAttModified) can be returned to the client
+	2.	ou1cimx1#493751 Querying the attributes of an open file on the emulator's Z: drive returns incorrect attributes
+
+
+Version 2.00.2502
+=================
+(Made by famustaf 14/07/2010)
+
+1.	frhofman
+	1.	ou1cimx1#489934 ENV F32TEST T_RCACHE test failure investigation (t_rcache.cpp:1556)
+
+2.	migubarr
+	1.	ou1cimx1#476545 Inefficiencies in RFile::SetSize() & RFile::Write()
+
+
+Version 2.00.2501
+=================
+(Made by famustaf 07/07/2010)
+
+1.	migubarr
+	1.	REQ 415-7212 NFE drive encryption on Demand Paging-enabled device
+
+
+Version 2.00.2500
+=================
+(Made by vfebvre 29/06/2010)
+
+1.	h14jiang
+	1.	ou1cimx1#428824 Not getting any Notification from RFs::NotifyDiskSpace() for E and F drive when when tested multiple time.
+
+
 Version 2.00.2065
 =================
 (Made by vfebvre 18/06/2010)
--- a/userlibandfileserver/fileserver/inc/f32fsys.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/inc/f32fsys.h	Thu Aug 19 11:14:22 2010 +0300
@@ -1629,6 +1629,7 @@
 	IMPORT_C TInt64 Size64() const;
 	IMPORT_C void SetSize64(TInt64 aSize, TBool aDriveLocked);
     IMPORT_C void SetMaxSupportedSize(TUint64 aMaxFileSize);
+	IMPORT_C TBool DirectIOMode(const RMessagePtr2& aMessage);
 
 
     TInt64 CachedSize64() const;
--- a/userlibandfileserver/fileserver/inc/f32ver.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/inc/f32ver.h	Thu Aug 19 11:14:22 2010 +0300
@@ -58,6 +58,6 @@
 
 @see TVersion
 */
-const TInt KF32BuildVersionNumber=2065;
+const TInt KF32BuildVersionNumber=2504;
 //
 #endif
--- a/userlibandfileserver/fileserver/sfat/sl_cache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat/sl_cache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -135,7 +135,7 @@
     for(TUint cnt=0; cnt<aNumPages; ++cnt)
         {
         CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
-        iPages.Append(pPage);
+        iPages.AppendL(pPage);
         }
 
     InvalidateCache();  
--- a/userlibandfileserver/fileserver/sfat/sl_fatcache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat/sl_fatcache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -358,7 +358,7 @@
 
     //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
     for(TUint i=0; i<numPages; ++i)
-        iPages.Append(NULL);
+        iPages.AppendL(NULL);
     
     }
 
--- a/userlibandfileserver/fileserver/sfat/sl_leafdir_cache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat/sl_leafdir_cache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -756,8 +756,8 @@
             else
                 {
                 iLruList.Remove(i);
-                iLruList.Insert(aNodeUsed, 0);
-                return KErrNone;
+                TInt r = iLruList.Insert(aNodeUsed, 0);
+                return r;
                 }
             }
         }
--- a/userlibandfileserver/fileserver/sfat32/fat_table32.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/fat_table32.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -402,7 +402,7 @@
     Notify the media drive about media areas that shall be treated as "deleted" if this feature is supported.
     @param aFreedClusters array with FAT numbers of clusters that shall be marked as "deleted"
 */
-void CFatTable::DoFreedClustersNotify(RClusterArray &aFreedClusters)
+void CFatTable::DoFreedClustersNotifyL(RClusterArray &aFreedClusters)
 {
     ASSERT(iMediaAtt & KMediaAttDeleteNotify);
 
@@ -423,7 +423,7 @@
         const TUint currCluster = aFreedClusters[i];
         
         if (deleteLen == 0)
-		    byteAddress = DataPositionInBytes(currCluster); //-- start of the media range
+		    byteAddress = DataPositionInBytesL(currCluster); //-- start of the media range
         
         deleteLen += bytesPerCluster;
 
@@ -438,7 +438,7 @@
                 {//-- if DeleteNotify() failed, it means that something terribly wrong happened to the NAND media; 
                  //-- in normal circumstances it can not happen. One of the reasons: totally worn out media.
                 const TBool platSecEnabled = PlatSec::ConfigSetting(PlatSec::EPlatSecEnforcement);
-                __PRINT3(_L("CFatTable::DoFreedClustersNotify() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
+                __PRINT3(_L("CFatTable::DoFreedClustersNotifyL() DeleteNotify failure! drv:%d err:%d, PlatSec:%d"),iOwner->DriveNumber(), r, platSecEnabled);
 
                 if(platSecEnabled)
                     {
@@ -521,7 +521,7 @@
             cntFreedClusters = 0;
 
             SetFreeClusterHint(lastKnownFreeCluster);
-            DoFreedClustersNotify(deletedClusters);
+            DoFreedClustersNotifyL(deletedClusters);
         }
 
     }
@@ -531,7 +531,7 @@
     SetFreeClusterHint(lastKnownFreeCluster);
     
     if(bFreeClustersNotify)
-        DoFreedClustersNotify(deletedClusters);
+        DoFreedClustersNotifyL(deletedClusters);
 
 	CleanupStack::PopAndDestroy(&deletedClusters);
 	}
@@ -671,14 +671,6 @@
     return (NumberOfFreeClusters() >= aClustersRequired);
     }
 
-//-----------------------------------------------------------------------------
-/**
-    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
-*/
-TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
-    {
-    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
-    }
     
 
 
@@ -1789,17 +1781,20 @@
 
 
 /**
-    Return the location of a Cluster in the data section of the media
+    Return media position in bytes of the cluster start
 
     @param aCluster to find location of
     @return Byte offset of the cluster data 
 */
-TInt64 CAtaFatTable::DataPositionInBytes(TUint32 aCluster) const
+TInt64 CAtaFatTable::DataPositionInBytesL(TUint32 aCluster) const
 	{
-
-    __ASSERT_DEBUG(ClusterNumberValid(aCluster), Fault(EFatTable_InvalidIndex));
-
-    const TInt clusterBasePosition=iOwner->ClusterBasePosition();
+    if(!ClusterNumberValid(aCluster))
+        {
+        __ASSERT_DEBUG(0, Fault(EFatTable_InvalidIndex));
+        User::Leave(KErrCorrupt);
+        }
+
+    const TUint32 clusterBasePosition=iOwner->ClusterBasePosition();
 	return(((TInt64(aCluster)-KFatFirstSearchCluster) << iOwner->ClusterSizeLog2()) + clusterBasePosition);
 	}
 
--- a/userlibandfileserver/fileserver/sfat32/inc/fat_table32.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/inc/fat_table32.h	Thu Aug 19 11:14:22 2010 +0300
@@ -50,7 +50,7 @@
     void WriteL(TUint32 aFatIndex, TUint32 aValue);
     void MountL(const TMountParams& aMountParam);
 
-    TInt64 DataPositionInBytes(TUint32 aCluster) const;
+    TInt64 DataPositionInBytesL(TUint32 aCluster) const;
 
     void InitializeL();
     void Dismount(TBool aDiscardDirtyData);
@@ -157,7 +157,7 @@
 
     TUint32 ReadL(TUint32 aFatIndex) const;
     void WriteL(TUint32 aFatIndex, TUint32 aValue);
-    TInt64 DataPositionInBytes(TUint32 aCluster) const;
+    TInt64 DataPositionInBytesL(TUint32 aCluster) const;
     void FreeClusterListL(TUint32 aCluster);
     TUint32 AllocateSingleClusterL(TUint32 aNearestCluster);
     void ExtendClusterListL(TUint32 aNumber, TUint32& aCluster);
@@ -176,7 +176,7 @@
     inline void WriteIndirectionTable(TInt aFatIndex,TInt aValue);
     inline TUint8* MemCopy(TAny* aTrg,const TAny* aSrc,TInt aLength);
     inline TUint8* MemCopyFillZ(TAny* aTrg, TAny* aSrc, TInt aLength);
-    inline void ZeroFillCluster(TInt aCluster);
+    inline void ZeroFillClusterL(TInt aCluster);
     
     void UpdateIndirectionTable(TUint32 aStartCluster,TUint32 anEndCluster,TInt aNum);
 
--- a/userlibandfileserver/fileserver/sfat32/inc/sl_std.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/inc/sl_std.h	Thu Aug 19 11:14:22 2010 +0300
@@ -92,12 +92,12 @@
 
     //-- public interface to the local drive. Provides media driver's error handling (critical and non-critical user notifiers)
     //-- and thread-safety if required.
-	TInt ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
+	TInt ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const;
 	TInt ReadNonCritical(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
 	TInt ReadCritical(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
 	
     TInt WriteCritical(TInt64 aPos,const TDesC8& aSrc);
-    TInt WriteNonCritical(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
+    TInt WriteNonCritical(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag);
 	
     TInt GetLastErrorInfo(TDes8& aErrorInfo) const;
 
@@ -148,9 +148,9 @@
         inline void LeaveCriticalSection() const {iLock.Signal();}
 
         //-- methods' wrappers that are used by TDriveInterface
-        TInt Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
+        TInt Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const;
         TInt Read(TInt64 aPos,TInt aLength,TDes8& aTrg) const;
-        TInt Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
+        TInt Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag);
         TInt Write(TInt64 aPos, const TDesC8& aSrc);
         TInt GetLastErrorInfo(TDes8& aErrorInfo) const;
         TInt Caps(TDes8& anInfo) const;
@@ -192,7 +192,7 @@
     //-- pure virtual interface
     virtual TUint32 ReadL(TUint32 aFatIndex) const = 0;
 	virtual void WriteL(TUint32 aFatIndex, TUint32 aValue) = 0;
-	virtual TInt64 DataPositionInBytes(TUint32 aCluster) const = 0;
+	virtual TInt64 DataPositionInBytesL(TUint32 aCluster) const = 0;
     virtual void MountL(const TMountParams& aMountParam) = 0;
     //-----------------------------------------------------------------
     //-- just virtual interface
@@ -266,7 +266,7 @@
     inline TBool ClusterNumberValid(TUint32 aClusterNo) const;
 
     typedef RArray<TUint> RClusterArray;
-    void DoFreedClustersNotify(RClusterArray &aFreedClusters);
+    void DoFreedClustersNotifyL(RClusterArray &aFreedClusters);
 
 
 protected:
@@ -336,7 +336,7 @@
 	@param aMessage	Refrence to server message from request
 	@param anOffset	Offset into read data to write
 	*/
-	virtual void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const = 0;
+	virtual void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const = 0;
 
 	/**
 	Disk write function
@@ -347,7 +347,7 @@
 	@param aMessage	Refrence to server message from request, contains data
 	@param anOffset	Offset into write data to use in write
 	*/
-	virtual void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset) = 0;
+	virtual void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) = 0;
 
     
     virtual inline MWTCacheInterface* DirCacheInterface();
@@ -570,8 +570,8 @@
     void DirReadL(const TEntryPos& aPos,TInt aLength,TDes8& aDes) const;
     void DirWriteL(const TEntryPos& aPos,const TDesC8& aDes);
 
-	void ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const;
-    void WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint& aBadcluster, TUint& aGoodcluster);
+	void ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset, TUint aFlag) const;
+    void WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint& aBadcluster, TUint& aGoodcluster, TUint aFlag);
 	
 	void MoveToNextEntryL(TEntryPos& aPos) const;
 	void MoveToDosEntryL(TEntryPos& aPos,TFatDirEntry& anEntry) const;
@@ -703,8 +703,8 @@
 	void DoCheckFatForLoopsL(TUint32 aCluster, TUint32& aPreviousCluster, TUint32& aChangePreviousCluster, TUint32& aCount) const;
     void InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool aIgnoreFSInfo=EFalse);
 
-	void DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const;
-    void DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint aLastcluster, TUint& aBadcluster, TUint& aGoodcluster);
+	void DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset, TUint aFlag) const;
+    void DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint aLastcluster, TUint& aBadcluster, TUint& aGoodcluster, TUint aFlag);
 
 	TBool IsUniqueNameL(const TShortName& aName, TUint32 aDirCluster);
 	TBool FindShortNameL(const TShortName& aName,TEntryPos& anEntryPos);
@@ -862,7 +862,6 @@
 	void SetSeekIndexValueL(TUint aFileCluster,TUint aStoredCluster);
 	void ResizeIndex(TInt aNewMult,TUint aNewSize);
 	TInt CalcSeekIndexSize(TUint aSize);
-	TBool IsSeekBackwards(TUint aPos);
 	void ClearIndex(TUint aNewSize);
 	void DoSetSizeL(TUint aSize, TBool aForceCachesFlush);
 	void WriteFileSizeL(TUint aSize);
--- a/userlibandfileserver/fileserver/sfat32/inc/sl_std.inl	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/inc/sl_std.inl	Thu Aug 19 11:14:22 2010 +0300
@@ -645,13 +645,23 @@
     }
 
 
+//-----------------------------------------------------------------------------
+/**
+    @return ETrue if the cluster number aClusterNo is valid, i.e. belongs to the FAT table
+*/
+inline TBool CFatTable::ClusterNumberValid(TUint32 aClusterNo) const 
+    {
+    return (aClusterNo >= KFatFirstSearchCluster) && (aClusterNo < iMaxEntries); 
+    }
+
+
 /**
 @return Maximal number of addresable FAT entries. This value is taken from the owning mount
 */
 inline TUint32 CFatTable::MaxEntries() const
     {
-        ASSERT(iMaxEntries > 0);
-        return iMaxEntries;
+    ASSERT(iMaxEntries > 0);
+    return iMaxEntries;
     }
 
 
--- a/userlibandfileserver/fileserver/sfat32/ram_fat_table32.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/ram_fat_table32.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -343,9 +343,9 @@
     Zero fill RAM area corresponding to the cluster number aCluster
     @param  aCluster a cluster number to be zero-filled
 */
-void CRamFatTable::ZeroFillCluster(TInt aCluster)
+void CRamFatTable::ZeroFillClusterL(TInt aCluster)
     {
-    TLinAddr clusterPos= I64LOW(DataPositionInBytes(aCluster));
+    TLinAddr clusterPos= I64LOW(DataPositionInBytesL(aCluster));
     Mem::FillZ(iRamDiskBase+clusterPos, 1<< iOwner->ClusterSizeLog2());     
     }
 
@@ -356,9 +356,15 @@
 @param aCluster to find location of
 @return Byte offset of the cluster data 
 */
-TInt64 CRamFatTable::DataPositionInBytes(TUint32 aCluster) const
+TInt64 CRamFatTable::DataPositionInBytesL(TUint32 aCluster) const
     {
     //__PRINT(_L("CRamFatTable::DataPositionInBytes"));
+    if(!ClusterNumberValid(aCluster))
+        {
+        __ASSERT_DEBUG(0, Fault(EFatTable_InvalidIndex));
+        User::Leave(KErrCorrupt);
+        }
+
     ReadIndirectionTable(aCluster);
     return(aCluster<<iOwner->ClusterSizeLog2());
     }
@@ -417,7 +423,7 @@
     __PRINT(_L("CRamFatTable::AllocateSingleClusterL"));
     iOwner->EnlargeL(1<<iOwner->ClusterSizeLog2()); //  First enlarge the RAM drive
     TInt fileAllocated=CFatTable::AllocateSingleClusterL(aNearestCluster); //   Now update the free cluster and fat/fit
-    ZeroFillCluster(fileAllocated);  //-- zero-fill allocated cluster 
+    ZeroFillClusterL(fileAllocated);  //-- zero-fill allocated cluster 
     return(fileAllocated);
     }   
 
@@ -458,7 +464,7 @@
         DecrementFreeClusterCount(1);
         WriteL(aCluster,freeCluster);
         aCluster=freeCluster;
-        ZeroFillCluster(freeCluster); //-- zero fill just allocated cluster (RAM area)
+        ZeroFillClusterL(freeCluster); //-- zero fill just allocated cluster (RAM area)
         }
 
     SetFreeClusterHint(aCluster); 
@@ -493,7 +499,7 @@
                 endCluster=EOF_32Bit;   // endCluster==0 -> file contained FAT loop
 
         //  Real position in bytes of the start cluster in the data area
-            TLinAddr startClusterPos=I64LOW(DataPositionInBytes(startCluster));
+            TLinAddr startClusterPos=I64LOW(DataPositionInBytesL(startCluster));
         //  Sliding value when more than one block is freed
             TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
             __PRINT1(_L("trg=0x%x"),trg);
@@ -515,7 +521,7 @@
                 __PRINT1(_L("srcEnd=0x%x"),srcEnd);
                 }
             else                        //  Just move up to the next part of the chain
-                srcEnd=I64LOW(DataPositionInBytes(endCluster));
+                srcEnd=I64LOW(DataPositionInBytesL(endCluster));
 
         //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
         //-- zero-filling free space to avoid leaving something important there
@@ -545,7 +551,7 @@
                 endCluster=EOF_16Bit;   // endCluster==0 -> file contained FAT loop
 
         //  Real position in bytes of the start cluster in the data area
-            TLinAddr startClusterPos=I64LOW(DataPositionInBytes(startCluster));
+            TLinAddr startClusterPos=I64LOW(DataPositionInBytesL(startCluster));
         //  Sliding value when more than one block is freed
             TLinAddr trg=startClusterPos-(totalFreed<<clusterShift);
             __PRINT1(_L("trg=0x%x"),trg);
@@ -567,7 +573,7 @@
                 __PRINT1(_L("srcEnd=0x%x"),srcEnd);
                 }
             else                        //  Just move up to the next part of the chain
-                srcEnd=I64LOW(DataPositionInBytes(endCluster));
+                srcEnd=I64LOW(DataPositionInBytesL(endCluster));
 
         //-- Copy (srcEnd-srcStart) bytes from iRamDiskBase+srcStart onto iRamDiskBase+trg
         //-- zero-filling free space to avoid leaving something important there
@@ -633,12 +639,12 @@
 	__PRINT2(_L("CRamFatTable::CountContiguousClustersL() start:%d, max:%d"),aStartCluster, aMaxCount);
 	TUint32 clusterListLen=1;
 	TUint32 endCluster=aStartCluster;
-	TInt64 endClusterPos=DataPositionInBytes(endCluster);
+	TInt64 endClusterPos=DataPositionInBytesL(endCluster);
 	while (clusterListLen<aMaxCount)
 		{
 		TInt oldCluster=endCluster;
 		TInt64 oldClusterPos=endClusterPos;
-		if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytes(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
+		if (GetNextClusterL(endCluster)==EFalse || (endClusterPos=DataPositionInBytesL(endCluster))!=(oldClusterPos+(1<<iOwner->ClusterSizeLog2())))
 			{
 			endCluster=oldCluster;
 			break;
--- a/userlibandfileserver/fileserver/sfat32/sl_cache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_cache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -119,7 +119,7 @@
     for(TUint cnt=0; cnt<aNumPages; ++cnt)
         {
         CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
-        iPages.Append(pPage);
+        iPages.AppendL(pPage);
         }
 
     InvalidateCache();  
--- a/userlibandfileserver/fileserver/sfat32/sl_disk.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_disk.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -286,13 +286,14 @@
 
     @leave on error
 */
-void CAtaDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
+void CAtaDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const
 	{
 
 	__PRINT4(_L("CAtaDisk::ReadL() pos:%u:%u, len:%u, offset:%u"), I64HIGH(aPos), I64LOW(aPos), aLength, anOffset);
-	User::LeaveIfError(iDrive.ReadNonCritical(aPos,aLength,aTrg,aMessage,anOffset));
+	User::LeaveIfError(iDrive.ReadNonCritical(aPos,aLength,aTrg,aMessage,anOffset, aFlag));
 	}
 
+
 //-------------------------------------------------------------------------------------
 
 /**
@@ -309,12 +310,12 @@
 
     @leave on error
 */
-void CAtaDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset)
+void CAtaDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag)
 	{
     __PRINT4(_L("CAtaDisk::WriteL() pos:%u:%u, len:%u, offset:%u"), I64HIGH(aPos), I64LOW(aPos), aLength, anOffset);
 
 	//-- write data to the media directly
-    User::LeaveIfError(iDrive.WriteNonCritical(aPos,aLength,aSrc,aMessage,anOffset));
+    User::LeaveIfError(iDrive.WriteNonCritical(aPos,aLength,aSrc,aMessage,anOffset, aFlag));
 
     //-- we need to invalidate UID cache page that corresponds to aPos (if any). This is UID caching specific. UID is stored in the first few bytes of 
     //-- the executable module and therefore belongs to one cache page only.
@@ -326,6 +327,7 @@
 
 	}
 
+
 //-------------------------------------------------------------------------------------
 
 /** Get information for last disk error */
@@ -444,7 +446,7 @@
 //
 // Read from ramDrive into thread relative descriptor
 //
-void CRamDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* /*aTrg*/,const RMessagePtr2 &aMessage,TInt anOffset) const
+void CRamDisk::ReadL(TInt64 aPos,TInt aLength,const TAny* /*aTrg*/,const RMessagePtr2 &aMessage,TInt anOffset, TUint /*aFlag*/) const
 	{
 	__PRINT2(_L("CRamDisk::ReadL TAny* Pos 0x%x, Len %d"),aPos,aLength);
 	__ASSERT_ALWAYS((aPos+aLength<=I64INT(iFatMount->Size())) && (aLength>=0),User::Leave(KErrCorrupt));
@@ -453,11 +455,12 @@
 	aMessage.WriteL(0,buf,anOffset);
 	}
 
+	
 //-------------------------------------------------------------------------------------
 //
 // Write from thread relative descriptor into ramDrive
 //
-void CRamDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* /*aSrc*/,const RMessagePtr2 &aMessage,TInt anOffset)
+void CRamDisk::WriteL(TInt64 aPos,TInt aLength,const TAny* /*aSrc*/,const RMessagePtr2 &aMessage,TInt anOffset, TUint /*aFlag*/)
 	{
 	__PRINT2(_L("CRamDisk::WriteL TAny* Pos 0x%x, Len %d"),aPos,aLength);
 	__ASSERT_ALWAYS(aPos+aLength<=I64INT(iFatMount->Size()),User::Leave(KErrCorrupt));
@@ -475,20 +478,3 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--- a/userlibandfileserver/fileserver/sfat32/sl_disk.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_disk.h	Thu Aug 19 11:14:22 2010 +0300
@@ -49,8 +49,8 @@
     virtual void InvalidateUidCachePage(TUint64 aPos);
 
 	
-    void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
-	void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
+    void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const;
+	void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag);
 	virtual TInt GetLastErrorInfo(TDes8& aErrorInfo) const;
 
     MWTCacheInterface* DirCacheInterface();
@@ -80,11 +80,9 @@
 public:
 	void ReadCachedL(TInt64 aPos,TInt aLength,TDes8& aDes) const;
 	void WriteCachedL(TInt64 aPos,const TDesC8& aDes);
-	void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const;
-	void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset);
-
-    
-
+	void ReadL(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const;
+	void WriteL(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag);
+	
 private:
 	inline TUint8 *RamDiskBase() const;
 
--- a/userlibandfileserver/fileserver/sfat32/sl_drv.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_drv.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -119,7 +119,7 @@
     @return KErrBadPower - failure due to low power
 
 */
-TInt TDriveInterface::ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
+TInt TDriveInterface::ReadNonCritical(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const
 {
     //__PRINT2(_L("#=+++ Read_nc2: pos:%LU, len:%u"), aPos, aLength);
 
@@ -128,7 +128,7 @@
 
     for(;;)
     {
-        nRes = iProxyDrive.Read(aPos, aLength, aTrg, aMessage, anOffset);
+        nRes = iProxyDrive.Read(aPos, aLength, aTrg, aMessage, anOffset, aFlag);
         if (nRes==KErrNone)
             break;
 
@@ -202,7 +202,7 @@
     @return KErrCorrupt - an illegal write is detected
     @return KErrAccessDenied - write to protected media
 */
-TInt TDriveInterface::WriteNonCritical(TInt64 aPos, TInt aLength, const TAny* aSrc, const RMessagePtr2 &aMessage, TInt anOffset)
+TInt TDriveInterface::WriteNonCritical(TInt64 aPos, TInt aLength, const TAny* aSrc, const RMessagePtr2 &aMessage, TInt anOffset, TUint aFlag)
 {
     //__PRINT2(_L("#=+++ Write_NC: pos:%LU, len:%u"), aPos, aLength);
 
@@ -213,7 +213,7 @@
     for(;;)
     {
         iMount->OpenMountForWrite(); //-- make a callback to CFatMountCB to perform some actions on 1st write.
-        nRes = iProxyDrive.Write(aPos, aLength, aSrc, aMessage, anOffset);
+        nRes = iProxyDrive.Write(aPos, aLength, aSrc, aMessage, anOffset, aFlag);
         if (nRes==KErrNone)
             break;
 
@@ -544,14 +544,14 @@
 
 //-- see original TDriveInterface methods
 
-TInt TDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset) const
+TInt TDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag) const
 {
     EnterCriticalSection();
-    TInt nRes = iLocalDrive->Read(aPos, aLength, aTrg, aMessage.Handle(), anOffset);
+    TInt nRes = iLocalDrive->Read(aPos, aLength, aTrg, aMessage.Handle(), anOffset, aFlag);
     LeaveCriticalSection();
     return nRes;
 }
-       
+
 TInt TDriveInterface::XProxyDriveWrapper::Read(TInt64 aPos,TInt aLength,TDes8& aTrg) const
 {
     EnterCriticalSection();
@@ -560,10 +560,10 @@
     return nRes;
 }
 
-TInt TDriveInterface::XProxyDriveWrapper::Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset)
+TInt TDriveInterface::XProxyDriveWrapper::Write(TInt64 aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2 &aMessage,TInt anOffset, TUint aFlag)
 {
     EnterCriticalSection();
-    TInt nRes = iLocalDrive->Write(aPos, aLength, aSrc, aMessage.Handle(), anOffset);
+    TInt nRes = iLocalDrive->Write(aPos, aLength, aSrc, aMessage.Handle(), anOffset, aFlag);
     LeaveCriticalSection();
     return nRes;
 }
--- a/userlibandfileserver/fileserver/sfat32/sl_fatcache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_fatcache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -349,7 +349,7 @@
 
     //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
     for(TUint i=0; i<numPages; ++i)
-        iPages.Append(NULL);
+        iPages.AppendL(NULL);
     
     }
 
--- a/userlibandfileserver/fileserver/sfat32/sl_file.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_file.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -103,18 +103,6 @@
 	iSeekIndex[seekPos] = aStoredCluster;
 	}
 
-TBool CFatFileCB::IsSeekBackwards(TUint aPos)
-//
-// Return true if aPos<currentPos
-//
-	{
-	
-	TUint cluster=iCurrentPos.iCluster<<ClusterSizeLog2();
-	TInt offset=ClusterRelativePos(iCurrentPos.iPos);
-	TUint currentPos=cluster+offset;
-	return(aPos<currentPos);
-	}
-
 void CFatFileCB::CheckPosL(TUint aPos)
 //
 // Check that the file is positioned correctly.
@@ -126,9 +114,6 @@
 		return;
     __ASSERT_DEBUG(aPos <= FCB_FileSize(), Fault(EFatFilePosBeyondEnd));
 
-	if (FileSizeModified() && IsSeekBackwards(aPos))
-		FlushDataL(); 
-	
 	TUint newRelCluster=aPos>>ClusterSizeLog2();
 	if ( aPos && (aPos==(newRelCluster<<ClusterSizeLog2())) )
 		newRelCluster--;
@@ -245,8 +230,10 @@
 	
 	if((startPos + length > curSize) || (startPos > startPos + length) )
 		aLength=curSize-startPos;
+		
+	TUint flag = DirectIOMode(aMessage) ? RLocalDrive::ELocDrvDirectIO : 0;
 	
-    FatMount().ReadFromClusterListL(iCurrentPos,aLength,aDes,aMessage,aOffset);
+    FatMount().ReadFromClusterListL(iCurrentPos,aLength,aDes,aMessage,aOffset, flag);
 	aLength=iCurrentPos.iPos-startPos;
 	}
 
@@ -295,7 +282,9 @@
 	TUint badcluster=0;
 	TUint goodcluster=0;
    	
-	TRAPD(ret, FatMount().WriteToClusterListL(iCurrentPos,aLength,aSrc,aMessage,aOffset,badcluster, goodcluster));
+	TUint flag = DirectIOMode(aMessage) ? RLocalDrive::ELocDrvDirectIO : 0;
+	
+	TRAPD(ret, FatMount().WriteToClusterListL(iCurrentPos,aLength,aSrc,aMessage,aOffset,badcluster, goodcluster, flag));
    	
 	if (ret == KErrCorrupt || ret == KErrDied)
 		{
@@ -864,10 +853,15 @@
 	else
 		return KErrNotSupported;
 
-	// Fetch the address of cluster 0
-	aInfo.iStartBlockAddress = fatMount.FAT().DataPositionInBytes(KFirstClusterNum);
+    TInt r;
+	
+    // Fetch the address of cluster 0
+	TRAP(r, aInfo.iStartBlockAddress = fatMount.FAT().DataPositionInBytesL(KFirstClusterNum));
+	if (r != KErrNone)
+		return r;
 
-	TRAPD(r, CheckPosL(startPos));
+
+	TRAP(r, CheckPosL(startPos));
 	if (r != KErrNone)
 		return r;
 
--- a/userlibandfileserver/fileserver/sfat32/sl_leafdir_cache.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_leafdir_cache.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -750,8 +750,8 @@
 			else
 				{
 				iLruList.Remove(i);
-				iLruList.Insert(aNodeUsed, 0);
-				return KErrNone;
+				TInt r = iLruList.Insert(aNodeUsed, 0);
+				return r;
 				}
 			}
 		}
--- a/userlibandfileserver/fileserver/sfat32/sl_mnt.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_mnt.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1610,7 +1610,7 @@
 /**
     Overwrite as many contiguous file clusters as possible.
 */
-void CFatMountCB::DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint aLastcluster, TUint& aBadcluster, TUint& aGoodcluster)
+void CFatMountCB::DoWriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint aLastcluster, TUint& aBadcluster, TUint& aGoodcluster, TUint aFlag)
     {
 
     __PRINT(_L("CFatMountCB::DoWriteToClusterListL"));
@@ -1622,9 +1622,9 @@
     const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1;
     const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters);
     const TInt writeLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos);
-    TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos;
-
-    TRAPD(r, iRawDisk->WriteL(dataStart,writeLength,aSrc,aMessage,anOffset));
+    TInt64 dataStart=FAT().DataPositionInBytesL(aPos.iCluster)+clusterRelativePos;
+
+    TRAPD(r, iRawDisk->WriteL(dataStart,writeLength,aSrc,aMessage,anOffset, aFlag));
 
     if(r == KErrNone) // Write succeded
         {
@@ -1653,7 +1653,7 @@
         if((aPos.iPos != 0) && (badcluster == aPos.iCluster) && (aLastcluster == 0) && (aPos.iCluster == cluster))
             { //Copy the contents already present in this cluster to new cluster allocated.
             const TInt sizeToRead = aPos.iPos - ((aPos.iPos >> ClusterSizeLog2()) << ClusterSizeLog2());
-            dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos((aPos.iPos - sizeToRead));
+            dataStart = FAT().DataPositionInBytesL(aPos.iCluster) + ClusterRelativePos((aPos.iPos - sizeToRead));
 
 
             //-- Allocate the buffer required to copy the contents from bad cluster
@@ -1682,7 +1682,7 @@
                 {
                 //Calculate and copy the contents to new cluster.
                 aPos.iCluster = goodcluster;
-                dataStart = FAT().DataPositionInBytes(aPos.iCluster) + ClusterRelativePos(aPos.iPos - sizeToRead);
+                dataStart = FAT().DataPositionInBytesL(aPos.iCluster) + ClusterRelativePos(aPos.iPos - sizeToRead);
 
                 r = LocalDrive()->Write(dataStart, clustBuf);
                 if(r == KErrNone)
@@ -1739,7 +1739,7 @@
 
 //-----------------------------------------------------------------------------------------
 
-void CFatMountCB::WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint& aBadcluster, TUint& aGoodcluster)
+void CFatMountCB::WriteToClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aSrc,const RMessagePtr2& aMessage,TInt anOffset, TUint& aBadcluster, TUint& aGoodcluster, TUint aFlag)
 //
 // Overwrite cluster list.
 //
@@ -1761,7 +1761,7 @@
     TInt previouscluster=0;
     FOREVER
         {
-        DoWriteToClusterListL(aPos,length-offset,aSrc,aMessage,anOffset+offset, previouscluster, aBadcluster, aGoodcluster);
+        DoWriteToClusterListL(aPos,length-offset,aSrc,aMessage,anOffset+offset, previouscluster, aBadcluster, aGoodcluster, aFlag);
         if (offset == (aPos.iPos-startPos))
             continue;
         offset=aPos.iPos-startPos;
@@ -1776,7 +1776,7 @@
 
 //-----------------------------------------------------------------------------------------
 
-void CFatMountCB::DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const
+void CFatMountCB::DoReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset, TUint aFlag) const
 //
 // Read from as many contiguous file clusters as possible
 //
@@ -1790,9 +1790,9 @@
     const TInt maxClusters=((aLength+clusterRelativePos-1)>>ClusterSizeLog2())+1;
     const TInt clusterListLen=FAT().CountContiguousClustersL(aPos.iCluster,endCluster,maxClusters);
     const TInt readLength=Min(aLength,(clusterListLen<<ClusterSizeLog2())-clusterRelativePos);
-    const TInt64 dataStart=FAT().DataPositionInBytes(aPos.iCluster)+clusterRelativePos;
-
-    TRAPD(r, iRawDisk->ReadL(dataStart,readLength,aTrg,aMessage,anOffset));
+    const TInt64 dataStart=FAT().DataPositionInBytesL(aPos.iCluster)+clusterRelativePos;
+
+    TRAPD(r, iRawDisk->ReadL(dataStart,readLength,aTrg,aMessage,anOffset, aFlag));
 
     if(r == KErrNone) // Read succeded
         {
@@ -1817,7 +1817,7 @@
 
 //-----------------------------------------------------------------------------------------
 
-void CFatMountCB::ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset) const
+void CFatMountCB::ReadFromClusterListL(TEntryPos& aPos,TInt aLength,const TAny* aTrg,const RMessagePtr2& aMessage,TInt anOffset, TUint aFlag) const
 //
 // Read from cluster list
 //
@@ -1837,7 +1837,7 @@
     TInt offset=0;
     FOREVER
         {
-        DoReadFromClusterListL(aPos,aLength-offset,aTrg,aMessage,anOffset+offset);
+        DoReadFromClusterListL(aPos,aLength-offset,aTrg,aMessage,anOffset+offset, aFlag);
         offset=aPos.iPos-startPos;
         if ((offset<aLength))
             {
@@ -3154,7 +3154,7 @@
         User::Leave(KErrCorrupt);
 
     TBuf8<sizeof(TCheckedUid)> uidBuf;
-    iRawDisk->ReadCachedL(FAT().DataPositionInBytes(aCluster),sizeof(TCheckedUid),uidBuf);
+    iRawDisk->ReadCachedL(FAT().DataPositionInBytesL(aCluster),sizeof(TCheckedUid),uidBuf);
     __ASSERT_DEBUG(uidBuf.Length()==sizeof(TCheckedUid),Fault(EFatReadUidFailed));
     TCheckedUid uid(uidBuf);
     anEntry.iType=uid.UidType();
@@ -3230,8 +3230,8 @@
 			//  Read the remaining length or the entire cluster block whichever is smaller
 			TInt readLength = Min(aLength-readTotal,(clusterListLen<<ClusterSizeLog2())-pos);
 			__ASSERT_DEBUG(readLength>0,Fault(EReadFileSectionFailed));
-			TInt64 dataAddress=(FAT().DataPositionInBytes(cluster))+pos;
-			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal);
+			TInt64 dataAddress=(FAT().DataPositionInBytesL(cluster))+pos;
+			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal, 0);
 			readTotal += readLength;
 
 			if (readTotal == aLength)
@@ -3259,7 +3259,7 @@
 // Read aLength of data from disk directly to thread relative descriptor
 //
     {
-    iRawDisk->ReadL(aPos,aLength,aTrg,aMessage,anOffset);
+    iRawDisk->ReadL(aPos,aLength,aTrg,aMessage,anOffset, 0);
     }
 
 //-----------------------------------------------------------------------------------------
@@ -3274,7 +3274,7 @@
 	//-- check if we are trying to write to the FAT directly and wait until FAT scan thread finishes in this case.
     FAT().RequestRawWriteAccess(aPos, aLength);
 
-    iRawDisk->WriteL(aPos,aLength,aSrc,aMessage,anOffset);
+    iRawDisk->WriteL(aPos,aLength,aSrc,aMessage,anOffset, 0);
     //-- Note: FAT directory cache will be invalidated in MountL()
     }
 
@@ -3434,7 +3434,7 @@
     if (!IsRootDir(aPos))
         {
         TInt relPos=ClusterRelativePos(aPos.iPos);
-        return FAT().DataPositionInBytes(aPos.iCluster)+relPos;
+        return FAT().DataPositionInBytesL(aPos.iCluster)+relPos;
         }
     if (aPos.iPos+StartOfRootDirInBytes()>=RootDirEnd())
         User::Leave(KErrDirFull); // Past last root dir entry
@@ -4070,7 +4070,7 @@
             User::LeaveIfError(r);
         if ( caps().iType&EMediaRam )
             {
-            realPosition = FAT().DataPositionInBytes( aPos.iCluster );
+            realPosition = FAT().DataPositionInBytesL( aPos.iCluster );
             aPos.iCluster = I64LOW((realPosition - aInfo.iStartBlockAddress)>>ClusterSizeLog2());
             blockMapEntry.SetStartBlock( aPos.iCluster );
             }
--- a/userlibandfileserver/fileserver/sfat32/sl_mnt32.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfat32/sl_mnt32.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1068,8 +1068,8 @@
 			//  Read the remaining length or the entire cluster block whichever is smaller
 			TInt readLength = (TInt)Min((TInt64)(aLength-readTotal),(clusterListLen<<ClusterSizeLog2())-pos);
 			__ASSERT_DEBUG(readLength>0,Fault(EReadFileSectionFailed));
-			TInt64 dataAddress=(FAT().DataPositionInBytes(cluster))+pos;
-			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal);
+			TInt64 dataAddress=(FAT().DataPositionInBytesL(cluster))+pos;
+			iRawDisk->ReadL(dataAddress,readLength,aTrg,aMessage,readTotal, 0);
 			readTotal += readLength;
 
 			if (readTotal == aLength)
--- a/userlibandfileserver/fileserver/sfile/sf_debug.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_debug.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -18,7 +18,7 @@
 #include "sf_std.h"
 #include <f32dbg.h>
 #include "f32image.h"
-#include <F32plugin.h>
+#include <f32plugin.h>
 #include "sf_file_cache.h"
 
 
--- a/userlibandfileserver/fileserver/sfile/sf_drv.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_drv.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -89,17 +89,13 @@
 // Do not allow the entry type to be changed
 //
 	{
-	const TUint KReadOnlySetAtts = KEntryAttVolume | 
-								   KEntryAttDir    | 
-								   KEntryAttRemote;
-
-	const TUint KReadOnlyClrAtts = KEntryAttVolume | 
-								   KEntryAttDir    | 
-								   KEntryAttRemote | 
-								   KEntryAttModified;
-
-	aSetAttMask   &= ~KReadOnlySetAtts;
-	aClearAttMask &= ~KReadOnlyClrAtts;
+	const TUint KReadOnlyAtts = KEntryAttVolume	| 
+								KEntryAttDir	| 
+								KEntryAttRemote	|
+								KEntryAttModified;
+
+	aSetAttMask   &= ~KReadOnlyAtts;
+	aClearAttMask &= ~KReadOnlyAtts;
 	}
 
 void CheckForLeaveAfterOpenL(TInt leaveError, CFsRequest* aRequest, TInt aHandle)
@@ -547,6 +543,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;
 	}
 
@@ -1235,6 +1244,31 @@
 		DriveNumber(), aName, I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()), aSetAttMask, aClearAttMask);
 	TRAP(r,CurrentMount().SetEntryL(entryName,aTime,aSetAttMask,aClearAttMask))
 	TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECMountCBSetEntryLRet, EF32TraceUidFileSys, r);
+	// If the file is already open then write the file attributes directly to the file
+	TFileName foldedName;
+	TUint32 nameHash=0;
+	foldedName.CopyF(aName);
+	nameHash=CalcNameHash(foldedName);
+
+	__CHECK_DRIVETHREAD(iDriveNumber);
+	TDblQueIter<CFileCB> q(CurrentMount().iMountQ);
+	CMountCB* currentMount = &CurrentMount();
+	CFileCB* file;
+	while ((file=q++)!=NULL)
+		{
+		if ((&file->Drive()==this) && 
+			&file->Mount() == currentMount &&
+			nameHash == file->NameHash() && 
+			file->FileNameF().Match(foldedName)==KErrNone)
+			{
+			TUint att = file->Att();
+			att |= aSetAttMask;
+			att &= ~aClearAttMask;
+			file->SetAtt(att | KEntryAttModified);
+			file->SetModified(aTime);
+			break;
+			}
+		}
 
 	return(r);
 	}
--- a/userlibandfileserver/fileserver/sfile/sf_file.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_file.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -699,8 +699,18 @@
 			// Current operation points to a local buffer
 			// The request originated from the file server (e.g. file cache) with a local message handle (KLocalMessageHandle)
 			TPtr8 dataDesc((TUint8*) currentOperation.iReadWriteArgs.iData + currentOperation.iReadWriteArgs.iOffset, len, len);
-			const RLocalMessage msg;
-			TRAP(r,file->ReadL(pos, len, &dataDesc, msg, 0));
+
+			// save the client's RMessage2
+			const RMessage2 msgClient = aRequest->Message();
+			
+			// overwrite RMessage2 in CFsMessageRequest with RLocalMessage 
+			const RLocalMessage msgLocal;					
+			const_cast<RMessage2&> (aRequest->Message()) = msgLocal;
+
+			TRAP(r,file->ReadL(pos, len, &dataDesc, aRequest->Message(), 0));
+							
+			// restore the client's RMessage2
+			const_cast<RMessage2&> (aRequest->Message()) = msgClient;
 			}
 		}
 
@@ -958,10 +968,6 @@
         {//-- this call is originated from explicit file write operation. Set 'Archive' attribute and new file time.
         aFile->SetArchiveAttribute(); //-- it will also set KEntryAttModified
         }
-    else
-        {//-- don't touch data and attributes if it is cache flushing dirty data
-        aFile->iAtt |= KEntryAttModified;
-        }
 
 
 	return KErrNone;
@@ -1094,8 +1100,18 @@
 		else
 			{
 			TPtr8 dataDesc((TUint8*) currentOperation.iReadWriteArgs.iData + currentOperation.iReadWriteArgs.iOffset, len, len);
-			const RLocalMessage msg;
-			TRAP(r,file->WriteL(pos, len, &dataDesc, msg, 0));
+
+			// save the client's RMessage2
+			const RMessage2 msgClient = aRequest->Message();
+			
+			// overwrite RMessage2 in CFsMessageRequest with RLocalMessage 
+			const RLocalMessage msgLocal;					
+			const_cast<RMessage2&> (aRequest->Message()) = msgLocal;
+
+			TRAP(r,file->WriteL(pos, len, &dataDesc, aRequest->Message(), 0));
+							
+			// restore the client's RMessage2
+			const_cast<RMessage2&> (aRequest->Message()) = msgClient;
 			}
 		}
 
@@ -1567,13 +1583,11 @@
 	
 	CFileCB& file=share->File();
 
-	// flush the write cache
-	CFileCache* fileCache = share->File().FileCache();
-	if (fileCache && (r = fileCache->FlushDirty(aRequest)) != CFsRequest::EReqActionComplete)
-		return r;
-	
 	if (size==file.Size64())
+		{
+		file.SetCachedSize64(size);	// Ensure the cache size doesn't exceeed the physical size
 		return(KErrNone);
+		}
 	
 	TBool fileHasGrown = size > file.Size64();
 	if (fileHasGrown)
@@ -1627,6 +1641,7 @@
 	CFileShare* share=(CFileShare*)aRequest->ScratchValue();
 //	TInt att=(TInt)aRequest->FileShare()->File().Att()&KEntryAttMaskSupported;
 	TInt att=(TInt)share->File().Att();	// DRM: let ROM XIP attribute through
+	att&= ~KEntryAttModified;	// this is an internal attribute and should not be returned to the client
 	TPtrC8 pA((TUint8*)&att,sizeof(TInt));
 	aRequest->WriteL(KMsgPtr0,pA);
 	
@@ -1666,7 +1681,7 @@
 	ValidateAtts(setAttMask,clearAttMask);
 
 	TRACE5(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryL, EF32TraceUidFileSys, &share->File(), 0, 0, setAttMask,clearAttMask);
-	TRAP(r,share->File().SetEntryL(TTime(0),setAttMask,clearAttMask))
+	TRAP(r,share->File().SetEntryL(share->File().Modified(),setAttMask,clearAttMask))
 	TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryLRet, EF32TraceUidFileSys, r);
 
 	return(r);
@@ -1775,12 +1790,12 @@
     TTime time;
 	TPtr8 t((TUint8*)&time,sizeof(TTime));
 	aRequest->ReadL(KMsgPtr0,t);
-	TUint setAttMask=(TUint)(aRequest->Message().Int1()|KEntryAttModified);
+	TUint setAttMask=(TUint)(aRequest->Message().Int1());
 	TUint clearAttMask=(TUint)aRequest->Message().Int2();
 	ValidateAtts(setAttMask,clearAttMask);//	Validate attributes
 
 	TRACE5(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryL, EF32TraceUidFileSys, &share->File(), 0, 0, setAttMask,clearAttMask);
-	TRAP(r,share->File().SetEntryL(time,setAttMask,clearAttMask))
+	TRAP(r,share->File().SetEntryL(time,setAttMask|KEntryAttModified,clearAttMask))
 	TRACERET1(UTF::EBorder, UTraceModuleFileSys::ECFileCBSetEntryLRet, EF32TraceUidFileSys, r);
 
 	return(r);
@@ -3624,13 +3639,25 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
+EXPORT_C TBool CFileCB::DirectIOMode(const RMessagePtr2& aMessage)
+	{
+	CFsMessageRequest* msgRequest = CFsMessageRequest::RequestFromMessage(aMessage);
+
+	TInt func = msgRequest->Operation()->Function();
+	ASSERT(func == EFsFileRead || func == EFsFileWrite || func == EFsFileWriteDirty  || func == EFsReadFileSection);
+
+	CFileShare* share;
+	CFileCB* file;
+	GetFileFromScratch(msgRequest, share, file);
+	if (share == NULL)		// no share indicates this is a request originating from the file cache
+		return EFalse;
+
+	return func == EFsFileRead ? share->iMode & EFileReadDirectIO : share->iMode & EFileWriteDirectIO; 
+	}
+
+
+
+
+
+
+
--- a/userlibandfileserver/fileserver/sfile/sf_memory_client.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_memory_client.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -145,6 +145,10 @@
 	iTouchedRegionFlag = 0;
 	iReusablePagePool.Close();
 	iReusablePagePool.Reserve(iReservedRegionMarkInSegs);
+    if (r != KErrNone)
+        {
+        ASSERT(0);
+        }
 	}
 
 /**
@@ -224,7 +228,9 @@
 	ASSERT(err == KErrNone);
 	if (err != KErrNone)
 		return err;
-	iReusablePagePool.Append(aStartRamAddr);
+	err = iReusablePagePool.Append(aStartRamAddr);
+    if (err != KErrNone)
+        return err;
 	return KErrNone;
 	}
 
--- a/userlibandfileserver/fileserver/sfile/sf_plugin.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_plugin.h	Thu Aug 19 11:14:22 2010 +0300
@@ -21,7 +21,7 @@
 
 #include "message.h"
 #include <f32fsys.h>
-#include <F32plugin.h>
+#include <f32plugin.h>
 
 class CFsSyncMessageScheduler;
 class CFsInternalRequest;
--- a/userlibandfileserver/fileserver/sfile/sf_pool.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_pool.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -64,7 +64,11 @@
 			{
 			return KErrNoMemory;
 			}
-		iFreeList.Append(t);	
+		r = iFreeList.Append(t);
+        if(r !=  KErrNone)
+            {
+            return r;
+            }
 		i++;
 		}
 	
--- a/userlibandfileserver/fileserver/sfile/sf_request.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_request.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -1116,7 +1116,9 @@
 		}
 
 	SetError(err);
-
+	
+    if (IsExpectedResult(err) && !IsPluginSpecific() && !IsNotifierSpecific())
+        DoNotifyDiskSpace(KErrNone);
 
 	// Start issuing the post-operation requests starting from the bottom of the chain
 	iCurrentPlugin = NULL;
@@ -1142,16 +1144,6 @@
 	{
 	__THRD_PRINT2(_L("----- CFsMessageRequest::Complete() req %08x with %d"), this, aError);
 
-	if (aError==KErrNoMemory)
-		{
-		if (iDrive)	// Not all message requests are associated with a drive!
-			{
-			TDriveInfo di;
-			iDrive->DriveInfo(di);
-			if (di.iType == EMediaRam)
-				aError = KErrNoMemory;
-			}
-		}
 	if(aError!=KErrNone)
 		{
 		if(iOperation->IsOpenSubSess())
@@ -1298,9 +1290,7 @@
 	if(aError==KErrNone)
 		{
 		if(!(FsNotify::IsChangeQueEmpty(driveNumber)))
-			FsNotify::HandleChange(this,driveNumber);	
-		if ((driveNumber != KDriveInvalid) && !(FsNotify::IsDiskSpaceQueEmpty(driveNumber)))
-			FsNotify::HandleDiskSpace(this, DriveNumber());
+			FsNotify::HandleChange(this,driveNumber);
 	
 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
 		if 	(iOperation->iFunction == EFsFileWrite)
@@ -1337,6 +1327,16 @@
 		}
 	}
 
+void CFsMessageRequest::DoNotifyDiskSpace(TInt aError)
+    {
+    __PRINT1(_L("----- CFsMessageRequest::DoNotifyDiskSpace() with %d"),aError);
+    if(aError != KErrNone)
+        return;
+
+    TInt driveNumber = DriveNumber();
+    if ((driveNumber != KDriveInvalid) && !(FsNotify::IsDiskSpaceQueEmpty(driveNumber)))
+        FsNotify::HandleDiskSpace(this, driveNumber);
+    }
 
 void CFsMessageRequest::Free()
 //
--- a/userlibandfileserver/fileserver/sfile/sf_std.h	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_std.h	Thu Aug 19 11:14:22 2010 +0300
@@ -32,7 +32,7 @@
 #include <e32const_private.h>
 #include "sf_plugin.h"
 #include "sf_func.h"
-#include <F32plugin.h>
+#include <f32plugin.h>
 #include "f32trace.h"
 #include <utraceefile.h>
 
@@ -115,6 +115,8 @@
 #define __PLUGIN_PRINT3(t,a,b,c)
 #endif
 
+#define _LOFF(p,T,f) ((T*)(((TUint8*)(p))-_FOFF(T,f)))
+
 const TInt KMaxTotalDriveReserved	=0x100000;
 const TInt KMaxSessionDriveReserved	=0x10000;
 
@@ -1312,11 +1314,13 @@
 	inline void Init();
 	void ReStart();
 	TBool IsPluginRequest();
+	static inline CFsMessageRequest* RequestFromMessage(const RMessagePtr2& aMessage);
 	
    // UID of the process to touching the file. (To be used in notification framework).
    // TUid iUID;
 private:
 	void DoNotify(TInt aError);
+	void DoNotifyDiskSpace(TInt aError);
 	TInt DoInitialise();
 	TInt PostInitialise();
 	TBool DispatchToPlugin();
--- a/userlibandfileserver/fileserver/sfile/sf_std.inl	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/sfile/sf_std.inl	Thu Aug 19 11:14:22 2010 +0300
@@ -252,6 +252,11 @@
 void CFsMessageRequest::SetMessage(RMessage2& aMessage) 
 	{iMessage=aMessage;}
 
+
+CFsMessageRequest* CFsMessageRequest::RequestFromMessage(const RMessagePtr2& aMessage)
+	{return _LOFF(&aMessage, CFsMessageRequest, iMessage);}
+
+
 TMsgOperation* CFsMessageRequest::CurrentOperationPtr()
 	{return iCurrentOperation;}
 
--- a/userlibandfileserver/fileserver/swins/elocal.cpp	Thu Jul 15 20:11:42 2010 +0300
+++ b/userlibandfileserver/fileserver/swins/elocal.cpp	Thu Aug 19 11:14:22 2010 +0300
@@ -855,8 +855,8 @@
     file.SetSize64(fileSize, EFalse);
 	file.SetAtt(info.dwFileAttributes&KEntryAttMaskSupported);
 
-//	if (IsRomDrive())
-//		file.iAtt|=KEntryAttReadOnly;
+	if (IsRomDrive())
+		file.SetAtt(file.Att() | KEntryAttReadOnly);
 	TTime tempTime=file.Modified();
 	fileTimeToTime(&info.ftLastWriteTime,tempTime);
 	file.SetModified(tempTime);