kernel/eka/drivers/locmedia/locmedia.cpp
changeset 0 a41df078684a
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/locmedia/locmedia.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,5109 @@
+// Copyright (c) 1998-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:
+// e32\drivers\locmedia\locmedia.cpp
+// 
+//
+
+#include "locmedia.h"
+#include <d32locd.h>
+#include "dmasupport.h"
+#include <kernel/cache.h>
+
+#if defined(_DEBUG) && defined(__DEMAND_PAGING__)
+//#define __DEBUG_DEMAND_PAGING__
+#endif
+
+
+#if 0
+#define CHECK_RET(r)	if ((r)==KErrNotSupported && (KDebugNum(KSCRATCH))) {NKern::Lock(); *(TInt*)0xfaece5=0;}
+//#define CHECK_RET(r)
+#else
+#define CHECK_RET(r)
+#endif
+
+_LIT(KLddName,"LocDrv");
+_LIT(KLitMediaDriverName, "Media.*");
+_LIT(KLitLocMedia,"LocMedia");
+
+#define LOCM_FAULT()	Kern::Fault("LOCMEDIA",__LINE__)
+
+const TInt KMaxLocalDriveCapsLength=256;
+const TInt KMaxQueryDeviceLength=256;
+
+// The maximum amount of user-data which will be pinned. If a request is longer 
+// than this value it will be split up into a number of requests
+// This value is a bit arbitrary - it needs to be sufficiently large so that transfer 
+// rates don't suffer too much - but it can't be too big or we'd be "stealing" too much 
+// memory from the demand paging pool and starving other processes
+const TInt KMaxPinData = 256*1024;
+
+// The number of locks available for pinning shared by all the drive threads in the system. 
+// If all locks are in use then a single pre-allocated lock is used.
+const TInt KDynamicPagingLockCount = 8;
+
+TLocDrv* TheDrives[KMaxLocalDrives];
+DMedia* TheMedia[KMaxLocalDrives];
+HBuf* DriveNames[KMaxLocalDrives];
+TInt UsedMedia=0;
+TPasswordStore* ThePasswordStore=NULL;
+
+class DPrimaryMediaBase::DBody : public DBase
+	{
+public:
+	TInt iPhysDevIndex;
+	TInt iRequestCount;
+#ifdef __DEMAND_PAGING__
+	DMediaPagingDevice* iPagingDevice;
+	TInt iPageSizeMsk;			// Mask of page size (e.g. 4096-1 -> 4095)
+	TInt iMediaChanges;
+#endif
+	};
+
+#ifdef __DEMAND_PAGING__
+DMediaPagingDevice* ThePagingDevices[KMaxLocalDrives];
+DPrimaryMediaBase* TheRomPagingMedia = NULL;
+DPrimaryMediaBase* TheDataPagingMedia = NULL;
+TBool DataPagingDeviceRegistered = EFalse;
+class DPinObjectAllocator;
+DPinObjectAllocator* ThePinObjectAllocator = NULL;
+
+// The paging media might share a DfcQ with other non-paging media (e.g. 2 MMC/SD cards sharing the same stack)
+// 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;}
+inline TBool RomPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
+	{return TheRomPagingMedia && TheRomPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
+
+
+
+/* 
+DPinObjectAllocator
+
+Internal class which contains :
+	(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
+*/
+NONSHARABLE_CLASS(DPinObjectAllocator) : public DBase
+	{
+public:
+	/*
+	SVirtualPinContainer
+	Internal class encapsulating a TVirtualPinObject.
+	Contains a SDblQueLink so that it may form part of a SDblQue
+	*/
+	typedef struct
+		{
+		TVirtualPinObject* iObject;
+		SDblQueLink iLink;
+		} SVirtualPinContainer;
+
+public:
+	inline DPinObjectAllocator() {};
+	~DPinObjectAllocator();
+	TInt Construct(TInt aObjectCount, TUint aNumPages);
+	
+	SVirtualPinContainer* AcquirePinObject();
+	void ReleasePinObject(SVirtualPinContainer* aVirtualPinObject);
+
+	inline DFragmentationPagingLock& PreAllocatedDataLock() {return *iPreAllocatedDataLock;}
+
+private:
+	// array of SVirtualPinContainer's
+	SVirtualPinContainer* iVirtualPinContainers;
+	TInt iObjectCount;
+
+	// queues containing SVirtualPinContainer's
+	SDblQue iFreeQ;
+	
+	// pre-allocated (small) buffers for locking client data should Kern::PinVirtualMemory() fail
+	DFragmentationPagingLock* iPreAllocatedDataLock;
+
+	// A mutex to protect access to the pinning objects.
+	NFastMutex iLock;
+
+public:
+	TUint iFragmentGranularity;
+	};
+
+
+DPinObjectAllocator::~DPinObjectAllocator()
+	{
+	if (iPreAllocatedDataLock)
+		{
+		iPreAllocatedDataLock->Cleanup();
+		delete iPreAllocatedDataLock;
+		}
+
+	for (TInt n=0; n<iObjectCount; n++)
+		{
+		SVirtualPinContainer& virtualPinContainer = iVirtualPinContainers[n];
+		if (virtualPinContainer.iObject)
+			Kern::DestroyVirtualPinObject(virtualPinContainer.iObject);
+		}
+
+	delete [] iVirtualPinContainers;
+	}
+
+TInt DPinObjectAllocator::Construct(TInt aObjectCount, TUint aNumPages)
+	{
+	TInt pageSize = Kern::RoundToPageSize(1);
+	iFragmentGranularity = pageSize * aNumPages;
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
+
+	// construct the paging lock containing pre-allocated buffers
+
+	iPreAllocatedDataLock = new DFragmentationPagingLock();
+	if(!iPreAllocatedDataLock)
+		return KErrNoMemory;
+	TInt r = iPreAllocatedDataLock->Construct(aNumPages);
+	if (r != KErrNone)
+		return r;
+
+
+	SVirtualPinContainer* iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
+	if (iVirtualPinContainers == NULL)
+		return KErrNoMemory;
+	memclr(iVirtualPinContainers, sizeof(SVirtualPinContainer) * aObjectCount);
+	iObjectCount = aObjectCount;
+
+	// construct the queue of dynamic paging locks
+	for (TInt n=0; n<aObjectCount; n++)
+		{
+		SVirtualPinContainer& pinContainer = iVirtualPinContainers[n];
+
+		TInt r = Kern::CreateVirtualPinObject(pinContainer.iObject);
+		if (r != KErrNone)
+			return KErrNoMemory;
+
+
+		iFreeQ.Add(&pinContainer.iLink);
+		}
+	return KErrNone;
+	}
+
+/** 
+returns a SVirtualPinContainer object or NULL if NULL available
+*/
+DPinObjectAllocator::SVirtualPinContainer* DPinObjectAllocator::AcquirePinObject()
+	{
+	SVirtualPinContainer* pinContainer = NULL;
+	
+	NKern::FMWait(&iLock);
+
+	if (!iFreeQ.IsEmpty())
+		{
+		SDblQueLink* link = iFreeQ.First();
+		pinContainer = _LOFF(link, SVirtualPinContainer, iLink);
+		link->Deque();
+		}
+
+
+	NKern::FMSignal(&iLock);
+	return pinContainer;
+	}
+
+/** 
+returns a SVirtualPinContainer object to the pool
+*/
+void DPinObjectAllocator::ReleasePinObject(SVirtualPinContainer* aPinContainer)
+	{
+	NKern::FMWait(&iLock);
+
+	iFreeQ.Add(&aPinContainer->iLink);
+
+	NKern::FMSignal(&iLock);
+	}
+
+#endif	// __DEMAND_PAGING__
+
+
+/********************************************
+ * Local drive device base class
+ ********************************************/
+DECLARE_EXTENSION_LDD()
+	{
+	return new DLocalDriveFactory;
+	}
+
+DLocalDriveFactory::DLocalDriveFactory()
+//
+// Constructor
+//
+	{
+	iParseMask=KDeviceAllowUnit|KDeviceAllowInfo;
+	iUnitsMask=~(0xffffffff<<KMaxLocalDrives);
+	iVersion=TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion);
+	}
+
+TInt DLocalDriveFactory::Install()
+//
+// Install the device driver.
+//
+	{
+	return SetName(&KLddName);
+	}
+
+void DLocalDriveFactory::GetCaps(TDes8& /*aDes*/) const
+//
+// Return the Comm capabilities.
+//
+	{
+//	TCapsLocalDriveV01 b;
+//	b.version=iVersion;
+//	aDes.FillZ(aDes.MaxLength());
+//	aDes.Copy((TUint8 *)&b,Min(aDes.MaxLength(),sizeof(b)));
+	}
+
+TInt DLocalDriveFactory::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a channel on the device.
+//
+	{
+	aChannel=new DLocalDrive;
+	return aChannel?KErrNone:KErrNoMemory;
+	}
+
+/********************************************
+ * Local drive interface class
+ ********************************************/
+DLocalDrive::DLocalDrive()
+	{
+//	iLink.iNext=NULL;
+	}
+
+DLocalDrive::~DLocalDrive()
+	{
+	if (iDrive)
+		{
+		__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
+		iDrive->Disconnect(this);
+		__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
+		}
+	DThread* pC=NULL;
+	NKern::LockSystem();
+	if (iCleanup.iThread)
+		{
+		pC=iCleanup.iThread;
+		iCleanup.Remove();
+		iCleanup.iThread=NULL;
+		}
+	NKern::UnlockSystem();
+	if (pC)	// original client may already have terminated
+		{
+		if (iNotifyChangeRequest)
+			Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrCancel);
+		pC->Close(NULL);	// balances Open() in DoCreate
+		}
+	if (iNotifyChangeRequest)
+		Kern::DestroyClientRequest(iNotifyChangeRequest);
+	}
+
+TInt DLocalDrive::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
+	{
+	if(!Kern::CurrentThreadHasCapability(ECapabilityTCB,__PLATSEC_DIAGNOSTIC_STRING("Checked by ELOCD.LDD (Local Media Driver)")))
+		return KErrPermissionDenied;
+	if (!Kern::QueryVersionSupported(TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion),aVer))
+		return KErrNotSupported;
+
+	NKern::ThreadEnterCS();
+	TInt r = Kern::CreateClientDataRequest(iNotifyChangeRequest);
+	NKern::ThreadLeaveCS();
+	if (r != KErrNone)
+		return r;
+
+	DThread& t=Kern::CurrentThread();
+	NKern::LockSystem();
+	t.AddCleanup(&iCleanup);
+	NKern::UnlockSystem();
+	t.Open();
+	iNotifyChangeRequest->SetDestPtr((TBool*) anInfo);
+
+	iDrive=TheDrives[aUnit];
+	if (!iDrive)
+		return KErrNotSupported;
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DLocalDrive Create - connect to drive %d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
+	r=iDrive->Connect(this);
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive Create D:%d, M:%08x r:%d",iDrive->iDriveNumber,iDrive->iMedia,r));
+	if (r!=KErrNone)
+		iDrive=NULL;	// didn't connect so don't disconnect
+	return r;
+	}
+
+#if defined(_DEBUG)
+void DebugDumpDriveCaps(const TLocDrv* aDrive, const TAny* aCaps)
+	{
+	const TLocalDriveCapsV5& c=*(const TLocalDriveCapsV5*)aCaps;
+	Kern::Printf("Drive %d Caps:", aDrive->iDriveNumber);
+	Kern::Printf("Size: %lx", c.iSize);
+	Kern::Printf("Type: %08x", c.iType);
+	Kern::Printf("Batt: %08x", c.iBattery);
+	Kern::Printf("DAtt: %08x", c.iDriveAtt);
+	Kern::Printf("MAtt: %08x", c.iMediaAtt);
+	Kern::Printf("Base: %08x", c.iBaseAddress);
+	Kern::Printf("FSID: %04x", c.iFileSystemId);
+	Kern::Printf("PTYP: %04x", c.iPartitionType);
+	Kern::Printf("HIDN: %08x", c.iHiddenSectors);
+	Kern::Printf("EBSZ: %08x", c.iEraseBlockSize);
+    //---------------- V5 ------------------//
+    if (c.iSerialNumLength != 0)
+        {
+        Kern::Printf("SN: length is %d", c.iSerialNumLength);
+        TBuf8<2*KMaxSerialNumLength+20> snBuf;
+        snBuf.Append(_L8("SN: content is "));
+        for (TUint i=0; i<c.iSerialNumLength; i++)
+            snBuf.AppendNumFixedWidth(c.iSerialNum[i], EHex, 2);
+        Kern::Printf((const char*)snBuf.Ptr());
+        }
+    else
+        Kern::Printf("SN: not supported");
+	}
+#endif
+
+/*
+ * Requests are passed in message as follows:
+ * iValue	= request ID
+ * iArg[0,1]= Position
+ * iArg[2,3]= Length
+ * iArg[4]	= Pointer to remote thread (NULL if client)
+ * iArg[5]	= Pointer to remote descriptor
+ * iArg[6]	= Offset into remote descriptor
+ * iArg[7]	= Flags (whole media)
+ * iArg[8]	= Pointer to TLocDrv
+ */
+
+TInt DLocalDrive::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	__TRACE_TIMING(0);
+	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoControl D:%d M:%08x F:%d A1:%08x A2:%08x",
+														iDrive->iDriveNumber, iDrive->iMedia, aFunction, a1, a2));
+	TInt r=KErrNotSupported;
+	TLocDrvRequest& m=TLocDrvRequest::Get();
+	m.Flags()=0;
+	m.Drive()=iDrive;
+	switch (aFunction)
+		{
+		case RLocalDrive::EControlRead:
+			{
+			m.Id()=ERead;
+			r=m.ProcessMessageData(a1);
+			__TRACE_TIMING(1);
+			if (r==KErrNone)
+				{
+				__TRACE_TIMING(2);
+				r=iDrive->Request(m);
+				__TRACE_TIMING(3);
+				}
+			m.CloseRemoteThread();
+			break;
+			}
+		case RLocalDrive::EControlWrite:
+			{
+			m.Id()=EWrite;
+			r=m.ProcessMessageData(a1);
+			if (r==KErrNone)
+				r=iDrive->Request(m);
+			m.CloseRemoteThread();
+			break;
+			}
+		case RLocalDrive::EControlCaps:
+			{
+			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
+			capsBuf.SetMax();
+			capsBuf.FillZ();
+			m.Id()=ECaps;
+			m.RemoteDes()=(TAny*)capsBuf.Ptr();	// overload this
+			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(_DEBUG)
+			__KTRACE_OPT(KLOCDRV,DebugDumpDriveCaps(iDrive,capsBuf.Ptr()));
+#endif
+			Kern::InfoCopy(*(TDes8*)a1, capsBuf);
+			break;
+			}
+		case RLocalDrive::EControlFormat:
+			{
+			m.Id()=EFormat;
+			r=m.ProcessMessageData(a1);
+			if (r==KErrNone)
+				r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlEnlarge:
+			if ((TInt)a1<0)
+				{
+				r=KErrArgument;
+				break;
+				}
+			m.Length()=(TInt)a1;
+			m.Id()=EEnlarge;
+			r=iDrive->Request(m);
+			break;
+		case RLocalDrive::EControlReduce:
+			{
+			if ((TInt)a1<0 || (TInt)a2<0)
+				{
+				r=KErrArgument;
+				break;
+				}
+			m.Pos()=(TInt)a1;
+			m.Length()=(TInt)a2;
+			m.Id()=EReduce;
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlForceMediaChange:
+			m.Pos()=(TInt)a1;
+			m.Id()=EForceMediaChange;
+			r = iDrive->Request(m);
+			break;
+		case RLocalDrive::EControlMediaDevice:
+			r=iDrive->iPrimaryMedia->iDevice;
+			break;
+		case RLocalDrive::EControlIsRemovable:
+			{
+			TInt sockNum;
+			r=iDrive->iPrimaryMedia->IsRemovableDevice(sockNum);
+			if (r)
+				kumemput32(a1,&sockNum,sizeof(TInt));
+			break;	
+			}
+		case RLocalDrive::EControlControlIO:
+			{
+			TLocalDriveControlIOData d;
+			kumemget32(&d,a1,sizeof(d));
+
+			m.Id() = EControlIO;
+			m.iArg[0] = (TAny*) d.iCommand;
+			m.iArg[1] = d.iParam1;
+			m.iArg[2] = d.iParam2;
+
+			// if d.iHandle is == KLocalMessageHandle (-1),
+			//	d.aParam1 and d.aParam2 are TAny* pointers
+			//
+			// if d.iHandle is == 0, 
+			//	d.aParam1 and d.aParam2 are TInts
+			//
+			// if d.iHandle is > 0, 
+			//	d.aParam1 is a data pointer (TUint8*) 
+			//	d.aParam2 is an optional extra paramater (TInt)
+			//	d.iHandle is a data length (TInt)
+			m.iArg[3] = (TAny*) d.iHandle;
+
+			//We're highjacking fields representing
+			//length and position in a normal message, so
+			//let's not have the dispatcher function attempt
+			//to adjust for partition size.
+			m.Flags() |= TLocDrvRequest::EAdjusted;
+
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlSetMountInfo:
+			{
+			m.Id()=ERead;
+			r=m.ProcessMessageData(a1);
+			DPrimaryMediaBase* pM=iDrive->iPrimaryMedia;
+			if(!pM || r!=KErrNone)
+				break;
+
+			if (pM->iMountInfo.iThread)
+				{
+				NKern::ThreadEnterCS();
+				//Close original thread
+				Kern::SafeClose((DObject*&) pM->iMountInfo.iThread,NULL);
+				if (m.RemoteDes()!=NULL)
+					{
+					//Set new mount info and leave setting thread open
+#ifdef __DEMAND_PAGING__
+					// lock the mount info if this is a data paging media - and keep it locked
+					if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
+						break;
+#endif
+					pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
+					pM->iMountInfo.iThread=m.RemoteThread();
+					}
+				else
+					{
+					//Clear existing mount info and close setting thread
+
+#ifdef __DEMAND_PAGING__
+					// unlock the mount info if this is a data paging media
+					UnlockMountInfo(*pM);
+#endif
+
+					pM->iMountInfo.iInfo=NULL;
+					pM->iMountInfo.iThread=NULL;
+					m.CloseRemoteThread();
+					}
+				NKern::ThreadLeaveCS();
+				r=KErrNone;
+				}
+			else
+				{
+				//Setting mount info for the first time
+				if (m.RemoteDes()==NULL)
+					{
+					// if no mount info, close setting thread opened in ProcessMessageData()
+					m.CloseRemoteThread();
+					break;
+					}
+
+				NKern::ThreadEnterCS();
+#ifdef __DEMAND_PAGING__
+				// lock the mount info if this is a data paging media - and keep it locked
+				if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
+					break;
+#endif
+
+				pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
+				pM->iMountInfo.iThread=m.RemoteThread();
+				NKern::ThreadLeaveCS();
+				r=KErrNone;
+				}
+			break;
+			}
+		case RLocalDrive::EControlPasswordLock:
+			{
+			m.Id()=EPasswordLock;
+			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
+			m.RemoteDes()=(TAny*)ppd;
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlPasswordUnlock:
+			{
+			m.Id()=EPasswordUnlock;
+			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
+			m.RemoteDes()=(TAny*)ppd;
+			r=iDrive->Request(m);
+			if(r == KErrNone)
+				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
+			break;
+			}
+		case RLocalDrive::EControlPasswordClear:
+			{
+			m.Id()=EPasswordClear;
+			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
+			m.RemoteDes()=(TAny*)ppd;
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlPasswordErase:
+			{
+			m.Id()=EPasswordErase;
+			r=iDrive->Request(m);
+			if(r == KErrNone)
+				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
+			break;
+			}
+		case RLocalDrive::EControlNotifyChange:
+			if (iCleanup.iThread != &Kern::CurrentThread())
+				Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
+			r=KErrNone;
+			if (!iNotifyChangeRequest->StatusPtr())
+				r = iNotifyChangeRequest->SetStatus((TRequestStatus*) a1);
+			break;
+		case RLocalDrive::EControlNotifyChangeCancel:
+			if (iCleanup.iThread != &Kern::CurrentThread())
+				Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
+			Kern::QueueRequestComplete(iCleanup.iThread,iNotifyChangeRequest,KErrCancel);
+			break;
+		case RLocalDrive::EControlReadPasswordStore:
+			{
+			m.Id()=EReadPasswordStore;
+			m.RemoteDes()=(TDes8*)a1;
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlWritePasswordStore:
+			{
+			m.Id()=EWritePasswordStore;
+			m.RemoteDes()=(TDes8*)a1;
+			r=iDrive->Request(m);
+			if(r == KErrNone)
+				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
+			break;
+			}
+		case RLocalDrive::EControlPasswordStoreLengthInBytes:
+			{
+			m.Id()=EPasswordStoreLengthInBytes;
+			m.RemoteDes()=a1;
+			r=iDrive->Request(m);
+			break;
+			}
+		case RLocalDrive::EControlGetLastErrorInfo:
+			{
+			m.Id()=EGetLastErrorInfo;
+			m.iArg[0]=this;
+			TErrorInfoBuf errorInfoBuf;
+			errorInfoBuf.SetMax();
+			errorInfoBuf.FillZ();
+			m.RemoteDes()=(TAny*) errorInfoBuf.Ptr();	// overload this
+			m.Length() = errorInfoBuf.MaxLength();
+			r=iDrive->Request(m);
+			Kern::InfoCopy(*(TDes8*)a1, errorInfoBuf);
+			break;
+			}
+		case RLocalDrive::EControlDeleteNotify:
+			{
+			m.Id()=EDeleteNotify;
+			r=m.ProcessMessageData(a1);
+			if (r==KErrNone)
+				r=iDrive->Request(m);
+			break;
+			}
+
+		case RLocalDrive::EControlQueryDevice:
+			{
+			TBuf8<KMaxQueryDeviceLength> queryBuf;
+			queryBuf.SetMax();
+			queryBuf.FillZ();
+
+			m.Id() = EQueryDevice;
+			m.iArg[0] = a1;		// RLocalDrive::TQueryDevice
+			m.RemoteDes() = (TAny*)queryBuf.Ptr();	// overload this
+			m.Length() = KMaxLocalDriveCapsLength;	// for pinning
+			r=iDrive->Request(m);
+
+			Kern::InfoCopy(*(TDes8*)a2, queryBuf);
+			break;
+			}
+
+		}
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoControl D:%d M:%08x ret %d",iDrive->iDriveNumber, iDrive->iMedia, r));
+	__TRACE_TIMING(4);
+	return r;
+	}
+
+#ifdef __DEMAND_PAGING__
+TInt DLocalDrive::LockMountInfo(DPrimaryMediaBase& aPrimaryMedia, TLocDrvRequest& aReq)
+	{
+	DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice;
+	if (pagingDevice == NULL)
+		return KErrNone;
+
+	__ASSERT_DEBUG(pagingDevice->iMountInfoDataLock == NULL, LOCM_FAULT());
+	__ASSERT_DEBUG(pagingDevice->iMountInfoDescHdrLock == NULL, LOCM_FAULT());
+	__ASSERT_DEBUG(pagingDevice->iMountInfoDescLenLock == NULL, LOCM_FAULT());
+
+	DThread* pT = aReq.RemoteThread();
+	if (!pT)
+		pT = &Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
+
+	TInt length = 0;
+	TInt maxLength = 0;
+	TUint8* desAddress = NULL;
+	TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,desAddress,EFalse);	// get descriptor length, maxlength and desAddress
+	if (r != KErrNone)
+		return r;
+	if (length == 0)
+		return KErrNone;
+
+
+	static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0};
+	TUint32 desHdr;
+	r = Kern::ThreadRawRead(pT, aReq.RemoteDes(), &desHdr, sizeof(desHdr));
+	if(r!=KErrNone)
+		return r;
+	TInt desType = desHdr >>KShiftDesType8;
+	TInt desHdrLen = LengthLookup[desType];
+	if(!desHdrLen)
+		return KErrBadDescriptor;
+
+
+	pagingDevice->iMountInfoDataLock = ThePinObjectAllocator->AcquirePinObject();
+	pagingDevice->iMountInfoDescHdrLock = ThePinObjectAllocator->AcquirePinObject();
+	pagingDevice->iMountInfoDescLenLock = ThePinObjectAllocator->AcquirePinObject();
+
+	if (pagingDevice->iMountInfoDataLock == NULL || 
+		pagingDevice->iMountInfoDescHdrLock == NULL || 
+		pagingDevice->iMountInfoDescLenLock == NULL)
+		{
+		UnlockMountInfo(aPrimaryMedia);	// tidy up
+		return KErrNoMemory;
+		}
+
+
+	// First pin the descriptor header 
+	DPinObjectAllocator::SVirtualPinContainer* lock;
+	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock;
+	r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) aReq.RemoteDes(), desHdrLen, pT);
+	if (r != KErrNone)
+		{
+		UnlockMountInfo(aPrimaryMedia);	// tidy up
+		return KErrNoMemory;
+		}
+
+	
+	
+	// For EBufCPtr-type descriptors, need to pin the extra length before the buffer (!)
+	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock;
+	if (desType == EBufCPtr)
+		{
+		TLinAddr extraLenAddr = TLinAddr(desAddress) - aReq.RemoteDesOffset() - sizeof(TUint32);
+		r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) extraLenAddr, sizeof(TUint32), pT);
+		if (r != KErrNone)
+			{
+			UnlockMountInfo(aPrimaryMedia);	// tidy up
+			return KErrNoMemory;
+			}
+		}
+
+
+	// Now pin the descriptor contents
+	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock;
+	r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) desAddress, length, pT);
+	if (r != KErrNone)
+		{
+		UnlockMountInfo(aPrimaryMedia);	// tidy up
+		return KErrNoMemory;
+		}
+
+
+	return KErrNone;
+	}
+
+
+void DLocalDrive::UnlockMountInfo(DPrimaryMediaBase& aPrimaryMedia)
+	{
+	DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice; 
+	if (pagingDevice == NULL || pagingDevice->iMountInfoDataLock == NULL)
+		return;
+
+
+	if (pagingDevice->iMountInfoDataLock)
+		{
+		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock)->iObject);
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock);
+		pagingDevice->iMountInfoDataLock = NULL;
+		}
+	
+	if (pagingDevice->iMountInfoDescHdrLock)
+		{
+		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock)->iObject);
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock);
+		pagingDevice->iMountInfoDescHdrLock = NULL;
+		}
+	
+	if (pagingDevice->iMountInfoDescLenLock)
+		{
+		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock)->iObject);
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock);
+		pagingDevice->iMountInfoDescLenLock = NULL;
+		}
+	
+	}
+#endif	// __DEMAND_PAGING__
+
+void DLocalDrive::NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange)
+	{
+#ifndef __DEMAND_PAGING__
+	aPrimaryMedia;
+#endif
+
+	// Complete any notification request on media change or power down
+	if (aMediaChange)
+		{
+		DThread* pC=NULL;
+		NKern::LockSystem();
+		if (iCleanup.iThread)
+			{
+			pC=iCleanup.iThread;
+			pC->Open();
+			}
+		NKern::UnlockSystem();
+		if (pC)
+			{
+			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
+#ifdef __DEMAND_PAGING__
+			else if (!DataPagingDfcQ(&aPrimaryMedia))
+#else
+			else
+#endif
+				{
+				Kern::ThreadRawWrite(pC, iNotifyChangeRequest->DestPtr(), &b, sizeof(b), NULL);
+				}
+			pC->AsyncClose();
+			}
+		}
+	}
+
+TLocalDriveCleanup::TLocalDriveCleanup()
+	{
+	}
+
+// This will be called when the original client thread exits
+// It is called in the context of the exiting thread with the system locked.
+void TLocalDriveCleanup::Cleanup()
+	{
+	DLocalDrive& d=LocalDrive();
+	d.iNotifyChangeRequest=NULL;
+	DThread* pC=iThread;
+	Remove();
+	iThread=NULL;
+	NKern::UnlockSystem();
+	pC->Close(NULL);	// balances Open() in DoCreate
+	NKern::LockSystem();
+	}
+
+/********************************************
+ * Local drive request class
+ ********************************************/
+ 
+/**
+Reads data from the descriptor specified in the request, from the requesting
+thread's process.
+
+This is used by the media driver to read data from a descriptor in the
+requesting thread.  The remote data is copied into the specified descriptor,
+starting at the specified offset within that descriptor's data area.
+
+@param aDes     The target descriptor into which data from the remote thread
+                is to be put.
+@param anOffset The offset within the target descriptor data area, where data
+                from the remote thread is to be put. Note that this parameter
+                may be useful when write operations to the media must be broken
+                up into smaller chunks than the length requested.
+
+@return KErrNone,if successful, otherwise one of the other
+        system-wide error codes.
+
+@see Kern::ThreadDesRead()
+*/
+EXPORT_C TInt TLocDrvRequest::ReadRemote(TDes8* aDes, TInt anOffset)
+	{
+	DThread* pT=RemoteThread();
+	if (!pT)
+		pT=Client();
+
+#ifdef __DEMAND_PAGING__	// only if driver has its own thread, we don't support paging in MD which run in the context of their clients
+	if (Flags() & ETClientBuffer)
+		return Kern::ThreadBufRead(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
+
+	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
+#endif
+
+	return Kern::ThreadDesRead(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
+	}
+
+
+
+
+/**
+Reads data from an arbitrary descriptor in the requesting thread's process.
+
+This is used by the media driver to read data from a descriptor in the
+requesting thread.  
+
+NB This is NOT supported in a datapaging environment as there is no guarantee 
+that the remote descriptor won't be paged out. If this function is called and
+data-paging is enabled the kernel will fault in debug mode and return 
+KErrNotSupported in release mode.
+
+@param aSrc     A pointer to the source descriptor in the requesting thread's
+                address space.
+@param aDes     The target descriptor into which data from the remote thread
+                is to be put.
+
+@return KErrNone,if successful, 
+		KErrNotSupported if data-paging is enabled
+		otherwise one of the other  system-wide error codes.
+
+@see Kern::ThreadDesRead()
+*/
+EXPORT_C TInt TLocDrvRequest::ReadRemote(const TAny* aSrc, TDes8* aDes)
+	{
+	DThread* pT=RemoteThread();
+	if (!pT)
+		pT=Client();
+
+#ifdef __DEMAND_PAGING__
+	__ASSERT_DEBUG(!DataPagingDeviceRegistered, LOCM_FAULT());
+	if (DataPagingDeviceRegistered)
+		return KErrNotSupported;
+#endif
+
+	return Kern::ThreadDesRead(pT,aSrc,*aDes,0,KChunkShiftBy0);
+	}
+
+
+
+
+/**
+Reads raw data from the requesting thread's process.
+
+This is used by the media driver to read raw data from a location in requesting
+thread's address space.  The remote data is copied into the specified
+buffer.
+
+@param aDest    A pointer to the buffer where the data is to be written.
+@param aSize    The number of bytes to read.
+
+@return KErrNone,if successful, otherwise one of the other
+        system-wide error codes.
+
+@see Kern::ThreadRawRead()
+*/
+EXPORT_C TInt TLocDrvRequest::ReadRemoteRaw(TAny* aDest, TInt aSize)
+	{
+	DThread* pT=RemoteThread();
+	if (!pT)
+		pT=Client();
+
+#ifdef __DEMAND_PAGING__
+	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
+#endif
+
+	return Kern::ThreadRawRead(pT,RemoteDes(),aDest,aSize);
+	}
+
+
+/**
+Writes data to a descriptor in the requesting thread's process.
+
+This is used by the media driver to write data to a descriptor in the requesting
+thread.  Data is copied from the specified descriptor, starting at the specified
+offset within that descriptor's data area.
+
+@param aDes     The source descriptor from which data is to be written to
+                the remote thread.
+                
+@param anOffset The offset within the source descriptor data area, from where data
+                is to be written to the remote thread. Note that this parameter
+                may be useful when read operations from the media must be broken
+                up into smaller chunks than the length requested.
+
+@return KErrNone,if successful, otherwise one of the other
+        system-wide error codes.
+
+@see Kern::ThreadDesWrite()
+*/
+EXPORT_C TInt TLocDrvRequest::WriteRemote(const TDesC8* aDes, TInt anOffset)
+	{
+	DThread* pC=Client();
+	DThread* pT=RemoteThread();
+	if (!pT)
+		pT=pC;
+
+#ifdef __DEMAND_PAGING__
+	if (Flags() & ETClientBuffer)
+		return Kern::ThreadBufWrite(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
+#endif
+
+	return Kern::ThreadDesWrite(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
+	}
+
+
+/**
+Writes raw data to the requesting thread's process.
+
+This is used by the media driver to write raw data to a location in the
+requesting thread's address space.
+
+@param aSrc     The source addres from which data is to be written to
+                the remote thread.
+                
+@param aSize    The number of bytes to write.
+
+@return KErrNone,if successful, otherwise one of the other
+        system-wide error codes.
+
+@see Kern::ThreadRawWrite()
+*/
+EXPORT_C TInt TLocDrvRequest::WriteRemoteRaw(const TAny* aSrc, TInt aSize)
+	{
+	DThread* pC=Client();
+	DThread* pT=RemoteThread();
+	if (!pT)
+		pT=pC;
+
+#ifdef __DEMAND_PAGING__
+	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
+#endif
+
+	return Kern::ThreadRawWrite(pT,RemoteDes(),aSrc,aSize,pC);
+	}
+
+
+TInt TLocDrvRequest::ProcessMessageData(TAny* aPtr)
+//
+// Get read/write parameters from client and open remote thread
+//
+	{
+	RemoteThread()=NULL;
+	DThread& t=Kern::CurrentThread();
+	TLocalDriveMessageData d;
+	kumemget32(&d,aPtr,sizeof(d));
+	if (d.iHandle!=KLocalMessageHandle && Id()!=DLocalDrive::EFormat)
+		{
+		NKern::LockSystem();
+		DThread* pT = RMessageK::MessageK(d.iHandle)->iClient;
+		if (!pT || pT->Open()!=KErrNone)
+			{
+			NKern::UnlockSystem();
+			return KErrBadHandle;
+			}
+		t.iExtTempObj=pT;
+		RemoteThread()=pT;
+		NKern::UnlockSystem();
+		}
+	Pos()=d.iPos;
+	Length()=d.iLength;
+	RemoteDes()=(TAny*)d.iPtr;
+	RemoteDesOffset()=d.iOffset;
+	DriverFlags()=d.iFlags;
+	if (Pos()<0 || Length()<0)
+		return KErrArgument;
+	return KErrNone;
+	}
+
+void TLocDrvRequest::CloseRemoteThread()
+	{
+	if (!RemoteThread())
+		return;
+	NKern::ThreadEnterCS();
+	DThread& t=Kern::CurrentThread();
+	RemoteThread()=NULL;
+	Kern::SafeClose((DObject*&)t.iExtTempObj,NULL);
+	NKern::ThreadLeaveCS();
+	}
+
+EXPORT_C TInt TLocDrvRequest::CheckAndAdjustForPartition()
+	{
+	TLocDrv& d=*Drive();
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("CheckAndAdjustForPartition drive %d partition len %lx",d.iDriveNumber,d.iPartitionLen));
+	Flags() |= EAdjusted;
+	switch (Id())
+		{
+		case DLocalDrive::ECaps:
+		case DLocalDrive::EForceMediaChange:
+		case DLocalDrive::EPasswordLock:
+		case DLocalDrive::EPasswordUnlock:
+		case DLocalDrive::EPasswordClear:
+		case DLocalDrive::EPasswordErase:
+		case DLocalDrive::EReadPasswordStore:
+ 		case DLocalDrive::EWritePasswordStore:
+ 		case DLocalDrive::EPasswordStoreLengthInBytes:
+		case DLocalDrive::EQueryDevice:
+			return KErrNone;
+		case DLocalDrive::EEnlarge:
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Enlarge request %lx",Length()));
+			if (Length()>KMaxTInt)
+				return KErrArgument;
+			return KErrNone;
+		case DLocalDrive::EReduce:
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Reduce request %lx@%lx",Length(),Pos()));
+			if (Pos()+Length()>d.iPartitionLen)
+				return KErrArgument;
+			return KErrNone;
+		case DLocalDrive::EFormat:
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Format request %lx@%lx",Length(),Pos()));
+			if (!(DriverFlags() & RLocalDrive::ELocDrvWholeMedia))
+				{
+				if (Pos()>d.iPartitionLen)
+					{
+					Length()=0;
+					return KErrEof;
+					}
+				Int64 left=d.iPartitionLen-Pos();
+				if (left<Length())
+					Length()=left;
+				Pos()+=d.iPartitionBaseAddr;
+				if (Length()==0)
+					return KErrEof;
+				}
+			return KErrNone;
+
+#ifdef __DEMAND_PAGING__
+		case DMediaPagingDevice::ERomPageInRequest:
+//          if the ROM was reported to LOCM then it will also need to be adjusted.... 
+//		    Otherwise the media driver adjust it internally
+		case DMediaPagingDevice::ECodePageInRequest:
+			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Adjusted Paging read request %lx@%lx",Length(),Pos()));
+			if (Pos()+Length()>d.iPartitionLen)
+				return KErrArgument;
+			Pos()+=d.iPartitionBaseAddr;
+			return KErrNone;
+#endif
+		
+		default:	// read or write or fragment
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("R/W request %lx@%lx",Length(),Pos()));
+
+			if (DriverFlags() & RLocalDrive::ELocDrvWholeMedia)
+				{
+				if (d.iMedia && d.iMedia->iDriver && Pos()+Length() > d.iMedia->iDriver->iTotalSizeInBytes)
+					return KErrArgument;
+				}
+			else
+				{
+				if (Pos()+Length() > d.iPartitionLen)
+					return KErrArgument;
+				Pos()+=d.iPartitionBaseAddr;
+				}
+			return KErrNone;
+		}
+	}
+
+/********************************************
+ * Local drive class
+ ********************************************/
+TLocDrv::TLocDrv(TInt aDriveNumber)
+	{
+	memclr(this, sizeof(TLocDrv));
+	iDriveNumber=aDriveNumber;
+	iPartitionNumber=-1;
+	}
+
+/**
+Initialises the DMedia entity with the media device number and ID.
+ 
+@param	aDevice		The unique ID for this device. This can take one of the
+					enumerated values defined in TMediaDevice enum.
+
+@param	aMediaId	The unique ID to associate with this media entity.
+
+@return KErrNone,if successful, otherwise one of the other
+        system-wide error codes.
+
+@see	TMediaDevice
+*/
+EXPORT_C TInt DMedia::Create(TMediaDevice aDevice, TInt aMediaId, TInt)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia::Create media %d device %d",aMediaId,aDevice));
+	iMediaId=aMediaId;
+	iDevice=aDevice;
+	return KErrNone;
+	}
+
+/********************************************
+ * Primary Media Class
+ ********************************************/
+void asyncDfc(TAny* aPtr)
+	{
+	DPrimaryMediaBase* pM=(DPrimaryMediaBase*)aPtr;
+	if (pM->iState==DMedia::EOpening)
+		pM->DoOpenMediaDriverComplete(pM->iAsyncErrorCode);
+	else if (pM->iState==DMedia::EReadPartitionInfo)
+		pM->DoPartitionInfoComplete(pM->iAsyncErrorCode);
+	}
+
+void handleMsg(TAny* aPtr)
+	{
+	DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
+
+	for(TLocDrvRequest* m = (TLocDrvRequest*) primaryMedia->iMsgQ.iMessage; 
+		m != NULL; 
+		m = (TLocDrvRequest*) primaryMedia->iMsgQ.Poll())
+		{
+#if defined(_DEBUG)	
+		if (!primaryMedia->iMsgQ.iQ.IsEmpty())	
+			__KTRACE_OPT(KLOCDRV, Kern::Printf("TRACE: handleMsg, queue not empty %08X", m));	
+#endif
+		primaryMedia->HandleMsg(*m);
+		
+#ifdef __DEMAND_PAGING__
+		// don't empty the queue if this media is paging as there 
+		// may be a (higher-priority) paging DFC waiting to run...
+		if (primaryMedia->iPagingMedia)
+			break;
+#endif
+		}
+
+
+	primaryMedia->iMsgQ.Receive();	// allow reception of more messages
+	}
+
+EXPORT_C DPrimaryMediaBase::DPrimaryMediaBase()
+	:	iMsgQ(handleMsg, this, NULL, 1),
+		iDeferred(NULL, NULL, NULL, 0),			// callback never used
+		iWaitMedChg(NULL, NULL, NULL, 0),		// callback never used
+		iAsyncDfc(asyncDfc, this, 1)
+/**
+Constructor of DPrimaryMediaBase class.
+Initialises the media state as closed.
+*/
+	{
+	iState = EClosed;
+	}
+
+
+
+EXPORT_C TInt DPrimaryMediaBase::Create(TMediaDevice aDevice, TInt aMediaId, TInt aLastMediaId)
+/**
+Called from LocDrv::RegisterMediaDevice() function.
+Calls DMedia::Create()
+
+@param aDevice Local media ID 
+@param aMediaId Media Id (unique for a media subsystem)
+@param aLastMediaId This indicates number of used media ids+ number of DMedia objects to be associated with the media driver.
+
+@return KErrNone
+@see TMediaDevice 
+
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::Create media %d-%d device %d",aMediaId,aLastMediaId,aDevice));
+	TInt r=DMedia::Create(aDevice,aMediaId,0);
+	if (r != KErrNone)
+		return r;
+	iBody = new DBody;
+	if (iBody == NULL)
+		return KErrNoMemory;
+
+#ifdef __DEMAND_PAGING__
+	TInt pageSize = Kern::RoundToPageSize(1);
+	iBody->iPageSizeMsk = pageSize-1;
+#endif
+
+	iLastMediaId=aLastMediaId;
+	if (r==KErrNone && iDfcQ)
+		{
+		iMsgQ.SetDfcQ(iDfcQ);
+		iDeferred.SetDfcQ(iDfcQ);
+		iWaitMedChg.SetDfcQ(iDfcQ);
+		iAsyncDfc.SetDfcQ(iDfcQ);
+		}
+	return KErrNone;
+	}
+
+
+EXPORT_C TInt DPrimaryMediaBase::Connect(DLocalDrive* aLocalDrive)
+/**
+Connects to a local drive
+
+@param aLocalDrive Local drive logical channel abstraction
+
+@pre Kernel must be unlocked
+@pre Current thread in critical section
+
+@post Kernel must be unlocked
+
+@return KErrNone, if successful
+		KErrNotFound, If no PDD matches criteria while getting driver list
+		KErrNoMemory, If the array could not be expanded at some point while getting driver list or ran out of memory while opening media driver
+		KErrNotReady, If not ready when trying to open media driver
+		otherwise, one of the other system wide error codes.
+
+@see DLocalDrive
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Connect %O",iMediaId,aLocalDrive));
+	if (iDfcQ)
+		{
+		TThreadMessage& m=Kern::Message();
+		m.iValue=EConnect;
+		m.iArg[0]=aLocalDrive;
+		return m.SendReceive(&iMsgQ);
+		}
+
+	// If no DFC queue, must be a fixed media device
+	// If this is the first connection, open media driver now
+	// Assume no non-primary media exist on this device
+	TInt r=KErrNone;
+	NKern::LockSystem();
+	TBool first=iConnectionQ.IsEmpty();
+	iConnectionQ.Add(&aLocalDrive->iLink);
+	NKern::UnlockSystem();
+	if (first)
+		{
+		r=OpenMediaDriver();
+		if (r!=KErrNone)
+			{
+			NKern::LockSystem();
+			aLocalDrive->Deque();
+			NKern::UnlockSystem();
+			}
+		}
+	if (r==KErrNone)
+		aLocalDrive->iDrive->iMedia=this;
+	return r;
+	}
+
+
+
+
+EXPORT_C void DPrimaryMediaBase::Disconnect(DLocalDrive* aLocalDrive)
+/**
+Disconnects from a local drive
+
+@param aLocalDrive Local drive logical channel abstraction
+
+@pre Kernel must be unlocked
+@pre Current thread in critical section
+
+@post Kernel must be unlocked
+@see DLocalDrive
+*/
+
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Disconnect %O",iMediaId,aLocalDrive));
+	if (iDfcQ)
+		{
+		TThreadMessage& m=Kern::Message();
+		m.iValue=EDisconnect;
+		m.iArg[0]=aLocalDrive;
+		m.SendReceive(&iMsgQ);
+		return;
+		}
+
+	// If no DFC queue, must be a fixed media device
+	// If this is the last connection, close media driver now
+	// Assume no non-primary media exist on this device
+	DMediaDriver* pD=NULL;
+	NKern::LockSystem();
+	aLocalDrive->iDrive->iMedia=NULL;
+	aLocalDrive->Deque();
+	if (iConnectionQ.IsEmpty())
+		{
+		pD=iDriver;
+		iDriver=NULL;
+		}
+	NKern::UnlockSystem();
+	if (pD)
+		pD->Close();
+	}
+
+EXPORT_C TInt DPrimaryMediaBase::Request(TLocDrvRequest& aReq)
+/**
+Issues a local drive request. It is called from TLocDrv::Request() function .
+Each local drive request is encapsulated as a TLocDrvRequest- a class derived from TThreadMessage, the kernel message class. 
+TLocDrvRequest contains information pertaining to the request, including the ID and any associated parameters such as drive position, length and source/destination location.
+Passes the request through to the media driver.
+
+@param m Encapsulates the request information received from the client
+
+@pre Enter with kernel unlocked
+
+@post Leave with Kernel unlocked
+
+@return KErrNone,if successful
+	KErrBadDescriptor, if request encapsulates a bad descriptor
+	Otherwise, one of the other system wide error codes.
+
+@see TLocDrvRequest
+*/
+	{
+
+	__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()));
+
+	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.)
+ 	 	{
+		return r;
+ 	  	}
+ 	  	
+
+	// for ERead & EWrite requests, get the linear address for pinning & DMA
+	TUint8* linAddress = NULL;
+	TClientBuffer clientBuffer;
+	DThread* pT = NULL;
+
+	if (reqId == DLocalDrive::ERead || reqId == DLocalDrive::EWrite)
+		{
+		pT = aReq.RemoteThread();
+		if (!pT)
+			pT = &Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
+
+		// for silly zero-length requests, return immediately, setting the client 
+		// descriptor length to zero if it's a read request
+		if (aReq.Length() == 0)
+			{
+			DThread* pC = &Kern::CurrentThread();
+			r = KErrNone;
+			if (reqId == DLocalDrive::ERead)
+				{
+				TPtrC8 ptr(NULL, 0);
+				r = Kern::ThreadDesWrite(pT, aReq.RemoteDes(), ptr, aReq.RemoteDesOffset(), KChunkShiftBy0,pC);
+				}
+			return r;
+			}
+
+		clientBuffer.SetFromDescriptor(aReq.RemoteDes(), pT);
+
+		TInt length = 0;
+		TInt maxLength = 0;
+		TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,linAddress,EFalse);	// get descriptor length, maxlength and linAddress
+		if (r != KErrNone)
+			return r;
+		linAddress+= aReq.RemoteDesOffset();
+
+#ifdef __DEMAND_PAGING__
+		// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points 
+		// to a TClientBuffer rather than the client's remote descriptor
+		if (DataPagingDeviceRegistered)
+			{
+			aReq.RemoteDes() = &clientBuffer;
+			aReq.Flags() |= TLocDrvRequest::ETClientBuffer;
+			}
+#endif
+		}
+
+	if (iDfcQ)
+		{
+		__TRACE_TIMING(0x10);
+
+
+#ifdef __DEMAND_PAGING__
+		// If this is a ROM/Code paging media, pin writes 
+		// If there is a Data paging media registered, pin all requests with descriptors 
+		if ( (DataPagingDeviceRegistered) || (reqId == DLocalDrive::EWrite && RomPagingDfcQ(this)) )
+			r = PinSendReceive(aReq, (TLinAddr) linAddress);
+		else
+#endif	// __DEMAND_PAGING__
+
+			r = SendReceive(aReq, (TLinAddr) linAddress);
+		}
+	else
+		{
+		// If no DFC queue, must be a fixed media device
+		// Media driver must already have been opened
+		// Assume no non-primary media exist on this device
+		// Just pass request straight through to media driver
+		r = aReq.CheckAndAdjustForPartition();
+		if (r == KErrNone)
+			r = iDriver->Request(aReq);
+		}
+
+#ifdef __DEMAND_PAGING__
+		// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points 
+		// to a TClientBuffer rather than the client's remote descriptor
+	if (reqId == DLocalDrive::ERead && DataPagingDeviceRegistered && r == KErrNone)
+		{
+		r = clientBuffer.UpdateDescriptorLength(pT);
+		}
+#endif
+
+	return r;
+	}
+
+
+#ifdef __DEMAND_PAGING__
+TInt DPrimaryMediaBase::PinSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
+	{
+	__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
+
+
+	TInt msgId = aReq.Id();
+
+
+	switch(msgId)
+		{
+		case DLocalDrive::EControlIO:
+			{
+			TInt controlIoType = aReq.Int3(); 
+			switch(controlIoType)
+				{
+				case KLocalMessageHandle:
+					// ControlIo is not supported if either of the two bare (TAny*) pointers are non-NULL 
+					// as it's not possible to determine what the pointers are pointing at...
+					if (aReq.Int1() || aReq.Int2())
+						{
+						__KTRACE_OPT(KDATAPAGEWARN, Kern::Printf("Data paging: Naked EControlIO not supported on paging device: fn=%x", aReq.Int0()));
+						return KErrNotSupported;
+						}
+					// fall into...
+				case 0:
+					return SendReceive(aReq);
+
+				default:
+					// if Int3() is > 0, Int1() is a data pointer, and Int3() is a length
+					if (controlIoType > (TInt) ThePinObjectAllocator->iFragmentGranularity)
+						return KErrTooBig;
+					if (controlIoType < 0)
+						return KErrArgument;
+					return PinFragmentSendReceive(aReq, (TLinAddr) aReq.Ptr1(), controlIoType);
+				}
+			}
+
+		case DLocalDrive::ECaps:
+		case DLocalDrive::EGetLastErrorInfo:
+		case DLocalDrive::EQueryDevice:
+			{
+			TInt len = aReq.Length();
+
+			if (len > (TInt) ThePinObjectAllocator->iFragmentGranularity)
+				return KErrTooBig;
+
+			return PinFragmentSendReceive(aReq, (TLinAddr) aReq.RemoteDes(), len);
+			}
+
+		case DLocalDrive::ERead:
+		case DLocalDrive::EWrite:
+			{
+			return PinFragmentSendReceive(aReq, aLinAddress, aReq.Length());
+			}
+		
+
+
+		// For the time being, don't support any password requests to the data paging device.
+		// This shouldn't be a problem as the device should be flagged as non-removable...
+		// This would be difficult to do anyway as it would involve pinning up to 3 buffers - 
+		// TLocalDrivePasswordData itself, iOldPasswd & iNewPasswd
+		case DLocalDrive::EPasswordLock:
+		case DLocalDrive::EPasswordUnlock:
+		case DLocalDrive::EPasswordClear:
+		case DLocalDrive::EReadPasswordStore:
+		case DLocalDrive::EWritePasswordStore:
+		case DLocalDrive::EPasswordStoreLengthInBytes:
+		case DLocalDrive::EPasswordErase:
+			return KErrNotSupported;
+
+		default:		
+			return SendReceive(aReq);
+		}
+	}
+
+TInt DPrimaryMediaBase::PinFragmentSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress, TInt aLength)
+	{
+	TLocDrvRequest fragment = aReq;		// create a request on the stack for use during fragmentation, pre-fill with the original req args, leave original Kernel message as repository (thread will block, message contents won't change)
+	TInt r = KErrNone;
+
+//	Kern::Printf(">PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
+
+	DThread* pT = aReq.RemoteThread();
+	if (!pT)
+		pT=&Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
+
+	__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Fragmenting Read/Write Request(0x%08x) on drive(%d), remote des(0x%x), offset into des(0x%x), original req Length(0x%x)",&aReq,aReq.Drive()->iDriveNumber,(TInt)(aReq.RemoteDes()),aReq.RemoteDesOffset(),aLength));
+	__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Remote thread(0x%08x), current thread(0x%08x), start of data to write(0x%08x)",aReq.RemoteThread(),&Kern::CurrentThread(),(TInt)aLinAddress));
+
+	// don't want this thread to be terminated until last fragment is sent to MD and mem can be free'd up
+	NKern::ThreadEnterCS();			
+
+	__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
+
+	TUint fragmentGranularity = ThePinObjectAllocator->iFragmentGranularity;
+	TInt dataLockResult = 0;
+	// fragmentation only allowed for read/write requests
+	__ASSERT_DEBUG(aLength <= (TInt) fragmentGranularity || (aReq.Id() == DLocalDrive::EWrite || aReq.Id() == DLocalDrive::ERead), LOCM_FAULT());
+
+	// Pin the client buffer
+	TInt pinnedLen;
+	for (TInt pos = 0; pos < aLength; pos+= pinnedLen, aLinAddress+= pinnedLen)
+		{
+		pinnedLen = 0;
+
+		// pin memory
+		TInt remainingLen = aLength - pos; // remaining length
+
+		// first attempt to pin memory with no pre-allocated buffers (which may fail)
+		DPinObjectAllocator::SVirtualPinContainer* pinDataObject = ThePinObjectAllocator->AcquirePinObject();
+
+		if (pinDataObject)
+			{
+			TInt lenToPin = Min(KMaxPinData, remainingLen);
+
+			TInt r = Kern::PinVirtualMemory(pinDataObject->iObject, aLinAddress, lenToPin, pT);
+			if (r == KErrNone)
+				{
+				pinnedLen = lenToPin;
+				}
+			else
+				{
+#ifdef __DEBUG_DEMAND_PAGING__
+				Kern::Printf("Kern::PinVirtualMemory() error %d", r);
+#endif
+				// pin failed, so use preallocated buffer instead
+				ThePinObjectAllocator->ReleasePinObject(pinDataObject);
+				pinDataObject = NULL;
+				}
+			}
+
+		if (!pinDataObject)
+			{
+			ThePinObjectAllocator->PreAllocatedDataLock().LockFragmentation();
+
+			TLinAddr start = aLinAddress;
+			do
+				{
+				TInt lenToPin = Min((TInt) fragmentGranularity, remainingLen - pinnedLen);
+
+#ifdef __DEBUG_DEMAND_PAGING__
+				Kern::Printf(">SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X", aReq.Id(), aLinAddress, lenToPin);
+#endif
+
+				dataLockResult = ThePinObjectAllocator->PreAllocatedDataLock().Lock(pT, start, lenToPin);
+
+#ifdef __DEBUG_DEMAND_PAGING__
+				Kern::Printf("<SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X r %d", aReq.Id(), aLinAddress, lenToPin, r);
+#endif
+
+				start+= lenToPin;
+				pinnedLen+= lenToPin;
+				}
+			while (dataLockResult == 0 && pinnedLen < remainingLen);
+			
+			// if nothing pinned (dataLockResult == 0) or error (dataLockResult <0), release the mutex,
+			// otherwise (dataLockResult > 0) release it after calling SendReceive()
+			if (dataLockResult <= 0)
+				ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
+
+#ifdef __DEBUG_DEMAND_PAGING__
+				if (dataLockResult < 0) 
+					Kern::Printf("DFragmentationPagingLock::Lock() %d", dataLockResult);
+#endif
+
+			if (dataLockResult < 0)	// if lock returned an error then give up
+				{
+				r = dataLockResult;
+				break;
+				}
+			}
+
+		// fragment request Id defaults to same as original request
+		fragment.Id() = aReq.Id();
+		fragment.Length() = Int64(pinnedLen);
+		fragment.RemoteDesOffset() = aReq.RemoteDesOffset() + pos;
+		fragment.Pos() = aReq.Pos() + pos;
+		fragment.Flags() = aReq.Flags();
+
+		__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Send fragment (0x%08x) type(%d), length(0x%x), offset within original req(0x%x), pos in media(0x%lx)",&fragment,fragment.Id(), pinnedLen, pos, fragment.Pos()));
+
+#ifdef BTRACE_PAGING_MEDIA
+		TInt buf[4];
+		buf[0] = pinnedLen;	// fragment length
+		buf[1] = pos;		// offset within original request
+		buf[2] = fragment.Pos(); // offset in media
+		buf[3] = (TInt)&pT->iNThread;	// thread that issued the original write req
+		BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentBegin,&fragment,fragment.Id(),buf,sizeof(buf));
+#endif
+
+		r = SendReceive(fragment, aLinAddress);	// only come back here when message (fragment) has been completed
+
+		// unpin memory
+		if (pinDataObject)
+			{
+			Kern::UnpinVirtualMemory(pinDataObject->iObject);
+			ThePinObjectAllocator->ReleasePinObject(pinDataObject);
+			}
+		else if (dataLockResult > 0)	// pinDataObject = NULL
+			{
+			__ASSERT_DEBUG(dataLockResult == 1, LOCM_FAULT());
+			ThePinObjectAllocator->PreAllocatedDataLock().Unlock();
+			ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
+			}
+
+#ifdef BTRACE_PAGING_MEDIA
+		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentEnd,&fragment,r);
+#endif
+
+		if (r != KErrNone)
+			break;
+		}
+
+	NKern::ThreadLeaveCS();
+
+//	Kern::Printf("<PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
+
+	return r;
+	}
+
+#endif	// __DEMAND_PAGING__
+
+
+TInt DPrimaryMediaBase::SendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
+/**
+ * If a Physical memory helper object is present for given drive,
+ * then message is routed via helper;
+ * 
+ * @return KErrNone, if successful;
+ * 		   otherwise, one of the other system wide error codes.
+ * 
+ * @see TLocDrvRequest::SendReceive()
+ * @see DDmaHelper::SendReceive()
+ */
+	{
+	DDmaHelper* dmaHelper = aReq.Drive()->iDmaHelper;
+
+#ifdef __DEMAND_PAGING__
+	RequestCountInc();
+#endif
+
+	TInt r;
+
+	if (dmaHelper)
+		r = dmaHelper->SendReceive(aReq, aLinAddress);
+	else
+		r = aReq.SendReceive(&iMsgQ);
+
+#ifdef __DEMAND_PAGING__
+	RequestCountDec();
+#endif
+
+	return r;
+	}
+
+
+
+EXPORT_C TInt DPrimaryMediaBase::ForceMediaChange(TInt)
+/**
+Forces a media change.The method can be overridden in the derived classes.
+@param mode Media change mode
+
+@return KErrNotSupported, in the default implementation
+		KErrNone, if successful
+		Otherwise, one of the other system wide error codes.
+
+*/
+	{
+	// default implementation
+	return KErrNotSupported;
+	}
+
+EXPORT_C TInt DPrimaryMediaBase::InitiatePowerUp()
+/**
+Initiates Power up sequence
+@return KErrCompletion, operation is complete successfully or otherwise
+		KErrNone, if successful
+		Otherwise, one of the other system wide error codes.
+
+*/
+	{
+	// default implementation, this is the default implementation.
+	return KErrCompletion;
+	}
+
+EXPORT_C TInt DPrimaryMediaBase::QuickCheckStatus()
+/**
+Checks the status of the media device, whether the device is present,absent,not ready,etc.
+The function can be overridden in the derived classes
+
+@return KErrNone, if successful
+		Otherwise, one of the other system wide error codes.
+
+*/
+	{
+	// default implementation
+	return KErrNone;
+	}
+
+EXPORT_C void DPrimaryMediaBase::DefaultDriveCaps(TLocalDriveCapsV2& aCaps)
+/**
+Fills in the default drive capabilities in TLocalDriveCapsV2 .
+It initializes media type of drive as unknown and has to be overridden in the derived class. Called from the Request ( ) function of the same class.
+
+@param aCaps Media drive capability fields. Extension to Capabilities fields(i.e) in addition to TLocalDriveCaps mainly to support Nor flash
+@see TLocalDriveCapsV2
+*/
+
+	{
+	// default implementation
+	// aCaps is zeroed beforehand
+	aCaps.iType = EMediaUnknown;
+	//	aCaps.iBattery = EBatNotSupported;
+	}
+	
+EXPORT_C TBool DPrimaryMediaBase::IsRemovableDevice(TInt& /*aSocketNum*/)
+/**
+Checks whether it is a removable device or not
+@param aSocketNum Socket number
+@return ETrue=Removable Device
+		EFalse=Non-Removable device, default implementation
+
+*/
+	{
+	// default implementation
+	return(EFalse);
+	}
+
+EXPORT_C void DPrimaryMediaBase::HandleMsg(TLocDrvRequest& m)
+/**
+It handles the drive request encapsulated in TLocDrvRequest depending on the message id.
+
+@param aRequest Encapsulates the request information received from the client
+@see TLocDrvRequest
+*/
+	{
+	switch (m.iValue)
+		{
+		case EConnect:
+			{
+			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
+			iConnectionQ.Add(&pD->iLink);
+			m.Complete(KErrNone, EFalse);
+			return;
+			}
+		case EDisconnect:
+			{
+			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
+			TLocDrv* pL=pD->iDrive;
+			DMedia* media=pL->iMedia;
+			if (iState==EReady && media && media->iDriver)
+				media->iDriver->Disconnect(pD,&m);
+			else
+				{
+				pD->Deque();
+				m.Complete(KErrNone, EFalse);
+				}
+			return;
+			}
+		case DLocalDrive::EForceMediaChange:
+			{
+			TUint flags = (TUint) m.Pos();
+
+			// 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));
+			if (flags == (TUint) KForceMediaChangeReOpenMediaDriver)
+				{
+				TInt sock;
+				if (!IsRemovableDevice(sock))
+					{
+					CompleteRequest(m, KErrNotSupported);
+					return;
+					}
+				// wait for power up and then call DPrimaryMediaBase::DoRequest()
+				break;
+				}
+
+			TInt r=ForceMediaChange(flags);
+			if (r==KErrNone)
+				{
+				// wait for media change notification to complete message
+				m.Forward(&iWaitMedChg,EFalse);
+				}
+			else
+				{
+				if (r==KErrNotSupported || r==KErrCompletion)
+					r=KErrNone;
+				CompleteRequest(m, r);
+				}
+			return;
+			}
+		case DLocalDrive::ECaps:
+			if (iState==EPoweredDown)
+				{
+				// The media is powered down, but the media driver still exists.
+				//  - Issue the ECaps request without powering the media back up.
+				DoRequest(m);
+				__TRACE_TIMING(0x101);
+				return;
+				}
+			break;
+
+		case DLocalDrive::ERead:
+		case DLocalDrive::EWrite:
+		case DLocalDrive::EFormat:
+		case DLocalDrive::EEnlarge:
+		case DLocalDrive::EReduce:
+		case DLocalDrive::EPasswordLock:
+		case DLocalDrive::EPasswordUnlock:
+		case DLocalDrive::EPasswordClear:
+		case DLocalDrive::EPasswordErase:
+		case DLocalDrive::EControlIO:
+		case DLocalDrive::EDeleteNotify:
+		case DLocalDrive::EQueryDevice:
+
+#ifdef __DEMAND_PAGING__
+		case DMediaPagingDevice::ERomPageInRequest:
+		case DMediaPagingDevice::ECodePageInRequest:
+#endif
+			break;
+		case DLocalDrive::EGetLastErrorInfo:
+			{
+			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
+			TLocDrv* pL=pD->iDrive;
+			*((TErrorInfo*) m.RemoteDes()) = pL->iLastErrorInfo;
+			CompleteRequest(m, KErrNone);
+			return;
+			}
+		case DLocalDrive::EReadPasswordStore:
+			{
+			TUint8  passData[TPasswordStore::EMaxPasswordLength];
+			TPtr8 pData(passData, TPasswordStore::EMaxPasswordLength);
+			TInt r = ThePasswordStore->ReadPasswordData(pData);
+			if (r==KErrNone)
+				r = m.WriteRemote(&pData,0);
+			CompleteRequest(m, r);
+			return;
+			}
+		case DLocalDrive::EWritePasswordStore:
+			{
+			TUint8  passData[TPasswordStore::EMaxPasswordLength];
+			TPtr8 pData(passData, TPasswordStore::EMaxPasswordLength);
+
+			DThread* pT=m.RemoteThread();
+			if (!pT)
+				pT=m.Client();
+
+			TInt lengthOrError = Kern::ThreadGetDesLength(pT, m.RemoteDes() );
+			if ( lengthOrError > pData.MaxLength() )
+				{
+				CompleteRequest(m, KErrOverflow);
+				return;
+				}
+			else if ( lengthOrError < KErrNone)
+				{
+				CompleteRequest(m, lengthOrError);
+				return;
+				}	
+
+			TInt r = m.ReadRemote(&pData,0);
+			if (r==KErrNone)
+				r = ThePasswordStore->WritePasswordData(pData);
+			if(r != KErrNone)
+				{
+				CompleteRequest(m, r);
+				return;
+				}
+
+			r = QuickCheckStatus();
+			if(r != KErrNone)
+				{
+				// Don't try to power up the device if it's not ready.
+				// - Note that this isn't an error that needs to be returned to the client.
+				CompleteRequest(m, KErrNone);
+				return;
+				}
+
+			break;
+			}
+		case DLocalDrive::EPasswordStoreLengthInBytes:
+			{
+			TInt length = ThePasswordStore->PasswordStoreLengthInBytes();
+			TInt r = m.WriteRemoteRaw(&length,sizeof(TInt));
+			CompleteRequest(m, r);
+			return;
+			}
+		default:
+			CHECK_RET(KErrNotSupported);
+			CompleteRequest(m, KErrNotSupported);
+			return;
+		}
+
+	__KTRACE_OPT(KFAIL,Kern::Printf("mdrq %d",m.Id()));
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::HandleMsg state %d req %d",iMediaId,iState,m.Id()));
+
+	// if media driver already open, pass request through
+	if (iState==EReady)
+		{
+		DoRequest(m);
+		__TRACE_TIMING(0x101);
+		return;
+		}
+
+	// if open or close in progress, defer this message
+	if (iState!=EClosed && iState!=EPoweredDown)
+		{
+#ifdef __DEMAND_PAGING__
+		if (DMediaPagingDevice::PagingRequest(m))
+			{
+			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
+			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+			__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
+
+			__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Deferring PageIn request 0x%08x because opening or closing",&m));
+			iBody->iPagingDevice->SendToDeferredQ(&m);
+			}
+		else
+#endif
+		m.Forward(&iDeferred,EFalse);
+		return;
+		}
+
+	// nothing is open, so try to open something
+	__ASSERT_ALWAYS(!iCurrentReq,LOCM_FAULT());
+
+#ifdef __DEMAND_PAGING__
+
+#ifdef BTRACE_PAGING_MEDIA
+	if (DMediaPagingDevice::PagingRequest(m))
+		BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInQuietlyDeferred,&m,iState,m.iValue);
+#endif	// BTRACE_PAGING_MEDIA
+
+#ifdef _DEBUG
+	__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
+
+	if (DMediaPagingDevice::PagingRequest(m))
+		{
+		__ASSERT_DEBUG(iPagingMedia,LOCM_FAULT());
+		__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+		__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Page request 0x%08x received -> opening MD",&m));
+		}
+#endif	// _DEBUG
+
+#endif	// __DEMAND_PAGING__
+
+	iCurrentReq=&m;
+	if(iState == EClosed)
+		{
+		iState=EPoweringUp1;
+		}
+	else if (iState == EPoweredDown)
+		{
+		iState=EPoweringUp2;
+		}
+
+	TInt r=InitiatePowerUp();
+	if (r==KErrNone || r==KErrServerBusy)
+		{
+		// wait for completion of power up request
+		return;
+		}
+	if (r==KErrCompletion)
+		r=KErrNone;		// device already powered up
+	PowerUpComplete(r);
+	}
+
+EXPORT_C TInt DPrimaryMediaBase::DoRequest(TLocDrvRequest& m)
+/**
+If the media exists, it tries to get the partition information if not there. 
+It then passes on the request to the media driver by calling its Request( ) function. 
+Then it completes the kernel thread message and the reference count of the thread is closed asynchronously.
+
+@param aRequest Encapsulates the request information received from the client
+
+@return KErrNone, if successful
+	KErrNotReady, if missing partitions on removable media
+	KErrNotSupported, if missing partitions on fixed media
+	KErrArgument Out of range argument ,encapsulated in Local drive request , passed while checking and adjusting for partition
+	KErrEOF, Reached the end of file
+	KErrBadDescriptor, if request encapsulates a bad descriptor
+	Otherwise, one of the other system wide error codes.
+
+*/
+	{
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DPrimaryMediaBase::DoRequest %d",m.Id()));
+	TLocDrv* pL=m.Drive();
+	DMedia* media=pL->iMedia;
+	TInt r=KErrNone;
+
+	// re-open this drive's media driver ?
+	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);
+		CompleteRequest(m, r);
+		return r;
+		}
+
+	if (!media || !media->iDriver || iState == EClosed)
+		{
+		// Return KErrNotReady for missing partitions on removable media
+		// as opposed to KErrNotSupported for missing partitions on fixed media
+		// since the latter don't exist whereas the former might exist at some time.
+		TInt sock;
+		r=IsRemovableDevice(sock) ? KErrNotReady : KErrNotSupported;
+		}
+
+	iCurrentReq=&m;
+	if (r==KErrNone)
+		{
+		if(iTotalPartitionsOpened == 0)
+			{
+			UpdatePartitionInfo();
+			return KErrNone;
+			}
+		if (!(m.Flags() & TLocDrvRequest::EAdjusted))
+			{
+			// If this isn't the only partition, don't allow access to the whole media 
+			if (iTotalPartitionsOpened > 1)
+				m.DriverFlags() &= ~RLocalDrive::ELocDrvWholeMedia;
+			r=m.CheckAndAdjustForPartition();
+			}
+		if (r==KErrNone)
+			{
+			r=media->iDriver->Request(m);
+			if (r>0)
+				{
+				// defer request
+#ifdef __DEMAND_PAGING__
+				if (DMediaPagingDevice::PagingRequest(m))
+					{
+					__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
+					__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
+					__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+					__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Defer PageIn request 0x%08x",&m));
+					DMediaPagingDevice* pagingdevice=iBody->iPagingDevice; 
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+					TInt id=m.iValue;
+					if (id==DMediaPagingDevice::ERomPageInRequest)
+						{
+						NKern::FMWait(&pagingdevice->iInstrumentationLock);
+						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
+							pagingdevice->iROMStats.iTotalReDeferrals++;
+						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
+							pagingdevice->iROMStats.iTotalSynchDeferredFromMainQ++;
+						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+						}
+					else if (m.Flags() & TLocDrvRequest::ECodePaging)
+						{
+						NKern::FMWait(&pagingdevice->iInstrumentationLock);
+						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
+							pagingdevice->iCodeStats.iTotalReDeferrals++;
+						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
+							pagingdevice->iCodeStats.iTotalSynchDeferredFromMainQ++;
+						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+						}
+					else if (m.Flags() & TLocDrvRequest::EDataPaging)
+						{
+						NKern::FMWait(&pagingdevice->iInstrumentationLock);
+						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
+							pagingdevice->iDataStats.iTotalReDeferrals++;
+						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
+							pagingdevice->iDataStats.iTotalSynchDeferredFromMainQ++;
+						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+						}
+#endif
+					pagingdevice->SendToDeferredQ(&m);
+					}
+				else
+#endif
+					m.Forward(&iDeferred,EFalse);
+				r=KErrNone;
+				}
+#if defined(__DEMAND_PAGING__) && defined(_DEBUG)
+			else if (r == KErrNone && DMediaPagingDevice::PagingRequest(m))
+				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("PageIn req 0x%08x completing asynchronously",&m));
+#endif
+			}
+		}
+
+	if (r!=KErrNone && iCurrentReq)
+		{
+		TInt s=(r==KErrCompletion)?KErrNone:r;
+		CHECK_RET(s);
+
+#ifdef __DEMAND_PAGING__
+		// got here because media driver cannot service or defer this request or did service it synchronously
+		if (DMediaPagingDevice::PagingRequest(m))
+			{
+			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
+			__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
+			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("media driver cannot service or defer PageIn request 0x%08x or serviced it synchronously (%d)",&m, s));
+			iBody->iPagingDevice->CompleteRequest(&m, s);
+			}
+		else
+#endif
+
+		CompleteRequest(m, s);
+
+		}
+
+	iCurrentReq=NULL;
+	return r;
+	}
+
+EXPORT_C void DPrimaryMediaBase::PowerUpComplete(TInt anError)
+/**
+Called after the device is powered up or there is some error while powering up the device. 
+If there is an error powering up the devices then it just completes the current running requests with an error 
+and also completes the outstanding requests on the iDeferred message queue by calling SetClosed( ).
+If the device is powered up OK then it either opens the media drivers 
+and if they are already open then it handles the current/pending requests.
+
+@param anError Error code to be passed on while completing outstanding requests.
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::PowerUpComplete err %d iState %d",iMediaId,anError,iState));
+	if (anError!=KErrNone)
+		{
+		// error powering up device
+		if (iState==EPoweringUp1 || iState==EPoweringUp2)
+			SetClosed(anError);
+		return;
+		}
+
+	// Powered up OK - now open media drivers
+	if (iState==EPoweringUp1)
+		{
+		iState=EOpening;
+		StartOpenMediaDrivers();
+		}
+	else if (iState==EPoweringUp2)
+		{
+		// media is powered up and ready, so handle the current/pending requests
+		MediaReadyHandleRequest();
+		}
+	}
+
+void DPrimaryMediaBase::CloseMediaDrivers(DMedia* aMedia)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
+
+	// 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))
+		{
+		__KTRACE_OPT(KLOCDRV,Kern::Printf("CloseMediaDrivers aborting for data paging media %08X", this));
+		return;
+		}
+#endif
+
+	TInt i;
+	for (i=0; i<KMaxLocalDrives; i++)
+		{
+		TLocDrv* pL=TheDrives[i];
+		if (pL && pL->iPrimaryMedia==this)
+			{
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d",i));
+			if (aMedia == NULL || pL->iMedia == aMedia)
+				{
+				pL->iMedia=NULL;
+				}
+			}
+		}
+	for (i=iLastMediaId; i>=iMediaId; i--)
+		{
+		DMedia* pM=TheMedia[i];
+		if (aMedia == NULL || pM == aMedia)
+			{
+			DMediaDriver* pD=pM->iDriver;
+			pM->iDriver=NULL;
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia[%d] @ %08x Driver @ %08x",i,pM,pD));
+			if (pD)
+				pD->Close();
+			}
+		}
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
+	}
+
+void DPrimaryMediaBase::StartOpenMediaDrivers()
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::StartOpenMediaDrivers",iMediaId));
+	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+
+	// Get a list of all currently loaded media drivers
+	// Most media drivers do not make use of the pointer iMountInfo.iInfo when 
+	// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList(). 
+	// However, a group of media drivers sharing the same id (passed in iDevice) may use 
+	// the additional information pointed to by iMountInfo.iInfo to distinguish 
+	// group members. This information is passed when the media driver is registered 
+	// using LocDrv::RegisterMediaDevice().
+	TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
+	if (r!=KErrNone)
+		{
+		// out of memory or no driver exists
+		SetClosed(r);
+		return;
+		}
+
+	// Go through them starting with highest priority
+	iNextMediaId=iMediaId;
+	iBody->iPhysDevIndex=iPhysDevArray.Count()-1;
+	iTotalPartitionsOpened=0;
+	iMediaDriversOpened=0;
+	iNextMediaDriver=NULL;
+	OpenNextMediaDriver();
+	}
+
+void DPrimaryMediaBase::OpenNextMediaDriver()
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::OpenNextMediaDriver, this %x mediaId %d iBody->iPhysDevIndex %d",iNextMediaId, this, iMediaId, iBody->iPhysDevIndex));
+
+	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+	SPhysicalDeviceEntry& e=iPhysDevArray[iBody->iPhysDevIndex];
+	DPhysicalDevice* pD=e.iPhysicalDevice;
+
+	iState = EOpening;
+
+	DMedia* pM=TheMedia[iNextMediaId];
+	if (pM && pM->iDriver != NULL)
+		{
+		iNextMediaDriver = pM->iDriver;
+		DoOpenMediaDriverComplete(KErrNone);
+		return;
+		}
+
+	// this may be asynchronous
+	TInt s=pD->Create( (DBase*&)iNextMediaDriver, iMediaId,  (TDesC8*) &iMountInfo, ver);
+
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,e.iPriority,s));
+	if (s!=KErrNone)
+		{
+		iAsyncErrorCode=s;
+		iAsyncDfc.Enque();
+		}
+	}
+
+// Called when a media driver has responded to the Open request
+void DPrimaryMediaBase::DoOpenMediaDriverComplete(TInt anError)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoOpenMediaDriverComplete error %d iNextMediaDriver %x",iNextMediaId,anError,iNextMediaDriver));
+
+	if (anError!=KErrNone)
+		{
+		DMediaDriver* md = iNextMediaDriver;
+		iNextMediaDriver = NULL;
+		if (md)
+			md->Close();
+		}
+	if (anError==KErrNotReady || anError==KErrNoMemory)
+		{
+		// if it's not ready or we're out of memory, abort
+		CloseMediaDrivers();
+		SetClosed(anError);
+		return;
+		}
+	if (anError==KErrNone)
+		{
+		DMedia* pM=TheMedia[iNextMediaId];
+		pM->iDriver=iNextMediaDriver;
+		DPhysicalDevice*& pD=iPhysDevArray[iBody->iPhysDevIndex].iPhysicalDevice;
+		iNextMediaDriver->iPhysicalDevice=pD;
+		pD=NULL;	// so it won't be closed when we tidy up
+		++iMediaDriversOpened;
+		}
+
+	// if no error, read partition info on media
+	iState = EReadPartitionInfo;
+
+	if (anError == KErrNone)
+		{
+		DMedia* pM=TheMedia[iNextMediaId];
+		TInt r = pM->iDriver->PartitionInfo(pM->iPartitionInfo);
+		if (r!=KErrNone)
+			{
+			if (r==KErrCompletion)
+				r=KErrNone;
+			DoPartitionInfoComplete(r);
+			}
+		}
+	else
+		{
+		DoPartitionInfoComplete(anError);
+		}
+	}
+
+void DPrimaryMediaBase::DoPartitionInfoComplete(TInt anError)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoPartitionInfoComplete error %d",iNextMediaId,anError));
+
+	DMedia* pM=TheMedia[iNextMediaId];
+	if (anError==KErrNone || anError == KErrLocked)
+		{
+		// successfully read partition info
+		iTotalPartitionsOpened+=pM->PartitionCount();
+		}
+	else
+		{
+		// couldn't read partition info or driver failed to open
+		if (pM->iDriver)
+			{
+#ifdef __DEMAND_PAGING__
+			if (DataPagingDfcQ(this))
+				{
+				__KTRACE_OPT(KLOCDRV,Kern::Printf("DoPartitionInfoComplete(%d) Close Media Driver aborted for data paging media %08X", this));
+				}
+			else
+#endif
+				{
+				pM->iDriver->Close();
+				pM->iDriver=NULL;
+				}
+			}
+		if (anError==KErrNotReady || anError==KErrNoMemory)
+			{
+			// if it's not ready or we're out of memory, or the drive is locked, abort
+			CloseMediaDrivers();
+			SetClosed(anError);
+			return;
+			}
+		}
+
+	// Open next media driver, if there is one
+	TBool complete = EFalse;
+	if (++iNextMediaId>iLastMediaId)
+		complete=ETrue;
+	if (iBody->iPhysDevIndex==0)
+		complete=ETrue;
+	else
+		iBody->iPhysDevIndex--;
+	if (!complete)
+		{
+		OpenNextMediaDriver();
+		return;
+		}
+
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d All media drivers open & partitions read",iMediaId));
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("%d media drivers opened",iMediaDriversOpened));
+	if (iMediaDriversOpened==0)
+		{
+		SetClosed(KErrNotSupported);
+		return;
+		}
+
+	// we are now finished with media driver list
+	iPhysDevArray.Close();
+
+	// Finished reading partition info
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d Read partition info complete",iMediaId));
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("%d total partitions",iTotalPartitionsOpened));
+	if (iTotalPartitionsOpened==0)
+		{
+		SetClosed(KErrNotSupported);
+		return;
+		}
+
+	// work out mapping of drives to partitions/media
+	TInt totalPartitions=iTotalPartitionsOpened;
+	TInt id=iMediaId;	// start with primary media
+	TInt partitionsOnThisMedia=PartitionCount();
+	TInt partition=0;
+	TInt j;
+	for (j=0; j<KMaxLocalDrives; j++)
+		{
+		TLocDrv* pD=TheDrives[j];
+		if (pD && pD->iPrimaryMedia==this)
+			{
+			if (totalPartitions==0)
+				{
+				pD->iMedia=NULL;
+				continue;
+				}
+			if (partition==partitionsOnThisMedia)
+				{
+				id++;
+				partition=0;
+				partitionsOnThisMedia=TheMedia[id]->PartitionCount();
+				}
+			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d = Media %d Partition %d",j,id,partition));
+			pD->iMedia=TheMedia[id];
+			pD->iPartitionNumber=partition;
+			memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
+			partition++;
+			totalPartitions--;
+			}
+		}
+
+	// media is now ready - handle current or deferred requests
+	MediaReadyHandleRequest();
+	}
+
+void DPrimaryMediaBase::MediaReadyHandleRequest()
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::MediaReadyHandleRequest() this %x", this));
+	iState = EReady;
+
+	// now we can process the current request
+	// careful - thread may have exited while we were powering up
+	if (iCurrentReq)
+		{
+		DoRequest(*iCurrentReq);	// this sets iCurrentReq=NULL
+		}
+
+	// see if we can process any other requests concurrently
+	RunDeferred();
+	}
+
+void DPrimaryMediaBase::UpdatePartitionInfo()
+	{
+	iState=EReadPartitionInfo;
+	iNextMediaId=iMediaId;
+	DMedia* pM=TheMedia[iNextMediaId];
+	TInt r=pM->iDriver->PartitionInfo(pM->iPartitionInfo);
+	if (r!=KErrNone)
+		{
+		if (r==KErrCompletion)
+			r=KErrNone;
+		DoPartitionInfoComplete(r);
+		}
+	}
+
+void DPrimaryMediaBase::CompleteCurrent(TInt anError)
+	{
+	if (iCurrentReq)
+		{
+		CHECK_RET(anError);
+#ifdef __DEMAND_PAGING__
+		// got here because it was powered down when powering up, or failed powering up or failed opening MD or got media change
+		if (DMediaPagingDevice::PagingRequest(*iCurrentReq))
+			{
+			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
+			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+			__ASSERT_ALWAYS( ((iCurrentReq->Flags() & TLocDrvRequest::ECodePaging) == 0) || (iCurrentReq->Drive()->iPagingDrv), LOCM_FAULT());
+
+			__KTRACE_OPT2(KLOCDPAGING,KFAIL,Kern::Printf("Got here because it was powered down when powering up, or failed powering up or failed opening MD or got media change"));
+			iBody->iPagingDevice->CompleteRequest(iCurrentReq, anError);
+			}
+		else
+#endif
+		CompleteRequest(*iCurrentReq, anError);
+		iCurrentReq=NULL;
+		}
+	}
+
+
+void DPrimaryMediaBase::CompleteRequest(TLocDrvRequest& aMsg, TInt aResult)
+	{
+	aMsg.Complete(aResult,EFalse);
+	}
+
+EXPORT_C void DPrimaryMediaBase::RunDeferred()
+/**
+Runs deferred Requests. Initiated from DPrimaryMediaBase::PowerUpComplete() function 
+to see if any other requests can be processed concurrently. 
+Can also be called from DPrimaryMediaBase::NotifyPowerDown 
+or DPrimaryMediaBase::NotifyEmergencyPowerDown() function or DMediaDriver::Complete()
+*/
+	{
+	// Do nothing if an open or close is in progress - this might be the case, for example, 
+	// if a EForceMediaChange request (with the  KForceMediaChangeReOpenMediaDriver flag) 
+	// has recently been processed
+	if (iState!=EReady && iState!=EClosed && iState!=EPoweredDown)
+		return;
+
+	// rerun deferred requests;
+#ifdef __DEMAND_PAGING__
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	TInt countROM=0;
+	TInt countCode=0;
+#endif
+
+	if(iPagingMedia)
+		{
+		__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
+		if(iBody->iPagingDevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)		// if already emptying deferred page in queue, don't reenter
+			{
+			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying deferred queue"));
+			return;
+			}
+
+		DMediaPagingDevice* pagingdevice=iBody->iPagingDevice;
+		TLocDrvRequest* pL = (TLocDrvRequest*) pagingdevice->iDeferredQ.Last();
+		if(pL)
+			{
+			pagingdevice->iEmptyingQ|= DMediaPagingDevice::EDeferredQ;			// prevent reentering when already emptying this queue
+			TLocDrvRequest* pM=NULL;
+			while (pM != pL && (pM = (TLocDrvRequest*) pagingdevice->iDeferredQ.Poll()) != NULL)	// synchronously empty deferred queue but ignore re-deferrals
+				{
+				__ASSERT_ALWAYS( DMediaPagingDevice::PagingRequest(*pL), LOCM_FAULT() );
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+				(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
+				if(pM==pL)
+					{
+					NKern::FMWait(&pagingdevice->iInstrumentationLock);
+					if(pM->iValue==DMediaPagingDevice::ERomPageInRequest && pagingdevice->iROMStats.iMaxReqsInDeferred<countROM)
+						pagingdevice->iROMStats.iMaxReqsInDeferred=countROM;
+					else if ((pM->Flags() & TLocDrvRequest::ECodePaging) && pagingdevice->iCodeStats.iMaxReqsInDeferred<countCode)
+							pagingdevice->iCodeStats.iMaxReqsInDeferred=countCode;
+					else if ((pM->Flags() & TLocDrvRequest::EDataPaging) && pagingdevice->iDataStats.iMaxReqsInDeferred<countCode)
+							pagingdevice->iDataStats.iMaxReqsInDeferred=countCode;
+					NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+					}
+#endif
+				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x, last in deferred queue 0x%08x",pM,pL));
+#ifdef BTRACE_PAGING_MEDIA
+				BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferredReposted,pM,pM->iValue);
+#endif
+				// if Page In requests are synchronous this services them all in sequence, 
+				// if they're asynch it re-defers them
+				DoRequest(*(TLocDrvRequest*)pM);	
+				}
+			pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EDeferredQ;
+			}
+
+		// the reason we now try an empty the main Page In queue is there is at least one type of Page In request 
+		// serviced synchronously in which case when we empty the deferred Page In queue as above, received Page In 
+		// requests are left in the main queue (not deferred) and we don't want to start processing deferred normal 
+		// requests before these Page In requests. If all deferred normal requests are synchronous, the received Page 
+		// In requests will have to wait until all are serviced. NB: requests may be deferred even if the MD services 
+		// all requests synchronously, but runs background tasks that cannot be interrupted. In this last case the 
+		// normal deferred queue may have some very long latency requests.
+		if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)	// already emptying main Page In queue, skip (any Page In requests will be deferred)
+			{
+			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying main queue"));
+			return;
+			}
+	
+		TLocDrvRequest* pM=NULL;
+		if (!pagingdevice->iMainQ.iReady)	// if it's ready, then queue is empty
+			{
+			pM = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
+			pagingdevice->iMainQ.iMessage = NULL;
+			if (pM == NULL)
+				pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll();
+			}
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+		countROM = countCode=0;
+#endif
+		if(pM)
+			{
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+			__e32_atomic_add_ord32(&pagingdevice->iROMStats.iTotalSynchEmptiedMainQ, 1);
+#endif
+			pagingdevice->iEmptyingQ|=DMediaPagingDevice::EMainQ;
+			for ( ; pM != NULL; pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
+				{
+				__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*pM), LOCM_FAULT());
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+				(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
+#endif
+
+				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x",pM));
+				DoRequest(*(TLocDrvRequest*)pM);	// if Page In requests are synchronous this services them all in sequence, if they're asynch it defers them
+				}
+
+			pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EMainQ;
+
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+			NKern::FMWait(&pagingdevice->iInstrumentationLock);
+			pagingdevice->iROMStats.iTotalSynchServicedFromMainQ+=countROM;
+			if(pagingdevice->iROMStats.iMaxReqsInPending<countROM)
+				pagingdevice->iROMStats.iMaxReqsInPending=countROM;
+			pagingdevice->iCodeStats.iTotalSynchServicedFromMainQ+=countCode;
+			if(pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
+				pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
+			NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+#endif
+			}	// if (pM)
+		}	// 	if(iPagingMedia)
+#endif
+	if (iRunningDeferred)
+		return;
+	TMessageBase* pL = iDeferred.Last();
+	if (!pL)
+		return;	// no deferred requests
+	iRunningDeferred=1;
+	TMessageBase* pM=NULL;
+
+	while( pM != pL && (pM=iDeferred.Poll()) != NULL)	// stop after processing last one (requests may be re-deferred)
+		DoRequest(*(TLocDrvRequest*)pM);
+	iRunningDeferred=0;
+	}
+
+void DPrimaryMediaBase::SetClosed(TInt anError)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::SetClosed error %d",iMediaId,anError));
+	CHECK_RET(anError);
+
+	// cancel DMediaDriver::OpenMediaDriverComplete() / DMediaDriver::PartitionInfoComplete() DFC
+	iAsyncDfc.Cancel();
+
+	iDeferred.CompleteAll(anError);
+
+#ifdef __DEMAND_PAGING__
+	if(iPagingMedia)
+		iBody->iPagingDevice->iDeferredQ.CompleteAll(anError);
+#endif
+
+	CompleteCurrent(anError);
+
+	
+
+	if (iState==EOpening)
+		iPhysDevArray.Close();
+
+	iState = EClosed;
+
+	iWaitMedChg.CompleteAll(KErrNone);
+	}
+
+void DPrimaryMediaBase::NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv)
+
+//
+// Notify all clients of a media change or power-down event
+//
+	{
+	SDblQueLink* pL=iConnectionQ.iA.iNext;
+	while (pL!=&iConnectionQ.iA)
+		{
+		DLocalDrive* pD=_LOFF(pL,DLocalDrive,iLink);
+		// 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);
+		pL=pL->iNext;
+		}
+	}
+
+EXPORT_C void DPrimaryMediaBase::NotifyMediaChange()
+/**
+Closes all media drivers on this device and notifies all connections that media change has occurred 
+and completes any outstanding requests with KErrNotReady. 
+This also completes any force media change requests with KErrNone.
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyMediaChange state %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();
+		}
+
+	// notify all connections that media change has occurred
+	NotifyClients(ETrue);
+
+	// complete any force media change requests
+	iWaitMedChg.CompleteAll(KErrNone);
+	}
+
+
+EXPORT_C void DPrimaryMediaBase::NotifyPowerDown()
+/**
+Called on machine power-down. Notifies all media drivers on this device. 
+If device is not ready then it completes current requests but leaves other outstanding requests
+If ready, media driver should complete current request.
+
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPowerDown state %d",iMediaId,iState));
+
+	TInt id;
+	TBool allPersistent = ETrue;
+	TBool allOpen = ETrue;
+
+	 // notify all media drivers on this device
+	for (id=iMediaId; id<=iLastMediaId; id++)
+		{
+		DMedia* pM = TheMedia[id];
+		DMediaDriver* pD = pM->iDriver; 
+		
+		if ((pD) && (iState==EReady || iState==EReadPartitionInfo || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering))
+			pD->NotifyPowerDown();
+
+		if (pD == NULL || pD->iPhysicalDevice == NULL)
+			allOpen = EFalse;
+		else if (pD->iPhysicalDevice->Info(DPhysicalDevice::EMediaDriverPersistent, NULL) != KErrNone)
+			{
+			// We must NOT destroy the media driver if this media is responsible for data paging as 
+			// re-opening the media driver would involve memory allocation which might cause a deadlock
+#ifdef __DEMAND_PAGING__
+			__ASSERT_ALWAYS(!DataPagingDfcQ(this), LOCM_FAULT());
+#endif
+			allPersistent = EFalse;
+			}
+		}
+
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("allPersistent(%d)::allOpen %d",allPersistent, allOpen));
+
+	if (allPersistent && allOpen && iState == EReady)
+		{
+		//
+		// The EPoweredDown state indicates that the media is powered down, but the media driver still exists.
+		//
+		//  - This allows the media driver to still be accessed (ie - to determine driver capabilities) without
+		//    the need to power up the device, which can be a lengthy operation.
+		//
+		//  - NOTE : This will need re-visiting if we ever re-enable standby mode on a platform that is not capable
+		//           of detecting door interrupts while in standby.  In such a scenario, problems could occur as 
+		//			the device capabilities may change without the local media subsystem recognising.
+		//
+		iState=EPoweredDown;
+		}
+	else
+		{
+		CloseMediaDrivers();
+		SetClosed(KErrNotReady);
+		}
+
+	NotifyClients(EFalse);
+	}
+
+
+EXPORT_C void DPrimaryMediaBase::NotifyPsuFault(TInt anError)
+/**
+Closes all media drivers on this device and completes any outstanding requests with error code.
+@param anError Error code to be passed on while closing media drivers and completing outstanding requests.
+*/
+
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPsuFault state %d, err %d",iMediaId,iState,anError));
+
+	if (iState>=EOpening)
+		{
+		CloseMediaDrivers();
+		}
+
+	// complete any outstanding requests with error
+	SetClosed(anError);
+	}
+
+EXPORT_C void DPrimaryMediaBase::NotifyEmergencyPowerDown()
+/**
+Called on emergency power down. Notifies all media drivers on this device. 
+If it is not in a ready state then it completes the current request but leaves other outstanding requests.
+If it is ready then the media driver should complete the current request. 
+It closes all media drivers and notifies all clients of a power down event.
+*/
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyEmergencyPowerDown state %d",iMediaId,iState));
+	TBool recover=EFalse;
+	if (iState==EReady && iCritical!=0)
+		{
+		// check if emergency power recovery supported
+		;
+		}
+	if (recover)
+		{
+		}
+
+	// else just return KErrAbort
+	// notify all media drivers on this device
+	if (iState==EReady || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering)
+		{
+		TInt id;
+		for (id=iMediaId; id<=iLastMediaId; id++)
+			{
+			DMedia* pM=TheMedia[id];
+			DMediaDriver* pD=pM->iDriver;
+			if (pD)
+				pD->NotifyEmergencyPowerDown();
+			}
+		}
+
+	if (iState!=EReady)
+		{
+		// complete current request but leave other outstanding requests
+		// if ready, media driver should complete current request
+		CompleteCurrent(KErrNotReady);
+		}
+	CloseMediaDrivers();
+	SetClosed(KErrNotReady);
+	NotifyClients(EFalse);
+	}
+
+EXPORT_C void DPrimaryMediaBase::NotifyMediaPresent()
+/**
+Notifies clients of a media change by calling NotifyClients ( ) function to indicate that media is present.
+*/
+	{
+	NotifyClients(ETrue);
+	}
+
+EXPORT_C TInt DPrimaryMediaBase::DoInCritical()
+/**
+Flags the media driver as entering a critical part of its processing.
+
+In this context, critical means that the driver must be allowed to complete
+its current activity.
+For example, a request to power down the device must be deferred until
+the driver exits the critical part.
+
+@return KErrNone, if the driver has been successfully flagged as being in
+        a critical part; otherwise, one of the other system-wide error codes.
+        The default implementation just returns KErrNone and can be overridden in the derived class
+@see DPrimaryMediaBase::DoEndInCritical()
+*/
+
+	{
+	return KErrNone;
+	}
+
+EXPORT_C void DPrimaryMediaBase::DoEndInCritical()
+/**
+Flags the media driver as leaving a critical part of its processing.
+
+Default implementation does nothing
+@see DPrimaryMediaBase::DoEndInCritical()
+*/
+	{
+	}
+
+TInt DPrimaryMediaBase::InCritical()
+	{
+	if (iCritical==0)
+		{
+		TInt r=DoInCritical();
+		if (r!=KErrNone)
+			return r;
+		}
+	++iCritical;
+	return KErrNone;
+	}
+
+void DPrimaryMediaBase::EndInCritical()
+	{
+	if (--iCritical==0)
+		DoEndInCritical();
+	}
+
+EXPORT_C void DPrimaryMediaBase::DeltaCurrentConsumption(TInt /*aCurrent*/)
+/**
+Sets the incremental value of current consumption to aCurrent.
+The default implementation does nothing .
+
+@param aCurrent Delta Current in Milliamps
+*/
+	{
+	// default implementation
+	}
+
+TInt DPrimaryMediaBase::OpenMediaDriver()
+//
+// Synchronous open for devices with no DFC queue (e.g. IRAM)
+//
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase:OpenMediaDriver-%d",iMediaId));
+	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+
+	// Get a list of all currently loaded media drivers
+	// Most media drivers do not make use of the pointer iMountInfo.iInfo when 
+	// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList(). 
+	// However, a group of media drivers sharing the same id (passed in iDevice) may use 
+	// the additional information pointed to by iMountInfo.iInfo to distinguish 
+	// group members. This information is passed when the media driver is registered 
+	// using LocDrv::RegisterMediaDevice().
+	TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
+	if (r!=KErrNone)
+		return r;
+
+	// Go through them starting with highest priority
+	TInt totalPartitions=0;
+	TInt c=iPhysDevArray.Count();	// can't be zero
+	TInt i=c-1;
+	r=KErrNotSupported;
+	for (iNextMediaId=iMediaId; i>=0 && iNextMediaId<=iLastMediaId && r!=KErrNotReady; i--)
+		{
+		DPhysicalDevice* pD=iPhysDevArray[i].iPhysicalDevice;
+		DMediaDriver *pM=NULL;
+
+		// try to open media driver
+		TInt s=pD->Create( (DBase*&)pM, iMediaId, NULL, ver); 
+
+		__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,iPhysDevArray[i].iPriority,s));
+		if (s!=KErrNone && pM)
+			{
+			pM->Close();
+			pM=NULL;
+			}
+		if (s==KErrNotReady)
+			{
+			r=KErrNotReady; // If it isn't ready - nothing will open.
+			break;
+			}
+		if (s==KErrNoMemory)
+			{
+			r=KErrNoMemory; // If we are out of memory, give up now
+			break;
+			}
+		if (s==KErrNone)
+			{
+			// Found a media driver for this device - check for valid partitions.
+			DMedia* media=TheMedia[iNextMediaId];
+			s=pM->PartitionInfo(media->iPartitionInfo);
+			if (s==KErrNone)
+				{
+				r=KErrNone;
+				media->iDriver=pM;
+				pM->iPhysicalDevice=pD;
+				iPhysDevArray[i].iPhysicalDevice=NULL;	// so it won't be closed when we tidy up
+				totalPartitions+=media->PartitionCount();
+				}
+			else
+				pM->Close();
+			}
+		}
+
+	// we are now finished with media driver list
+	iPhysDevArray.Close();
+
+	// if driver opened OK, work out mapping of drives to partitions/media
+	if (r==KErrNone)
+		{
+		TInt id=iMediaId;	// start with primary media
+		TInt partitionsOnThisMedia=PartitionCount();
+		TInt partition=0;
+		TInt j;
+		for (j=0; j<KMaxLocalDrives; j++)
+			{
+			TLocDrv* pD=TheDrives[j];
+			if (pD && pD->iPrimaryMedia==this)
+				{
+				if (totalPartitions==0)
+					{
+					pD->iMedia=NULL;
+					continue;
+					}
+				if (partition==partitionsOnThisMedia)
+					{
+					id++;
+					partition=0;
+					partitionsOnThisMedia=TheMedia[id]->PartitionCount();
+					}
+				pD->iMedia=TheMedia[id];
+				pD->iPartitionNumber=partition;
+				memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
+				partition++;
+				totalPartitions--;
+				}
+			}
+		}
+
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase:OpenMediaDriver-%d",r));
+	return r;
+	}
+
+#ifdef __DEMAND_PAGING__
+// RequestCountInc()
+// 
+// Counts the number of outstanding requests
+// For data-paging media, calls DPagingDevice::NotifyBusy() when count goes positive
+//
+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);
+	if (oldVal == 0 && iBody->iPagingDevice)
+		{
+//Kern::Printf("RCINC: NotifyBusy()");
+		iBody->iPagingDevice->NotifyBusy();
+		}
+	}
+
+// RequestCountDec()
+// 
+// Counts the number of outstanding requests
+// For data-paging media, calls DPagingDevice::NotifyIdle() when count reaches zero
+//
+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);
+	if (oldVal == 1 && iBody->iPagingDevice)
+		{
+//Kern::Printf("RCDEC: NotifyIdle()");
+		iBody->iPagingDevice->NotifyIdle();
+		}
+	__ASSERT_DEBUG(iBody->iRequestCount >= 0, LOCM_FAULT());
+	}
+#endif	// __DEMAND_PAGING__
+
+
+TPartitionInfo::TPartitionInfo()
+//
+// Constructor
+//
+	{
+	memclr(this, sizeof(TPartitionInfo));
+	}
+
+#ifdef __DEMAND_PAGING__
+
+void pageInDfc(TAny* aPtr)
+	{
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("pageInDfc"));
+	DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
+	__ASSERT_ALWAYS(primaryMedia && primaryMedia->iPagingMedia && primaryMedia->iBody->iPagingDevice,LOCM_FAULT());
+	DMediaPagingDevice* pagingdevice=primaryMedia->iBody->iPagingDevice;
+
+	TLocDrvRequest* m = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
+	pagingdevice->iMainQ.iMessage = NULL;
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	if (!m)
+		__e32_atomic_add_ord8(&pagingdevice->iROMStats.iTotalRunDry, 1);
+#endif
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	TInt countROM=0;
+	TInt countCode=0;
+#endif
+
+	for ( ; m != NULL; m = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
+		{
+		__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*m), LOCM_FAULT());
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+		(m->iValue == DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
+#endif
+		__KTRACE_OPT(KLOCDPAGING, Kern::Printf("pageInDfc: process request 0x%08x, last in queue 0x%08x",m, pagingdevice->iMainQ.Last()) );
+
+		primaryMedia->HandleMsg(*m);
+		}
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	NKern::FMWait(&pagingdevice->iInstrumentationLock);
+	if (pagingdevice->iROMStats.iMaxReqsInPending<countROM)
+		pagingdevice->iROMStats.iMaxReqsInPending=countROM;
+	if (pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
+		pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
+	NKern::FMSignal(&pagingdevice->iInstrumentationLock);
+#endif
+
+	pagingdevice->iMainQ.Receive();	// allow reception of more messages
+	}
+
+DMediaPagingDevice::DMediaPagingDevice(DPrimaryMediaBase* aPtr)
+	:	iMainQ(pageInDfc, aPtr, NULL, KMaxDfcPriority),
+		iDeferredQ(NULL, NULL, NULL, 0),			// callback never used
+		iEmptyingQ(NULL),
+		iInstrumentationLock()
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+		,iServicingROM(NULL), iServicingCode(NULL)
+#endif
+	{
+	iPrimaryMedia = aPtr;
+	if (iPrimaryMedia->iDfcQ)	// media driver has its own thread
+		{
+		iMainQ.SetDfcQ(iPrimaryMedia->iDfcQ);
+		}
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	memclr((TAny*)&iROMStats,sizeof(SMediaROMPagingConcurrencyInfo)+sizeof(SMediaCodePagingConcurrencyInfo));
+#endif
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	iROMBenchmarkData.iCount=iROMBenchmarkData.iTotalTime=iROMBenchmarkData.iMaxTime=0;
+	iROMBenchmarkData.iMinTime = KMaxTInt;
+	iCodeBenchmarkData.iCount=iCodeBenchmarkData.iTotalTime=iCodeBenchmarkData.iMaxTime=0;
+	iCodeBenchmarkData.iMinTime = KMaxTInt;
+	iDataInBenchmarkData.iCount=iDataInBenchmarkData.iTotalTime=iDataInBenchmarkData.iMaxTime=0;
+	iDataInBenchmarkData.iMinTime = KMaxTInt;
+	iDataOutBenchmarkData.iCount=iDataOutBenchmarkData.iTotalTime=iDataOutBenchmarkData.iMaxTime=0;
+	iDataOutBenchmarkData.iMinTime = KMaxTInt;
+#endif
+
+	iMainQ.Receive();
+	}
+
+DMediaPagingDevice::~DMediaPagingDevice()
+	{
+
+	if (iMountInfoDataLock)
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDataLock);
+	
+	if (iMountInfoDescHdrLock)
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescHdrLock);
+	
+	if (iMountInfoDescLenLock)
+		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescLenLock);
+	}
+
+
+void DMediaPagingDevice::SendToMainQueueDfcAndBlock(TThreadMessage* aMsg)
+	{
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("Send request 0x%08x to main queue",aMsg));
+	__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EFree,LOCM_FAULT());	// check that message was previously completed or never queued
+
+	// if drive supports DMA, turn on Physical memory flag & sync memory
+	TLocDrvRequest& m=*(TLocDrvRequest*)(aMsg);
+	
+	TLinAddr addr = (TLinAddr) m.RemoteDes();
+	TInt len = I64LOW(m.Length());
+
+	TBool needSyncAfterRead = EFalse;
+	if (m.Drive()->iDmaHelper)
+		{
+		m.Flags() |= TLocDrvRequest::EPhysAddr;
+		if (m.Id() == DLocalDrive::EWrite)
+			{
+			Cache::SyncMemoryBeforeDmaWrite(addr, len);
+			}
+		else
+			{
+			Cache::SyncMemoryBeforeDmaRead(addr, len);
+			needSyncAfterRead = ETrue;
+			}
+		}
+
+	// Count the number of outstanding requests if this is the data-paging media, so that
+	// we can call DPagingDevice::NotifyBusy() / DPagingDevice::NotifyIdle()
+	if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
+		iPrimaryMedia->RequestCountInc();
+
+	aMsg->SendReceive(&iMainQ);
+
+#ifdef __DEMAND_PAGING__
+	if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
+		iPrimaryMedia->RequestCountDec();
+#endif
+
+	if (needSyncAfterRead)
+		{
+		Cache::SyncMemoryAfterDmaRead(addr, len);
+		}
+
+	
+	// come back here when request is completed
+	__ASSERT_DEBUG(aMsg->iState==TMessageBase::EFree,LOCM_FAULT());		// check message has been completed
+	}
+
+void DMediaPagingDevice::SendToDeferredQ(TThreadMessage* aMsg)
+	{
+	// This queue is only accessed from MD thread
+	__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT());	// check that message was previously dequeued
+#ifdef BTRACE_PAGING_MEDIA
+	if(iEmptyingQ&DMediaPagingDevice::EDeferredQ)		// already deferring
+		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInReDeferred,aMsg,aMsg->iValue);
+	else
+		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferred,aMsg,aMsg->iValue);
+#endif
+
+	aMsg->Forward(&iDeferredQ, EFalse);
+	}
+
+
+void DMediaPagingDevice::CompleteRequest(TThreadMessage* aMsg, TInt aResult)
+	{
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::CompleteRequest, request 0x%08x result %d", aMsg, aResult));
+	__ASSERT_DEBUG(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT());
+
+#ifdef BTRACE_PAGING_MEDIA
+	BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInPagedIn,aMsg,aResult,aMsg->iValue);
+#endif
+
+	iPrimaryMedia->CompleteRequest(*((TLocDrvRequest*) aMsg), aResult);
+	}
+
+TInt DMediaPagingDevice::Read(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt aDrvNumber)
+	{
+	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
+	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
+	__ASSERT_CRITICAL
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	TUint32 bmStart = NKern::FastCounter();
+#endif
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	TUint8* servicingCount;
+	NKern::FMWait(&iInstrumentationLock);
+	if(aDrvNumber == EDriveRomPaging)	// ROM paging
+		{
+		servicingCount = &iServicingROM;
+		if(iServicingROM)
+			iROMStats.iTotalConcurrentReqs++;
+		if(!(++iServicingROM))
+			{
+			iServicingROM=1;					// overflow...
+			iROMStats.iTotalConcurrentReqs=0;	// ...reset this
+			}
+		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
+		if(!empty)
+			iROMStats.iTotalReqIssuedNonEmptyQ++;
+		}
+	else if (aDrvNumber == EDriveDataPaging)	// Data paging
+		{
+		servicingCount = &iServicingDataIn;
+		if(iServicingDataIn)
+			iDataStats.iTotalConcurrentReqs++;
+		if(!(++iServicingDataIn))
+			{
+			iServicingDataIn=1;					// overflow...
+			iDataStats.iTotalConcurrentReqs=0;	// ...reset this
+			}
+		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
+		if(!empty)
+			iDataStats.iTotalReqIssuedNonEmptyQ++;
+		}
+	else
+		{
+		servicingCount = &iServicingCode;
+		if(iServicingCode)
+			iCodeStats.iTotalConcurrentReqs++;
+		if(!(++iServicingCode))
+			{
+			iServicingCode=1;					// overflow...
+			iCodeStats.iTotalConcurrentReqs=0;	// ...reset this
+			}
+		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
+		if(!empty)
+			iCodeStats.iTotalReqIssuedNonEmptyQ++;
+		}
+	NKern::FMSignal(&iInstrumentationLock);
+#endif
+
+	TUint offset=aOffset<<iReadUnitShift;
+	TUint size=aSize<<iReadUnitShift;
+
+#ifdef BTRACE_PAGING_MEDIA
+	TInt buf[3];
+	buf[0]=size;		// page in request length
+	buf[1]=aDrvNumber;	// local drive number (-1 if ROM)
+	buf[2]=(TInt)aReq;	// address of request object
+	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInBegin,aBuffer,offset,buf,sizeof(buf));
+#endif
+
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Read, Req(0x%08x), Buff(0x%x),Offset(%d),Size(%d),DrvNo(%d)",aReq,aBuffer,offset,size,aDrvNumber));
+	
+	// no DFCQ, media driver executes in the context of calling thread
+	if (!iPrimaryMedia->iDfcQ)
+		{
+		LOCM_FAULT();		// don't allow paging
+		return KErrNone;	// keep compiler happy
+		}
+
+
+	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	SPagingBenchmarkInfo* info = NULL;
+#endif
+
+
+	// Read from the media and allow for retries in the unlikely event of an error.
+	const TInt KPageInRetries = 5;
+	TInt retVal = KErrGeneral;
+	for (TInt i=0; retVal != KErrNone && i < KPageInRetries; i++)
+		{
+		m.Flags() = TLocDrvRequest::EPaging;
+		TLocDrv* pL=NULL;
+		if(aDrvNumber == EDriveRomPaging)					// ROM paging
+			{
+			m.Id() = DMediaPagingDevice::ERomPageInRequest;
+			if (iRomPagingDriveNumber == KErrNotFound)
+			    {
+			    // ROM partition has not been reported by the media driver
+			    // it is assumed that the media driver will adjust the request accordingly
+			    m.Flags() |= TLocDrvRequest::EAdjusted;
+				// Use a media drive number so the request reaches the correct media...
+				m.Drive() = TheDrives[iFirstLocalDriveNumber];
+			    }
+			else
+			    {
+			    //ROM partition has been reported
+			    //Set drive for use with CheckAndAdjustForPartition
+                m.Drive() = TheDrives[iRomPagingDriveNumber];
+			    }
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+			__e32_atomic_add_ord32(&iMediaPagingInfo.iRomPageInCount, (TUint) 1);
+			info = &iROMBenchmarkData;
+#endif
+			}
+		else if(aDrvNumber == EDriveDataPaging)				// Data paging
+			{
+			m.Id() = DLocalDrive::ERead;
+			m.Flags() |= TLocDrvRequest::EDataPaging;
+			m.Drive() = TheDrives[iDataPagingDriveNumber];
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+			__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageInCount, (TUint) 1);
+			info = &iDataInBenchmarkData;
+#endif
+			}
+		else if ((aDrvNumber >=0) && (aDrvNumber<KMaxLocalDrives))	// Code paging
+			{
+			m.Id() = DMediaPagingDevice::ECodePageInRequest;
+			m.Flags() |= TLocDrvRequest::ECodePaging;
+			pL=TheDrives[aDrvNumber];
+			__ASSERT_DEBUG(pL&&(pL->iPrimaryMedia==iPrimaryMedia),LOCM_FAULT());	// valid drive number?
+			m.Drive()=pL;
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+			__e32_atomic_add_ord32(&iMediaPagingInfo.iCodePageInCount, (TUint) 1);
+			info = &iCodeBenchmarkData;
+#endif
+			}
+		else
+			LOCM_FAULT(); // invalid drive number
+
+		m.RemoteThread()=NULL;
+		m.Pos()=offset;
+		m.Length()=Int64(size);
+		m.RemoteDes()=(TAny*)aBuffer;
+		m.RemoteDesOffset()=0;		// pre-aligned
+		m.DriverFlags()=0;
+		__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
+
+		__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
+		TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
+
+		SendToMainQueueDfcAndBlock(&m);		// queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
+		retVal = m.iValue;
+
+#ifdef __DEBUG_DEMAND_PAGING__
+		if (retVal != KErrNone)
+			Kern::Printf("Pagin Failure %d, retry %d", retVal, i);
+#endif
+
+		// reset retry count if there's ben a media change
+		if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
+			i = 0;
+		}	// for ()
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	NKern::FMWait(&iInstrumentationLock);
+	if (*servicingCount)
+		(*servicingCount)--;
+	NKern::FMSignal(&iInstrumentationLock);
+#endif
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	TUint32 bmEnd = NKern::FastCounter();
+	++info->iCount;
+#if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
+	TInt64 elapsed=bmEnd-bmStart;
+#else
+	TInt64 elapsed=bmStart-bmEnd;
+#endif
+	info->iTotalTime += elapsed;
+	if (elapsed > info->iMaxTime)
+		info->iMaxTime = elapsed;
+	if (elapsed < info->iMinTime)
+		info->iMinTime = elapsed;
+#endif // __DEMAND_PAGING_BENCHMARKS__
+
+	return retVal;
+	}
+
+TInt DMediaPagingDevice::Write(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TBool aBackground)
+	{
+	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
+	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
+	__ASSERT_CRITICAL
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	TUint32 bmStart = NKern::FastCounter();
+#endif
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	NKern::FMWait(&iInstrumentationLock);
+	if(iServicingDataOut)
+		iDataStats.iTotalConcurrentReqs++;
+	if(!(++iServicingDataOut))
+		{
+		iServicingDataOut=1;				// overflow...
+		iDataStats.iTotalConcurrentReqs=0;	// ...reset this
+		}
+	TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
+	if(!empty)
+		iDataStats.iTotalReqIssuedNonEmptyQ++;
+	NKern::FMSignal(&iInstrumentationLock);
+#endif
+
+	TUint offset=aOffset<<iReadUnitShift;
+	TUint size=aSize<<iReadUnitShift;
+
+#ifdef BTRACE_PAGING_MEDIA
+	TInt buf[2];
+	buf[0] = size;				// page out request length
+	buf[1] = (TInt)aReq;		// address of request object
+	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageOutBegin,aBuffer,offset,buf,sizeof(buf));
+#endif
+
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Buff(0x%x),Offset(%d),Size(%d)",aReq,aBuffer,offset,size));
+	
+	// no DFCQ, media driver executes in the context of calling thread
+	if (!iPrimaryMedia->iDfcQ)
+		{
+		LOCM_FAULT();		// don't allow paging
+		return KErrNone;	// keep compiler happy
+		}
+
+
+	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutCount, (TUint) 1);
+	if (aBackground)
+		__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutBackgroundCount, (TUint) 1);
+#endif
+
+	// Write to the media and allow for retries in the unlikely event of an error.
+	const TInt KPageOutRetries = 5;
+	TInt retVal = KErrGeneral;
+	for (TInt i=0; retVal != KErrNone && i < KPageOutRetries; i++)
+		{
+		m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging | (aBackground ? TLocDrvRequest::EBackgroundPaging : 0);
+
+		m.Id() = DLocalDrive::EWrite;
+		m.Drive() = TheDrives[iDataPagingDriveNumber];
+
+		m.RemoteThread()=NULL;
+		m.Pos()=offset;
+		m.Length()=Int64(size);
+		m.RemoteDes()=(TAny*)aBuffer;
+		m.RemoteDesOffset()=0;		// pre-aligned
+		m.DriverFlags()=0;
+		__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
+
+		__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
+		TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
+
+		SendToMainQueueDfcAndBlock(&m);		// queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
+		retVal = m.iValue;
+
+#ifdef __DEBUG_DEMAND_PAGING__
+		if (retVal != KErrNone)
+			Kern::Printf("Pagout Failure %d, retry %d", retVal, i);
+#endif
+		// reset retry count if there's ben a media change
+		if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
+			i = 0;
+		}	// for ()
+
+#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
+	NKern::FMWait(&iInstrumentationLock);
+	if (iServicingDataOut)
+		iServicingDataOut--;
+	NKern::FMSignal(&iInstrumentationLock);
+#endif
+
+#ifdef __DEMAND_PAGING_BENCHMARKS__
+	SPagingBenchmarkInfo& info = iDataOutBenchmarkData;
+	TUint32 bmEnd = NKern::FastCounter();
+	++info.iCount;
+#if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
+	TInt64 elapsed=bmEnd-bmStart;
+#else
+	TInt64 elapsed=bmStart-bmEnd;
+#endif
+	info.iTotalTime += elapsed;
+	if (elapsed > info.iMaxTime)
+		info.iMaxTime = elapsed;
+	if (elapsed < info.iMinTime)
+		info.iMinTime = elapsed;
+#endif // __DEMAND_PAGING_BENCHMARKS__
+
+	return retVal;
+	}
+
+
+TInt DMediaPagingDevice::DeleteNotify(TThreadMessage* aReq,TUint aOffset,TUint aSize)
+	{
+	if (iDeleteNotifyNotSupported)
+		return KErrNotSupported;
+
+	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
+	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
+	__ASSERT_ALWAYS(DataPagingDfcQ(iPrimaryMedia),LOCM_FAULT());
+	__ASSERT_CRITICAL
+
+	TUint offset = aOffset<<iReadUnitShift;
+	TUint size = aSize<<iReadUnitShift;
+
+#ifdef BTRACE_PAGING_MEDIA
+	TInt buf[2];
+	buf[0] = size;		// delete notify length
+	buf[1] = (TInt)aReq;	// address of request object
+	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedDeleteNotifyBegin,NULL,offset,buf,sizeof(buf));
+#endif
+
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Offset(%d),Size(%d)",aReq,offset,size));
+	
+	// no DFCQ, media driver executes in the context of calling thread
+	if (!iPrimaryMedia->iDfcQ)
+		{
+		LOCM_FAULT();		// don't allow paging
+		return KErrNone;	// keep compiler happy
+		}
+
+	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
+
+
+	m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging;
+	m.Id() = DLocalDrive::EDeleteNotify;
+	m.Drive() = TheDrives[iDataPagingDriveNumber];
+
+	m.RemoteThread() = NULL;
+	m.Pos() = offset;
+	m.Length() = Int64(size);
+	m.RemoteDes() = NULL;
+	m.RemoteDesOffset() = 0;		// pre-aligned
+	m.DriverFlags()=0;
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("ReqId=%d, Pos=0x%lx, Len=0x%lx, remote Des 0x%x",m.Id(),m.Pos(),m.Length(),m.RemoteDes()));
+
+
+	// send request aynchronously as we don't particularly care about the result 
+	// and waiting would slow down the thread taking the page fault
+	iPrimaryMedia->RequestCountInc();
+
+	m.SendReceive(&iMainQ);	// send  request synchronously
+
+#ifdef __DEMAND_PAGING__
+	iPrimaryMedia->RequestCountDec();
+#endif
+
+	TInt retVal = m.iValue;
+
+	if (retVal == KErrNotSupported)
+		iDeleteNotifyNotSupported = ETrue;
+
+	return retVal;
+	}
+
+
+
+EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset)
+	{
+#ifdef BTRACE_PAGING_MEDIA
+	TMediaDevice medDev=Drive()->iMedia->iDevice;
+	TInt buf[3];
+	buf[0]=(TUint32)RemoteDes();
+	buf[1]=anOffset;
+	buf[2]=aSize;
+	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvWriteBack,medDev,this,buf,sizeof(buf));
+#endif
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::WriteToPageHandler, memcpy((aTrg)%08x, (aSrc)%08x, (aLength)%08x)",(TUint32)RemoteDes()+anOffset,aSrc,aSize));
+	(void)memcpy((TAny*)((TUint32)RemoteDes()+anOffset), aSrc, aSize);	// maybe in later versions this could be something else
+	return KErrNone;
+	}
+
+EXPORT_C TInt TLocDrvRequest::ReadFromPageHandler(TAny* aDst, TInt aSize, TInt anOffset)
+	{
+#ifdef BTRACE_PAGING_MEDIA
+	TMediaDevice medDev=Drive()->iMedia->iDevice;
+	TInt buf[3];
+	buf[0]=(TUint32)RemoteDes();
+	buf[1]=anOffset;
+	buf[2]=aSize;
+	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvRead,medDev,this,buf,sizeof(buf));
+#endif
+	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::ReadFromPageHandler, memcpy((aDst)%08x, (aTrg)%08x, (aLength)%08x)",aDst,(TUint32)RemoteDes()+anOffset,aSize));
+	(void)memcpy(aDst, (TAny*)((TUint32)RemoteDes()+anOffset), aSize);	// maybe in later versions this could be something else
+	return KErrNone;
+	}
+
+_LIT(KLitFragmentationMutexName, "FRAGMENTATION_MUTEX");
+
+TInt DFragmentationPagingLock::Construct(TUint aNumPages)
+	{
+	TInt r=KErrNone;
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: creating Mutex"));
+	r=Kern::MutexCreate(this->iFragmentationMutex, KLitFragmentationMutexName, KMutexOrdNone);
+	if (r!=KErrNone)
+		return r;
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: Mutex created OK"));
+
+	iFragmentGranularity = 0;
+	if (aNumPages == 0)
+		return KErrNone;
+
+	// in CS
+	TInt pageSize=Kern::RoundToPageSize(1);
+	LockFragmentation();
+	r=Alloc(pageSize*aNumPages);	// alloc pages
+	UnlockFragmentation();
+
+	if(r==KErrNone)
+		{
+		iFragmentGranularity = pageSize * aNumPages;
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
+		}
+
+	return r;
+	}
+
+void DFragmentationPagingLock::Cleanup()
+	{
+	// in CS
+	if (iFragmentationMutex)
+		{
+		LockFragmentation();
+		Free();					// at last!
+		UnlockFragmentation();
+		Kern::SafeClose((DObject*&)iFragmentationMutex,NULL);
+		}
+	}
+
+#else
+#if !defined(__WINS__)
+EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* , TInt , TInt)
+	{
+	return KErrNone;		// stub for def file
+	}
+#endif // __WINS__
+#endif //__DEMAND_PAGING__
+/********************************************
+ * Media driver base class
+ ********************************************/
+ 
+ 
+ 
+ 
+/**
+Constructor.
+
+This is called, typically, by a derived class constructor in its ctor list.
+
+@param aMediaId The value of the unique media ID assigned when the media
+                driver is registered.
+                
+@see LocDrv::RegisterMediaDevice()                
+*/
+EXPORT_C DMediaDriver::DMediaDriver(TInt aMediaId)
+	{
+//	iPhysicalDevice=NULL;
+//	iTotalSizeInBytes=0;
+//	iCurrentConsumption=0;
+//	iPrimaryMedia=NULL;
+//	iCritical=EFalse;
+	iPrimaryMedia=(DPrimaryMediaBase*)TheMedia[aMediaId];
+	}
+
+
+
+
+/**
+Destructor.
+
+Sets the device's current consumption to zero, and calls Close() on
+the PDD factory object.
+
+@see DObject::Close()
+*/
+EXPORT_C DMediaDriver::~DMediaDriver()
+	{
+	SetCurrentConsumption(0);
+	Kern::SafeClose((DObject*&)iPhysicalDevice,NULL);
+	}
+
+
+
+
+/**
+Closes the media driver.
+
+This default implementation simply deletes this DMediaDriver 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 DMediaDriver::Close()
+	{
+	delete this;
+	}
+
+
+
+
+/**
+Sets the total size of the media device.
+
+The function must be called by the media driver's implementation of PartitionInfo().
+
+@param aTotalSizeInBytes The total size of the media, in bytes.
+@param aLocDrv           This is not used by media drivers; the class
+                         definition provides a default value.
+
+@see DMediaDriver::PartitionInfo()
+*/
+EXPORT_C void DMediaDriver::SetTotalSizeInBytes(Int64 aTotalSizeInBytes, TLocDrv* aLocDrv)
+	{
+	iTotalSizeInBytes=aTotalSizeInBytes;
+	if (aLocDrv)
+		aLocDrv->iPartitionLen=aTotalSizeInBytes;
+	}
+
+
+
+
+/**
+Gets the total size of the media.
+
+@return The total size of the media, in bytes.
+
+@see DMediaDriver::SetTotalSizeInBytes()
+*/
+EXPORT_C Int64 DMediaDriver::TotalSizeInBytes()
+	{
+	return iTotalSizeInBytes;
+	}
+
+
+
+
+/**
+Flags the media driver as entering a critical part of its processing.
+
+In this context, critical means that the driver must be allowed to complete
+its current activity.
+For example, a request to power down the device must be deferred until
+the driver exits the critical part.
+
+@return KErrNone, if the driver has been successfully flagged as being in
+        a critical part; otherwise, one of the other system-wide error codes.
+        
+@see DMediaDriver::EndInCritical()
+*/
+EXPORT_C TInt DMediaDriver::InCritical()
+	{
+	if (!iCritical)
+		{
+		TInt r=iPrimaryMedia->InCritical();
+		if (r!=KErrNone)
+			return r;
+		iCritical=ETrue;
+		}
+	return KErrNone;
+	}
+
+
+
+
+/**
+Flags the media driver as leaving a critical part of its processing.
+
+@see DMediaDriver::InCritical()
+*/
+EXPORT_C void DMediaDriver::EndInCritical()
+	{
+	if (iCritical)
+		{
+		iCritical=EFalse;
+		iPrimaryMedia->EndInCritical();
+		}
+	}
+
+
+
+
+/**
+@internalComponent
+*/
+EXPORT_C void DMediaDriver::SetCurrentConsumption(TInt aValue)
+	{
+	TInt old = (TInt)__e32_atomic_swp_ord32(&iCurrentConsumption, aValue);
+	TInt delta = aValue - old;
+	iPrimaryMedia->DeltaCurrentConsumption(delta);
+	}
+
+
+
+
+/**
+Informs the media driver subsystem that an asynchronous request is complete.
+
+@param m       The request that this call is completing.
+@param aResult The return code for the asynchronous request. Typically, this
+               is KErrNone to report success, or one of the other system-wide
+               error codes to report failure or other problems.
+*/
+EXPORT_C void DMediaDriver::Complete(TLocDrvRequest& m, TInt aResult)
+	{
+	CHECK_RET(aResult);
+#ifdef __DEMAND_PAGING__
+	if (DMediaPagingDevice::PagingRequest(m))
+		{
+		__ASSERT_ALWAYS(iPrimaryMedia && iPrimaryMedia->iPagingMedia && iPrimaryMedia->iBody->iPagingDevice,LOCM_FAULT());
+		__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
+		DMediaPagingDevice* pagingdevice = iPrimaryMedia->iBody->iPagingDevice;
+		pagingdevice->CompleteRequest(&m, aResult);
+		}
+	else
+#endif
+	iPrimaryMedia->CompleteRequest(m, aResult);
+	
+	if (&m == iPrimaryMedia->iCurrentReq)	// Complete() called on request serviced synchronously
+		iPrimaryMedia->iCurrentReq = NULL;
+
+	iPrimaryMedia->RunDeferred();
+	}
+
+
+
+ 
+/**
+Informs the media driver subsystem that the media driver is open
+and has been initialised.
+
+This can be called from the PDD factory function Create(), if opening and
+initialising the media driver is synchronous, otherwise it should be called by
+the asynchronous media driver function that is responsible for opening and
+initialising the driver.
+
+@param anError KErrNone if successful, otherwise one of the other system wide
+       error codes.
+*/
+EXPORT_C void DMediaDriver::OpenMediaDriverComplete(TInt anError)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::OpenMediaDriverComplete(%d) this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
+	DPrimaryMediaBase* pM=iPrimaryMedia;
+	pM->iAsyncErrorCode=anError;
+	pM->iAsyncDfc.Enque();
+	}
+
+
+
+
+/**
+Informs the media driver subsystem that the media driver has completed
+the provision of partition information.
+
+The media driver provides partition information in its implementation
+of PartitionInfo().
+
+@param anError KErrNone if successful, otherwise one of the other system wide
+       error codes.
+
+@see DMediaDriver::PartitionInfo()
+*/
+EXPORT_C void DMediaDriver::PartitionInfoComplete(TInt anError)
+	{
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::PartitionInfoComplete(%d) anError %d this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
+	DPrimaryMediaBase* pM=iPrimaryMedia;
+	pM->iAsyncErrorCode=anError;
+	pM->iAsyncDfc.Enque();
+	}
+
+
+
+
+/**
+@internalComponent
+*/
+// Default implementation
+EXPORT_C void DMediaDriver::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
+	{
+	// don't need to worry about DLocalDrive going away
+	aLocalDrive->Deque();
+
+	aMsg->Complete(KErrNone, EFalse);
+	}
+
+
+
+
+/**
+Registers a media driver with the Local Media Subsystem, and provides
+information about the number of supported drives, partitions,
+names and drive numbers.
+
+@param aDevice       The unique Media ID for this device.
+                     This can take one of the enumerated values defined
+                     by the TMediaDevice enum.
+@param aDriveCount   Specifies the number of local drive objects to be assigned
+                     to the media driver. Drives that support more than one
+                     partition must specify a number greater than 1.
+@param aDriveList    A pointer to an array of TInt values, which define
+                     the drive numbers that are to be allocated to each partition.
+                     0 signifies Drive C, 1 signifies drive D, etc. For example,
+                     to allocate drive letters J and K, specify an array
+                     containing the values [7,8].
+                     Note that the size of this array must be the same as the value 
+                     specified by aDriveCount.
+@param aPrimaryMedia A pointer to the primary DPrimaryMedia object to be
+                     associated with the media. This object is responsible for
+                     the overall state of the media, i.e. powering up, reading
+                     partition information etc. It also has overall control over
+                     all partitions as represented by the additional (aNumMedia-1)
+                     DMedia objects. 
+@param aNumMedia     Specifies the total number of DMedia objects to be
+                     associated with the media driver. This number includes the
+                     primary DPrimaryMedia object referred to by aPrimaryMedia,
+                     plus all of the DMedia objects that are created for each
+                     additional drive, and which hold basic information about
+                     partitions.
+@param aName         The name of the media driver, for example: PCCard
+       
+@return              KErrNone, if successful;
+                     KErrInUse, if a drive is already in use;
+                     KErrNoMemory, if there is insufficient memory;
+                     or one of the other system-wide error codes.  
+*/
+EXPORT_C TInt LocDrv::RegisterMediaDevice(TMediaDevice aDevice, TInt aDriveCount, const TInt* aDriveList, DPrimaryMediaBase* aPrimaryMedia, TInt aNumMedia, const TDesC& aName)
+	{
+	// 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));
+	const TInt* p=aDriveList;
+	TInt i;
+	TInt r=0;
+	if (UsedMedia+aNumMedia>KMaxLocalDrives)
+		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));
+		if (TheDrives[drv])
+			{
+			__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d already in use", drv));
+			return KErrInUse;
+			}
+		}
+	HBuf* pN=HBuf::New(aName);
+	if (!pN)
+		return KErrNoMemory;
+	TInt lastMedia=UsedMedia+aNumMedia-1;
+	for (i=UsedMedia; i<=lastMedia; ++i)
+		{
+		if (i==UsedMedia)
+			TheMedia[i]=aPrimaryMedia;
+		else
+			TheMedia[i]=new DMedia;
+		if (!TheMedia[i])
+			return KErrNoMemory;
+		r=TheMedia[i]->Create(aDevice,i,lastMedia);
+		__KTRACE_OPT(KBOOT,Kern::Printf("Media %d Create() returns %d",i,r));
+		if (r!=KErrNone)
+			return r;
+		}
+
+	__KTRACE_OPT(KBOOT,Kern::Printf("FirstMedia %d LastMedia %d",UsedMedia,lastMedia));
+	UsedMedia+=aNumMedia;
+	p=aDriveList;
+	for (i=0; i<aDriveCount; ++i)
+		{
+		TInt drv=*p++;
+		if (drv == -1)
+			continue;
+		TLocDrv* pL=new TLocDrv(drv);
+		if (!pL)
+			return KErrNoMemory;
+		TheDrives[drv]=pL;
+		DriveNames[drv]=pN;
+		pL->iPrimaryMedia=aPrimaryMedia;
+		__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d: TLocDrv @ %08x",drv,pL));
+		}
+	return KErrNone;
+	}
+
+
+
+
+/**
+A utility function that is used internally to register the specified
+password store.
+
+The password store is used to save passwords for local media.
+
+@param aStore A pointer to the password store to be registered.
+
+@return KErrNone, if successful;
+        KErrAlreadyExists, if a password store has already been registered.
+*/ 
+EXPORT_C TInt LocDrv::RegisterPasswordStore(TPasswordStore* aStore)
+	{
+	// Create TLocDrv / DMedia objects to handle a media device
+	__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPasswordStore"));
+
+	TInt r = KErrNone;
+
+	if(ThePasswordStore == NULL)
+		ThePasswordStore = aStore;
+	else
+		r = KErrAlreadyExists;
+
+	return r;
+	}
+
+/**
+Returns a pointer to the registered password store.
+
+The password store is used to save passwords for local media.
+
+@return A pointer to the registered password store.
+*/ 
+EXPORT_C TPasswordStore* LocDrv::PasswordStore()
+	{
+	return ThePasswordStore;
+	}
+
+
+#ifdef __DEMAND_PAGING__
+/**
+Registers a paging device with the Local Media Subsystem, and provides
+information about drive numbers used in Code Paging.
+
+@param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated 
+					 with the media.
+@param aPagingDriveList    A pointer to an array of TInt values, which define
+                     the drive numbers used as Code backup in Code Paging, which
+					 are the target of Page In requests. For NAND these will
+					 will be usually associated with ROFS and/or User Data drives.
+					 In ROM pagigng systems no drive is specified, it is assumed
+					 a fixed media for which no non-primary media exists, will be 
+					 used.
+@param aDriveCount   Specifies the number of local drives associated with this
+					 media device which can be used for code paging. 
+@param aPagingType	 Identifies the type of Paging this media device is capable
+					 of servicing.
+@param aReadShift	 Log2 of the read unit size. A read unit is the number of bytes
+					 which the device can optimally read from the underlying media.
+					 E.g. for small block NAND, a read unit would be equal to the 
+					 page size,	512 bytes, therefore iReadShift would be set to 9.
+@param aNumPages     The number of pages to alloc for each drive associated with this
+					 media driver. The pages are used in request fragmentation.
+
+@return              KErrNone, if successful;
+					 KErrNotFound, if at least one of the drive numbers
+					 specified has not yet been mapped.
+					 KErrArgument, if the passed in an invalid argument.
+					 KErrNotSupported, if at least one of the drive numbers 
+					 specifed is not associated with this Primary Media.
+                     KErrNoMemory, if there is insufficient memory;
+                     or one of the other system-wide error codes.  
+*/
+EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* aPrimaryMedia, const TInt* aPagingDriveList, TInt aDriveCount, TUint aPagingType, TInt aReadShift, TUint aNumPages)
+	{
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf(">RegisterPagingDevice: paging type=%d PM=0x%x read shift=%d",aPagingType,aPrimaryMedia,aReadShift));
+	TInt i;
+
+	if(!aPagingType || (aPagingType&~(DPagingDevice::ERom | DPagingDevice::ECode | DPagingDevice::EData)))
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Unsupported paging type, exiting"));
+		return KErrArgument;
+		}
+
+
+
+	for(i=0; i<KMaxLocalDrives; 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));
+			}
+		}
+
+
+	if (aPagingType == 0)
+		{
+		// there's already a ROM or Data paging device & this doesn't support code paging so quietly exit without further addo
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Nothing left to register on locdrv no %d, exiting",i));
+		return KErrNone;
+		}
+
+	const TInt* p=aPagingDriveList;
+	if(aPagingType&DPagingDevice::ECode)	// supports code paging, do argument check
+		{
+		if(!aDriveCount || (aDriveCount>=KMaxLocalDrives))
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count: %d", aDriveCount));
+			return KErrArgument;
+			}
+
+		TInt drvCount=0;
+		for(i=0; i<KMaxLocalDrives; i++)
+			if(TheDrives[i] && TheDrives[i]->iPrimaryMedia==aPrimaryMedia)
+				drvCount++;
+		if(aDriveCount>drvCount)	// can't exceed number of drives registered by this device
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count: %d total %d", aDriveCount, drvCount));
+			return KErrArgument;
+			}
+
+		for (i=0; i<aDriveCount; ++i)
+			{
+			__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPagingDevice: registering drive=%d ",*p));
+			TInt drv=*p++;
+			if(drv>=KMaxLocalDrives)
+				{
+				__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive number: %d", drv));
+				return KErrArgument;
+				}
+			TLocDrv* pD=TheDrives[drv];
+			if (!pD)
+				return KErrNotFound;
+			if (pD->iPrimaryMedia!=aPrimaryMedia)
+				return KErrNotSupported;
+			}
+		}
+
+
+	TInt firstLocalDriveNumber = KErrNotFound; 
+	TInt romPagingDriveNumber = KErrNotFound;
+
+	TInt dataPagingDriveNumber = KErrNotFound;
+	TInt swapSize = 0;
+
+	// find the local drive assocated with the primary media
+	for (i=0; i<KMaxLocalDrives; ++i)
+		{
+		if(TheDrives[i] && TheDrives[i]->iPrimaryMedia == aPrimaryMedia)
+			{
+			firstLocalDriveNumber = i;
+			break;
+			}
+		}
+	__ASSERT_ALWAYS(i < KMaxLocalDrives, LOCM_FAULT());
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("DMediaPagingDevice(), firstLocalDriveNumber %d", firstLocalDriveNumber)); 
+
+
+	// Send an ECaps message to wake up the media driver & ensure all partitions are 
+	// reported, then search for paged-data or paged-ROM partitions
+	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)
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: Message queue not started"));
+			return KErrNotReady;
+			}
+
+
+		TLocDrvRequest m;
+		memclr(&m, sizeof(m));
+		
+
+		// Get the Caps from the device. NB for MMC/SD we may need to retry as some PSLs start up
+		// in "door open" or "media not present" state which can result in the cancellation of requests
+		TInt i;
+		const TInt KRetries = 5;
+		TInt r = KErrNotReady;
+		for (i=0; r == KErrNotReady && i < KRetries; i++)
+			{
+			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
+			capsBuf.SetMax();
+			capsBuf.FillZ();
+			m.Drive() = TheDrives[firstLocalDriveNumber];
+			m.Id() = DLocalDrive::ECaps;
+			m.RemoteDes() = (TAny*)capsBuf.Ptr();	// overload this
+			m.Length() = KMaxLocalDriveCapsLength;	// for pinning
+			r = aPrimaryMedia->Request(m);
+
+//Kern::Printf("EQueryPageDeviceInfo: i %d: r %d ", i, r);
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Paging device ECaps: i %d: r %d ", i, r));
+			}
+
+		if (r != KErrNone)
+			return r;
+
+		TLocDrv* drive;
+		for (i=0; i<KMaxLocalDrives; ++i)
+			{
+			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)));
+				// ROM partition ?
+				if ((romPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypeROM))
+					{
+					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found ROM partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
+					romPagingDriveNumber = i;
+					}
+			    // swap partition ?
+				else if ((dataPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypePagedData))
+					{
+					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found swap partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
+					dataPagingDriveNumber = i;
+					swapSize = drive->iPartitionLen >> aReadShift;
+					}
+				}
+			}
+
+		if (swapSize == 0)
+			{
+			__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Disabling data paging"));
+			aPagingType &= ~DPagingDevice::EData;
+			}
+
+		}
+
+
+	// create and set up a DPagingDevice to allow PageIn request servicing
+	DMediaPagingDevice* pagingDevice = new DMediaPagingDevice(aPrimaryMedia);
+	if(!pagingDevice)
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create paging device"));
+		return KErrNoMemory;
+		}
+
+	pagingDevice->iType = aPagingType;
+	pagingDevice->iReadUnitShift = aReadShift;
+
+	pagingDevice->iFirstLocalDriveNumber = firstLocalDriveNumber;
+	pagingDevice->iRomPagingDriveNumber = romPagingDriveNumber;
+
+	pagingDevice->iDataPagingDriveNumber = dataPagingDriveNumber;
+	pagingDevice->iSwapSize = swapSize;
+
+#ifdef __DEBUG_DEMAND_PAGING__
+	Kern::Printf("PagingDevice :");
+	Kern::Printf("iType 0x%x\n", pagingDevice->iType);
+	Kern::Printf("iReadUnitShift 0x%x\n", pagingDevice->iReadUnitShift);
+	Kern::Printf("iFirstLocalDriveNumber 0x%x\n", pagingDevice->iFirstLocalDriveNumber);
+	Kern::Printf("iRomPagingDriveNumber 0x%x\n", pagingDevice->iRomPagingDriveNumber);
+	Kern::Printf("iDataPagingDriveNumber 0x%x\n", pagingDevice->iDataPagingDriveNumber);
+	Kern::Printf("iSwapSize 0x%x\n", pagingDevice->iSwapSize);
+#endif
+
+
+	// This table is indexed by DPagingDevice::TType
+	const char* DeviceName[] = 
+		{
+		"Error",
+		"RomPagingDevice",
+		"CodePagingDevice",
+		"RomAndCodePagingDevice",
+		"DataPagingDevice",
+		"RomAndDataPagingDevice",
+		"CodeAndDataPagingDevice",
+		"RomAndCodeAndDataPagingDevice"
+		};
+
+
+	if(aPagingType & DPagingDevice::ECode)
+		{
+		for (i=0; i<aDriveCount; ++i)
+			pagingDevice->iDrivesSupported|=(0x1<<aPagingDriveList[i]);
+		}
+	pagingDevice->iName = DeviceName[aPagingType];
+
+	if (ThePinObjectAllocator == NULL)
+		ThePinObjectAllocator = new DPinObjectAllocator();
+	if(!ThePinObjectAllocator)
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create ThePinObjectAllocator"));
+		return KErrNoMemory;
+		}
+	TInt r = ThePinObjectAllocator->Construct(KDynamicPagingLockCount, aNumPages);
+	if (r != KErrNone)
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not construct ThePinObjectAllocator"));
+		return r;
+		}
+
+
+	// Register our DPagingDevice with the Kernel
+	r=Kern::InstallPagingDevice(pagingDevice);
+
+#ifdef __DEBUG_DEMAND_PAGING__
+	Kern::Printf("Kern::InstallPagingDevice() r %d", r);
+#endif
+
+	if (r!=KErrNone)
+		{
+		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not install paging device"));
+		delete pagingDevice;
+		return r;
+		}
+
+	// all hunky dory, save paging device and mark our media as pageable
+	ThePagingDevices[aPrimaryMedia->iMediaId] = pagingDevice;	// association created between PrimaryMedia and PagingDevice via iMediaId
+	aPrimaryMedia->iPagingMedia = 1;
+
+	// mark our drives as pageable
+	p=aPagingDriveList;
+	if (aPagingType&DPagingDevice::ECode)
+		{
+		for (i=0; i<aDriveCount; ++i)
+			{
+			TLocDrv* pD=TheDrives[*p++];
+			pD->iPagingDrv=1;
+			}
+		}
+
+	// Flags to indicate that a paging device is registered and pinning of user requests may be required
+	aPrimaryMedia->iPagingMedia = 1;
+
+	// point the primary media to the paging device
+	aPrimaryMedia->iBody->iPagingDevice = pagingDevice;
+
+	if (aPagingType & DPagingDevice::ERom)
+		{
+		aPrimaryMedia->iRomPagingMedia = 1;
+		TheRomPagingMedia = aPrimaryMedia;
+		}
+	
+	// Is data paging enabled in this ROM ?
+	TInt memModelAttributes = Kern::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
+	TBool dataPagingSupported = memModelAttributes & EMemModelAttrDataPaging;
+#ifdef __DEBUG_DEMAND_PAGING__
+	Kern::Printf("memModelAttributes %08X", memModelAttributes);
+	Kern::Printf("DataPagingSupported %d", dataPagingSupported);
+#endif
+	if (!dataPagingSupported)
+		{
+#ifdef __DEBUG_DEMAND_PAGING__
+		if (aPagingType & DPagingDevice::EData)
+			Kern::Printf("Disabling data paging, not supported in this ROM");
+#endif
+		aPagingType&= ~DPagingDevice::EData;
+		}
+
+
+	if (aPagingType & DPagingDevice::EData)
+		{
+		DataPagingDeviceRegistered = ETrue;
+		aPrimaryMedia->iDataPagingMedia = 1;
+		TheDataPagingMedia = aPrimaryMedia;
+		}
+
+	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("<RegisterPagingDevice"));
+	return KErrNone;
+	}
+
+#else //__DEMAND_PAGING__
+
+#if !defined(__WINS__)
+EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* , const TInt* , TInt , TUint , TInt , TUint )
+	{
+	return KErrNotSupported;
+	}		// stub for def file
+#endif // __WINS__
+
+#endif //__DEMAND_PAGING__
+
+
+/**
+Registers a media device with physical memory addressing capabilities with the
+Local Media Subsystem.
+
+@param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated 
+					 with the media device.
+@param aMediaBlockSize The Minimum transfer size (bytes) for the media device.
+@param aDmaMaxAddressable The Maximum Addressing Range for the media device's DMA controller, 0 if None.				 
+@param aDmaAlignment The required memory alignment for the media device's DMA controller.
+
+@return KErrNone, Always;
+*/
+EXPORT_C TInt LocDrv::RegisterDmaDevice(DPrimaryMediaBase* aPrimaryMedia, 
+										TInt aMediaBlockSize,				// Minimum transfer size (bytes) for the media
+										TInt aDmaMaxAddressable,			// Max Addressing Range for DMA controller, 0 if None.
+										TInt aDmaAlignment)					// DMA Alignment e.g. word alignment required = 2
+	{
+	__KTRACE_OPT(KBOOT ,Kern::Printf("RegisterPhysicalAddrDevice: PM=0x%x BS=%d MaxAddr=%d DMA=%d", 
+									aPrimaryMedia, aMediaBlockSize, aDmaMaxAddressable, aDmaAlignment));
+
+	for (TInt i=0; i<KMaxLocalDrives; ++i)
+		{
+		TLocDrv* pL=TheDrives[i];
+		if (pL && pL->iPrimaryMedia == aPrimaryMedia && pL->iDmaHelper == NULL)
+			{
+			pL->iDmaHelper = new DDmaHelper;
+			__ASSERT_ALWAYS(pL != NULL, LOCM_FAULT());
+			
+			// if no limit stated on addressing range use 1MB
+			TInt MaxAddress = aDmaMaxAddressable ? (1024*1024) : aDmaMaxAddressable;
+			
+			TInt r = pL->iDmaHelper->Construct(MaxAddress, aMediaBlockSize, aDmaAlignment);
+			__ASSERT_ALWAYS(r == KErrNone, LOCM_FAULT());
+			}
+		}
+
+	return KErrNone;
+	}
+
+void GetDriveInfo(TDriveInfoV1& info)
+	{
+	TInt i;
+	TInt drives=0;
+	TUint32 sock_mask=0;
+	TInt sockets=0;
+
+	info.iRegisteredDriveBitmask = 0;
+
+	for (i=0; i<KMaxPBusSockets; ++i)
+		info.iSocketName[i].Zero();
+	for (i=0; i<KMaxLocalDrives; ++i)
+		{
+		TLocDrv* pL=TheDrives[i];
+		if (pL)
+			{
+			++drives;
+			TInt sockNum;
+			DPrimaryMediaBase* pM=pL->iPrimaryMedia;
+			if (pM->IsRemovableDevice(sockNum))
+				{
+				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]));
+					if ( (sockNum + 1) > sockets )
+						sockets = sockNum + 1;
+					}
+				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]));
+			
+			info.iRegisteredDriveBitmask |= (0x01 << i);
+			}
+		}
+	info.iTotalSupportedDrives=drives;
+	info.iTotalSockets=sockets;
+	info.iRuggedFileSystem=ETrue;
+	__KTRACE_OPT(KLOCDRV,Kern::Printf("Total drives=%d, sockets=%d",drives,sockets));
+	}
+
+#if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
+void ResetConcurrencyStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
+	{
+	NKern::FMWait(&aDevice->iInstrumentationLock);
+	switch(aStats)
+		{
+		case EMediaPagingStatsRom:
+			aDevice->iServicingROM=0;
+			memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
+			break;
+		case EMediaPagingStatsCode:
+			aDevice->iServicingCode=0;
+			memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
+			break;
+		case EMediaPagingStatsDataIn:
+			aDevice->iServicingDataIn=0;
+			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
+			break;
+		case EMediaPagingStatsDataOut:
+			aDevice->iServicingDataOut=0;
+			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
+			break;
+		case EMediaPagingStatsAll:
+			aDevice->iServicingROM=0;
+			aDevice->iServicingCode=0;
+			aDevice->iServicingDataIn=0;
+			aDevice->iServicingDataOut=0;
+			memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
+			memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
+			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
+			break;
+		}
+	NKern::FMSignal(&aDevice->iInstrumentationLock);
+	}
+#endif
+#if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
+void ResetBenchmarkStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
+	{
+	NKern::FMWait(&aDevice->iInstrumentationLock);
+	switch(aStats)
+		{
+		case EMediaPagingStatsRom:
+			aDevice->iROMBenchmarkData.iCount = 0;
+			aDevice->iROMBenchmarkData.iTotalTime = 0;
+			aDevice->iROMBenchmarkData.iMaxTime = 0;
+			aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
+			break;
+		case EMediaPagingStatsCode:
+			aDevice->iCodeBenchmarkData.iCount = 0;
+			aDevice->iCodeBenchmarkData.iTotalTime = 0;
+			aDevice->iCodeBenchmarkData.iMaxTime = 0;
+			aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
+			break;
+		case EMediaPagingStatsDataIn:
+			aDevice->iDataInBenchmarkData.iCount = 0;
+			aDevice->iDataInBenchmarkData.iTotalTime = 0;
+			aDevice->iDataInBenchmarkData.iMaxTime = 0;
+			aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
+			break;
+		case EMediaPagingStatsDataOut:
+			aDevice->iDataOutBenchmarkData.iCount = 0;
+			aDevice->iDataOutBenchmarkData.iTotalTime = 0;
+			aDevice->iDataOutBenchmarkData.iMaxTime = 0;
+			aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
+			break;
+		case EMediaPagingStatsAll:
+			aDevice->iDataInBenchmarkData.iCount = 0;
+			aDevice->iDataInBenchmarkData.iTotalTime = 0;
+			aDevice->iDataInBenchmarkData.iMaxTime = 0;
+			aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
+
+			aDevice->iDataOutBenchmarkData.iCount = 0;
+			aDevice->iDataOutBenchmarkData.iTotalTime = 0;
+			aDevice->iDataOutBenchmarkData.iMaxTime = 0;
+			aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
+
+			aDevice->iROMBenchmarkData.iCount = 0;
+			aDevice->iROMBenchmarkData.iTotalTime = 0;
+			aDevice->iROMBenchmarkData.iMaxTime = 0;
+			aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
+
+			aDevice->iCodeBenchmarkData.iCount = 0;
+			aDevice->iCodeBenchmarkData.iTotalTime = 0;
+			aDevice->iCodeBenchmarkData.iMaxTime = 0;
+			aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
+			break;
+		}
+	NKern::FMSignal(&aDevice->iInstrumentationLock);
+	}
+#endif
+
+TInt MediaHalFunction(TAny*, TInt aFunction, TAny* a1, TAny* a2)
+	{
+	TInt r=KErrNotSupported;
+	switch (aFunction)
+		{
+		case EMediaHalDriveInfo:
+			{
+			(void) a2;
+			TDriveInfoV1Buf infoBuf;
+			TDriveInfoV1& info=infoBuf();
+			GetDriveInfo(info);
+			Kern::InfoCopy(*(TDes8*)a1,infoBuf);
+			r=KErrNone;
+			break;
+			}
+#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;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SMediaROMPagingConcurrencyInfo info=device->iROMStats;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}
+		case EMediaHalGetCodeConcurrencyInfo:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SMediaCodePagingConcurrencyInfo info=device->iCodeStats;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}
+		case EMediaHalGetDataConcurrencyInfo:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SMediaDataPagingConcurrencyInfo info=device->iDataStats;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}
+		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);
+			r=KErrNone;
+			break;
+			}
+#endif
+#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;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SPagingBenchmarkInfo info = device->iROMBenchmarkData;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}		
+		case EMediaHalGetCodePagingBenchmark:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SPagingBenchmarkInfo info = device->iCodeBenchmarkData;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}	
+		case EMediaHalGetDataInPagingBenchmark:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SPagingBenchmarkInfo info = device->iDataInBenchmarkData;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}		
+		case EMediaHalGetDataOutPagingBenchmark:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SPagingBenchmarkInfo info = device->iDataOutBenchmarkData;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}		
+		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);
+			r=KErrNone;
+			break;
+			}
+		case EMediaHalGetPagingInfo:
+			{
+			TInt drvNo=(TInt)a1;
+			TLocDrv* drv=TheDrives[drvNo];
+			if(!drv)
+				break;
+			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
+			if(!device)
+				break;
+			NKern::FMWait(&device->iInstrumentationLock);
+			SMediaPagingInfo info = device->iMediaPagingInfo;
+			NKern::FMSignal(&device->iInstrumentationLock);
+			kumemput32(a2,&info,sizeof(info));
+			r=KErrNone;
+			break;
+			}		
+#endif
+		default:
+			break;
+		}
+	return r;
+	}
+
+
+/******************************************************************************
+ Partition table scanner
+ ******************************************************************************/
+
+#ifdef _DEBUG
+#define DMEMDUMP(base,size)	DbgMemDump((TLinAddr)base,size)
+void DbgMemDump(TLinAddr aBase, TInt aSize)
+	{
+	TInt off;
+	const TUint8* p=(const TUint8*)aBase;
+	NKern::Lock();
+	for (off=0; off<aSize; off+=16, p+=16)
+		{
+		Kern::Printf("%04x: %02x %02x %02x %02x  %02x %02x %02x %02x | %02x %02x %02x %02x  %02x %02x %02x %02x",
+			off,	p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+					p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+		}
+	NKern::Unlock();
+	}
+#else
+#define DMEMDUMP(base,size)
+#endif
+
+EXPORT_C void TPartitionTableScanner::Set(TUint8* aSectorBuffer, TPartitionEntry* aEntry, TInt aMaxPartitions, TInt64 aMediaSize)
+	{
+	__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner @ %08x : buf %08x entry %08x max %d sz %08x %08x",
+								this, aSectorBuffer, aEntry, aMaxPartitions, I64HIGH(aMediaSize), I64LOW(aMediaSize)));
+	__ASSERT_ALWAYS(aMaxPartitions>0, LOCM_FAULT());
+	memclr(this, sizeof(TPartitionTableScanner));
+	iLBA = -1;
+	iSectorBuffer = aSectorBuffer;
+	iFirstEntry = aEntry;
+	iNextEntry = aEntry;
+	iLimit = aEntry + aMaxPartitions;
+	iMediaSize = aMediaSize;
+	}
+
+EXPORT_C TInt TPartitionTableScanner::NumberOfPartitionsFound() const
+	{
+	TInt n = iNextEntry - iFirstEntry;
+	__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner N=%d", n));
+	return n;
+	}
+
+TPartitionTableScanner::SPart::SPart(const TUint8* a)
+	{
+	iBootInd = a[0];
+	iType = a[4];
+	iRSS = a[8]|(a[9]<<8)|(a[10]<<16)|(a[11]<<24);
+	iSectors = a[12]|(a[13]<<8)|(a[14]<<16)|(a[15]<<24);
+	__KTRACE_OPT(KLOCDRV, Kern::Printf("SPart: BI=%02x TYPE=%02x RSS=%08x SIZE=%08x", iBootInd, iType, iRSS, iSectors));
+	}
+
+TInt TPartitionTableScanner::MakeEntry(const SPart& a)
+	{
+	if (iNextEntry == iLimit)
+		return KErrOverflow;
+	if (a.iRSS<=0 || a.iSectors<=0 || a.iRSS>=iMediaSize)
+		return KErrCorrupt;
+	if (TUint64(a.iRSS) + TUint64(a.iSectors) > TUint64(iMediaSize))
+		return KErrCorrupt;
+	iNextEntry->iBootIndicator = a.iBootInd;
+	iNextEntry->iPartitionType = a.iType;
+	iNextEntry->iPartitionBaseAddr = TInt64(a.iRSS)<<ESectorShift;
+	iNextEntry->iPartitionLen = TInt64(a.iSectors)<<ESectorShift;
+	++iNextEntry;
+	return KErrNone;
+	}
+
+EXPORT_C TInt64 TPartitionTableScanner::NextLBA()
+	{
+	__KTRACE_OPT(KLOCDRV, Kern::Printf(">TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
+	TInt r;
+	TUint8* b = iSectorBuffer;
+	TUint8* pS = b + 0x1be;
+	TUint8* pE = pS + 64;
+	TUint8* p = pS;
+	TInt orig_sp = iStackPointer;
+	TInt sp;
+	if (iLBA < 0)
+		{
+		iLBA = 0;
+		goto end;
+		}
+	__KTRACE_OPT(KLOCDRV,DMEMDUMP(b, ESectorSize));
+	if (b[ESectorSize-2]!=0x55 || b[ESectorSize-1]!=0xaa)
+		{
+		__KTRACE_OPT(KLOCDRV, Kern::Printf("Bad signature"));
+		iLBA = KErrCorrupt;
+		goto end;
+		}
+	if (iLBA==0 && iNextEntry==iFirstEntry)
+		{
+		// Look for bootable partition first
+		for (; p<pE; p+=16)
+			{
+			SPart pt(p);
+			if (pt.iBootInd==0x80 && pt.iType && pt.iSectors>0)
+				{
+				p[4] = 0;
+				r = MakeEntry(pt);
+				if (r!=KErrNone)
+					{
+					iLBA = r;
+					goto end;
+					}
+				}
+			}
+		}
+	// Look for extended partitions
+	for (p=pE-16; p>=pS; p-=16)
+		{
+		SPart pt(p);
+		if ((pt.iType==0x05 || pt.iType==0x0f) && pt.iSectors>0)
+			{
+			// This one is an EBR
+			p[4] = 0;
+			if (iStackPointer == EMaxNest)
+				{
+				if (iStackPointer == orig_sp)
+					continue;
+				--iStackPointer;
+				for(sp = orig_sp; sp<iStackPointer; ++sp)
+					iStack[sp] = iStack[sp+1];
+				}
+			iStack[iStackPointer].iRSS = pt.iRSS;
+			iStack[iStackPointer].iSectors = pt.iSectors;
+			++iStackPointer;
+#ifdef _DEBUG
+			for (sp=0; sp<iStackPointer; ++sp)
+				{
+				const TInt64& rss = iStack[sp].iRSS;
+				const TInt64& size = iStack[sp].iSectors;
+				__KTRACE_OPT(KLOCDRV, Kern::Printf("Stack[%d] RSS %08x %08x SIZE %08x %08x", sp,
+					I64HIGH(rss), I64LOW(rss), I64HIGH(size), I64LOW(size) ));
+				}
+#endif
+			}
+		}
+	// Look for other data partitions
+	for (p=pS; p<pE; p+=16)
+		{
+		SPart pt(p);
+		if (pt.iType && pt.iSectors>0)
+			{
+			pt.iRSS += TUint32(iLBA);	// data partitions are specified relative to the EBR they appear in
+			r = MakeEntry(pt);
+			if (r!=KErrNone)
+				{
+				iLBA = r;
+				goto end;
+				}
+			}
+		}
+	// If any EBRs on stack, pop off the first and process it
+	if (iStackPointer)
+		{
+		--iStackPointer;
+		iLBA = iFirstEBR + iStack[iStackPointer].iRSS;	// LBA of second and subsequent EBR is specified relative to first EBR
+		if (!iFirstEBR)
+			iFirstEBR = iLBA;
+		}
+	else
+		iLBA = KErrEof;	// finished
+
+end:
+	__KTRACE_OPT(KLOCDRV, Kern::Printf("<TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
+	return iLBA;
+	}
+
+/**
+ * Returns Address and Length of next contiguous Physical memory fragment
+ * 
+ * @param aAddr On success, populated with the Physical Address of the next fragment.
+ * @param aLen  On success, populated with the length in bytes of the next fragment.
+ * 
+ * @return KErrNone, if successful;
+ * 		   KErrNoMemory, if no more memory fragments left.
+ * 		   KErrNotSupported, if Physical Memory addressing is not supported by this Media.
+ */
+EXPORT_C TInt TLocDrvRequest::GetNextPhysicalAddress(TPhysAddr& aAddr, TInt& aLen)
+	{
+	if (Flags() & EPhysAddr) 
+		{
+
+#ifdef __DEMAND_PAGING__
+		if (DMediaPagingDevice::PagingRequest(*this))
+			{
+			return DDmaHelper::GetPhysicalAddress(*this, aAddr, aLen);
+			}
+#endif
+		return Drive()->iDmaHelper->GetPhysicalAddress(aAddr, aLen);
+		}
+	else
+		{
+		return KErrNotSupported;
+		}
+	}
+
+
+/******************************************************************************
+ Entry point
+ ******************************************************************************/
+DECLARE_STANDARD_EXTENSION()
+	{
+	__KTRACE_OPT(KBOOT,Kern::Printf("Starting LOCMEDIA extension"));
+
+	// install the HAL function
+	TInt r=Kern::AddHalEntry(EHalGroupMedia,MediaHalFunction,NULL);
+#ifdef __DEMAND_PAGING__
+	if (r==KErrNone)
+		{
+		__KTRACE_OPT(KBOOT,Kern::Printf("Creating LocDrv device"));
+		DLocalDriveFactory* device = new DLocalDriveFactory;
+		if (device==NULL)
+			r=KErrNoMemory;
+		else
+			r=Kern::InstallLogicalDevice(device);
+		__KTRACE_OPT(KBOOT,Kern::Printf("Installing LocDrv device in kernel returned %d",r));
+		}
+#endif // __DEMAND_PAGING__
+	return r;
+	}
+
+