kernel/eka/drivers/locmedia/locmedia.cpp
changeset 0 a41df078684a
child 33 0173bcd7697c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32\drivers\locmedia\locmedia.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "locmedia.h"
       
    19 #include <d32locd.h>
       
    20 #include "dmasupport.h"
       
    21 #include <kernel/cache.h>
       
    22 
       
    23 #if defined(_DEBUG) && defined(__DEMAND_PAGING__)
       
    24 //#define __DEBUG_DEMAND_PAGING__
       
    25 #endif
       
    26 
       
    27 
       
    28 #if 0
       
    29 #define CHECK_RET(r)	if ((r)==KErrNotSupported && (KDebugNum(KSCRATCH))) {NKern::Lock(); *(TInt*)0xfaece5=0;}
       
    30 //#define CHECK_RET(r)
       
    31 #else
       
    32 #define CHECK_RET(r)
       
    33 #endif
       
    34 
       
    35 _LIT(KLddName,"LocDrv");
       
    36 _LIT(KLitMediaDriverName, "Media.*");
       
    37 _LIT(KLitLocMedia,"LocMedia");
       
    38 
       
    39 #define LOCM_FAULT()	Kern::Fault("LOCMEDIA",__LINE__)
       
    40 
       
    41 const TInt KMaxLocalDriveCapsLength=256;
       
    42 const TInt KMaxQueryDeviceLength=256;
       
    43 
       
    44 // The maximum amount of user-data which will be pinned. If a request is longer 
       
    45 // than this value it will be split up into a number of requests
       
    46 // This value is a bit arbitrary - it needs to be sufficiently large so that transfer 
       
    47 // rates don't suffer too much - but it can't be too big or we'd be "stealing" too much 
       
    48 // memory from the demand paging pool and starving other processes
       
    49 const TInt KMaxPinData = 256*1024;
       
    50 
       
    51 // The number of locks available for pinning shared by all the drive threads in the system. 
       
    52 // If all locks are in use then a single pre-allocated lock is used.
       
    53 const TInt KDynamicPagingLockCount = 8;
       
    54 
       
    55 TLocDrv* TheDrives[KMaxLocalDrives];
       
    56 DMedia* TheMedia[KMaxLocalDrives];
       
    57 HBuf* DriveNames[KMaxLocalDrives];
       
    58 TInt UsedMedia=0;
       
    59 TPasswordStore* ThePasswordStore=NULL;
       
    60 
       
    61 class DPrimaryMediaBase::DBody : public DBase
       
    62 	{
       
    63 public:
       
    64 	TInt iPhysDevIndex;
       
    65 	TInt iRequestCount;
       
    66 #ifdef __DEMAND_PAGING__
       
    67 	DMediaPagingDevice* iPagingDevice;
       
    68 	TInt iPageSizeMsk;			// Mask of page size (e.g. 4096-1 -> 4095)
       
    69 	TInt iMediaChanges;
       
    70 #endif
       
    71 	};
       
    72 
       
    73 #ifdef __DEMAND_PAGING__
       
    74 DMediaPagingDevice* ThePagingDevices[KMaxLocalDrives];
       
    75 DPrimaryMediaBase* TheRomPagingMedia = NULL;
       
    76 DPrimaryMediaBase* TheDataPagingMedia = NULL;
       
    77 TBool DataPagingDeviceRegistered = EFalse;
       
    78 class DPinObjectAllocator;
       
    79 DPinObjectAllocator* ThePinObjectAllocator = NULL;
       
    80 
       
    81 // The paging media might share a DfcQ with other non-paging media (e.g. 2 MMC/SD cards sharing the same stack)
       
    82 // In this case, we need to avoid taking page faults on the non-paging media too, hence the need for these checks:
       
    83 inline TBool DataPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
       
    84 	{return TheDataPagingMedia && TheDataPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
       
    85 inline TBool RomPagingDfcQ(DPrimaryMediaBase* aPrimaryMedia)
       
    86 	{return TheRomPagingMedia && TheRomPagingMedia->iDfcQ == aPrimaryMedia->iDfcQ;}
       
    87 
       
    88 
       
    89 
       
    90 /* 
       
    91 DPinObjectAllocator
       
    92 
       
    93 Internal class which contains :
       
    94 	(1) a queue of pre-allocated TVirtualPinObject's; 
       
    95 	(2) a single pre-allocated DFragmentationPagingLock object: 
       
    96 		this may be used if there are no TVirtualPinObject's available or if Kern::PinVirtualMemory() fails
       
    97 */
       
    98 NONSHARABLE_CLASS(DPinObjectAllocator) : public DBase
       
    99 	{
       
   100 public:
       
   101 	/*
       
   102 	SVirtualPinContainer
       
   103 	Internal class encapsulating a TVirtualPinObject.
       
   104 	Contains a SDblQueLink so that it may form part of a SDblQue
       
   105 	*/
       
   106 	typedef struct
       
   107 		{
       
   108 		TVirtualPinObject* iObject;
       
   109 		SDblQueLink iLink;
       
   110 		} SVirtualPinContainer;
       
   111 
       
   112 public:
       
   113 	inline DPinObjectAllocator() {};
       
   114 	~DPinObjectAllocator();
       
   115 	TInt Construct(TInt aObjectCount, TUint aNumPages);
       
   116 	
       
   117 	SVirtualPinContainer* AcquirePinObject();
       
   118 	void ReleasePinObject(SVirtualPinContainer* aVirtualPinObject);
       
   119 
       
   120 	inline DFragmentationPagingLock& PreAllocatedDataLock() {return *iPreAllocatedDataLock;}
       
   121 
       
   122 private:
       
   123 	// array of SVirtualPinContainer's
       
   124 	SVirtualPinContainer* iVirtualPinContainers;
       
   125 	TInt iObjectCount;
       
   126 
       
   127 	// queues containing SVirtualPinContainer's
       
   128 	SDblQue iFreeQ;
       
   129 	
       
   130 	// pre-allocated (small) buffers for locking client data should Kern::PinVirtualMemory() fail
       
   131 	DFragmentationPagingLock* iPreAllocatedDataLock;
       
   132 
       
   133 	// A mutex to protect access to the pinning objects.
       
   134 	NFastMutex iLock;
       
   135 
       
   136 public:
       
   137 	TUint iFragmentGranularity;
       
   138 	};
       
   139 
       
   140 
       
   141 DPinObjectAllocator::~DPinObjectAllocator()
       
   142 	{
       
   143 	if (iPreAllocatedDataLock)
       
   144 		{
       
   145 		iPreAllocatedDataLock->Cleanup();
       
   146 		delete iPreAllocatedDataLock;
       
   147 		}
       
   148 
       
   149 	for (TInt n=0; n<iObjectCount; n++)
       
   150 		{
       
   151 		SVirtualPinContainer& virtualPinContainer = iVirtualPinContainers[n];
       
   152 		if (virtualPinContainer.iObject)
       
   153 			Kern::DestroyVirtualPinObject(virtualPinContainer.iObject);
       
   154 		}
       
   155 
       
   156 	delete [] iVirtualPinContainers;
       
   157 	}
       
   158 
       
   159 TInt DPinObjectAllocator::Construct(TInt aObjectCount, TUint aNumPages)
       
   160 	{
       
   161 	TInt pageSize = Kern::RoundToPageSize(1);
       
   162 	iFragmentGranularity = pageSize * aNumPages;
       
   163 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
       
   164 
       
   165 	// construct the paging lock containing pre-allocated buffers
       
   166 
       
   167 	iPreAllocatedDataLock = new DFragmentationPagingLock();
       
   168 	if(!iPreAllocatedDataLock)
       
   169 		return KErrNoMemory;
       
   170 	TInt r = iPreAllocatedDataLock->Construct(aNumPages);
       
   171 	if (r != KErrNone)
       
   172 		return r;
       
   173 
       
   174 
       
   175 	SVirtualPinContainer* iVirtualPinContainers = new SVirtualPinContainer[aObjectCount];
       
   176 	if (iVirtualPinContainers == NULL)
       
   177 		return KErrNoMemory;
       
   178 	memclr(iVirtualPinContainers, sizeof(SVirtualPinContainer) * aObjectCount);
       
   179 	iObjectCount = aObjectCount;
       
   180 
       
   181 	// construct the queue of dynamic paging locks
       
   182 	for (TInt n=0; n<aObjectCount; n++)
       
   183 		{
       
   184 		SVirtualPinContainer& pinContainer = iVirtualPinContainers[n];
       
   185 
       
   186 		TInt r = Kern::CreateVirtualPinObject(pinContainer.iObject);
       
   187 		if (r != KErrNone)
       
   188 			return KErrNoMemory;
       
   189 
       
   190 
       
   191 		iFreeQ.Add(&pinContainer.iLink);
       
   192 		}
       
   193 	return KErrNone;
       
   194 	}
       
   195 
       
   196 /** 
       
   197 returns a SVirtualPinContainer object or NULL if NULL available
       
   198 */
       
   199 DPinObjectAllocator::SVirtualPinContainer* DPinObjectAllocator::AcquirePinObject()
       
   200 	{
       
   201 	SVirtualPinContainer* pinContainer = NULL;
       
   202 	
       
   203 	NKern::FMWait(&iLock);
       
   204 
       
   205 	if (!iFreeQ.IsEmpty())
       
   206 		{
       
   207 		SDblQueLink* link = iFreeQ.First();
       
   208 		pinContainer = _LOFF(link, SVirtualPinContainer, iLink);
       
   209 		link->Deque();
       
   210 		}
       
   211 
       
   212 
       
   213 	NKern::FMSignal(&iLock);
       
   214 	return pinContainer;
       
   215 	}
       
   216 
       
   217 /** 
       
   218 returns a SVirtualPinContainer object to the pool
       
   219 */
       
   220 void DPinObjectAllocator::ReleasePinObject(SVirtualPinContainer* aPinContainer)
       
   221 	{
       
   222 	NKern::FMWait(&iLock);
       
   223 
       
   224 	iFreeQ.Add(&aPinContainer->iLink);
       
   225 
       
   226 	NKern::FMSignal(&iLock);
       
   227 	}
       
   228 
       
   229 #endif	// __DEMAND_PAGING__
       
   230 
       
   231 
       
   232 /********************************************
       
   233  * Local drive device base class
       
   234  ********************************************/
       
   235 DECLARE_EXTENSION_LDD()
       
   236 	{
       
   237 	return new DLocalDriveFactory;
       
   238 	}
       
   239 
       
   240 DLocalDriveFactory::DLocalDriveFactory()
       
   241 //
       
   242 // Constructor
       
   243 //
       
   244 	{
       
   245 	iParseMask=KDeviceAllowUnit|KDeviceAllowInfo;
       
   246 	iUnitsMask=~(0xffffffff<<KMaxLocalDrives);
       
   247 	iVersion=TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion);
       
   248 	}
       
   249 
       
   250 TInt DLocalDriveFactory::Install()
       
   251 //
       
   252 // Install the device driver.
       
   253 //
       
   254 	{
       
   255 	return SetName(&KLddName);
       
   256 	}
       
   257 
       
   258 void DLocalDriveFactory::GetCaps(TDes8& /*aDes*/) const
       
   259 //
       
   260 // Return the Comm capabilities.
       
   261 //
       
   262 	{
       
   263 //	TCapsLocalDriveV01 b;
       
   264 //	b.version=iVersion;
       
   265 //	aDes.FillZ(aDes.MaxLength());
       
   266 //	aDes.Copy((TUint8 *)&b,Min(aDes.MaxLength(),sizeof(b)));
       
   267 	}
       
   268 
       
   269 TInt DLocalDriveFactory::Create(DLogicalChannelBase*& aChannel)
       
   270 //
       
   271 // Create a channel on the device.
       
   272 //
       
   273 	{
       
   274 	aChannel=new DLocalDrive;
       
   275 	return aChannel?KErrNone:KErrNoMemory;
       
   276 	}
       
   277 
       
   278 /********************************************
       
   279  * Local drive interface class
       
   280  ********************************************/
       
   281 DLocalDrive::DLocalDrive()
       
   282 	{
       
   283 //	iLink.iNext=NULL;
       
   284 	}
       
   285 
       
   286 DLocalDrive::~DLocalDrive()
       
   287 	{
       
   288 	if (iDrive)
       
   289 		{
       
   290 		__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
       
   291 		iDrive->Disconnect(this);
       
   292 		__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoClose D:%d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
       
   293 		}
       
   294 	DThread* pC=NULL;
       
   295 	NKern::LockSystem();
       
   296 	if (iCleanup.iThread)
       
   297 		{
       
   298 		pC=iCleanup.iThread;
       
   299 		iCleanup.Remove();
       
   300 		iCleanup.iThread=NULL;
       
   301 		}
       
   302 	NKern::UnlockSystem();
       
   303 	if (pC)	// original client may already have terminated
       
   304 		{
       
   305 		if (iNotifyChangeRequest)
       
   306 			Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrCancel);
       
   307 		pC->Close(NULL);	// balances Open() in DoCreate
       
   308 		}
       
   309 	if (iNotifyChangeRequest)
       
   310 		Kern::DestroyClientRequest(iNotifyChangeRequest);
       
   311 	}
       
   312 
       
   313 TInt DLocalDrive::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
       
   314 	{
       
   315 	if(!Kern::CurrentThreadHasCapability(ECapabilityTCB,__PLATSEC_DIAGNOSTIC_STRING("Checked by ELOCD.LDD (Local Media Driver)")))
       
   316 		return KErrPermissionDenied;
       
   317 	if (!Kern::QueryVersionSupported(TVersion(KLocalDriveMajorVersion,KLocalDriveMinorVersion,KLocalDriveBuildVersion),aVer))
       
   318 		return KErrNotSupported;
       
   319 
       
   320 	NKern::ThreadEnterCS();
       
   321 	TInt r = Kern::CreateClientDataRequest(iNotifyChangeRequest);
       
   322 	NKern::ThreadLeaveCS();
       
   323 	if (r != KErrNone)
       
   324 		return r;
       
   325 
       
   326 	DThread& t=Kern::CurrentThread();
       
   327 	NKern::LockSystem();
       
   328 	t.AddCleanup(&iCleanup);
       
   329 	NKern::UnlockSystem();
       
   330 	t.Open();
       
   331 	iNotifyChangeRequest->SetDestPtr((TBool*) anInfo);
       
   332 
       
   333 	iDrive=TheDrives[aUnit];
       
   334 	if (!iDrive)
       
   335 		return KErrNotSupported;
       
   336 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DLocalDrive Create - connect to drive %d, M:%08x",iDrive->iDriveNumber,iDrive->iMedia));
       
   337 	r=iDrive->Connect(this);
       
   338 	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive Create D:%d, M:%08x r:%d",iDrive->iDriveNumber,iDrive->iMedia,r));
       
   339 	if (r!=KErrNone)
       
   340 		iDrive=NULL;	// didn't connect so don't disconnect
       
   341 	return r;
       
   342 	}
       
   343 
       
   344 #if defined(_DEBUG)
       
   345 void DebugDumpDriveCaps(const TLocDrv* aDrive, const TAny* aCaps)
       
   346 	{
       
   347 	const TLocalDriveCapsV5& c=*(const TLocalDriveCapsV5*)aCaps;
       
   348 	Kern::Printf("Drive %d Caps:", aDrive->iDriveNumber);
       
   349 	Kern::Printf("Size: %lx", c.iSize);
       
   350 	Kern::Printf("Type: %08x", c.iType);
       
   351 	Kern::Printf("Batt: %08x", c.iBattery);
       
   352 	Kern::Printf("DAtt: %08x", c.iDriveAtt);
       
   353 	Kern::Printf("MAtt: %08x", c.iMediaAtt);
       
   354 	Kern::Printf("Base: %08x", c.iBaseAddress);
       
   355 	Kern::Printf("FSID: %04x", c.iFileSystemId);
       
   356 	Kern::Printf("PTYP: %04x", c.iPartitionType);
       
   357 	Kern::Printf("HIDN: %08x", c.iHiddenSectors);
       
   358 	Kern::Printf("EBSZ: %08x", c.iEraseBlockSize);
       
   359     //---------------- V5 ------------------//
       
   360     if (c.iSerialNumLength != 0)
       
   361         {
       
   362         Kern::Printf("SN: length is %d", c.iSerialNumLength);
       
   363         TBuf8<2*KMaxSerialNumLength+20> snBuf;
       
   364         snBuf.Append(_L8("SN: content is "));
       
   365         for (TUint i=0; i<c.iSerialNumLength; i++)
       
   366             snBuf.AppendNumFixedWidth(c.iSerialNum[i], EHex, 2);
       
   367         Kern::Printf((const char*)snBuf.Ptr());
       
   368         }
       
   369     else
       
   370         Kern::Printf("SN: not supported");
       
   371 	}
       
   372 #endif
       
   373 
       
   374 /*
       
   375  * Requests are passed in message as follows:
       
   376  * iValue	= request ID
       
   377  * iArg[0,1]= Position
       
   378  * iArg[2,3]= Length
       
   379  * iArg[4]	= Pointer to remote thread (NULL if client)
       
   380  * iArg[5]	= Pointer to remote descriptor
       
   381  * iArg[6]	= Offset into remote descriptor
       
   382  * iArg[7]	= Flags (whole media)
       
   383  * iArg[8]	= Pointer to TLocDrv
       
   384  */
       
   385 
       
   386 TInt DLocalDrive::Request(TInt aFunction, TAny* a1, TAny* a2)
       
   387 	{
       
   388 	__TRACE_TIMING(0);
       
   389 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DLocalDrive::DoControl D:%d M:%08x F:%d A1:%08x A2:%08x",
       
   390 														iDrive->iDriveNumber, iDrive->iMedia, aFunction, a1, a2));
       
   391 	TInt r=KErrNotSupported;
       
   392 	TLocDrvRequest& m=TLocDrvRequest::Get();
       
   393 	m.Flags()=0;
       
   394 	m.Drive()=iDrive;
       
   395 	switch (aFunction)
       
   396 		{
       
   397 		case RLocalDrive::EControlRead:
       
   398 			{
       
   399 			m.Id()=ERead;
       
   400 			r=m.ProcessMessageData(a1);
       
   401 			__TRACE_TIMING(1);
       
   402 			if (r==KErrNone)
       
   403 				{
       
   404 				__TRACE_TIMING(2);
       
   405 				r=iDrive->Request(m);
       
   406 				__TRACE_TIMING(3);
       
   407 				}
       
   408 			m.CloseRemoteThread();
       
   409 			break;
       
   410 			}
       
   411 		case RLocalDrive::EControlWrite:
       
   412 			{
       
   413 			m.Id()=EWrite;
       
   414 			r=m.ProcessMessageData(a1);
       
   415 			if (r==KErrNone)
       
   416 				r=iDrive->Request(m);
       
   417 			m.CloseRemoteThread();
       
   418 			break;
       
   419 			}
       
   420 		case RLocalDrive::EControlCaps:
       
   421 			{
       
   422 			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
       
   423 			capsBuf.SetMax();
       
   424 			capsBuf.FillZ();
       
   425 			m.Id()=ECaps;
       
   426 			m.RemoteDes()=(TAny*)capsBuf.Ptr();	// overload this
       
   427 			m.Length()=KMaxLocalDriveCapsLength;	// for pinning
       
   428 			r=iDrive->Request(m);
       
   429 
       
   430 			if(r == KErrNone && iDrive->iMedia != NULL && iDrive->iMedia->iDriver != NULL)
       
   431 				{
       
   432 				// Fill in default media size if not specified by the driver
       
   433 				//
       
   434 				// - This uses the members of TLocalDriveCapsV4 which was primarily used
       
   435 				//   to report NAND flash characteristics, but are general enough to be
       
   436 				//	 used to report the size of any type of media without adding yet
       
   437 				//	 another extension to TLocalDriveCapsVx.
       
   438 				//
       
   439 				
       
   440 				TLocalDriveCapsV4& caps = *(TLocalDriveCapsV4*)capsBuf.Ptr();
       
   441 				
       
   442 				if(caps.iSectorSizeInBytes == 0)
       
   443 					{
       
   444 					// Fill in a default value for the disk sector size
       
   445 					caps.iSectorSizeInBytes = 512;
       
   446 
       
   447 					// Zero the number of sectors, as a sector count makes no sense without a sector size
       
   448 					//  - Fault in debug mode if a sector count is provided to ensure that media driver creators
       
   449 					//	  set this value,but in release mode continue gracefully be recalculating the sector count.
       
   450 					__ASSERT_DEBUG(caps.iNumberOfSectors == 0, LOCM_FAULT());
       
   451 					caps.iNumberOfSectors  = 0;
       
   452 					caps.iNumPagesPerBlock = 1;	// ...to ensure compatiility with NAND semantics
       
   453 					}
       
   454 
       
   455 				if(caps.iNumberOfSectors == 0)
       
   456 					{
       
   457 					const Int64 totalSizeInSectors = iDrive->iMedia->iDriver->TotalSizeInBytes() / caps.iSectorSizeInBytes;
       
   458 					__ASSERT_DEBUG(I64HIGH(totalSizeInSectors) == 0, LOCM_FAULT());
       
   459 
       
   460 					if(I64HIGH(totalSizeInSectors) == 0)
       
   461 						{
       
   462 						caps.iNumberOfSectors = I64LOW(totalSizeInSectors);
       
   463 						}
       
   464 					}
       
   465 				}
       
   466 
       
   467 #if defined(_DEBUG)
       
   468 			__KTRACE_OPT(KLOCDRV,DebugDumpDriveCaps(iDrive,capsBuf.Ptr()));
       
   469 #endif
       
   470 			Kern::InfoCopy(*(TDes8*)a1, capsBuf);
       
   471 			break;
       
   472 			}
       
   473 		case RLocalDrive::EControlFormat:
       
   474 			{
       
   475 			m.Id()=EFormat;
       
   476 			r=m.ProcessMessageData(a1);
       
   477 			if (r==KErrNone)
       
   478 				r=iDrive->Request(m);
       
   479 			break;
       
   480 			}
       
   481 		case RLocalDrive::EControlEnlarge:
       
   482 			if ((TInt)a1<0)
       
   483 				{
       
   484 				r=KErrArgument;
       
   485 				break;
       
   486 				}
       
   487 			m.Length()=(TInt)a1;
       
   488 			m.Id()=EEnlarge;
       
   489 			r=iDrive->Request(m);
       
   490 			break;
       
   491 		case RLocalDrive::EControlReduce:
       
   492 			{
       
   493 			if ((TInt)a1<0 || (TInt)a2<0)
       
   494 				{
       
   495 				r=KErrArgument;
       
   496 				break;
       
   497 				}
       
   498 			m.Pos()=(TInt)a1;
       
   499 			m.Length()=(TInt)a2;
       
   500 			m.Id()=EReduce;
       
   501 			r=iDrive->Request(m);
       
   502 			break;
       
   503 			}
       
   504 		case RLocalDrive::EControlForceMediaChange:
       
   505 			m.Pos()=(TInt)a1;
       
   506 			m.Id()=EForceMediaChange;
       
   507 			r = iDrive->Request(m);
       
   508 			break;
       
   509 		case RLocalDrive::EControlMediaDevice:
       
   510 			r=iDrive->iPrimaryMedia->iDevice;
       
   511 			break;
       
   512 		case RLocalDrive::EControlIsRemovable:
       
   513 			{
       
   514 			TInt sockNum;
       
   515 			r=iDrive->iPrimaryMedia->IsRemovableDevice(sockNum);
       
   516 			if (r)
       
   517 				kumemput32(a1,&sockNum,sizeof(TInt));
       
   518 			break;	
       
   519 			}
       
   520 		case RLocalDrive::EControlControlIO:
       
   521 			{
       
   522 			TLocalDriveControlIOData d;
       
   523 			kumemget32(&d,a1,sizeof(d));
       
   524 
       
   525 			m.Id() = EControlIO;
       
   526 			m.iArg[0] = (TAny*) d.iCommand;
       
   527 			m.iArg[1] = d.iParam1;
       
   528 			m.iArg[2] = d.iParam2;
       
   529 
       
   530 			// if d.iHandle is == KLocalMessageHandle (-1),
       
   531 			//	d.aParam1 and d.aParam2 are TAny* pointers
       
   532 			//
       
   533 			// if d.iHandle is == 0, 
       
   534 			//	d.aParam1 and d.aParam2 are TInts
       
   535 			//
       
   536 			// if d.iHandle is > 0, 
       
   537 			//	d.aParam1 is a data pointer (TUint8*) 
       
   538 			//	d.aParam2 is an optional extra paramater (TInt)
       
   539 			//	d.iHandle is a data length (TInt)
       
   540 			m.iArg[3] = (TAny*) d.iHandle;
       
   541 
       
   542 			//We're highjacking fields representing
       
   543 			//length and position in a normal message, so
       
   544 			//let's not have the dispatcher function attempt
       
   545 			//to adjust for partition size.
       
   546 			m.Flags() |= TLocDrvRequest::EAdjusted;
       
   547 
       
   548 			r=iDrive->Request(m);
       
   549 			break;
       
   550 			}
       
   551 		case RLocalDrive::EControlSetMountInfo:
       
   552 			{
       
   553 			m.Id()=ERead;
       
   554 			r=m.ProcessMessageData(a1);
       
   555 			DPrimaryMediaBase* pM=iDrive->iPrimaryMedia;
       
   556 			if(!pM || r!=KErrNone)
       
   557 				break;
       
   558 
       
   559 			if (pM->iMountInfo.iThread)
       
   560 				{
       
   561 				NKern::ThreadEnterCS();
       
   562 				//Close original thread
       
   563 				Kern::SafeClose((DObject*&) pM->iMountInfo.iThread,NULL);
       
   564 				if (m.RemoteDes()!=NULL)
       
   565 					{
       
   566 					//Set new mount info and leave setting thread open
       
   567 #ifdef __DEMAND_PAGING__
       
   568 					// lock the mount info if this is a data paging media - and keep it locked
       
   569 					if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
       
   570 						break;
       
   571 #endif
       
   572 					pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
       
   573 					pM->iMountInfo.iThread=m.RemoteThread();
       
   574 					}
       
   575 				else
       
   576 					{
       
   577 					//Clear existing mount info and close setting thread
       
   578 
       
   579 #ifdef __DEMAND_PAGING__
       
   580 					// unlock the mount info if this is a data paging media
       
   581 					UnlockMountInfo(*pM);
       
   582 #endif
       
   583 
       
   584 					pM->iMountInfo.iInfo=NULL;
       
   585 					pM->iMountInfo.iThread=NULL;
       
   586 					m.CloseRemoteThread();
       
   587 					}
       
   588 				NKern::ThreadLeaveCS();
       
   589 				r=KErrNone;
       
   590 				}
       
   591 			else
       
   592 				{
       
   593 				//Setting mount info for the first time
       
   594 				if (m.RemoteDes()==NULL)
       
   595 					{
       
   596 					// if no mount info, close setting thread opened in ProcessMessageData()
       
   597 					m.CloseRemoteThread();
       
   598 					break;
       
   599 					}
       
   600 
       
   601 				NKern::ThreadEnterCS();
       
   602 #ifdef __DEMAND_PAGING__
       
   603 				// lock the mount info if this is a data paging media - and keep it locked
       
   604 				if ((DataPagingDfcQ(pM)) && ((r = LockMountInfo(*pM, m)) != KErrNone))
       
   605 					break;
       
   606 #endif
       
   607 
       
   608 				pM->iMountInfo.iInfo=(TDesC8*)m.RemoteDes();
       
   609 				pM->iMountInfo.iThread=m.RemoteThread();
       
   610 				NKern::ThreadLeaveCS();
       
   611 				r=KErrNone;
       
   612 				}
       
   613 			break;
       
   614 			}
       
   615 		case RLocalDrive::EControlPasswordLock:
       
   616 			{
       
   617 			m.Id()=EPasswordLock;
       
   618 			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
       
   619 			m.RemoteDes()=(TAny*)ppd;
       
   620 			r=iDrive->Request(m);
       
   621 			break;
       
   622 			}
       
   623 		case RLocalDrive::EControlPasswordUnlock:
       
   624 			{
       
   625 			m.Id()=EPasswordUnlock;
       
   626 			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
       
   627 			m.RemoteDes()=(TAny*)ppd;
       
   628 			r=iDrive->Request(m);
       
   629 			if(r == KErrNone)
       
   630 				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
       
   631 			break;
       
   632 			}
       
   633 		case RLocalDrive::EControlPasswordClear:
       
   634 			{
       
   635 			m.Id()=EPasswordClear;
       
   636 			TLocalDrivePasswordData* ppd = (TLocalDrivePasswordData*)a1;
       
   637 			m.RemoteDes()=(TAny*)ppd;
       
   638 			r=iDrive->Request(m);
       
   639 			break;
       
   640 			}
       
   641 		case RLocalDrive::EControlPasswordErase:
       
   642 			{
       
   643 			m.Id()=EPasswordErase;
       
   644 			r=iDrive->Request(m);
       
   645 			if(r == KErrNone)
       
   646 				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
       
   647 			break;
       
   648 			}
       
   649 		case RLocalDrive::EControlNotifyChange:
       
   650 			if (iCleanup.iThread != &Kern::CurrentThread())
       
   651 				Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
       
   652 			r=KErrNone;
       
   653 			if (!iNotifyChangeRequest->StatusPtr())
       
   654 				r = iNotifyChangeRequest->SetStatus((TRequestStatus*) a1);
       
   655 			break;
       
   656 		case RLocalDrive::EControlNotifyChangeCancel:
       
   657 			if (iCleanup.iThread != &Kern::CurrentThread())
       
   658 				Kern::PanicCurrentThread(KLitLocMedia,KErrAccessDenied);
       
   659 			Kern::QueueRequestComplete(iCleanup.iThread,iNotifyChangeRequest,KErrCancel);
       
   660 			break;
       
   661 		case RLocalDrive::EControlReadPasswordStore:
       
   662 			{
       
   663 			m.Id()=EReadPasswordStore;
       
   664 			m.RemoteDes()=(TDes8*)a1;
       
   665 			r=iDrive->Request(m);
       
   666 			break;
       
   667 			}
       
   668 		case RLocalDrive::EControlWritePasswordStore:
       
   669 			{
       
   670 			m.Id()=EWritePasswordStore;
       
   671 			m.RemoteDes()=(TDes8*)a1;
       
   672 			r=iDrive->Request(m);
       
   673 			if(r == KErrNone)
       
   674 				iDrive->iPrimaryMedia->iTotalPartitionsOpened = 0;
       
   675 			break;
       
   676 			}
       
   677 		case RLocalDrive::EControlPasswordStoreLengthInBytes:
       
   678 			{
       
   679 			m.Id()=EPasswordStoreLengthInBytes;
       
   680 			m.RemoteDes()=a1;
       
   681 			r=iDrive->Request(m);
       
   682 			break;
       
   683 			}
       
   684 		case RLocalDrive::EControlGetLastErrorInfo:
       
   685 			{
       
   686 			m.Id()=EGetLastErrorInfo;
       
   687 			m.iArg[0]=this;
       
   688 			TErrorInfoBuf errorInfoBuf;
       
   689 			errorInfoBuf.SetMax();
       
   690 			errorInfoBuf.FillZ();
       
   691 			m.RemoteDes()=(TAny*) errorInfoBuf.Ptr();	// overload this
       
   692 			m.Length() = errorInfoBuf.MaxLength();
       
   693 			r=iDrive->Request(m);
       
   694 			Kern::InfoCopy(*(TDes8*)a1, errorInfoBuf);
       
   695 			break;
       
   696 			}
       
   697 		case RLocalDrive::EControlDeleteNotify:
       
   698 			{
       
   699 			m.Id()=EDeleteNotify;
       
   700 			r=m.ProcessMessageData(a1);
       
   701 			if (r==KErrNone)
       
   702 				r=iDrive->Request(m);
       
   703 			break;
       
   704 			}
       
   705 
       
   706 		case RLocalDrive::EControlQueryDevice:
       
   707 			{
       
   708 			TBuf8<KMaxQueryDeviceLength> queryBuf;
       
   709 			queryBuf.SetMax();
       
   710 			queryBuf.FillZ();
       
   711 
       
   712 			m.Id() = EQueryDevice;
       
   713 			m.iArg[0] = a1;		// RLocalDrive::TQueryDevice
       
   714 			m.RemoteDes() = (TAny*)queryBuf.Ptr();	// overload this
       
   715 			m.Length() = KMaxLocalDriveCapsLength;	// for pinning
       
   716 			r=iDrive->Request(m);
       
   717 
       
   718 			Kern::InfoCopy(*(TDes8*)a2, queryBuf);
       
   719 			break;
       
   720 			}
       
   721 
       
   722 		}
       
   723 	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DLocalDrive::DoControl D:%d M:%08x ret %d",iDrive->iDriveNumber, iDrive->iMedia, r));
       
   724 	__TRACE_TIMING(4);
       
   725 	return r;
       
   726 	}
       
   727 
       
   728 #ifdef __DEMAND_PAGING__
       
   729 TInt DLocalDrive::LockMountInfo(DPrimaryMediaBase& aPrimaryMedia, TLocDrvRequest& aReq)
       
   730 	{
       
   731 	DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice;
       
   732 	if (pagingDevice == NULL)
       
   733 		return KErrNone;
       
   734 
       
   735 	__ASSERT_DEBUG(pagingDevice->iMountInfoDataLock == NULL, LOCM_FAULT());
       
   736 	__ASSERT_DEBUG(pagingDevice->iMountInfoDescHdrLock == NULL, LOCM_FAULT());
       
   737 	__ASSERT_DEBUG(pagingDevice->iMountInfoDescLenLock == NULL, LOCM_FAULT());
       
   738 
       
   739 	DThread* pT = aReq.RemoteThread();
       
   740 	if (!pT)
       
   741 		pT = &Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
       
   742 
       
   743 	TInt length = 0;
       
   744 	TInt maxLength = 0;
       
   745 	TUint8* desAddress = NULL;
       
   746 	TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,desAddress,EFalse);	// get descriptor length, maxlength and desAddress
       
   747 	if (r != KErrNone)
       
   748 		return r;
       
   749 	if (length == 0)
       
   750 		return KErrNone;
       
   751 
       
   752 
       
   753 	static const TUint8 LengthLookup[16]={4,8,12,8,12,0,0,0,0,0,0,0,0,0,0,0};
       
   754 	TUint32 desHdr;
       
   755 	r = Kern::ThreadRawRead(pT, aReq.RemoteDes(), &desHdr, sizeof(desHdr));
       
   756 	if(r!=KErrNone)
       
   757 		return r;
       
   758 	TInt desType = desHdr >>KShiftDesType8;
       
   759 	TInt desHdrLen = LengthLookup[desType];
       
   760 	if(!desHdrLen)
       
   761 		return KErrBadDescriptor;
       
   762 
       
   763 
       
   764 	pagingDevice->iMountInfoDataLock = ThePinObjectAllocator->AcquirePinObject();
       
   765 	pagingDevice->iMountInfoDescHdrLock = ThePinObjectAllocator->AcquirePinObject();
       
   766 	pagingDevice->iMountInfoDescLenLock = ThePinObjectAllocator->AcquirePinObject();
       
   767 
       
   768 	if (pagingDevice->iMountInfoDataLock == NULL || 
       
   769 		pagingDevice->iMountInfoDescHdrLock == NULL || 
       
   770 		pagingDevice->iMountInfoDescLenLock == NULL)
       
   771 		{
       
   772 		UnlockMountInfo(aPrimaryMedia);	// tidy up
       
   773 		return KErrNoMemory;
       
   774 		}
       
   775 
       
   776 
       
   777 	// First pin the descriptor header 
       
   778 	DPinObjectAllocator::SVirtualPinContainer* lock;
       
   779 	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock;
       
   780 	r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) aReq.RemoteDes(), desHdrLen, pT);
       
   781 	if (r != KErrNone)
       
   782 		{
       
   783 		UnlockMountInfo(aPrimaryMedia);	// tidy up
       
   784 		return KErrNoMemory;
       
   785 		}
       
   786 
       
   787 	
       
   788 	
       
   789 	// For EBufCPtr-type descriptors, need to pin the extra length before the buffer (!)
       
   790 	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock;
       
   791 	if (desType == EBufCPtr)
       
   792 		{
       
   793 		TLinAddr extraLenAddr = TLinAddr(desAddress) - aReq.RemoteDesOffset() - sizeof(TUint32);
       
   794 		r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) (TUint8*) extraLenAddr, sizeof(TUint32), pT);
       
   795 		if (r != KErrNone)
       
   796 			{
       
   797 			UnlockMountInfo(aPrimaryMedia);	// tidy up
       
   798 			return KErrNoMemory;
       
   799 			}
       
   800 		}
       
   801 
       
   802 
       
   803 	// Now pin the descriptor contents
       
   804 	lock = (DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock;
       
   805 	r = Kern::PinVirtualMemory(lock->iObject, (TLinAddr) desAddress, length, pT);
       
   806 	if (r != KErrNone)
       
   807 		{
       
   808 		UnlockMountInfo(aPrimaryMedia);	// tidy up
       
   809 		return KErrNoMemory;
       
   810 		}
       
   811 
       
   812 
       
   813 	return KErrNone;
       
   814 	}
       
   815 
       
   816 
       
   817 void DLocalDrive::UnlockMountInfo(DPrimaryMediaBase& aPrimaryMedia)
       
   818 	{
       
   819 	DMediaPagingDevice* pagingDevice = aPrimaryMedia.iBody->iPagingDevice; 
       
   820 	if (pagingDevice == NULL || pagingDevice->iMountInfoDataLock == NULL)
       
   821 		return;
       
   822 
       
   823 
       
   824 	if (pagingDevice->iMountInfoDataLock)
       
   825 		{
       
   826 		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock)->iObject);
       
   827 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDataLock);
       
   828 		pagingDevice->iMountInfoDataLock = NULL;
       
   829 		}
       
   830 	
       
   831 	if (pagingDevice->iMountInfoDescHdrLock)
       
   832 		{
       
   833 		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock)->iObject);
       
   834 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescHdrLock);
       
   835 		pagingDevice->iMountInfoDescHdrLock = NULL;
       
   836 		}
       
   837 	
       
   838 	if (pagingDevice->iMountInfoDescLenLock)
       
   839 		{
       
   840 		Kern::UnpinVirtualMemory(((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock)->iObject);
       
   841 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) pagingDevice->iMountInfoDescLenLock);
       
   842 		pagingDevice->iMountInfoDescLenLock = NULL;
       
   843 		}
       
   844 	
       
   845 	}
       
   846 #endif	// __DEMAND_PAGING__
       
   847 
       
   848 void DLocalDrive::NotifyChange(DPrimaryMediaBase& aPrimaryMedia, TBool aMediaChange)
       
   849 	{
       
   850 #ifndef __DEMAND_PAGING__
       
   851 	aPrimaryMedia;
       
   852 #endif
       
   853 
       
   854 	// Complete any notification request on media change or power down
       
   855 	if (aMediaChange)
       
   856 		{
       
   857 		DThread* pC=NULL;
       
   858 		NKern::LockSystem();
       
   859 		if (iCleanup.iThread)
       
   860 			{
       
   861 			pC=iCleanup.iThread;
       
   862 			pC->Open();
       
   863 			}
       
   864 		NKern::UnlockSystem();
       
   865 		if (pC)
       
   866 			{
       
   867 			TBool b = ETrue;
       
   868 			// if change not yet queued, queue it now
       
   869 			if (iNotifyChangeRequest->IsReady())
       
   870 				{
       
   871 				*((TBool*) iNotifyChangeRequest->Buffer()) = b;
       
   872 				Kern::QueueRequestComplete(pC,iNotifyChangeRequest,KErrNone);
       
   873 				}
       
   874 			// If change has not even been requested by the client, maintain the pre-wdp behaviour 
       
   875 			// and write data immediately back to client (possibly taking a page fault)
       
   876 			// N.B. Must NOT do this on data paging media
       
   877 #ifdef __DEMAND_PAGING__
       
   878 			else if (!DataPagingDfcQ(&aPrimaryMedia))
       
   879 #else
       
   880 			else
       
   881 #endif
       
   882 				{
       
   883 				Kern::ThreadRawWrite(pC, iNotifyChangeRequest->DestPtr(), &b, sizeof(b), NULL);
       
   884 				}
       
   885 			pC->AsyncClose();
       
   886 			}
       
   887 		}
       
   888 	}
       
   889 
       
   890 TLocalDriveCleanup::TLocalDriveCleanup()
       
   891 	{
       
   892 	}
       
   893 
       
   894 // This will be called when the original client thread exits
       
   895 // It is called in the context of the exiting thread with the system locked.
       
   896 void TLocalDriveCleanup::Cleanup()
       
   897 	{
       
   898 	DLocalDrive& d=LocalDrive();
       
   899 	d.iNotifyChangeRequest=NULL;
       
   900 	DThread* pC=iThread;
       
   901 	Remove();
       
   902 	iThread=NULL;
       
   903 	NKern::UnlockSystem();
       
   904 	pC->Close(NULL);	// balances Open() in DoCreate
       
   905 	NKern::LockSystem();
       
   906 	}
       
   907 
       
   908 /********************************************
       
   909  * Local drive request class
       
   910  ********************************************/
       
   911  
       
   912 /**
       
   913 Reads data from the descriptor specified in the request, from the requesting
       
   914 thread's process.
       
   915 
       
   916 This is used by the media driver to read data from a descriptor in the
       
   917 requesting thread.  The remote data is copied into the specified descriptor,
       
   918 starting at the specified offset within that descriptor's data area.
       
   919 
       
   920 @param aDes     The target descriptor into which data from the remote thread
       
   921                 is to be put.
       
   922 @param anOffset The offset within the target descriptor data area, where data
       
   923                 from the remote thread is to be put. Note that this parameter
       
   924                 may be useful when write operations to the media must be broken
       
   925                 up into smaller chunks than the length requested.
       
   926 
       
   927 @return KErrNone,if successful, otherwise one of the other
       
   928         system-wide error codes.
       
   929 
       
   930 @see Kern::ThreadDesRead()
       
   931 */
       
   932 EXPORT_C TInt TLocDrvRequest::ReadRemote(TDes8* aDes, TInt anOffset)
       
   933 	{
       
   934 	DThread* pT=RemoteThread();
       
   935 	if (!pT)
       
   936 		pT=Client();
       
   937 
       
   938 #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
       
   939 	if (Flags() & ETClientBuffer)
       
   940 		return Kern::ThreadBufRead(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
       
   941 
       
   942 	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
       
   943 #endif
       
   944 
       
   945 	return Kern::ThreadDesRead(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0);
       
   946 	}
       
   947 
       
   948 
       
   949 
       
   950 
       
   951 /**
       
   952 Reads data from an arbitrary descriptor in the requesting thread's process.
       
   953 
       
   954 This is used by the media driver to read data from a descriptor in the
       
   955 requesting thread.  
       
   956 
       
   957 NB This is NOT supported in a datapaging environment as there is no guarantee 
       
   958 that the remote descriptor won't be paged out. If this function is called and
       
   959 data-paging is enabled the kernel will fault in debug mode and return 
       
   960 KErrNotSupported in release mode.
       
   961 
       
   962 @param aSrc     A pointer to the source descriptor in the requesting thread's
       
   963                 address space.
       
   964 @param aDes     The target descriptor into which data from the remote thread
       
   965                 is to be put.
       
   966 
       
   967 @return KErrNone,if successful, 
       
   968 		KErrNotSupported if data-paging is enabled
       
   969 		otherwise one of the other  system-wide error codes.
       
   970 
       
   971 @see Kern::ThreadDesRead()
       
   972 */
       
   973 EXPORT_C TInt TLocDrvRequest::ReadRemote(const TAny* aSrc, TDes8* aDes)
       
   974 	{
       
   975 	DThread* pT=RemoteThread();
       
   976 	if (!pT)
       
   977 		pT=Client();
       
   978 
       
   979 #ifdef __DEMAND_PAGING__
       
   980 	__ASSERT_DEBUG(!DataPagingDeviceRegistered, LOCM_FAULT());
       
   981 	if (DataPagingDeviceRegistered)
       
   982 		return KErrNotSupported;
       
   983 #endif
       
   984 
       
   985 	return Kern::ThreadDesRead(pT,aSrc,*aDes,0,KChunkShiftBy0);
       
   986 	}
       
   987 
       
   988 
       
   989 
       
   990 
       
   991 /**
       
   992 Reads raw data from the requesting thread's process.
       
   993 
       
   994 This is used by the media driver to read raw data from a location in requesting
       
   995 thread's address space.  The remote data is copied into the specified
       
   996 buffer.
       
   997 
       
   998 @param aDest    A pointer to the buffer where the data is to be written.
       
   999 @param aSize    The number of bytes to read.
       
  1000 
       
  1001 @return KErrNone,if successful, otherwise one of the other
       
  1002         system-wide error codes.
       
  1003 
       
  1004 @see Kern::ThreadRawRead()
       
  1005 */
       
  1006 EXPORT_C TInt TLocDrvRequest::ReadRemoteRaw(TAny* aDest, TInt aSize)
       
  1007 	{
       
  1008 	DThread* pT=RemoteThread();
       
  1009 	if (!pT)
       
  1010 		pT=Client();
       
  1011 
       
  1012 #ifdef __DEMAND_PAGING__
       
  1013 	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
       
  1014 #endif
       
  1015 
       
  1016 	return Kern::ThreadRawRead(pT,RemoteDes(),aDest,aSize);
       
  1017 	}
       
  1018 
       
  1019 
       
  1020 /**
       
  1021 Writes data to a descriptor in the requesting thread's process.
       
  1022 
       
  1023 This is used by the media driver to write data to a descriptor in the requesting
       
  1024 thread.  Data is copied from the specified descriptor, starting at the specified
       
  1025 offset within that descriptor's data area.
       
  1026 
       
  1027 @param aDes     The source descriptor from which data is to be written to
       
  1028                 the remote thread.
       
  1029                 
       
  1030 @param anOffset The offset within the source descriptor data area, from where data
       
  1031                 is to be written to the remote thread. Note that this parameter
       
  1032                 may be useful when read operations from the media must be broken
       
  1033                 up into smaller chunks than the length requested.
       
  1034 
       
  1035 @return KErrNone,if successful, otherwise one of the other
       
  1036         system-wide error codes.
       
  1037 
       
  1038 @see Kern::ThreadDesWrite()
       
  1039 */
       
  1040 EXPORT_C TInt TLocDrvRequest::WriteRemote(const TDesC8* aDes, TInt anOffset)
       
  1041 	{
       
  1042 	DThread* pC=Client();
       
  1043 	DThread* pT=RemoteThread();
       
  1044 	if (!pT)
       
  1045 		pT=pC;
       
  1046 
       
  1047 #ifdef __DEMAND_PAGING__
       
  1048 	if (Flags() & ETClientBuffer)
       
  1049 		return Kern::ThreadBufWrite(pT, (TClientBuffer*) RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
       
  1050 #endif
       
  1051 
       
  1052 	return Kern::ThreadDesWrite(pT,RemoteDes(),*aDes,anOffset+RemoteDesOffset(),KChunkShiftBy0,pC);
       
  1053 	}
       
  1054 
       
  1055 
       
  1056 /**
       
  1057 Writes raw data to the requesting thread's process.
       
  1058 
       
  1059 This is used by the media driver to write raw data to a location in the
       
  1060 requesting thread's address space.
       
  1061 
       
  1062 @param aSrc     The source addres from which data is to be written to
       
  1063                 the remote thread.
       
  1064                 
       
  1065 @param aSize    The number of bytes to write.
       
  1066 
       
  1067 @return KErrNone,if successful, otherwise one of the other
       
  1068         system-wide error codes.
       
  1069 
       
  1070 @see Kern::ThreadRawWrite()
       
  1071 */
       
  1072 EXPORT_C TInt TLocDrvRequest::WriteRemoteRaw(const TAny* aSrc, TInt aSize)
       
  1073 	{
       
  1074 	DThread* pC=Client();
       
  1075 	DThread* pT=RemoteThread();
       
  1076 	if (!pT)
       
  1077 		pT=pC;
       
  1078 
       
  1079 #ifdef __DEMAND_PAGING__
       
  1080 	__ASSERT_ALWAYS((Flags() & ETClientBuffer) == 0, LOCM_FAULT());
       
  1081 #endif
       
  1082 
       
  1083 	return Kern::ThreadRawWrite(pT,RemoteDes(),aSrc,aSize,pC);
       
  1084 	}
       
  1085 
       
  1086 
       
  1087 TInt TLocDrvRequest::ProcessMessageData(TAny* aPtr)
       
  1088 //
       
  1089 // Get read/write parameters from client and open remote thread
       
  1090 //
       
  1091 	{
       
  1092 	RemoteThread()=NULL;
       
  1093 	DThread& t=Kern::CurrentThread();
       
  1094 	TLocalDriveMessageData d;
       
  1095 	kumemget32(&d,aPtr,sizeof(d));
       
  1096 	if (d.iHandle!=KLocalMessageHandle && Id()!=DLocalDrive::EFormat)
       
  1097 		{
       
  1098 		NKern::LockSystem();
       
  1099 		DThread* pT = RMessageK::MessageK(d.iHandle)->iClient;
       
  1100 		if (!pT || pT->Open()!=KErrNone)
       
  1101 			{
       
  1102 			NKern::UnlockSystem();
       
  1103 			return KErrBadHandle;
       
  1104 			}
       
  1105 		t.iExtTempObj=pT;
       
  1106 		RemoteThread()=pT;
       
  1107 		NKern::UnlockSystem();
       
  1108 		}
       
  1109 	Pos()=d.iPos;
       
  1110 	Length()=d.iLength;
       
  1111 	RemoteDes()=(TAny*)d.iPtr;
       
  1112 	RemoteDesOffset()=d.iOffset;
       
  1113 	DriverFlags()=d.iFlags;
       
  1114 	if (Pos()<0 || Length()<0)
       
  1115 		return KErrArgument;
       
  1116 	return KErrNone;
       
  1117 	}
       
  1118 
       
  1119 void TLocDrvRequest::CloseRemoteThread()
       
  1120 	{
       
  1121 	if (!RemoteThread())
       
  1122 		return;
       
  1123 	NKern::ThreadEnterCS();
       
  1124 	DThread& t=Kern::CurrentThread();
       
  1125 	RemoteThread()=NULL;
       
  1126 	Kern::SafeClose((DObject*&)t.iExtTempObj,NULL);
       
  1127 	NKern::ThreadLeaveCS();
       
  1128 	}
       
  1129 
       
  1130 EXPORT_C TInt TLocDrvRequest::CheckAndAdjustForPartition()
       
  1131 	{
       
  1132 	TLocDrv& d=*Drive();
       
  1133 	__KTRACE_OPT(KLOCDRV,Kern::Printf("CheckAndAdjustForPartition drive %d partition len %lx",d.iDriveNumber,d.iPartitionLen));
       
  1134 	Flags() |= EAdjusted;
       
  1135 	switch (Id())
       
  1136 		{
       
  1137 		case DLocalDrive::ECaps:
       
  1138 		case DLocalDrive::EForceMediaChange:
       
  1139 		case DLocalDrive::EPasswordLock:
       
  1140 		case DLocalDrive::EPasswordUnlock:
       
  1141 		case DLocalDrive::EPasswordClear:
       
  1142 		case DLocalDrive::EPasswordErase:
       
  1143 		case DLocalDrive::EReadPasswordStore:
       
  1144  		case DLocalDrive::EWritePasswordStore:
       
  1145  		case DLocalDrive::EPasswordStoreLengthInBytes:
       
  1146 		case DLocalDrive::EQueryDevice:
       
  1147 			return KErrNone;
       
  1148 		case DLocalDrive::EEnlarge:
       
  1149 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Enlarge request %lx",Length()));
       
  1150 			if (Length()>KMaxTInt)
       
  1151 				return KErrArgument;
       
  1152 			return KErrNone;
       
  1153 		case DLocalDrive::EReduce:
       
  1154 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Reduce request %lx@%lx",Length(),Pos()));
       
  1155 			if (Pos()+Length()>d.iPartitionLen)
       
  1156 				return KErrArgument;
       
  1157 			return KErrNone;
       
  1158 		case DLocalDrive::EFormat:
       
  1159 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Format request %lx@%lx",Length(),Pos()));
       
  1160 			if (!(DriverFlags() & RLocalDrive::ELocDrvWholeMedia))
       
  1161 				{
       
  1162 				if (Pos()>d.iPartitionLen)
       
  1163 					{
       
  1164 					Length()=0;
       
  1165 					return KErrEof;
       
  1166 					}
       
  1167 				Int64 left=d.iPartitionLen-Pos();
       
  1168 				if (left<Length())
       
  1169 					Length()=left;
       
  1170 				Pos()+=d.iPartitionBaseAddr;
       
  1171 				if (Length()==0)
       
  1172 					return KErrEof;
       
  1173 				}
       
  1174 			return KErrNone;
       
  1175 
       
  1176 #ifdef __DEMAND_PAGING__
       
  1177 		case DMediaPagingDevice::ERomPageInRequest:
       
  1178 //          if the ROM was reported to LOCM then it will also need to be adjusted.... 
       
  1179 //		    Otherwise the media driver adjust it internally
       
  1180 		case DMediaPagingDevice::ECodePageInRequest:
       
  1181 			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Adjusted Paging read request %lx@%lx",Length(),Pos()));
       
  1182 			if (Pos()+Length()>d.iPartitionLen)
       
  1183 				return KErrArgument;
       
  1184 			Pos()+=d.iPartitionBaseAddr;
       
  1185 			return KErrNone;
       
  1186 #endif
       
  1187 		
       
  1188 		default:	// read or write or fragment
       
  1189 			__KTRACE_OPT(KLOCDRV,Kern::Printf("R/W request %lx@%lx",Length(),Pos()));
       
  1190 
       
  1191 			if (DriverFlags() & RLocalDrive::ELocDrvWholeMedia)
       
  1192 				{
       
  1193 				if (d.iMedia && d.iMedia->iDriver && Pos()+Length() > d.iMedia->iDriver->iTotalSizeInBytes)
       
  1194 					return KErrArgument;
       
  1195 				}
       
  1196 			else
       
  1197 				{
       
  1198 				if (Pos()+Length() > d.iPartitionLen)
       
  1199 					return KErrArgument;
       
  1200 				Pos()+=d.iPartitionBaseAddr;
       
  1201 				}
       
  1202 			return KErrNone;
       
  1203 		}
       
  1204 	}
       
  1205 
       
  1206 /********************************************
       
  1207  * Local drive class
       
  1208  ********************************************/
       
  1209 TLocDrv::TLocDrv(TInt aDriveNumber)
       
  1210 	{
       
  1211 	memclr(this, sizeof(TLocDrv));
       
  1212 	iDriveNumber=aDriveNumber;
       
  1213 	iPartitionNumber=-1;
       
  1214 	}
       
  1215 
       
  1216 /**
       
  1217 Initialises the DMedia entity with the media device number and ID.
       
  1218  
       
  1219 @param	aDevice		The unique ID for this device. This can take one of the
       
  1220 					enumerated values defined in TMediaDevice enum.
       
  1221 
       
  1222 @param	aMediaId	The unique ID to associate with this media entity.
       
  1223 
       
  1224 @return KErrNone,if successful, otherwise one of the other
       
  1225         system-wide error codes.
       
  1226 
       
  1227 @see	TMediaDevice
       
  1228 */
       
  1229 EXPORT_C TInt DMedia::Create(TMediaDevice aDevice, TInt aMediaId, TInt)
       
  1230 	{
       
  1231 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia::Create media %d device %d",aMediaId,aDevice));
       
  1232 	iMediaId=aMediaId;
       
  1233 	iDevice=aDevice;
       
  1234 	return KErrNone;
       
  1235 	}
       
  1236 
       
  1237 /********************************************
       
  1238  * Primary Media Class
       
  1239  ********************************************/
       
  1240 void asyncDfc(TAny* aPtr)
       
  1241 	{
       
  1242 	DPrimaryMediaBase* pM=(DPrimaryMediaBase*)aPtr;
       
  1243 	if (pM->iState==DMedia::EOpening)
       
  1244 		pM->DoOpenMediaDriverComplete(pM->iAsyncErrorCode);
       
  1245 	else if (pM->iState==DMedia::EReadPartitionInfo)
       
  1246 		pM->DoPartitionInfoComplete(pM->iAsyncErrorCode);
       
  1247 	}
       
  1248 
       
  1249 void handleMsg(TAny* aPtr)
       
  1250 	{
       
  1251 	DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
       
  1252 
       
  1253 	for(TLocDrvRequest* m = (TLocDrvRequest*) primaryMedia->iMsgQ.iMessage; 
       
  1254 		m != NULL; 
       
  1255 		m = (TLocDrvRequest*) primaryMedia->iMsgQ.Poll())
       
  1256 		{
       
  1257 #if defined(_DEBUG)	
       
  1258 		if (!primaryMedia->iMsgQ.iQ.IsEmpty())	
       
  1259 			__KTRACE_OPT(KLOCDRV, Kern::Printf("TRACE: handleMsg, queue not empty %08X", m));	
       
  1260 #endif
       
  1261 		primaryMedia->HandleMsg(*m);
       
  1262 		
       
  1263 #ifdef __DEMAND_PAGING__
       
  1264 		// don't empty the queue if this media is paging as there 
       
  1265 		// may be a (higher-priority) paging DFC waiting to run...
       
  1266 		if (primaryMedia->iPagingMedia)
       
  1267 			break;
       
  1268 #endif
       
  1269 		}
       
  1270 
       
  1271 
       
  1272 	primaryMedia->iMsgQ.Receive();	// allow reception of more messages
       
  1273 	}
       
  1274 
       
  1275 EXPORT_C DPrimaryMediaBase::DPrimaryMediaBase()
       
  1276 	:	iMsgQ(handleMsg, this, NULL, 1),
       
  1277 		iDeferred(NULL, NULL, NULL, 0),			// callback never used
       
  1278 		iWaitMedChg(NULL, NULL, NULL, 0),		// callback never used
       
  1279 		iAsyncDfc(asyncDfc, this, 1)
       
  1280 /**
       
  1281 Constructor of DPrimaryMediaBase class.
       
  1282 Initialises the media state as closed.
       
  1283 */
       
  1284 	{
       
  1285 	iState = EClosed;
       
  1286 	}
       
  1287 
       
  1288 
       
  1289 
       
  1290 EXPORT_C TInt DPrimaryMediaBase::Create(TMediaDevice aDevice, TInt aMediaId, TInt aLastMediaId)
       
  1291 /**
       
  1292 Called from LocDrv::RegisterMediaDevice() function.
       
  1293 Calls DMedia::Create()
       
  1294 
       
  1295 @param aDevice Local media ID 
       
  1296 @param aMediaId Media Id (unique for a media subsystem)
       
  1297 @param aLastMediaId This indicates number of used media ids+ number of DMedia objects to be associated with the media driver.
       
  1298 
       
  1299 @return KErrNone
       
  1300 @see TMediaDevice 
       
  1301 
       
  1302 */
       
  1303 	{
       
  1304 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::Create media %d-%d device %d",aMediaId,aLastMediaId,aDevice));
       
  1305 	TInt r=DMedia::Create(aDevice,aMediaId,0);
       
  1306 	if (r != KErrNone)
       
  1307 		return r;
       
  1308 	iBody = new DBody;
       
  1309 	if (iBody == NULL)
       
  1310 		return KErrNoMemory;
       
  1311 
       
  1312 #ifdef __DEMAND_PAGING__
       
  1313 	TInt pageSize = Kern::RoundToPageSize(1);
       
  1314 	iBody->iPageSizeMsk = pageSize-1;
       
  1315 #endif
       
  1316 
       
  1317 	iLastMediaId=aLastMediaId;
       
  1318 	if (r==KErrNone && iDfcQ)
       
  1319 		{
       
  1320 		iMsgQ.SetDfcQ(iDfcQ);
       
  1321 		iDeferred.SetDfcQ(iDfcQ);
       
  1322 		iWaitMedChg.SetDfcQ(iDfcQ);
       
  1323 		iAsyncDfc.SetDfcQ(iDfcQ);
       
  1324 		}
       
  1325 	return KErrNone;
       
  1326 	}
       
  1327 
       
  1328 
       
  1329 EXPORT_C TInt DPrimaryMediaBase::Connect(DLocalDrive* aLocalDrive)
       
  1330 /**
       
  1331 Connects to a local drive
       
  1332 
       
  1333 @param aLocalDrive Local drive logical channel abstraction
       
  1334 
       
  1335 @pre Kernel must be unlocked
       
  1336 @pre Current thread in critical section
       
  1337 
       
  1338 @post Kernel must be unlocked
       
  1339 
       
  1340 @return KErrNone, if successful
       
  1341 		KErrNotFound, If no PDD matches criteria while getting driver list
       
  1342 		KErrNoMemory, If the array could not be expanded at some point while getting driver list or ran out of memory while opening media driver
       
  1343 		KErrNotReady, If not ready when trying to open media driver
       
  1344 		otherwise, one of the other system wide error codes.
       
  1345 
       
  1346 @see DLocalDrive
       
  1347 */
       
  1348 	{
       
  1349 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Connect %O",iMediaId,aLocalDrive));
       
  1350 	if (iDfcQ)
       
  1351 		{
       
  1352 		TThreadMessage& m=Kern::Message();
       
  1353 		m.iValue=EConnect;
       
  1354 		m.iArg[0]=aLocalDrive;
       
  1355 		return m.SendReceive(&iMsgQ);
       
  1356 		}
       
  1357 
       
  1358 	// If no DFC queue, must be a fixed media device
       
  1359 	// If this is the first connection, open media driver now
       
  1360 	// Assume no non-primary media exist on this device
       
  1361 	TInt r=KErrNone;
       
  1362 	NKern::LockSystem();
       
  1363 	TBool first=iConnectionQ.IsEmpty();
       
  1364 	iConnectionQ.Add(&aLocalDrive->iLink);
       
  1365 	NKern::UnlockSystem();
       
  1366 	if (first)
       
  1367 		{
       
  1368 		r=OpenMediaDriver();
       
  1369 		if (r!=KErrNone)
       
  1370 			{
       
  1371 			NKern::LockSystem();
       
  1372 			aLocalDrive->Deque();
       
  1373 			NKern::UnlockSystem();
       
  1374 			}
       
  1375 		}
       
  1376 	if (r==KErrNone)
       
  1377 		aLocalDrive->iDrive->iMedia=this;
       
  1378 	return r;
       
  1379 	}
       
  1380 
       
  1381 
       
  1382 
       
  1383 
       
  1384 EXPORT_C void DPrimaryMediaBase::Disconnect(DLocalDrive* aLocalDrive)
       
  1385 /**
       
  1386 Disconnects from a local drive
       
  1387 
       
  1388 @param aLocalDrive Local drive logical channel abstraction
       
  1389 
       
  1390 @pre Kernel must be unlocked
       
  1391 @pre Current thread in critical section
       
  1392 
       
  1393 @post Kernel must be unlocked
       
  1394 @see DLocalDrive
       
  1395 */
       
  1396 
       
  1397 	{
       
  1398 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Disconnect %O",iMediaId,aLocalDrive));
       
  1399 	if (iDfcQ)
       
  1400 		{
       
  1401 		TThreadMessage& m=Kern::Message();
       
  1402 		m.iValue=EDisconnect;
       
  1403 		m.iArg[0]=aLocalDrive;
       
  1404 		m.SendReceive(&iMsgQ);
       
  1405 		return;
       
  1406 		}
       
  1407 
       
  1408 	// If no DFC queue, must be a fixed media device
       
  1409 	// If this is the last connection, close media driver now
       
  1410 	// Assume no non-primary media exist on this device
       
  1411 	DMediaDriver* pD=NULL;
       
  1412 	NKern::LockSystem();
       
  1413 	aLocalDrive->iDrive->iMedia=NULL;
       
  1414 	aLocalDrive->Deque();
       
  1415 	if (iConnectionQ.IsEmpty())
       
  1416 		{
       
  1417 		pD=iDriver;
       
  1418 		iDriver=NULL;
       
  1419 		}
       
  1420 	NKern::UnlockSystem();
       
  1421 	if (pD)
       
  1422 		pD->Close();
       
  1423 	}
       
  1424 
       
  1425 EXPORT_C TInt DPrimaryMediaBase::Request(TLocDrvRequest& aReq)
       
  1426 /**
       
  1427 Issues a local drive request. It is called from TLocDrv::Request() function .
       
  1428 Each local drive request is encapsulated as a TLocDrvRequest- a class derived from TThreadMessage, the kernel message class. 
       
  1429 TLocDrvRequest contains information pertaining to the request, including the ID and any associated parameters such as drive position, length and source/destination location.
       
  1430 Passes the request through to the media driver.
       
  1431 
       
  1432 @param m Encapsulates the request information received from the client
       
  1433 
       
  1434 @pre Enter with kernel unlocked
       
  1435 
       
  1436 @post Leave with Kernel unlocked
       
  1437 
       
  1438 @return KErrNone,if successful
       
  1439 	KErrBadDescriptor, if request encapsulates a bad descriptor
       
  1440 	Otherwise, one of the other system wide error codes.
       
  1441 
       
  1442 @see TLocDrvRequest
       
  1443 */
       
  1444 	{
       
  1445 
       
  1446 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::Request(%08x)",iMediaId,&aReq));
       
  1447 	__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()));
       
  1448 
       
  1449 	TInt reqId = aReq.Id();
       
  1450 
       
  1451 	if (reqId == DLocalDrive::ECaps)
       
  1452 		DefaultDriveCaps(*(TLocalDriveCapsV2*)aReq.RemoteDes());	// fill in stuff we know even if no media present
       
  1453 
       
  1454 	TInt r = QuickCheckStatus();
       
  1455 	if (r != KErrNone && aReq.Id()!=DLocalDrive::EForceMediaChange &&			// EForceMediaChange, and 
       
  1456  			 			 aReq.Id()!=DLocalDrive::EReadPasswordStore &&			// Password store operations 
       
  1457  						 aReq.Id()!=DLocalDrive::EWritePasswordStore &&			// do not require the media 
       
  1458  						 aReq.Id()!=DLocalDrive::EPasswordStoreLengthInBytes)	// to be ready.)
       
  1459  	 	{
       
  1460 		return r;
       
  1461  	  	}
       
  1462  	  	
       
  1463 
       
  1464 	// for ERead & EWrite requests, get the linear address for pinning & DMA
       
  1465 	TUint8* linAddress = NULL;
       
  1466 	TClientBuffer clientBuffer;
       
  1467 	DThread* pT = NULL;
       
  1468 
       
  1469 	if (reqId == DLocalDrive::ERead || reqId == DLocalDrive::EWrite)
       
  1470 		{
       
  1471 		pT = aReq.RemoteThread();
       
  1472 		if (!pT)
       
  1473 			pT = &Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
       
  1474 
       
  1475 		// for silly zero-length requests, return immediately, setting the client 
       
  1476 		// descriptor length to zero if it's a read request
       
  1477 		if (aReq.Length() == 0)
       
  1478 			{
       
  1479 			DThread* pC = &Kern::CurrentThread();
       
  1480 			r = KErrNone;
       
  1481 			if (reqId == DLocalDrive::ERead)
       
  1482 				{
       
  1483 				TPtrC8 ptr(NULL, 0);
       
  1484 				r = Kern::ThreadDesWrite(pT, aReq.RemoteDes(), ptr, aReq.RemoteDesOffset(), KChunkShiftBy0,pC);
       
  1485 				}
       
  1486 			return r;
       
  1487 			}
       
  1488 
       
  1489 		clientBuffer.SetFromDescriptor(aReq.RemoteDes(), pT);
       
  1490 
       
  1491 		TInt length = 0;
       
  1492 		TInt maxLength = 0;
       
  1493 		TInt r = Kern::ThreadGetDesInfo(pT,aReq.RemoteDes(),length,maxLength,linAddress,EFalse);	// get descriptor length, maxlength and linAddress
       
  1494 		if (r != KErrNone)
       
  1495 			return r;
       
  1496 		linAddress+= aReq.RemoteDesOffset();
       
  1497 
       
  1498 #ifdef __DEMAND_PAGING__
       
  1499 		// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points 
       
  1500 		// to a TClientBuffer rather than the client's remote descriptor
       
  1501 		if (DataPagingDeviceRegistered)
       
  1502 			{
       
  1503 			aReq.RemoteDes() = &clientBuffer;
       
  1504 			aReq.Flags() |= TLocDrvRequest::ETClientBuffer;
       
  1505 			}
       
  1506 #endif
       
  1507 		}
       
  1508 
       
  1509 	if (iDfcQ)
       
  1510 		{
       
  1511 		__TRACE_TIMING(0x10);
       
  1512 
       
  1513 
       
  1514 #ifdef __DEMAND_PAGING__
       
  1515 		// If this is a ROM/Code paging media, pin writes 
       
  1516 		// If there is a Data paging media registered, pin all requests with descriptors 
       
  1517 		if ( (DataPagingDeviceRegistered) || (reqId == DLocalDrive::EWrite && RomPagingDfcQ(this)) )
       
  1518 			r = PinSendReceive(aReq, (TLinAddr) linAddress);
       
  1519 		else
       
  1520 #endif	// __DEMAND_PAGING__
       
  1521 
       
  1522 			r = SendReceive(aReq, (TLinAddr) linAddress);
       
  1523 		}
       
  1524 	else
       
  1525 		{
       
  1526 		// If no DFC queue, must be a fixed media device
       
  1527 		// Media driver must already have been opened
       
  1528 		// Assume no non-primary media exist on this device
       
  1529 		// Just pass request straight through to media driver
       
  1530 		r = aReq.CheckAndAdjustForPartition();
       
  1531 		if (r == KErrNone)
       
  1532 			r = iDriver->Request(aReq);
       
  1533 		}
       
  1534 
       
  1535 #ifdef __DEMAND_PAGING__
       
  1536 		// NB change in behavior IF DATA PAGING IS ENABLED: TLocDrvRequest::RemoteDes() points 
       
  1537 		// to a TClientBuffer rather than the client's remote descriptor
       
  1538 	if (reqId == DLocalDrive::ERead && DataPagingDeviceRegistered && r == KErrNone)
       
  1539 		{
       
  1540 		r = clientBuffer.UpdateDescriptorLength(pT);
       
  1541 		}
       
  1542 #endif
       
  1543 
       
  1544 	return r;
       
  1545 	}
       
  1546 
       
  1547 
       
  1548 #ifdef __DEMAND_PAGING__
       
  1549 TInt DPrimaryMediaBase::PinSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
       
  1550 	{
       
  1551 	__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
       
  1552 
       
  1553 
       
  1554 	TInt msgId = aReq.Id();
       
  1555 
       
  1556 
       
  1557 	switch(msgId)
       
  1558 		{
       
  1559 		case DLocalDrive::EControlIO:
       
  1560 			{
       
  1561 			TInt controlIoType = aReq.Int3(); 
       
  1562 			switch(controlIoType)
       
  1563 				{
       
  1564 				case KLocalMessageHandle:
       
  1565 					// ControlIo is not supported if either of the two bare (TAny*) pointers are non-NULL 
       
  1566 					// as it's not possible to determine what the pointers are pointing at...
       
  1567 					if (aReq.Int1() || aReq.Int2())
       
  1568 						{
       
  1569 						__KTRACE_OPT(KDATAPAGEWARN, Kern::Printf("Data paging: Naked EControlIO not supported on paging device: fn=%x", aReq.Int0()));
       
  1570 						return KErrNotSupported;
       
  1571 						}
       
  1572 					// fall into...
       
  1573 				case 0:
       
  1574 					return SendReceive(aReq);
       
  1575 
       
  1576 				default:
       
  1577 					// if Int3() is > 0, Int1() is a data pointer, and Int3() is a length
       
  1578 					if (controlIoType > (TInt) ThePinObjectAllocator->iFragmentGranularity)
       
  1579 						return KErrTooBig;
       
  1580 					if (controlIoType < 0)
       
  1581 						return KErrArgument;
       
  1582 					return PinFragmentSendReceive(aReq, (TLinAddr) aReq.Ptr1(), controlIoType);
       
  1583 				}
       
  1584 			}
       
  1585 
       
  1586 		case DLocalDrive::ECaps:
       
  1587 		case DLocalDrive::EGetLastErrorInfo:
       
  1588 		case DLocalDrive::EQueryDevice:
       
  1589 			{
       
  1590 			TInt len = aReq.Length();
       
  1591 
       
  1592 			if (len > (TInt) ThePinObjectAllocator->iFragmentGranularity)
       
  1593 				return KErrTooBig;
       
  1594 
       
  1595 			return PinFragmentSendReceive(aReq, (TLinAddr) aReq.RemoteDes(), len);
       
  1596 			}
       
  1597 
       
  1598 		case DLocalDrive::ERead:
       
  1599 		case DLocalDrive::EWrite:
       
  1600 			{
       
  1601 			return PinFragmentSendReceive(aReq, aLinAddress, aReq.Length());
       
  1602 			}
       
  1603 		
       
  1604 
       
  1605 
       
  1606 		// For the time being, don't support any password requests to the data paging device.
       
  1607 		// This shouldn't be a problem as the device should be flagged as non-removable...
       
  1608 		// This would be difficult to do anyway as it would involve pinning up to 3 buffers - 
       
  1609 		// TLocalDrivePasswordData itself, iOldPasswd & iNewPasswd
       
  1610 		case DLocalDrive::EPasswordLock:
       
  1611 		case DLocalDrive::EPasswordUnlock:
       
  1612 		case DLocalDrive::EPasswordClear:
       
  1613 		case DLocalDrive::EReadPasswordStore:
       
  1614 		case DLocalDrive::EWritePasswordStore:
       
  1615 		case DLocalDrive::EPasswordStoreLengthInBytes:
       
  1616 		case DLocalDrive::EPasswordErase:
       
  1617 			return KErrNotSupported;
       
  1618 
       
  1619 		default:		
       
  1620 			return SendReceive(aReq);
       
  1621 		}
       
  1622 	}
       
  1623 
       
  1624 TInt DPrimaryMediaBase::PinFragmentSendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress, TInt aLength)
       
  1625 	{
       
  1626 	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)
       
  1627 	TInt r = KErrNone;
       
  1628 
       
  1629 //	Kern::Printf(">PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
       
  1630 
       
  1631 	DThread* pT = aReq.RemoteThread();
       
  1632 	if (!pT)
       
  1633 		pT=&Kern::CurrentThread();	// e.g. when using TBusLocalDrive directly
       
  1634 
       
  1635 	__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));
       
  1636 	__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));
       
  1637 
       
  1638 	// don't want this thread to be terminated until last fragment is sent to MD and mem can be free'd up
       
  1639 	NKern::ThreadEnterCS();			
       
  1640 
       
  1641 	__ASSERT_DEBUG(ThePinObjectAllocator, LOCM_FAULT());
       
  1642 
       
  1643 	TUint fragmentGranularity = ThePinObjectAllocator->iFragmentGranularity;
       
  1644 	TInt dataLockResult = 0;
       
  1645 	// fragmentation only allowed for read/write requests
       
  1646 	__ASSERT_DEBUG(aLength <= (TInt) fragmentGranularity || (aReq.Id() == DLocalDrive::EWrite || aReq.Id() == DLocalDrive::ERead), LOCM_FAULT());
       
  1647 
       
  1648 	// Pin the client buffer
       
  1649 	TInt pinnedLen;
       
  1650 	for (TInt pos = 0; pos < aLength; pos+= pinnedLen, aLinAddress+= pinnedLen)
       
  1651 		{
       
  1652 		pinnedLen = 0;
       
  1653 
       
  1654 		// pin memory
       
  1655 		TInt remainingLen = aLength - pos; // remaining length
       
  1656 
       
  1657 		// first attempt to pin memory with no pre-allocated buffers (which may fail)
       
  1658 		DPinObjectAllocator::SVirtualPinContainer* pinDataObject = ThePinObjectAllocator->AcquirePinObject();
       
  1659 
       
  1660 		if (pinDataObject)
       
  1661 			{
       
  1662 			TInt lenToPin = Min(KMaxPinData, remainingLen);
       
  1663 
       
  1664 			TInt r = Kern::PinVirtualMemory(pinDataObject->iObject, aLinAddress, lenToPin, pT);
       
  1665 			if (r == KErrNone)
       
  1666 				{
       
  1667 				pinnedLen = lenToPin;
       
  1668 				}
       
  1669 			else
       
  1670 				{
       
  1671 #ifdef __DEBUG_DEMAND_PAGING__
       
  1672 				Kern::Printf("Kern::PinVirtualMemory() error %d", r);
       
  1673 #endif
       
  1674 				// pin failed, so use preallocated buffer instead
       
  1675 				ThePinObjectAllocator->ReleasePinObject(pinDataObject);
       
  1676 				pinDataObject = NULL;
       
  1677 				}
       
  1678 			}
       
  1679 
       
  1680 		if (!pinDataObject)
       
  1681 			{
       
  1682 			ThePinObjectAllocator->PreAllocatedDataLock().LockFragmentation();
       
  1683 
       
  1684 			TLinAddr start = aLinAddress;
       
  1685 			do
       
  1686 				{
       
  1687 				TInt lenToPin = Min((TInt) fragmentGranularity, remainingLen - pinnedLen);
       
  1688 
       
  1689 #ifdef __DEBUG_DEMAND_PAGING__
       
  1690 				Kern::Printf(">SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X", aReq.Id(), aLinAddress, lenToPin);
       
  1691 #endif
       
  1692 
       
  1693 				dataLockResult = ThePinObjectAllocator->PreAllocatedDataLock().Lock(pT, start, lenToPin);
       
  1694 
       
  1695 #ifdef __DEBUG_DEMAND_PAGING__
       
  1696 				Kern::Printf("<SR PinS Id %d aLinAddress %08X lenToPin %08X offset %08X r %d", aReq.Id(), aLinAddress, lenToPin, r);
       
  1697 #endif
       
  1698 
       
  1699 				start+= lenToPin;
       
  1700 				pinnedLen+= lenToPin;
       
  1701 				}
       
  1702 			while (dataLockResult == 0 && pinnedLen < remainingLen);
       
  1703 			
       
  1704 			// if nothing pinned (dataLockResult == 0) or error (dataLockResult <0), release the mutex,
       
  1705 			// otherwise (dataLockResult > 0) release it after calling SendReceive()
       
  1706 			if (dataLockResult <= 0)
       
  1707 				ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
       
  1708 
       
  1709 #ifdef __DEBUG_DEMAND_PAGING__
       
  1710 				if (dataLockResult < 0) 
       
  1711 					Kern::Printf("DFragmentationPagingLock::Lock() %d", dataLockResult);
       
  1712 #endif
       
  1713 
       
  1714 			if (dataLockResult < 0)	// if lock returned an error then give up
       
  1715 				{
       
  1716 				r = dataLockResult;
       
  1717 				break;
       
  1718 				}
       
  1719 			}
       
  1720 
       
  1721 		// fragment request Id defaults to same as original request
       
  1722 		fragment.Id() = aReq.Id();
       
  1723 		fragment.Length() = Int64(pinnedLen);
       
  1724 		fragment.RemoteDesOffset() = aReq.RemoteDesOffset() + pos;
       
  1725 		fragment.Pos() = aReq.Pos() + pos;
       
  1726 		fragment.Flags() = aReq.Flags();
       
  1727 
       
  1728 		__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()));
       
  1729 
       
  1730 #ifdef BTRACE_PAGING_MEDIA
       
  1731 		TInt buf[4];
       
  1732 		buf[0] = pinnedLen;	// fragment length
       
  1733 		buf[1] = pos;		// offset within original request
       
  1734 		buf[2] = fragment.Pos(); // offset in media
       
  1735 		buf[3] = (TInt)&pT->iNThread;	// thread that issued the original write req
       
  1736 		BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentBegin,&fragment,fragment.Id(),buf,sizeof(buf));
       
  1737 #endif
       
  1738 
       
  1739 		r = SendReceive(fragment, aLinAddress);	// only come back here when message (fragment) has been completed
       
  1740 
       
  1741 		// unpin memory
       
  1742 		if (pinDataObject)
       
  1743 			{
       
  1744 			Kern::UnpinVirtualMemory(pinDataObject->iObject);
       
  1745 			ThePinObjectAllocator->ReleasePinObject(pinDataObject);
       
  1746 			}
       
  1747 		else if (dataLockResult > 0)	// pinDataObject = NULL
       
  1748 			{
       
  1749 			__ASSERT_DEBUG(dataLockResult == 1, LOCM_FAULT());
       
  1750 			ThePinObjectAllocator->PreAllocatedDataLock().Unlock();
       
  1751 			ThePinObjectAllocator->PreAllocatedDataLock().UnlockFragmentation();
       
  1752 			}
       
  1753 
       
  1754 #ifdef BTRACE_PAGING_MEDIA
       
  1755 		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedFragmentEnd,&fragment,r);
       
  1756 #endif
       
  1757 
       
  1758 		if (r != KErrNone)
       
  1759 			break;
       
  1760 		}
       
  1761 
       
  1762 	NKern::ThreadLeaveCS();
       
  1763 
       
  1764 //	Kern::Printf("<PFSR %02X aReq %08X aLinAddress %08X aLen %08X offset %08X", aReq.Id(), &aReq, aLinAddress, aLength, aReq.RemoteDesOffset());
       
  1765 
       
  1766 	return r;
       
  1767 	}
       
  1768 
       
  1769 #endif	// __DEMAND_PAGING__
       
  1770 
       
  1771 
       
  1772 TInt DPrimaryMediaBase::SendReceive(TLocDrvRequest& aReq, TLinAddr aLinAddress)
       
  1773 /**
       
  1774  * If a Physical memory helper object is present for given drive,
       
  1775  * then message is routed via helper;
       
  1776  * 
       
  1777  * @return KErrNone, if successful;
       
  1778  * 		   otherwise, one of the other system wide error codes.
       
  1779  * 
       
  1780  * @see TLocDrvRequest::SendReceive()
       
  1781  * @see DDmaHelper::SendReceive()
       
  1782  */
       
  1783 	{
       
  1784 	DDmaHelper* dmaHelper = aReq.Drive()->iDmaHelper;
       
  1785 
       
  1786 #ifdef __DEMAND_PAGING__
       
  1787 	RequestCountInc();
       
  1788 #endif
       
  1789 
       
  1790 	TInt r;
       
  1791 
       
  1792 	if (dmaHelper)
       
  1793 		r = dmaHelper->SendReceive(aReq, aLinAddress);
       
  1794 	else
       
  1795 		r = aReq.SendReceive(&iMsgQ);
       
  1796 
       
  1797 #ifdef __DEMAND_PAGING__
       
  1798 	RequestCountDec();
       
  1799 #endif
       
  1800 
       
  1801 	return r;
       
  1802 	}
       
  1803 
       
  1804 
       
  1805 
       
  1806 EXPORT_C TInt DPrimaryMediaBase::ForceMediaChange(TInt)
       
  1807 /**
       
  1808 Forces a media change.The method can be overridden in the derived classes.
       
  1809 @param mode Media change mode
       
  1810 
       
  1811 @return KErrNotSupported, in the default implementation
       
  1812 		KErrNone, if successful
       
  1813 		Otherwise, one of the other system wide error codes.
       
  1814 
       
  1815 */
       
  1816 	{
       
  1817 	// default implementation
       
  1818 	return KErrNotSupported;
       
  1819 	}
       
  1820 
       
  1821 EXPORT_C TInt DPrimaryMediaBase::InitiatePowerUp()
       
  1822 /**
       
  1823 Initiates Power up sequence
       
  1824 @return KErrCompletion, operation is complete successfully or otherwise
       
  1825 		KErrNone, if successful
       
  1826 		Otherwise, one of the other system wide error codes.
       
  1827 
       
  1828 */
       
  1829 	{
       
  1830 	// default implementation, this is the default implementation.
       
  1831 	return KErrCompletion;
       
  1832 	}
       
  1833 
       
  1834 EXPORT_C TInt DPrimaryMediaBase::QuickCheckStatus()
       
  1835 /**
       
  1836 Checks the status of the media device, whether the device is present,absent,not ready,etc.
       
  1837 The function can be overridden in the derived classes
       
  1838 
       
  1839 @return KErrNone, if successful
       
  1840 		Otherwise, one of the other system wide error codes.
       
  1841 
       
  1842 */
       
  1843 	{
       
  1844 	// default implementation
       
  1845 	return KErrNone;
       
  1846 	}
       
  1847 
       
  1848 EXPORT_C void DPrimaryMediaBase::DefaultDriveCaps(TLocalDriveCapsV2& aCaps)
       
  1849 /**
       
  1850 Fills in the default drive capabilities in TLocalDriveCapsV2 .
       
  1851 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.
       
  1852 
       
  1853 @param aCaps Media drive capability fields. Extension to Capabilities fields(i.e) in addition to TLocalDriveCaps mainly to support Nor flash
       
  1854 @see TLocalDriveCapsV2
       
  1855 */
       
  1856 
       
  1857 	{
       
  1858 	// default implementation
       
  1859 	// aCaps is zeroed beforehand
       
  1860 	aCaps.iType = EMediaUnknown;
       
  1861 	//	aCaps.iBattery = EBatNotSupported;
       
  1862 	}
       
  1863 	
       
  1864 EXPORT_C TBool DPrimaryMediaBase::IsRemovableDevice(TInt& /*aSocketNum*/)
       
  1865 /**
       
  1866 Checks whether it is a removable device or not
       
  1867 @param aSocketNum Socket number
       
  1868 @return ETrue=Removable Device
       
  1869 		EFalse=Non-Removable device, default implementation
       
  1870 
       
  1871 */
       
  1872 	{
       
  1873 	// default implementation
       
  1874 	return(EFalse);
       
  1875 	}
       
  1876 
       
  1877 EXPORT_C void DPrimaryMediaBase::HandleMsg(TLocDrvRequest& m)
       
  1878 /**
       
  1879 It handles the drive request encapsulated in TLocDrvRequest depending on the message id.
       
  1880 
       
  1881 @param aRequest Encapsulates the request information received from the client
       
  1882 @see TLocDrvRequest
       
  1883 */
       
  1884 	{
       
  1885 	switch (m.iValue)
       
  1886 		{
       
  1887 		case EConnect:
       
  1888 			{
       
  1889 			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
       
  1890 			iConnectionQ.Add(&pD->iLink);
       
  1891 			m.Complete(KErrNone, EFalse);
       
  1892 			return;
       
  1893 			}
       
  1894 		case EDisconnect:
       
  1895 			{
       
  1896 			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
       
  1897 			TLocDrv* pL=pD->iDrive;
       
  1898 			DMedia* media=pL->iMedia;
       
  1899 			if (iState==EReady && media && media->iDriver)
       
  1900 				media->iDriver->Disconnect(pD,&m);
       
  1901 			else
       
  1902 				{
       
  1903 				pD->Deque();
       
  1904 				m.Complete(KErrNone, EFalse);
       
  1905 				}
       
  1906 			return;
       
  1907 			}
       
  1908 		case DLocalDrive::EForceMediaChange:
       
  1909 			{
       
  1910 			TUint flags = (TUint) m.Pos();
       
  1911 
       
  1912 			// if KForceMediaChangeReOpenDriver specified wait for power up, 
       
  1913 			// and then re-open this drive's media driver
       
  1914 			__KTRACE_OPT(KLOCDRV, Kern::Printf("EForceMediaChange, flags %08X\n", flags));
       
  1915 			if (flags == (TUint) KForceMediaChangeReOpenMediaDriver)
       
  1916 				{
       
  1917 				TInt sock;
       
  1918 				if (!IsRemovableDevice(sock))
       
  1919 					{
       
  1920 					CompleteRequest(m, KErrNotSupported);
       
  1921 					return;
       
  1922 					}
       
  1923 				// wait for power up and then call DPrimaryMediaBase::DoRequest()
       
  1924 				break;
       
  1925 				}
       
  1926 
       
  1927 			TInt r=ForceMediaChange(flags);
       
  1928 			if (r==KErrNone)
       
  1929 				{
       
  1930 				// wait for media change notification to complete message
       
  1931 				m.Forward(&iWaitMedChg,EFalse);
       
  1932 				}
       
  1933 			else
       
  1934 				{
       
  1935 				if (r==KErrNotSupported || r==KErrCompletion)
       
  1936 					r=KErrNone;
       
  1937 				CompleteRequest(m, r);
       
  1938 				}
       
  1939 			return;
       
  1940 			}
       
  1941 		case DLocalDrive::ECaps:
       
  1942 			if (iState==EPoweredDown)
       
  1943 				{
       
  1944 				// The media is powered down, but the media driver still exists.
       
  1945 				//  - Issue the ECaps request without powering the media back up.
       
  1946 				DoRequest(m);
       
  1947 				__TRACE_TIMING(0x101);
       
  1948 				return;
       
  1949 				}
       
  1950 			break;
       
  1951 
       
  1952 		case DLocalDrive::ERead:
       
  1953 		case DLocalDrive::EWrite:
       
  1954 		case DLocalDrive::EFormat:
       
  1955 		case DLocalDrive::EEnlarge:
       
  1956 		case DLocalDrive::EReduce:
       
  1957 		case DLocalDrive::EPasswordLock:
       
  1958 		case DLocalDrive::EPasswordUnlock:
       
  1959 		case DLocalDrive::EPasswordClear:
       
  1960 		case DLocalDrive::EPasswordErase:
       
  1961 		case DLocalDrive::EControlIO:
       
  1962 		case DLocalDrive::EDeleteNotify:
       
  1963 		case DLocalDrive::EQueryDevice:
       
  1964 
       
  1965 #ifdef __DEMAND_PAGING__
       
  1966 		case DMediaPagingDevice::ERomPageInRequest:
       
  1967 		case DMediaPagingDevice::ECodePageInRequest:
       
  1968 #endif
       
  1969 			break;
       
  1970 		case DLocalDrive::EGetLastErrorInfo:
       
  1971 			{
       
  1972 			DLocalDrive* pD=(DLocalDrive*)m.Ptr0();
       
  1973 			TLocDrv* pL=pD->iDrive;
       
  1974 			*((TErrorInfo*) m.RemoteDes()) = pL->iLastErrorInfo;
       
  1975 			CompleteRequest(m, KErrNone);
       
  1976 			return;
       
  1977 			}
       
  1978 		case DLocalDrive::EReadPasswordStore:
       
  1979 			{
       
  1980 			TUint8  passData[TPasswordStore::EMaxPasswordLength];
       
  1981 			TPtr8 pData(passData, TPasswordStore::EMaxPasswordLength);
       
  1982 			TInt r = ThePasswordStore->ReadPasswordData(pData);
       
  1983 			if (r==KErrNone)
       
  1984 				r = m.WriteRemote(&pData,0);
       
  1985 			CompleteRequest(m, r);
       
  1986 			return;
       
  1987 			}
       
  1988 		case DLocalDrive::EWritePasswordStore:
       
  1989 			{
       
  1990 			TUint8  passData[TPasswordStore::EMaxPasswordLength];
       
  1991 			TPtr8 pData(passData, TPasswordStore::EMaxPasswordLength);
       
  1992 
       
  1993 			DThread* pT=m.RemoteThread();
       
  1994 			if (!pT)
       
  1995 				pT=m.Client();
       
  1996 
       
  1997 			TInt lengthOrError = Kern::ThreadGetDesLength(pT, m.RemoteDes() );
       
  1998 			if ( lengthOrError > pData.MaxLength() )
       
  1999 				{
       
  2000 				CompleteRequest(m, KErrOverflow);
       
  2001 				return;
       
  2002 				}
       
  2003 			else if ( lengthOrError < KErrNone)
       
  2004 				{
       
  2005 				CompleteRequest(m, lengthOrError);
       
  2006 				return;
       
  2007 				}	
       
  2008 
       
  2009 			TInt r = m.ReadRemote(&pData,0);
       
  2010 			if (r==KErrNone)
       
  2011 				r = ThePasswordStore->WritePasswordData(pData);
       
  2012 			if(r != KErrNone)
       
  2013 				{
       
  2014 				CompleteRequest(m, r);
       
  2015 				return;
       
  2016 				}
       
  2017 
       
  2018 			r = QuickCheckStatus();
       
  2019 			if(r != KErrNone)
       
  2020 				{
       
  2021 				// Don't try to power up the device if it's not ready.
       
  2022 				// - Note that this isn't an error that needs to be returned to the client.
       
  2023 				CompleteRequest(m, KErrNone);
       
  2024 				return;
       
  2025 				}
       
  2026 
       
  2027 			break;
       
  2028 			}
       
  2029 		case DLocalDrive::EPasswordStoreLengthInBytes:
       
  2030 			{
       
  2031 			TInt length = ThePasswordStore->PasswordStoreLengthInBytes();
       
  2032 			TInt r = m.WriteRemoteRaw(&length,sizeof(TInt));
       
  2033 			CompleteRequest(m, r);
       
  2034 			return;
       
  2035 			}
       
  2036 		default:
       
  2037 			CHECK_RET(KErrNotSupported);
       
  2038 			CompleteRequest(m, KErrNotSupported);
       
  2039 			return;
       
  2040 		}
       
  2041 
       
  2042 	__KTRACE_OPT(KFAIL,Kern::Printf("mdrq %d",m.Id()));
       
  2043 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::HandleMsg state %d req %d",iMediaId,iState,m.Id()));
       
  2044 
       
  2045 	// if media driver already open, pass request through
       
  2046 	if (iState==EReady)
       
  2047 		{
       
  2048 		DoRequest(m);
       
  2049 		__TRACE_TIMING(0x101);
       
  2050 		return;
       
  2051 		}
       
  2052 
       
  2053 	// if open or close in progress, defer this message
       
  2054 	if (iState!=EClosed && iState!=EPoweredDown)
       
  2055 		{
       
  2056 #ifdef __DEMAND_PAGING__
       
  2057 		if (DMediaPagingDevice::PagingRequest(m))
       
  2058 			{
       
  2059 			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
       
  2060 			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2061 			__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
       
  2062 
       
  2063 			__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Deferring PageIn request 0x%08x because opening or closing",&m));
       
  2064 			iBody->iPagingDevice->SendToDeferredQ(&m);
       
  2065 			}
       
  2066 		else
       
  2067 #endif
       
  2068 		m.Forward(&iDeferred,EFalse);
       
  2069 		return;
       
  2070 		}
       
  2071 
       
  2072 	// nothing is open, so try to open something
       
  2073 	__ASSERT_ALWAYS(!iCurrentReq,LOCM_FAULT());
       
  2074 
       
  2075 #ifdef __DEMAND_PAGING__
       
  2076 
       
  2077 #ifdef BTRACE_PAGING_MEDIA
       
  2078 	if (DMediaPagingDevice::PagingRequest(m))
       
  2079 		BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInQuietlyDeferred,&m,iState,m.iValue);
       
  2080 #endif	// BTRACE_PAGING_MEDIA
       
  2081 
       
  2082 #ifdef _DEBUG
       
  2083 	__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
       
  2084 
       
  2085 	if (DMediaPagingDevice::PagingRequest(m))
       
  2086 		{
       
  2087 		__ASSERT_DEBUG(iPagingMedia,LOCM_FAULT());
       
  2088 		__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2089 		__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Page request 0x%08x received -> opening MD",&m));
       
  2090 		}
       
  2091 #endif	// _DEBUG
       
  2092 
       
  2093 #endif	// __DEMAND_PAGING__
       
  2094 
       
  2095 	iCurrentReq=&m;
       
  2096 	if(iState == EClosed)
       
  2097 		{
       
  2098 		iState=EPoweringUp1;
       
  2099 		}
       
  2100 	else if (iState == EPoweredDown)
       
  2101 		{
       
  2102 		iState=EPoweringUp2;
       
  2103 		}
       
  2104 
       
  2105 	TInt r=InitiatePowerUp();
       
  2106 	if (r==KErrNone || r==KErrServerBusy)
       
  2107 		{
       
  2108 		// wait for completion of power up request
       
  2109 		return;
       
  2110 		}
       
  2111 	if (r==KErrCompletion)
       
  2112 		r=KErrNone;		// device already powered up
       
  2113 	PowerUpComplete(r);
       
  2114 	}
       
  2115 
       
  2116 EXPORT_C TInt DPrimaryMediaBase::DoRequest(TLocDrvRequest& m)
       
  2117 /**
       
  2118 If the media exists, it tries to get the partition information if not there. 
       
  2119 It then passes on the request to the media driver by calling its Request( ) function. 
       
  2120 Then it completes the kernel thread message and the reference count of the thread is closed asynchronously.
       
  2121 
       
  2122 @param aRequest Encapsulates the request information received from the client
       
  2123 
       
  2124 @return KErrNone, if successful
       
  2125 	KErrNotReady, if missing partitions on removable media
       
  2126 	KErrNotSupported, if missing partitions on fixed media
       
  2127 	KErrArgument Out of range argument ,encapsulated in Local drive request , passed while checking and adjusting for partition
       
  2128 	KErrEOF, Reached the end of file
       
  2129 	KErrBadDescriptor, if request encapsulates a bad descriptor
       
  2130 	Otherwise, one of the other system wide error codes.
       
  2131 
       
  2132 */
       
  2133 	{
       
  2134 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DPrimaryMediaBase::DoRequest %d",m.Id()));
       
  2135 	TLocDrv* pL=m.Drive();
       
  2136 	DMedia* media=pL->iMedia;
       
  2137 	TInt r=KErrNone;
       
  2138 
       
  2139 	// re-open this drive's media driver ?
       
  2140 	if (m.iValue == DLocalDrive::EForceMediaChange)
       
  2141 		{
       
  2142 		__ASSERT_DEBUG(((TUint) m.Pos()) == (TUint) KForceMediaChangeReOpenMediaDriver, LOCM_FAULT());
       
  2143 
       
  2144 		iCurrentReq=NULL;
       
  2145 
       
  2146 		TLocDrv* pL = m.Drive();
       
  2147 		DMedia* media = pL->iMedia;
       
  2148 		if (media && media->iDriver)
       
  2149 			CloseMediaDrivers(media);
       
  2150 
       
  2151 		iState=EOpening;
       
  2152 		StartOpenMediaDrivers();
       
  2153 
       
  2154 		NotifyClients(ETrue,pL);
       
  2155 		CompleteRequest(m, r);
       
  2156 		return r;
       
  2157 		}
       
  2158 
       
  2159 	if (!media || !media->iDriver || iState == EClosed)
       
  2160 		{
       
  2161 		// Return KErrNotReady for missing partitions on removable media
       
  2162 		// as opposed to KErrNotSupported for missing partitions on fixed media
       
  2163 		// since the latter don't exist whereas the former might exist at some time.
       
  2164 		TInt sock;
       
  2165 		r=IsRemovableDevice(sock) ? KErrNotReady : KErrNotSupported;
       
  2166 		}
       
  2167 
       
  2168 	iCurrentReq=&m;
       
  2169 	if (r==KErrNone)
       
  2170 		{
       
  2171 		if(iTotalPartitionsOpened == 0)
       
  2172 			{
       
  2173 			UpdatePartitionInfo();
       
  2174 			return KErrNone;
       
  2175 			}
       
  2176 		if (!(m.Flags() & TLocDrvRequest::EAdjusted))
       
  2177 			{
       
  2178 			// If this isn't the only partition, don't allow access to the whole media 
       
  2179 			if (iTotalPartitionsOpened > 1)
       
  2180 				m.DriverFlags() &= ~RLocalDrive::ELocDrvWholeMedia;
       
  2181 			r=m.CheckAndAdjustForPartition();
       
  2182 			}
       
  2183 		if (r==KErrNone)
       
  2184 			{
       
  2185 			r=media->iDriver->Request(m);
       
  2186 			if (r>0)
       
  2187 				{
       
  2188 				// defer request
       
  2189 #ifdef __DEMAND_PAGING__
       
  2190 				if (DMediaPagingDevice::PagingRequest(m))
       
  2191 					{
       
  2192 					__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
       
  2193 					__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
       
  2194 					__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2195 					__KTRACE_OPT2(KLOCDPAGING,KLOCDRV,Kern::Printf("Defer PageIn request 0x%08x",&m));
       
  2196 					DMediaPagingDevice* pagingdevice=iBody->iPagingDevice; 
       
  2197 
       
  2198 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2199 					TInt id=m.iValue;
       
  2200 					if (id==DMediaPagingDevice::ERomPageInRequest)
       
  2201 						{
       
  2202 						NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  2203 						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
       
  2204 							pagingdevice->iROMStats.iTotalReDeferrals++;
       
  2205 						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
       
  2206 							pagingdevice->iROMStats.iTotalSynchDeferredFromMainQ++;
       
  2207 						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  2208 						}
       
  2209 					else if (m.Flags() & TLocDrvRequest::ECodePaging)
       
  2210 						{
       
  2211 						NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  2212 						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
       
  2213 							pagingdevice->iCodeStats.iTotalReDeferrals++;
       
  2214 						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
       
  2215 							pagingdevice->iCodeStats.iTotalSynchDeferredFromMainQ++;
       
  2216 						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  2217 						}
       
  2218 					else if (m.Flags() & TLocDrvRequest::EDataPaging)
       
  2219 						{
       
  2220 						NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  2221 						if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)
       
  2222 							pagingdevice->iDataStats.iTotalReDeferrals++;
       
  2223 						else if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)
       
  2224 							pagingdevice->iDataStats.iTotalSynchDeferredFromMainQ++;
       
  2225 						NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  2226 						}
       
  2227 #endif
       
  2228 					pagingdevice->SendToDeferredQ(&m);
       
  2229 					}
       
  2230 				else
       
  2231 #endif
       
  2232 					m.Forward(&iDeferred,EFalse);
       
  2233 				r=KErrNone;
       
  2234 				}
       
  2235 #if defined(__DEMAND_PAGING__) && defined(_DEBUG)
       
  2236 			else if (r == KErrNone && DMediaPagingDevice::PagingRequest(m))
       
  2237 				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("PageIn req 0x%08x completing asynchronously",&m));
       
  2238 #endif
       
  2239 			}
       
  2240 		}
       
  2241 
       
  2242 	if (r!=KErrNone && iCurrentReq)
       
  2243 		{
       
  2244 		TInt s=(r==KErrCompletion)?KErrNone:r;
       
  2245 		CHECK_RET(s);
       
  2246 
       
  2247 #ifdef __DEMAND_PAGING__
       
  2248 		// got here because media driver cannot service or defer this request or did service it synchronously
       
  2249 		if (DMediaPagingDevice::PagingRequest(m))
       
  2250 			{
       
  2251 			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
       
  2252 			__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
       
  2253 			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2254 			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("media driver cannot service or defer PageIn request 0x%08x or serviced it synchronously (%d)",&m, s));
       
  2255 			iBody->iPagingDevice->CompleteRequest(&m, s);
       
  2256 			}
       
  2257 		else
       
  2258 #endif
       
  2259 
       
  2260 		CompleteRequest(m, s);
       
  2261 
       
  2262 		}
       
  2263 
       
  2264 	iCurrentReq=NULL;
       
  2265 	return r;
       
  2266 	}
       
  2267 
       
  2268 EXPORT_C void DPrimaryMediaBase::PowerUpComplete(TInt anError)
       
  2269 /**
       
  2270 Called after the device is powered up or there is some error while powering up the device. 
       
  2271 If there is an error powering up the devices then it just completes the current running requests with an error 
       
  2272 and also completes the outstanding requests on the iDeferred message queue by calling SetClosed( ).
       
  2273 If the device is powered up OK then it either opens the media drivers 
       
  2274 and if they are already open then it handles the current/pending requests.
       
  2275 
       
  2276 @param anError Error code to be passed on while completing outstanding requests.
       
  2277 */
       
  2278 	{
       
  2279 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::PowerUpComplete err %d iState %d",iMediaId,anError,iState));
       
  2280 	if (anError!=KErrNone)
       
  2281 		{
       
  2282 		// error powering up device
       
  2283 		if (iState==EPoweringUp1 || iState==EPoweringUp2)
       
  2284 			SetClosed(anError);
       
  2285 		return;
       
  2286 		}
       
  2287 
       
  2288 	// Powered up OK - now open media drivers
       
  2289 	if (iState==EPoweringUp1)
       
  2290 		{
       
  2291 		iState=EOpening;
       
  2292 		StartOpenMediaDrivers();
       
  2293 		}
       
  2294 	else if (iState==EPoweringUp2)
       
  2295 		{
       
  2296 		// media is powered up and ready, so handle the current/pending requests
       
  2297 		MediaReadyHandleRequest();
       
  2298 		}
       
  2299 	}
       
  2300 
       
  2301 void DPrimaryMediaBase::CloseMediaDrivers(DMedia* aMedia)
       
  2302 	{
       
  2303 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
       
  2304 
       
  2305 	// we mustn't ever close the media driver if it's responsible for data paging as re-opening the drive
       
  2306 	// would involve memory allocation which might cause deadlock if the kernel heap were to grow
       
  2307 #ifdef __DEMAND_PAGING__
       
  2308 	if (DataPagingDfcQ(this))
       
  2309 		{
       
  2310 		__KTRACE_OPT(KLOCDRV,Kern::Printf("CloseMediaDrivers aborting for data paging media %08X", this));
       
  2311 		return;
       
  2312 		}
       
  2313 #endif
       
  2314 
       
  2315 	TInt i;
       
  2316 	for (i=0; i<KMaxLocalDrives; i++)
       
  2317 		{
       
  2318 		TLocDrv* pL=TheDrives[i];
       
  2319 		if (pL && pL->iPrimaryMedia==this)
       
  2320 			{
       
  2321 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d",i));
       
  2322 			if (aMedia == NULL || pL->iMedia == aMedia)
       
  2323 				{
       
  2324 				pL->iMedia=NULL;
       
  2325 				}
       
  2326 			}
       
  2327 		}
       
  2328 	for (i=iLastMediaId; i>=iMediaId; i--)
       
  2329 		{
       
  2330 		DMedia* pM=TheMedia[i];
       
  2331 		if (aMedia == NULL || pM == aMedia)
       
  2332 			{
       
  2333 			DMediaDriver* pD=pM->iDriver;
       
  2334 			pM->iDriver=NULL;
       
  2335 			__KTRACE_OPT(KLOCDRV,Kern::Printf("DMedia[%d] @ %08x Driver @ %08x",i,pM,pD));
       
  2336 			if (pD)
       
  2337 				pD->Close();
       
  2338 			}
       
  2339 		}
       
  2340 	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase(%d)::CloseMediaDrivers",iMediaId));
       
  2341 	}
       
  2342 
       
  2343 void DPrimaryMediaBase::StartOpenMediaDrivers()
       
  2344 	{
       
  2345 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::StartOpenMediaDrivers",iMediaId));
       
  2346 	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
       
  2347 
       
  2348 	// Get a list of all currently loaded media drivers
       
  2349 	// Most media drivers do not make use of the pointer iMountInfo.iInfo when 
       
  2350 	// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList(). 
       
  2351 	// However, a group of media drivers sharing the same id (passed in iDevice) may use 
       
  2352 	// the additional information pointed to by iMountInfo.iInfo to distinguish 
       
  2353 	// group members. This information is passed when the media driver is registered 
       
  2354 	// using LocDrv::RegisterMediaDevice().
       
  2355 	TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
       
  2356 	if (r!=KErrNone)
       
  2357 		{
       
  2358 		// out of memory or no driver exists
       
  2359 		SetClosed(r);
       
  2360 		return;
       
  2361 		}
       
  2362 
       
  2363 	// Go through them starting with highest priority
       
  2364 	iNextMediaId=iMediaId;
       
  2365 	iBody->iPhysDevIndex=iPhysDevArray.Count()-1;
       
  2366 	iTotalPartitionsOpened=0;
       
  2367 	iMediaDriversOpened=0;
       
  2368 	iNextMediaDriver=NULL;
       
  2369 	OpenNextMediaDriver();
       
  2370 	}
       
  2371 
       
  2372 void DPrimaryMediaBase::OpenNextMediaDriver()
       
  2373 	{
       
  2374 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::OpenNextMediaDriver, this %x mediaId %d iBody->iPhysDevIndex %d",iNextMediaId, this, iMediaId, iBody->iPhysDevIndex));
       
  2375 
       
  2376 	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
       
  2377 	SPhysicalDeviceEntry& e=iPhysDevArray[iBody->iPhysDevIndex];
       
  2378 	DPhysicalDevice* pD=e.iPhysicalDevice;
       
  2379 
       
  2380 	iState = EOpening;
       
  2381 
       
  2382 	DMedia* pM=TheMedia[iNextMediaId];
       
  2383 	if (pM && pM->iDriver != NULL)
       
  2384 		{
       
  2385 		iNextMediaDriver = pM->iDriver;
       
  2386 		DoOpenMediaDriverComplete(KErrNone);
       
  2387 		return;
       
  2388 		}
       
  2389 
       
  2390 	// this may be asynchronous
       
  2391 	TInt s=pD->Create( (DBase*&)iNextMediaDriver, iMediaId,  (TDesC8*) &iMountInfo, ver);
       
  2392 
       
  2393 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,e.iPriority,s));
       
  2394 	if (s!=KErrNone)
       
  2395 		{
       
  2396 		iAsyncErrorCode=s;
       
  2397 		iAsyncDfc.Enque();
       
  2398 		}
       
  2399 	}
       
  2400 
       
  2401 // Called when a media driver has responded to the Open request
       
  2402 void DPrimaryMediaBase::DoOpenMediaDriverComplete(TInt anError)
       
  2403 	{
       
  2404 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoOpenMediaDriverComplete error %d iNextMediaDriver %x",iNextMediaId,anError,iNextMediaDriver));
       
  2405 
       
  2406 	if (anError!=KErrNone)
       
  2407 		{
       
  2408 		DMediaDriver* md = iNextMediaDriver;
       
  2409 		iNextMediaDriver = NULL;
       
  2410 		if (md)
       
  2411 			md->Close();
       
  2412 		}
       
  2413 	if (anError==KErrNotReady || anError==KErrNoMemory)
       
  2414 		{
       
  2415 		// if it's not ready or we're out of memory, abort
       
  2416 		CloseMediaDrivers();
       
  2417 		SetClosed(anError);
       
  2418 		return;
       
  2419 		}
       
  2420 	if (anError==KErrNone)
       
  2421 		{
       
  2422 		DMedia* pM=TheMedia[iNextMediaId];
       
  2423 		pM->iDriver=iNextMediaDriver;
       
  2424 		DPhysicalDevice*& pD=iPhysDevArray[iBody->iPhysDevIndex].iPhysicalDevice;
       
  2425 		iNextMediaDriver->iPhysicalDevice=pD;
       
  2426 		pD=NULL;	// so it won't be closed when we tidy up
       
  2427 		++iMediaDriversOpened;
       
  2428 		}
       
  2429 
       
  2430 	// if no error, read partition info on media
       
  2431 	iState = EReadPartitionInfo;
       
  2432 
       
  2433 	if (anError == KErrNone)
       
  2434 		{
       
  2435 		DMedia* pM=TheMedia[iNextMediaId];
       
  2436 		TInt r = pM->iDriver->PartitionInfo(pM->iPartitionInfo);
       
  2437 		if (r!=KErrNone)
       
  2438 			{
       
  2439 			if (r==KErrCompletion)
       
  2440 				r=KErrNone;
       
  2441 			DoPartitionInfoComplete(r);
       
  2442 			}
       
  2443 		}
       
  2444 	else
       
  2445 		{
       
  2446 		DoPartitionInfoComplete(anError);
       
  2447 		}
       
  2448 	}
       
  2449 
       
  2450 void DPrimaryMediaBase::DoPartitionInfoComplete(TInt anError)
       
  2451 	{
       
  2452 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::DoPartitionInfoComplete error %d",iNextMediaId,anError));
       
  2453 
       
  2454 	DMedia* pM=TheMedia[iNextMediaId];
       
  2455 	if (anError==KErrNone || anError == KErrLocked)
       
  2456 		{
       
  2457 		// successfully read partition info
       
  2458 		iTotalPartitionsOpened+=pM->PartitionCount();
       
  2459 		}
       
  2460 	else
       
  2461 		{
       
  2462 		// couldn't read partition info or driver failed to open
       
  2463 		if (pM->iDriver)
       
  2464 			{
       
  2465 #ifdef __DEMAND_PAGING__
       
  2466 			if (DataPagingDfcQ(this))
       
  2467 				{
       
  2468 				__KTRACE_OPT(KLOCDRV,Kern::Printf("DoPartitionInfoComplete(%d) Close Media Driver aborted for data paging media %08X", this));
       
  2469 				}
       
  2470 			else
       
  2471 #endif
       
  2472 				{
       
  2473 				pM->iDriver->Close();
       
  2474 				pM->iDriver=NULL;
       
  2475 				}
       
  2476 			}
       
  2477 		if (anError==KErrNotReady || anError==KErrNoMemory)
       
  2478 			{
       
  2479 			// if it's not ready or we're out of memory, or the drive is locked, abort
       
  2480 			CloseMediaDrivers();
       
  2481 			SetClosed(anError);
       
  2482 			return;
       
  2483 			}
       
  2484 		}
       
  2485 
       
  2486 	// Open next media driver, if there is one
       
  2487 	TBool complete = EFalse;
       
  2488 	if (++iNextMediaId>iLastMediaId)
       
  2489 		complete=ETrue;
       
  2490 	if (iBody->iPhysDevIndex==0)
       
  2491 		complete=ETrue;
       
  2492 	else
       
  2493 		iBody->iPhysDevIndex--;
       
  2494 	if (!complete)
       
  2495 		{
       
  2496 		OpenNextMediaDriver();
       
  2497 		return;
       
  2498 		}
       
  2499 
       
  2500 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d All media drivers open & partitions read",iMediaId));
       
  2501 	__KTRACE_OPT(KLOCDRV,Kern::Printf("%d media drivers opened",iMediaDriversOpened));
       
  2502 	if (iMediaDriversOpened==0)
       
  2503 		{
       
  2504 		SetClosed(KErrNotSupported);
       
  2505 		return;
       
  2506 		}
       
  2507 
       
  2508 	// we are now finished with media driver list
       
  2509 	iPhysDevArray.Close();
       
  2510 
       
  2511 	// Finished reading partition info
       
  2512 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase %d Read partition info complete",iMediaId));
       
  2513 	__KTRACE_OPT(KLOCDRV,Kern::Printf("%d total partitions",iTotalPartitionsOpened));
       
  2514 	if (iTotalPartitionsOpened==0)
       
  2515 		{
       
  2516 		SetClosed(KErrNotSupported);
       
  2517 		return;
       
  2518 		}
       
  2519 
       
  2520 	// work out mapping of drives to partitions/media
       
  2521 	TInt totalPartitions=iTotalPartitionsOpened;
       
  2522 	TInt id=iMediaId;	// start with primary media
       
  2523 	TInt partitionsOnThisMedia=PartitionCount();
       
  2524 	TInt partition=0;
       
  2525 	TInt j;
       
  2526 	for (j=0; j<KMaxLocalDrives; j++)
       
  2527 		{
       
  2528 		TLocDrv* pD=TheDrives[j];
       
  2529 		if (pD && pD->iPrimaryMedia==this)
       
  2530 			{
       
  2531 			if (totalPartitions==0)
       
  2532 				{
       
  2533 				pD->iMedia=NULL;
       
  2534 				continue;
       
  2535 				}
       
  2536 			if (partition==partitionsOnThisMedia)
       
  2537 				{
       
  2538 				id++;
       
  2539 				partition=0;
       
  2540 				partitionsOnThisMedia=TheMedia[id]->PartitionCount();
       
  2541 				}
       
  2542 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d = Media %d Partition %d",j,id,partition));
       
  2543 			pD->iMedia=TheMedia[id];
       
  2544 			pD->iPartitionNumber=partition;
       
  2545 			memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
       
  2546 			partition++;
       
  2547 			totalPartitions--;
       
  2548 			}
       
  2549 		}
       
  2550 
       
  2551 	// media is now ready - handle current or deferred requests
       
  2552 	MediaReadyHandleRequest();
       
  2553 	}
       
  2554 
       
  2555 void DPrimaryMediaBase::MediaReadyHandleRequest()
       
  2556 	{
       
  2557 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase::MediaReadyHandleRequest() this %x", this));
       
  2558 	iState = EReady;
       
  2559 
       
  2560 	// now we can process the current request
       
  2561 	// careful - thread may have exited while we were powering up
       
  2562 	if (iCurrentReq)
       
  2563 		{
       
  2564 		DoRequest(*iCurrentReq);	// this sets iCurrentReq=NULL
       
  2565 		}
       
  2566 
       
  2567 	// see if we can process any other requests concurrently
       
  2568 	RunDeferred();
       
  2569 	}
       
  2570 
       
  2571 void DPrimaryMediaBase::UpdatePartitionInfo()
       
  2572 	{
       
  2573 	iState=EReadPartitionInfo;
       
  2574 	iNextMediaId=iMediaId;
       
  2575 	DMedia* pM=TheMedia[iNextMediaId];
       
  2576 	TInt r=pM->iDriver->PartitionInfo(pM->iPartitionInfo);
       
  2577 	if (r!=KErrNone)
       
  2578 		{
       
  2579 		if (r==KErrCompletion)
       
  2580 			r=KErrNone;
       
  2581 		DoPartitionInfoComplete(r);
       
  2582 		}
       
  2583 	}
       
  2584 
       
  2585 void DPrimaryMediaBase::CompleteCurrent(TInt anError)
       
  2586 	{
       
  2587 	if (iCurrentReq)
       
  2588 		{
       
  2589 		CHECK_RET(anError);
       
  2590 #ifdef __DEMAND_PAGING__
       
  2591 		// got here because it was powered down when powering up, or failed powering up or failed opening MD or got media change
       
  2592 		if (DMediaPagingDevice::PagingRequest(*iCurrentReq))
       
  2593 			{
       
  2594 			__ASSERT_ALWAYS(iPagingMedia,LOCM_FAULT());
       
  2595 			__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2596 			__ASSERT_ALWAYS( ((iCurrentReq->Flags() & TLocDrvRequest::ECodePaging) == 0) || (iCurrentReq->Drive()->iPagingDrv), LOCM_FAULT());
       
  2597 
       
  2598 			__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"));
       
  2599 			iBody->iPagingDevice->CompleteRequest(iCurrentReq, anError);
       
  2600 			}
       
  2601 		else
       
  2602 #endif
       
  2603 		CompleteRequest(*iCurrentReq, anError);
       
  2604 		iCurrentReq=NULL;
       
  2605 		}
       
  2606 	}
       
  2607 
       
  2608 
       
  2609 void DPrimaryMediaBase::CompleteRequest(TLocDrvRequest& aMsg, TInt aResult)
       
  2610 	{
       
  2611 	aMsg.Complete(aResult,EFalse);
       
  2612 	}
       
  2613 
       
  2614 EXPORT_C void DPrimaryMediaBase::RunDeferred()
       
  2615 /**
       
  2616 Runs deferred Requests. Initiated from DPrimaryMediaBase::PowerUpComplete() function 
       
  2617 to see if any other requests can be processed concurrently. 
       
  2618 Can also be called from DPrimaryMediaBase::NotifyPowerDown 
       
  2619 or DPrimaryMediaBase::NotifyEmergencyPowerDown() function or DMediaDriver::Complete()
       
  2620 */
       
  2621 	{
       
  2622 	// Do nothing if an open or close is in progress - this might be the case, for example, 
       
  2623 	// if a EForceMediaChange request (with the  KForceMediaChangeReOpenMediaDriver flag) 
       
  2624 	// has recently been processed
       
  2625 	if (iState!=EReady && iState!=EClosed && iState!=EPoweredDown)
       
  2626 		return;
       
  2627 
       
  2628 	// rerun deferred requests;
       
  2629 #ifdef __DEMAND_PAGING__
       
  2630 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2631 	TInt countROM=0;
       
  2632 	TInt countCode=0;
       
  2633 #endif
       
  2634 
       
  2635 	if(iPagingMedia)
       
  2636 		{
       
  2637 		__ASSERT_DEBUG(iBody->iPagingDevice,LOCM_FAULT());
       
  2638 		if(iBody->iPagingDevice->iEmptyingQ & DMediaPagingDevice::EDeferredQ)		// if already emptying deferred page in queue, don't reenter
       
  2639 			{
       
  2640 			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying deferred queue"));
       
  2641 			return;
       
  2642 			}
       
  2643 
       
  2644 		DMediaPagingDevice* pagingdevice=iBody->iPagingDevice;
       
  2645 		TLocDrvRequest* pL = (TLocDrvRequest*) pagingdevice->iDeferredQ.Last();
       
  2646 		if(pL)
       
  2647 			{
       
  2648 			pagingdevice->iEmptyingQ|= DMediaPagingDevice::EDeferredQ;			// prevent reentering when already emptying this queue
       
  2649 			TLocDrvRequest* pM=NULL;
       
  2650 			while (pM != pL && (pM = (TLocDrvRequest*) pagingdevice->iDeferredQ.Poll()) != NULL)	// synchronously empty deferred queue but ignore re-deferrals
       
  2651 				{
       
  2652 				__ASSERT_ALWAYS( DMediaPagingDevice::PagingRequest(*pL), LOCM_FAULT() );
       
  2653 
       
  2654 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2655 				(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
       
  2656 				if(pM==pL)
       
  2657 					{
       
  2658 					NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  2659 					if(pM->iValue==DMediaPagingDevice::ERomPageInRequest && pagingdevice->iROMStats.iMaxReqsInDeferred<countROM)
       
  2660 						pagingdevice->iROMStats.iMaxReqsInDeferred=countROM;
       
  2661 					else if ((pM->Flags() & TLocDrvRequest::ECodePaging) && pagingdevice->iCodeStats.iMaxReqsInDeferred<countCode)
       
  2662 							pagingdevice->iCodeStats.iMaxReqsInDeferred=countCode;
       
  2663 					else if ((pM->Flags() & TLocDrvRequest::EDataPaging) && pagingdevice->iDataStats.iMaxReqsInDeferred<countCode)
       
  2664 							pagingdevice->iDataStats.iMaxReqsInDeferred=countCode;
       
  2665 					NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  2666 					}
       
  2667 #endif
       
  2668 				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x, last in deferred queue 0x%08x",pM,pL));
       
  2669 #ifdef BTRACE_PAGING_MEDIA
       
  2670 				BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferredReposted,pM,pM->iValue);
       
  2671 #endif
       
  2672 				// if Page In requests are synchronous this services them all in sequence, 
       
  2673 				// if they're asynch it re-defers them
       
  2674 				DoRequest(*(TLocDrvRequest*)pM);	
       
  2675 				}
       
  2676 			pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EDeferredQ;
       
  2677 			}
       
  2678 
       
  2679 		// the reason we now try an empty the main Page In queue is there is at least one type of Page In request 
       
  2680 		// serviced synchronously in which case when we empty the deferred Page In queue as above, received Page In 
       
  2681 		// requests are left in the main queue (not deferred) and we don't want to start processing deferred normal 
       
  2682 		// requests before these Page In requests. If all deferred normal requests are synchronous, the received Page 
       
  2683 		// In requests will have to wait until all are serviced. NB: requests may be deferred even if the MD services 
       
  2684 		// all requests synchronously, but runs background tasks that cannot be interrupted. In this last case the 
       
  2685 		// normal deferred queue may have some very long latency requests.
       
  2686 		if(pagingdevice->iEmptyingQ & DMediaPagingDevice::EMainQ)	// already emptying main Page In queue, skip (any Page In requests will be deferred)
       
  2687 			{
       
  2688 			__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Already emptying main queue"));
       
  2689 			return;
       
  2690 			}
       
  2691 	
       
  2692 		TLocDrvRequest* pM=NULL;
       
  2693 		if (!pagingdevice->iMainQ.iReady)	// if it's ready, then queue is empty
       
  2694 			{
       
  2695 			pM = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
       
  2696 			pagingdevice->iMainQ.iMessage = NULL;
       
  2697 			if (pM == NULL)
       
  2698 				pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll();
       
  2699 			}
       
  2700 
       
  2701 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2702 		countROM = countCode=0;
       
  2703 #endif
       
  2704 		if(pM)
       
  2705 			{
       
  2706 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2707 			__e32_atomic_add_ord32(&pagingdevice->iROMStats.iTotalSynchEmptiedMainQ, 1);
       
  2708 #endif
       
  2709 			pagingdevice->iEmptyingQ|=DMediaPagingDevice::EMainQ;
       
  2710 			for ( ; pM != NULL; pM = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
       
  2711 				{
       
  2712 				__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*pM), LOCM_FAULT());
       
  2713 
       
  2714 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2715 				(pM->iValue==DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
       
  2716 #endif
       
  2717 
       
  2718 				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("RunDeferred: process req 0x%08x",pM));
       
  2719 				DoRequest(*(TLocDrvRequest*)pM);	// if Page In requests are synchronous this services them all in sequence, if they're asynch it defers them
       
  2720 				}
       
  2721 
       
  2722 			pagingdevice->iEmptyingQ&= ~DMediaPagingDevice::EMainQ;
       
  2723 
       
  2724 
       
  2725 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  2726 			NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  2727 			pagingdevice->iROMStats.iTotalSynchServicedFromMainQ+=countROM;
       
  2728 			if(pagingdevice->iROMStats.iMaxReqsInPending<countROM)
       
  2729 				pagingdevice->iROMStats.iMaxReqsInPending=countROM;
       
  2730 			pagingdevice->iCodeStats.iTotalSynchServicedFromMainQ+=countCode;
       
  2731 			if(pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
       
  2732 				pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
       
  2733 			NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  2734 #endif
       
  2735 			}	// if (pM)
       
  2736 		}	// 	if(iPagingMedia)
       
  2737 #endif
       
  2738 	if (iRunningDeferred)
       
  2739 		return;
       
  2740 	TMessageBase* pL = iDeferred.Last();
       
  2741 	if (!pL)
       
  2742 		return;	// no deferred requests
       
  2743 	iRunningDeferred=1;
       
  2744 	TMessageBase* pM=NULL;
       
  2745 
       
  2746 	while( pM != pL && (pM=iDeferred.Poll()) != NULL)	// stop after processing last one (requests may be re-deferred)
       
  2747 		DoRequest(*(TLocDrvRequest*)pM);
       
  2748 	iRunningDeferred=0;
       
  2749 	}
       
  2750 
       
  2751 void DPrimaryMediaBase::SetClosed(TInt anError)
       
  2752 	{
       
  2753 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::SetClosed error %d",iMediaId,anError));
       
  2754 	CHECK_RET(anError);
       
  2755 
       
  2756 	// cancel DMediaDriver::OpenMediaDriverComplete() / DMediaDriver::PartitionInfoComplete() DFC
       
  2757 	iAsyncDfc.Cancel();
       
  2758 
       
  2759 	iDeferred.CompleteAll(anError);
       
  2760 
       
  2761 #ifdef __DEMAND_PAGING__
       
  2762 	if(iPagingMedia)
       
  2763 		iBody->iPagingDevice->iDeferredQ.CompleteAll(anError);
       
  2764 #endif
       
  2765 
       
  2766 	CompleteCurrent(anError);
       
  2767 
       
  2768 	
       
  2769 
       
  2770 	if (iState==EOpening)
       
  2771 		iPhysDevArray.Close();
       
  2772 
       
  2773 	iState = EClosed;
       
  2774 
       
  2775 	iWaitMedChg.CompleteAll(KErrNone);
       
  2776 	}
       
  2777 
       
  2778 void DPrimaryMediaBase::NotifyClients(TBool aMediaChange,TLocDrv* aLocDrv)
       
  2779 
       
  2780 //
       
  2781 // Notify all clients of a media change or power-down event
       
  2782 //
       
  2783 	{
       
  2784 	SDblQueLink* pL=iConnectionQ.iA.iNext;
       
  2785 	while (pL!=&iConnectionQ.iA)
       
  2786 		{
       
  2787 		DLocalDrive* pD=_LOFF(pL,DLocalDrive,iLink);
       
  2788 		// Issue the notification if the caller wants to notify all drives (aLocDrv == NULL) or 
       
  2789 		// the specified drive matches this one
       
  2790 		if (aLocDrv == NULL || aLocDrv == pD->iDrive)
       
  2791 			pD->NotifyChange(*this, aMediaChange);
       
  2792 		pL=pL->iNext;
       
  2793 		}
       
  2794 	}
       
  2795 
       
  2796 EXPORT_C void DPrimaryMediaBase::NotifyMediaChange()
       
  2797 /**
       
  2798 Closes all media drivers on this device and notifies all connections that media change has occurred 
       
  2799 and completes any outstanding requests with KErrNotReady. 
       
  2800 This also completes any force media change requests with KErrNone.
       
  2801 */
       
  2802 	{
       
  2803 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyMediaChange state %d",iMediaId,iState));
       
  2804 
       
  2805 	TInt state=iState;
       
  2806 
       
  2807 	__ASSERT_DEBUG(iBody, LOCM_FAULT());
       
  2808 
       
  2809 #ifdef __DEMAND_PAGING__
       
  2810 	iBody->iMediaChanges++;
       
  2811 
       
  2812 	// As data paging media never close, need to ensure the media driver cancels
       
  2813 	// any requests it owns as the stack may be powered down by DPBusPrimaryMedia::ForceMediaChange().
       
  2814 	// DMediaDriver::NotifyPowerDown() should do this
       
  2815 	if(DataPagingDfcQ(this))
       
  2816 		NotifyPowerDown();
       
  2817 #endif
       
  2818 
       
  2819 	// complete any outstanding requests with KErrNotReady
       
  2820 	// and any force media change requests with KErrNone
       
  2821 	SetClosed(KErrNotReady);
       
  2822 
       
  2823 	// close all media drivers on this device
       
  2824 	if (state>=EOpening)
       
  2825 		{
       
  2826 		CloseMediaDrivers();
       
  2827 		}
       
  2828 
       
  2829 	// notify all connections that media change has occurred
       
  2830 	NotifyClients(ETrue);
       
  2831 
       
  2832 	// complete any force media change requests
       
  2833 	iWaitMedChg.CompleteAll(KErrNone);
       
  2834 	}
       
  2835 
       
  2836 
       
  2837 EXPORT_C void DPrimaryMediaBase::NotifyPowerDown()
       
  2838 /**
       
  2839 Called on machine power-down. Notifies all media drivers on this device. 
       
  2840 If device is not ready then it completes current requests but leaves other outstanding requests
       
  2841 If ready, media driver should complete current request.
       
  2842 
       
  2843 */
       
  2844 	{
       
  2845 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPowerDown state %d",iMediaId,iState));
       
  2846 
       
  2847 	TInt id;
       
  2848 	TBool allPersistent = ETrue;
       
  2849 	TBool allOpen = ETrue;
       
  2850 
       
  2851 	 // notify all media drivers on this device
       
  2852 	for (id=iMediaId; id<=iLastMediaId; id++)
       
  2853 		{
       
  2854 		DMedia* pM = TheMedia[id];
       
  2855 		DMediaDriver* pD = pM->iDriver; 
       
  2856 		
       
  2857 		if ((pD) && (iState==EReady || iState==EReadPartitionInfo || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering))
       
  2858 			pD->NotifyPowerDown();
       
  2859 
       
  2860 		if (pD == NULL || pD->iPhysicalDevice == NULL)
       
  2861 			allOpen = EFalse;
       
  2862 		else if (pD->iPhysicalDevice->Info(DPhysicalDevice::EMediaDriverPersistent, NULL) != KErrNone)
       
  2863 			{
       
  2864 			// We must NOT destroy the media driver if this media is responsible for data paging as 
       
  2865 			// re-opening the media driver would involve memory allocation which might cause a deadlock
       
  2866 #ifdef __DEMAND_PAGING__
       
  2867 			__ASSERT_ALWAYS(!DataPagingDfcQ(this), LOCM_FAULT());
       
  2868 #endif
       
  2869 			allPersistent = EFalse;
       
  2870 			}
       
  2871 		}
       
  2872 
       
  2873 	__KTRACE_OPT(KLOCDRV,Kern::Printf("allPersistent(%d)::allOpen %d",allPersistent, allOpen));
       
  2874 
       
  2875 	if (allPersistent && allOpen && iState == EReady)
       
  2876 		{
       
  2877 		//
       
  2878 		// The EPoweredDown state indicates that the media is powered down, but the media driver still exists.
       
  2879 		//
       
  2880 		//  - This allows the media driver to still be accessed (ie - to determine driver capabilities) without
       
  2881 		//    the need to power up the device, which can be a lengthy operation.
       
  2882 		//
       
  2883 		//  - NOTE : This will need re-visiting if we ever re-enable standby mode on a platform that is not capable
       
  2884 		//           of detecting door interrupts while in standby.  In such a scenario, problems could occur as 
       
  2885 		//			the device capabilities may change without the local media subsystem recognising.
       
  2886 		//
       
  2887 		iState=EPoweredDown;
       
  2888 		}
       
  2889 	else
       
  2890 		{
       
  2891 		CloseMediaDrivers();
       
  2892 		SetClosed(KErrNotReady);
       
  2893 		}
       
  2894 
       
  2895 	NotifyClients(EFalse);
       
  2896 	}
       
  2897 
       
  2898 
       
  2899 EXPORT_C void DPrimaryMediaBase::NotifyPsuFault(TInt anError)
       
  2900 /**
       
  2901 Closes all media drivers on this device and completes any outstanding requests with error code.
       
  2902 @param anError Error code to be passed on while closing media drivers and completing outstanding requests.
       
  2903 */
       
  2904 
       
  2905 	{
       
  2906 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyPsuFault state %d, err %d",iMediaId,iState,anError));
       
  2907 
       
  2908 	if (iState>=EOpening)
       
  2909 		{
       
  2910 		CloseMediaDrivers();
       
  2911 		}
       
  2912 
       
  2913 	// complete any outstanding requests with error
       
  2914 	SetClosed(anError);
       
  2915 	}
       
  2916 
       
  2917 EXPORT_C void DPrimaryMediaBase::NotifyEmergencyPowerDown()
       
  2918 /**
       
  2919 Called on emergency power down. Notifies all media drivers on this device. 
       
  2920 If it is not in a ready state then it completes the current request but leaves other outstanding requests.
       
  2921 If it is ready then the media driver should complete the current request. 
       
  2922 It closes all media drivers and notifies all clients of a power down event.
       
  2923 */
       
  2924 	{
       
  2925 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DPrimaryMediaBase(%d)::NotifyEmergencyPowerDown state %d",iMediaId,iState));
       
  2926 	TBool recover=EFalse;
       
  2927 	if (iState==EReady && iCritical!=0)
       
  2928 		{
       
  2929 		// check if emergency power recovery supported
       
  2930 		;
       
  2931 		}
       
  2932 	if (recover)
       
  2933 		{
       
  2934 		}
       
  2935 
       
  2936 	// else just return KErrAbort
       
  2937 	// notify all media drivers on this device
       
  2938 	if (iState==EReady || iState==EOpening || iState==EPoweringUp2 || iState==ERecovering)
       
  2939 		{
       
  2940 		TInt id;
       
  2941 		for (id=iMediaId; id<=iLastMediaId; id++)
       
  2942 			{
       
  2943 			DMedia* pM=TheMedia[id];
       
  2944 			DMediaDriver* pD=pM->iDriver;
       
  2945 			if (pD)
       
  2946 				pD->NotifyEmergencyPowerDown();
       
  2947 			}
       
  2948 		}
       
  2949 
       
  2950 	if (iState!=EReady)
       
  2951 		{
       
  2952 		// complete current request but leave other outstanding requests
       
  2953 		// if ready, media driver should complete current request
       
  2954 		CompleteCurrent(KErrNotReady);
       
  2955 		}
       
  2956 	CloseMediaDrivers();
       
  2957 	SetClosed(KErrNotReady);
       
  2958 	NotifyClients(EFalse);
       
  2959 	}
       
  2960 
       
  2961 EXPORT_C void DPrimaryMediaBase::NotifyMediaPresent()
       
  2962 /**
       
  2963 Notifies clients of a media change by calling NotifyClients ( ) function to indicate that media is present.
       
  2964 */
       
  2965 	{
       
  2966 	NotifyClients(ETrue);
       
  2967 	}
       
  2968 
       
  2969 EXPORT_C TInt DPrimaryMediaBase::DoInCritical()
       
  2970 /**
       
  2971 Flags the media driver as entering a critical part of its processing.
       
  2972 
       
  2973 In this context, critical means that the driver must be allowed to complete
       
  2974 its current activity.
       
  2975 For example, a request to power down the device must be deferred until
       
  2976 the driver exits the critical part.
       
  2977 
       
  2978 @return KErrNone, if the driver has been successfully flagged as being in
       
  2979         a critical part; otherwise, one of the other system-wide error codes.
       
  2980         The default implementation just returns KErrNone and can be overridden in the derived class
       
  2981 @see DPrimaryMediaBase::DoEndInCritical()
       
  2982 */
       
  2983 
       
  2984 	{
       
  2985 	return KErrNone;
       
  2986 	}
       
  2987 
       
  2988 EXPORT_C void DPrimaryMediaBase::DoEndInCritical()
       
  2989 /**
       
  2990 Flags the media driver as leaving a critical part of its processing.
       
  2991 
       
  2992 Default implementation does nothing
       
  2993 @see DPrimaryMediaBase::DoEndInCritical()
       
  2994 */
       
  2995 	{
       
  2996 	}
       
  2997 
       
  2998 TInt DPrimaryMediaBase::InCritical()
       
  2999 	{
       
  3000 	if (iCritical==0)
       
  3001 		{
       
  3002 		TInt r=DoInCritical();
       
  3003 		if (r!=KErrNone)
       
  3004 			return r;
       
  3005 		}
       
  3006 	++iCritical;
       
  3007 	return KErrNone;
       
  3008 	}
       
  3009 
       
  3010 void DPrimaryMediaBase::EndInCritical()
       
  3011 	{
       
  3012 	if (--iCritical==0)
       
  3013 		DoEndInCritical();
       
  3014 	}
       
  3015 
       
  3016 EXPORT_C void DPrimaryMediaBase::DeltaCurrentConsumption(TInt /*aCurrent*/)
       
  3017 /**
       
  3018 Sets the incremental value of current consumption to aCurrent.
       
  3019 The default implementation does nothing .
       
  3020 
       
  3021 @param aCurrent Delta Current in Milliamps
       
  3022 */
       
  3023 	{
       
  3024 	// default implementation
       
  3025 	}
       
  3026 
       
  3027 TInt DPrimaryMediaBase::OpenMediaDriver()
       
  3028 //
       
  3029 // Synchronous open for devices with no DFC queue (e.g. IRAM)
       
  3030 //
       
  3031 	{
       
  3032 	__KTRACE_OPT(KLOCDRV,Kern::Printf(">DPrimaryMediaBase:OpenMediaDriver-%d",iMediaId));
       
  3033 	TVersion ver(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
       
  3034 
       
  3035 	// Get a list of all currently loaded media drivers
       
  3036 	// Most media drivers do not make use of the pointer iMountInfo.iInfo when 
       
  3037 	// their Validate() procedures are called from RPhysicalDeviceArray::GetDriverList(). 
       
  3038 	// However, a group of media drivers sharing the same id (passed in iDevice) may use 
       
  3039 	// the additional information pointed to by iMountInfo.iInfo to distinguish 
       
  3040 	// group members. This information is passed when the media driver is registered 
       
  3041 	// using LocDrv::RegisterMediaDevice().
       
  3042 	TInt r=iPhysDevArray.GetDriverList(KLitMediaDriverName,iDevice,iMountInfo.iInfo,ver);
       
  3043 	if (r!=KErrNone)
       
  3044 		return r;
       
  3045 
       
  3046 	// Go through them starting with highest priority
       
  3047 	TInt totalPartitions=0;
       
  3048 	TInt c=iPhysDevArray.Count();	// can't be zero
       
  3049 	TInt i=c-1;
       
  3050 	r=KErrNotSupported;
       
  3051 	for (iNextMediaId=iMediaId; i>=0 && iNextMediaId<=iLastMediaId && r!=KErrNotReady; i--)
       
  3052 		{
       
  3053 		DPhysicalDevice* pD=iPhysDevArray[i].iPhysicalDevice;
       
  3054 		DMediaDriver *pM=NULL;
       
  3055 
       
  3056 		// try to open media driver
       
  3057 		TInt s=pD->Create( (DBase*&)pM, iMediaId, NULL, ver); 
       
  3058 
       
  3059 		__KTRACE_OPT(KLOCDRV,Kern::Printf("Media:Open-Opening %o(PRI:%d)-%d",pD,iPhysDevArray[i].iPriority,s));
       
  3060 		if (s!=KErrNone && pM)
       
  3061 			{
       
  3062 			pM->Close();
       
  3063 			pM=NULL;
       
  3064 			}
       
  3065 		if (s==KErrNotReady)
       
  3066 			{
       
  3067 			r=KErrNotReady; // If it isn't ready - nothing will open.
       
  3068 			break;
       
  3069 			}
       
  3070 		if (s==KErrNoMemory)
       
  3071 			{
       
  3072 			r=KErrNoMemory; // If we are out of memory, give up now
       
  3073 			break;
       
  3074 			}
       
  3075 		if (s==KErrNone)
       
  3076 			{
       
  3077 			// Found a media driver for this device - check for valid partitions.
       
  3078 			DMedia* media=TheMedia[iNextMediaId];
       
  3079 			s=pM->PartitionInfo(media->iPartitionInfo);
       
  3080 			if (s==KErrNone)
       
  3081 				{
       
  3082 				r=KErrNone;
       
  3083 				media->iDriver=pM;
       
  3084 				pM->iPhysicalDevice=pD;
       
  3085 				iPhysDevArray[i].iPhysicalDevice=NULL;	// so it won't be closed when we tidy up
       
  3086 				totalPartitions+=media->PartitionCount();
       
  3087 				}
       
  3088 			else
       
  3089 				pM->Close();
       
  3090 			}
       
  3091 		}
       
  3092 
       
  3093 	// we are now finished with media driver list
       
  3094 	iPhysDevArray.Close();
       
  3095 
       
  3096 	// if driver opened OK, work out mapping of drives to partitions/media
       
  3097 	if (r==KErrNone)
       
  3098 		{
       
  3099 		TInt id=iMediaId;	// start with primary media
       
  3100 		TInt partitionsOnThisMedia=PartitionCount();
       
  3101 		TInt partition=0;
       
  3102 		TInt j;
       
  3103 		for (j=0; j<KMaxLocalDrives; j++)
       
  3104 			{
       
  3105 			TLocDrv* pD=TheDrives[j];
       
  3106 			if (pD && pD->iPrimaryMedia==this)
       
  3107 				{
       
  3108 				if (totalPartitions==0)
       
  3109 					{
       
  3110 					pD->iMedia=NULL;
       
  3111 					continue;
       
  3112 					}
       
  3113 				if (partition==partitionsOnThisMedia)
       
  3114 					{
       
  3115 					id++;
       
  3116 					partition=0;
       
  3117 					partitionsOnThisMedia=TheMedia[id]->PartitionCount();
       
  3118 					}
       
  3119 				pD->iMedia=TheMedia[id];
       
  3120 				pD->iPartitionNumber=partition;
       
  3121 				memcpy(pD, pD->iMedia->iPartitionInfo.iEntry+partition, sizeof(TPartitionEntry));
       
  3122 				partition++;
       
  3123 				totalPartitions--;
       
  3124 				}
       
  3125 			}
       
  3126 		}
       
  3127 
       
  3128 	__KTRACE_OPT(KLOCDRV,Kern::Printf("<DPrimaryMediaBase:OpenMediaDriver-%d",r));
       
  3129 	return r;
       
  3130 	}
       
  3131 
       
  3132 #ifdef __DEMAND_PAGING__
       
  3133 // RequestCountInc()
       
  3134 // 
       
  3135 // Counts the number of outstanding requests
       
  3136 // For data-paging media, calls DPagingDevice::NotifyBusy() when count goes positive
       
  3137 //
       
  3138 void DPrimaryMediaBase::RequestCountInc()
       
  3139 	{
       
  3140 	__ASSERT_DEBUG(iBody, LOCM_FAULT());
       
  3141 	TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) 1);
       
  3142 //Kern::Printf("RCINC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
       
  3143 	if (oldVal == 0 && iBody->iPagingDevice)
       
  3144 		{
       
  3145 //Kern::Printf("RCINC: NotifyBusy()");
       
  3146 		iBody->iPagingDevice->NotifyBusy();
       
  3147 		}
       
  3148 	}
       
  3149 
       
  3150 // RequestCountDec()
       
  3151 // 
       
  3152 // Counts the number of outstanding requests
       
  3153 // For data-paging media, calls DPagingDevice::NotifyIdle() when count reaches zero
       
  3154 //
       
  3155 void DPrimaryMediaBase::RequestCountDec()
       
  3156 	{
       
  3157 	__ASSERT_DEBUG(iBody, LOCM_FAULT());
       
  3158 	TInt oldVal = (TInt) __e32_atomic_add_ord32(&iBody->iRequestCount, (TUint) -1);
       
  3159 //Kern::Printf("RCDEC: this %x cnt %d, old %d", this, iBody->iRequestCount, oldVal);
       
  3160 	if (oldVal == 1 && iBody->iPagingDevice)
       
  3161 		{
       
  3162 //Kern::Printf("RCDEC: NotifyIdle()");
       
  3163 		iBody->iPagingDevice->NotifyIdle();
       
  3164 		}
       
  3165 	__ASSERT_DEBUG(iBody->iRequestCount >= 0, LOCM_FAULT());
       
  3166 	}
       
  3167 #endif	// __DEMAND_PAGING__
       
  3168 
       
  3169 
       
  3170 TPartitionInfo::TPartitionInfo()
       
  3171 //
       
  3172 // Constructor
       
  3173 //
       
  3174 	{
       
  3175 	memclr(this, sizeof(TPartitionInfo));
       
  3176 	}
       
  3177 
       
  3178 #ifdef __DEMAND_PAGING__
       
  3179 
       
  3180 void pageInDfc(TAny* aPtr)
       
  3181 	{
       
  3182 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("pageInDfc"));
       
  3183 	DPrimaryMediaBase* primaryMedia=(DPrimaryMediaBase*)aPtr;
       
  3184 	__ASSERT_ALWAYS(primaryMedia && primaryMedia->iPagingMedia && primaryMedia->iBody->iPagingDevice,LOCM_FAULT());
       
  3185 	DMediaPagingDevice* pagingdevice=primaryMedia->iBody->iPagingDevice;
       
  3186 
       
  3187 	TLocDrvRequest* m = (TLocDrvRequest*) pagingdevice->iMainQ.iMessage;
       
  3188 	pagingdevice->iMainQ.iMessage = NULL;
       
  3189 
       
  3190 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3191 	if (!m)
       
  3192 		__e32_atomic_add_ord8(&pagingdevice->iROMStats.iTotalRunDry, 1);
       
  3193 #endif
       
  3194 
       
  3195 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3196 	TInt countROM=0;
       
  3197 	TInt countCode=0;
       
  3198 #endif
       
  3199 
       
  3200 	for ( ; m != NULL; m = (TLocDrvRequest*) pagingdevice->iMainQ.Poll())
       
  3201 		{
       
  3202 		__ASSERT_ALWAYS(DMediaPagingDevice::PagingRequest(*m), LOCM_FAULT());
       
  3203 
       
  3204 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3205 		(m->iValue == DMediaPagingDevice::ERomPageInRequest)?(countROM++):(countCode++);
       
  3206 #endif
       
  3207 		__KTRACE_OPT(KLOCDPAGING, Kern::Printf("pageInDfc: process request 0x%08x, last in queue 0x%08x",m, pagingdevice->iMainQ.Last()) );
       
  3208 
       
  3209 		primaryMedia->HandleMsg(*m);
       
  3210 		}
       
  3211 
       
  3212 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3213 	NKern::FMWait(&pagingdevice->iInstrumentationLock);
       
  3214 	if (pagingdevice->iROMStats.iMaxReqsInPending<countROM)
       
  3215 		pagingdevice->iROMStats.iMaxReqsInPending=countROM;
       
  3216 	if (pagingdevice->iCodeStats.iMaxReqsInPending<countCode)
       
  3217 		pagingdevice->iCodeStats.iMaxReqsInPending=countCode;
       
  3218 	NKern::FMSignal(&pagingdevice->iInstrumentationLock);
       
  3219 #endif
       
  3220 
       
  3221 	pagingdevice->iMainQ.Receive();	// allow reception of more messages
       
  3222 	}
       
  3223 
       
  3224 DMediaPagingDevice::DMediaPagingDevice(DPrimaryMediaBase* aPtr)
       
  3225 	:	iMainQ(pageInDfc, aPtr, NULL, KMaxDfcPriority),
       
  3226 		iDeferredQ(NULL, NULL, NULL, 0),			// callback never used
       
  3227 		iEmptyingQ(NULL),
       
  3228 		iInstrumentationLock()
       
  3229 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3230 		,iServicingROM(NULL), iServicingCode(NULL)
       
  3231 #endif
       
  3232 	{
       
  3233 	iPrimaryMedia = aPtr;
       
  3234 	if (iPrimaryMedia->iDfcQ)	// media driver has its own thread
       
  3235 		{
       
  3236 		iMainQ.SetDfcQ(iPrimaryMedia->iDfcQ);
       
  3237 		}
       
  3238 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3239 	memclr((TAny*)&iROMStats,sizeof(SMediaROMPagingConcurrencyInfo)+sizeof(SMediaCodePagingConcurrencyInfo));
       
  3240 #endif
       
  3241 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3242 	iROMBenchmarkData.iCount=iROMBenchmarkData.iTotalTime=iROMBenchmarkData.iMaxTime=0;
       
  3243 	iROMBenchmarkData.iMinTime = KMaxTInt;
       
  3244 	iCodeBenchmarkData.iCount=iCodeBenchmarkData.iTotalTime=iCodeBenchmarkData.iMaxTime=0;
       
  3245 	iCodeBenchmarkData.iMinTime = KMaxTInt;
       
  3246 	iDataInBenchmarkData.iCount=iDataInBenchmarkData.iTotalTime=iDataInBenchmarkData.iMaxTime=0;
       
  3247 	iDataInBenchmarkData.iMinTime = KMaxTInt;
       
  3248 	iDataOutBenchmarkData.iCount=iDataOutBenchmarkData.iTotalTime=iDataOutBenchmarkData.iMaxTime=0;
       
  3249 	iDataOutBenchmarkData.iMinTime = KMaxTInt;
       
  3250 #endif
       
  3251 
       
  3252 	iMainQ.Receive();
       
  3253 	}
       
  3254 
       
  3255 DMediaPagingDevice::~DMediaPagingDevice()
       
  3256 	{
       
  3257 
       
  3258 	if (iMountInfoDataLock)
       
  3259 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDataLock);
       
  3260 	
       
  3261 	if (iMountInfoDescHdrLock)
       
  3262 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescHdrLock);
       
  3263 	
       
  3264 	if (iMountInfoDescLenLock)
       
  3265 		ThePinObjectAllocator->ReleasePinObject((DPinObjectAllocator::SVirtualPinContainer*) iMountInfoDescLenLock);
       
  3266 	}
       
  3267 
       
  3268 
       
  3269 void DMediaPagingDevice::SendToMainQueueDfcAndBlock(TThreadMessage* aMsg)
       
  3270 	{
       
  3271 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("Send request 0x%08x to main queue",aMsg));
       
  3272 	__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EFree,LOCM_FAULT());	// check that message was previously completed or never queued
       
  3273 
       
  3274 	// if drive supports DMA, turn on Physical memory flag & sync memory
       
  3275 	TLocDrvRequest& m=*(TLocDrvRequest*)(aMsg);
       
  3276 	
       
  3277 	TLinAddr addr = (TLinAddr) m.RemoteDes();
       
  3278 	TInt len = I64LOW(m.Length());
       
  3279 
       
  3280 	TBool needSyncAfterRead = EFalse;
       
  3281 	if (m.Drive()->iDmaHelper)
       
  3282 		{
       
  3283 		m.Flags() |= TLocDrvRequest::EPhysAddr;
       
  3284 		if (m.Id() == DLocalDrive::EWrite)
       
  3285 			{
       
  3286 			Cache::SyncMemoryBeforeDmaWrite(addr, len);
       
  3287 			}
       
  3288 		else
       
  3289 			{
       
  3290 			Cache::SyncMemoryBeforeDmaRead(addr, len);
       
  3291 			needSyncAfterRead = ETrue;
       
  3292 			}
       
  3293 		}
       
  3294 
       
  3295 	// Count the number of outstanding requests if this is the data-paging media, so that
       
  3296 	// we can call DPagingDevice::NotifyBusy() / DPagingDevice::NotifyIdle()
       
  3297 	if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
       
  3298 		iPrimaryMedia->RequestCountInc();
       
  3299 
       
  3300 	aMsg->SendReceive(&iMainQ);
       
  3301 
       
  3302 #ifdef __DEMAND_PAGING__
       
  3303 	if ((m.Flags() & TLocDrvRequest::EBackgroundPaging) == 0)
       
  3304 		iPrimaryMedia->RequestCountDec();
       
  3305 #endif
       
  3306 
       
  3307 	if (needSyncAfterRead)
       
  3308 		{
       
  3309 		Cache::SyncMemoryAfterDmaRead(addr, len);
       
  3310 		}
       
  3311 
       
  3312 	
       
  3313 	// come back here when request is completed
       
  3314 	__ASSERT_DEBUG(aMsg->iState==TMessageBase::EFree,LOCM_FAULT());		// check message has been completed
       
  3315 	}
       
  3316 
       
  3317 void DMediaPagingDevice::SendToDeferredQ(TThreadMessage* aMsg)
       
  3318 	{
       
  3319 	// This queue is only accessed from MD thread
       
  3320 	__ASSERT_ALWAYS(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT());	// check that message was previously dequeued
       
  3321 #ifdef BTRACE_PAGING_MEDIA
       
  3322 	if(iEmptyingQ&DMediaPagingDevice::EDeferredQ)		// already deferring
       
  3323 		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInReDeferred,aMsg,aMsg->iValue);
       
  3324 	else
       
  3325 		BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInDeferred,aMsg,aMsg->iValue);
       
  3326 #endif
       
  3327 
       
  3328 	aMsg->Forward(&iDeferredQ, EFalse);
       
  3329 	}
       
  3330 
       
  3331 
       
  3332 void DMediaPagingDevice::CompleteRequest(TThreadMessage* aMsg, TInt aResult)
       
  3333 	{
       
  3334 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::CompleteRequest, request 0x%08x result %d", aMsg, aResult));
       
  3335 	__ASSERT_DEBUG(aMsg->iState==TMessageBase::EAccepted,LOCM_FAULT());
       
  3336 
       
  3337 #ifdef BTRACE_PAGING_MEDIA
       
  3338 	BTraceContext12(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInPagedIn,aMsg,aResult,aMsg->iValue);
       
  3339 #endif
       
  3340 
       
  3341 	iPrimaryMedia->CompleteRequest(*((TLocDrvRequest*) aMsg), aResult);
       
  3342 	}
       
  3343 
       
  3344 TInt DMediaPagingDevice::Read(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TInt aDrvNumber)
       
  3345 	{
       
  3346 	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
       
  3347 	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
       
  3348 	__ASSERT_CRITICAL
       
  3349 
       
  3350 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3351 	TUint32 bmStart = NKern::FastCounter();
       
  3352 #endif
       
  3353 
       
  3354 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3355 	TUint8* servicingCount;
       
  3356 	NKern::FMWait(&iInstrumentationLock);
       
  3357 	if(aDrvNumber == EDriveRomPaging)	// ROM paging
       
  3358 		{
       
  3359 		servicingCount = &iServicingROM;
       
  3360 		if(iServicingROM)
       
  3361 			iROMStats.iTotalConcurrentReqs++;
       
  3362 		if(!(++iServicingROM))
       
  3363 			{
       
  3364 			iServicingROM=1;					// overflow...
       
  3365 			iROMStats.iTotalConcurrentReqs=0;	// ...reset this
       
  3366 			}
       
  3367 		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
       
  3368 		if(!empty)
       
  3369 			iROMStats.iTotalReqIssuedNonEmptyQ++;
       
  3370 		}
       
  3371 	else if (aDrvNumber == EDriveDataPaging)	// Data paging
       
  3372 		{
       
  3373 		servicingCount = &iServicingDataIn;
       
  3374 		if(iServicingDataIn)
       
  3375 			iDataStats.iTotalConcurrentReqs++;
       
  3376 		if(!(++iServicingDataIn))
       
  3377 			{
       
  3378 			iServicingDataIn=1;					// overflow...
       
  3379 			iDataStats.iTotalConcurrentReqs=0;	// ...reset this
       
  3380 			}
       
  3381 		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
       
  3382 		if(!empty)
       
  3383 			iDataStats.iTotalReqIssuedNonEmptyQ++;
       
  3384 		}
       
  3385 	else
       
  3386 		{
       
  3387 		servicingCount = &iServicingCode;
       
  3388 		if(iServicingCode)
       
  3389 			iCodeStats.iTotalConcurrentReqs++;
       
  3390 		if(!(++iServicingCode))
       
  3391 			{
       
  3392 			iServicingCode=1;					// overflow...
       
  3393 			iCodeStats.iTotalConcurrentReqs=0;	// ...reset this
       
  3394 			}
       
  3395 		TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
       
  3396 		if(!empty)
       
  3397 			iCodeStats.iTotalReqIssuedNonEmptyQ++;
       
  3398 		}
       
  3399 	NKern::FMSignal(&iInstrumentationLock);
       
  3400 #endif
       
  3401 
       
  3402 	TUint offset=aOffset<<iReadUnitShift;
       
  3403 	TUint size=aSize<<iReadUnitShift;
       
  3404 
       
  3405 #ifdef BTRACE_PAGING_MEDIA
       
  3406 	TInt buf[3];
       
  3407 	buf[0]=size;		// page in request length
       
  3408 	buf[1]=aDrvNumber;	// local drive number (-1 if ROM)
       
  3409 	buf[2]=(TInt)aReq;	// address of request object
       
  3410 	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageInBegin,aBuffer,offset,buf,sizeof(buf));
       
  3411 #endif
       
  3412 
       
  3413 	__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));
       
  3414 	
       
  3415 	// no DFCQ, media driver executes in the context of calling thread
       
  3416 	if (!iPrimaryMedia->iDfcQ)
       
  3417 		{
       
  3418 		LOCM_FAULT();		// don't allow paging
       
  3419 		return KErrNone;	// keep compiler happy
       
  3420 		}
       
  3421 
       
  3422 
       
  3423 	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
       
  3424 
       
  3425 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3426 	SPagingBenchmarkInfo* info = NULL;
       
  3427 #endif
       
  3428 
       
  3429 
       
  3430 	// Read from the media and allow for retries in the unlikely event of an error.
       
  3431 	const TInt KPageInRetries = 5;
       
  3432 	TInt retVal = KErrGeneral;
       
  3433 	for (TInt i=0; retVal != KErrNone && i < KPageInRetries; i++)
       
  3434 		{
       
  3435 		m.Flags() = TLocDrvRequest::EPaging;
       
  3436 		TLocDrv* pL=NULL;
       
  3437 		if(aDrvNumber == EDriveRomPaging)					// ROM paging
       
  3438 			{
       
  3439 			m.Id() = DMediaPagingDevice::ERomPageInRequest;
       
  3440 			if (iRomPagingDriveNumber == KErrNotFound)
       
  3441 			    {
       
  3442 			    // ROM partition has not been reported by the media driver
       
  3443 			    // it is assumed that the media driver will adjust the request accordingly
       
  3444 			    m.Flags() |= TLocDrvRequest::EAdjusted;
       
  3445 				// Use a media drive number so the request reaches the correct media...
       
  3446 				m.Drive() = TheDrives[iFirstLocalDriveNumber];
       
  3447 			    }
       
  3448 			else
       
  3449 			    {
       
  3450 			    //ROM partition has been reported
       
  3451 			    //Set drive for use with CheckAndAdjustForPartition
       
  3452                 m.Drive() = TheDrives[iRomPagingDriveNumber];
       
  3453 			    }
       
  3454 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3455 			__e32_atomic_add_ord32(&iMediaPagingInfo.iRomPageInCount, (TUint) 1);
       
  3456 			info = &iROMBenchmarkData;
       
  3457 #endif
       
  3458 			}
       
  3459 		else if(aDrvNumber == EDriveDataPaging)				// Data paging
       
  3460 			{
       
  3461 			m.Id() = DLocalDrive::ERead;
       
  3462 			m.Flags() |= TLocDrvRequest::EDataPaging;
       
  3463 			m.Drive() = TheDrives[iDataPagingDriveNumber];
       
  3464 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3465 			__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageInCount, (TUint) 1);
       
  3466 			info = &iDataInBenchmarkData;
       
  3467 #endif
       
  3468 			}
       
  3469 		else if ((aDrvNumber >=0) && (aDrvNumber<KMaxLocalDrives))	// Code paging
       
  3470 			{
       
  3471 			m.Id() = DMediaPagingDevice::ECodePageInRequest;
       
  3472 			m.Flags() |= TLocDrvRequest::ECodePaging;
       
  3473 			pL=TheDrives[aDrvNumber];
       
  3474 			__ASSERT_DEBUG(pL&&(pL->iPrimaryMedia==iPrimaryMedia),LOCM_FAULT());	// valid drive number?
       
  3475 			m.Drive()=pL;
       
  3476 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3477 			__e32_atomic_add_ord32(&iMediaPagingInfo.iCodePageInCount, (TUint) 1);
       
  3478 			info = &iCodeBenchmarkData;
       
  3479 #endif
       
  3480 			}
       
  3481 		else
       
  3482 			LOCM_FAULT(); // invalid drive number
       
  3483 
       
  3484 		m.RemoteThread()=NULL;
       
  3485 		m.Pos()=offset;
       
  3486 		m.Length()=Int64(size);
       
  3487 		m.RemoteDes()=(TAny*)aBuffer;
       
  3488 		m.RemoteDesOffset()=0;		// pre-aligned
       
  3489 		m.DriverFlags()=0;
       
  3490 		__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()));
       
  3491 
       
  3492 		__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
       
  3493 		TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
       
  3494 
       
  3495 		SendToMainQueueDfcAndBlock(&m);		// queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
       
  3496 		retVal = m.iValue;
       
  3497 
       
  3498 #ifdef __DEBUG_DEMAND_PAGING__
       
  3499 		if (retVal != KErrNone)
       
  3500 			Kern::Printf("Pagin Failure %d, retry %d", retVal, i);
       
  3501 #endif
       
  3502 
       
  3503 		// reset retry count if there's ben a media change
       
  3504 		if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
       
  3505 			i = 0;
       
  3506 		}	// for ()
       
  3507 
       
  3508 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3509 	NKern::FMWait(&iInstrumentationLock);
       
  3510 	if (*servicingCount)
       
  3511 		(*servicingCount)--;
       
  3512 	NKern::FMSignal(&iInstrumentationLock);
       
  3513 #endif
       
  3514 
       
  3515 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3516 	TUint32 bmEnd = NKern::FastCounter();
       
  3517 	++info->iCount;
       
  3518 #if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
       
  3519 	TInt64 elapsed=bmEnd-bmStart;
       
  3520 #else
       
  3521 	TInt64 elapsed=bmStart-bmEnd;
       
  3522 #endif
       
  3523 	info->iTotalTime += elapsed;
       
  3524 	if (elapsed > info->iMaxTime)
       
  3525 		info->iMaxTime = elapsed;
       
  3526 	if (elapsed < info->iMinTime)
       
  3527 		info->iMinTime = elapsed;
       
  3528 #endif // __DEMAND_PAGING_BENCHMARKS__
       
  3529 
       
  3530 	return retVal;
       
  3531 	}
       
  3532 
       
  3533 TInt DMediaPagingDevice::Write(TThreadMessage* aReq,TLinAddr aBuffer,TUint aOffset,TUint aSize,TBool aBackground)
       
  3534 	{
       
  3535 	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
       
  3536 	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
       
  3537 	__ASSERT_CRITICAL
       
  3538 
       
  3539 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3540 	TUint32 bmStart = NKern::FastCounter();
       
  3541 #endif
       
  3542 
       
  3543 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3544 	NKern::FMWait(&iInstrumentationLock);
       
  3545 	if(iServicingDataOut)
       
  3546 		iDataStats.iTotalConcurrentReqs++;
       
  3547 	if(!(++iServicingDataOut))
       
  3548 		{
       
  3549 		iServicingDataOut=1;				// overflow...
       
  3550 		iDataStats.iTotalConcurrentReqs=0;	// ...reset this
       
  3551 		}
       
  3552 	TBool empty = iMainQ.iReady && iDeferredQ.iQ.IsEmpty();
       
  3553 	if(!empty)
       
  3554 		iDataStats.iTotalReqIssuedNonEmptyQ++;
       
  3555 	NKern::FMSignal(&iInstrumentationLock);
       
  3556 #endif
       
  3557 
       
  3558 	TUint offset=aOffset<<iReadUnitShift;
       
  3559 	TUint size=aSize<<iReadUnitShift;
       
  3560 
       
  3561 #ifdef BTRACE_PAGING_MEDIA
       
  3562 	TInt buf[2];
       
  3563 	buf[0] = size;				// page out request length
       
  3564 	buf[1] = (TInt)aReq;		// address of request object
       
  3565 	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedPageOutBegin,aBuffer,offset,buf,sizeof(buf));
       
  3566 #endif
       
  3567 
       
  3568 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Buff(0x%x),Offset(%d),Size(%d)",aReq,aBuffer,offset,size));
       
  3569 	
       
  3570 	// no DFCQ, media driver executes in the context of calling thread
       
  3571 	if (!iPrimaryMedia->iDfcQ)
       
  3572 		{
       
  3573 		LOCM_FAULT();		// don't allow paging
       
  3574 		return KErrNone;	// keep compiler happy
       
  3575 		}
       
  3576 
       
  3577 
       
  3578 	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
       
  3579 
       
  3580 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3581 	__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutCount, (TUint) 1);
       
  3582 	if (aBackground)
       
  3583 		__e32_atomic_add_ord32(&iMediaPagingInfo.iDataPageOutBackgroundCount, (TUint) 1);
       
  3584 #endif
       
  3585 
       
  3586 	// Write to the media and allow for retries in the unlikely event of an error.
       
  3587 	const TInt KPageOutRetries = 5;
       
  3588 	TInt retVal = KErrGeneral;
       
  3589 	for (TInt i=0; retVal != KErrNone && i < KPageOutRetries; i++)
       
  3590 		{
       
  3591 		m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging | (aBackground ? TLocDrvRequest::EBackgroundPaging : 0);
       
  3592 
       
  3593 		m.Id() = DLocalDrive::EWrite;
       
  3594 		m.Drive() = TheDrives[iDataPagingDriveNumber];
       
  3595 
       
  3596 		m.RemoteThread()=NULL;
       
  3597 		m.Pos()=offset;
       
  3598 		m.Length()=Int64(size);
       
  3599 		m.RemoteDes()=(TAny*)aBuffer;
       
  3600 		m.RemoteDesOffset()=0;		// pre-aligned
       
  3601 		m.DriverFlags()=0;
       
  3602 		__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()));
       
  3603 
       
  3604 		__ASSERT_DEBUG(iPrimaryMedia->iBody, LOCM_FAULT());
       
  3605 		TInt mediaChanges = iPrimaryMedia->iBody->iMediaChanges;
       
  3606 
       
  3607 		SendToMainQueueDfcAndBlock(&m);		// queues request, sets and opens client thread, queues dfc and blocks thread until request is completed
       
  3608 		retVal = m.iValue;
       
  3609 
       
  3610 #ifdef __DEBUG_DEMAND_PAGING__
       
  3611 		if (retVal != KErrNone)
       
  3612 			Kern::Printf("Pagout Failure %d, retry %d", retVal, i);
       
  3613 #endif
       
  3614 		// reset retry count if there's ben a media change
       
  3615 		if (retVal != KErrNone && mediaChanges != iPrimaryMedia->iBody->iMediaChanges)
       
  3616 			i = 0;
       
  3617 		}	// for ()
       
  3618 
       
  3619 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
       
  3620 	NKern::FMWait(&iInstrumentationLock);
       
  3621 	if (iServicingDataOut)
       
  3622 		iServicingDataOut--;
       
  3623 	NKern::FMSignal(&iInstrumentationLock);
       
  3624 #endif
       
  3625 
       
  3626 #ifdef __DEMAND_PAGING_BENCHMARKS__
       
  3627 	SPagingBenchmarkInfo& info = iDataOutBenchmarkData;
       
  3628 	TUint32 bmEnd = NKern::FastCounter();
       
  3629 	++info.iCount;
       
  3630 #if !defined(HIGHIGH_RES_TIMER) || defined(HIGH_RES_TIMER_COUNTS_UP)
       
  3631 	TInt64 elapsed=bmEnd-bmStart;
       
  3632 #else
       
  3633 	TInt64 elapsed=bmStart-bmEnd;
       
  3634 #endif
       
  3635 	info.iTotalTime += elapsed;
       
  3636 	if (elapsed > info.iMaxTime)
       
  3637 		info.iMaxTime = elapsed;
       
  3638 	if (elapsed < info.iMinTime)
       
  3639 		info.iMinTime = elapsed;
       
  3640 #endif // __DEMAND_PAGING_BENCHMARKS__
       
  3641 
       
  3642 	return retVal;
       
  3643 	}
       
  3644 
       
  3645 
       
  3646 TInt DMediaPagingDevice::DeleteNotify(TThreadMessage* aReq,TUint aOffset,TUint aSize)
       
  3647 	{
       
  3648 	if (iDeleteNotifyNotSupported)
       
  3649 		return KErrNotSupported;
       
  3650 
       
  3651 	__ASSERT_ALWAYS(NKern::CurrentThread()!=iPrimaryMedia->iDfcQ->iThread,LOCM_FAULT());	// that would lock up the system, thus better die now
       
  3652 	__ASSERT_ALWAYS(aReq,LOCM_FAULT());
       
  3653 	__ASSERT_ALWAYS(DataPagingDfcQ(iPrimaryMedia),LOCM_FAULT());
       
  3654 	__ASSERT_CRITICAL
       
  3655 
       
  3656 	TUint offset = aOffset<<iReadUnitShift;
       
  3657 	TUint size = aSize<<iReadUnitShift;
       
  3658 
       
  3659 #ifdef BTRACE_PAGING_MEDIA
       
  3660 	TInt buf[2];
       
  3661 	buf[0] = size;		// delete notify length
       
  3662 	buf[1] = (TInt)aReq;	// address of request object
       
  3663 	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaLocMedDeleteNotifyBegin,NULL,offset,buf,sizeof(buf));
       
  3664 #endif
       
  3665 
       
  3666 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("DMediaPagingDevice::Write, Req(0x%08x), Offset(%d),Size(%d)",aReq,offset,size));
       
  3667 	
       
  3668 	// no DFCQ, media driver executes in the context of calling thread
       
  3669 	if (!iPrimaryMedia->iDfcQ)
       
  3670 		{
       
  3671 		LOCM_FAULT();		// don't allow paging
       
  3672 		return KErrNone;	// keep compiler happy
       
  3673 		}
       
  3674 
       
  3675 	TLocDrvRequest& m=*(TLocDrvRequest*)(aReq);
       
  3676 
       
  3677 
       
  3678 	m.Flags() = TLocDrvRequest::EPaging | TLocDrvRequest::EDataPaging;
       
  3679 	m.Id() = DLocalDrive::EDeleteNotify;
       
  3680 	m.Drive() = TheDrives[iDataPagingDriveNumber];
       
  3681 
       
  3682 	m.RemoteThread() = NULL;
       
  3683 	m.Pos() = offset;
       
  3684 	m.Length() = Int64(size);
       
  3685 	m.RemoteDes() = NULL;
       
  3686 	m.RemoteDesOffset() = 0;		// pre-aligned
       
  3687 	m.DriverFlags()=0;
       
  3688 	__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()));
       
  3689 
       
  3690 
       
  3691 	// send request aynchronously as we don't particularly care about the result 
       
  3692 	// and waiting would slow down the thread taking the page fault
       
  3693 	iPrimaryMedia->RequestCountInc();
       
  3694 
       
  3695 	m.SendReceive(&iMainQ);	// send  request synchronously
       
  3696 
       
  3697 #ifdef __DEMAND_PAGING__
       
  3698 	iPrimaryMedia->RequestCountDec();
       
  3699 #endif
       
  3700 
       
  3701 	TInt retVal = m.iValue;
       
  3702 
       
  3703 	if (retVal == KErrNotSupported)
       
  3704 		iDeleteNotifyNotSupported = ETrue;
       
  3705 
       
  3706 	return retVal;
       
  3707 	}
       
  3708 
       
  3709 
       
  3710 
       
  3711 EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* aSrc, TInt aSize, TInt anOffset)
       
  3712 	{
       
  3713 #ifdef BTRACE_PAGING_MEDIA
       
  3714 	TMediaDevice medDev=Drive()->iMedia->iDevice;
       
  3715 	TInt buf[3];
       
  3716 	buf[0]=(TUint32)RemoteDes();
       
  3717 	buf[1]=anOffset;
       
  3718 	buf[2]=aSize;
       
  3719 	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvWriteBack,medDev,this,buf,sizeof(buf));
       
  3720 #endif
       
  3721 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::WriteToPageHandler, memcpy((aTrg)%08x, (aSrc)%08x, (aLength)%08x)",(TUint32)RemoteDes()+anOffset,aSrc,aSize));
       
  3722 	(void)memcpy((TAny*)((TUint32)RemoteDes()+anOffset), aSrc, aSize);	// maybe in later versions this could be something else
       
  3723 	return KErrNone;
       
  3724 	}
       
  3725 
       
  3726 EXPORT_C TInt TLocDrvRequest::ReadFromPageHandler(TAny* aDst, TInt aSize, TInt anOffset)
       
  3727 	{
       
  3728 #ifdef BTRACE_PAGING_MEDIA
       
  3729 	TMediaDevice medDev=Drive()->iMedia->iDevice;
       
  3730 	TInt buf[3];
       
  3731 	buf[0]=(TUint32)RemoteDes();
       
  3732 	buf[1]=anOffset;
       
  3733 	buf[2]=aSize;
       
  3734 	BTraceContextN(BTrace::EPagingMedia,BTrace::EPagingMediaMedDrvRead,medDev,this,buf,sizeof(buf));
       
  3735 #endif
       
  3736 	__KTRACE_OPT2(KLOCDRV,KLOCDPAGING,Kern::Printf("TLocDrvRequest::ReadFromPageHandler, memcpy((aDst)%08x, (aTrg)%08x, (aLength)%08x)",aDst,(TUint32)RemoteDes()+anOffset,aSize));
       
  3737 	(void)memcpy(aDst, (TAny*)((TUint32)RemoteDes()+anOffset), aSize);	// maybe in later versions this could be something else
       
  3738 	return KErrNone;
       
  3739 	}
       
  3740 
       
  3741 _LIT(KLitFragmentationMutexName, "FRAGMENTATION_MUTEX");
       
  3742 
       
  3743 TInt DFragmentationPagingLock::Construct(TUint aNumPages)
       
  3744 	{
       
  3745 	TInt r=KErrNone;
       
  3746 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: creating Mutex"));
       
  3747 	r=Kern::MutexCreate(this->iFragmentationMutex, KLitFragmentationMutexName, KMutexOrdNone);
       
  3748 	if (r!=KErrNone)
       
  3749 		return r;
       
  3750 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation Lock: Mutex created OK"));
       
  3751 
       
  3752 	iFragmentGranularity = 0;
       
  3753 	if (aNumPages == 0)
       
  3754 		return KErrNone;
       
  3755 
       
  3756 	// in CS
       
  3757 	TInt pageSize=Kern::RoundToPageSize(1);
       
  3758 	LockFragmentation();
       
  3759 	r=Alloc(pageSize*aNumPages);	// alloc pages
       
  3760 	UnlockFragmentation();
       
  3761 
       
  3762 	if(r==KErrNone)
       
  3763 		{
       
  3764 		iFragmentGranularity = pageSize * aNumPages;
       
  3765 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Fragmentation granularity set to 0x%x", iFragmentGranularity));
       
  3766 		}
       
  3767 
       
  3768 	return r;
       
  3769 	}
       
  3770 
       
  3771 void DFragmentationPagingLock::Cleanup()
       
  3772 	{
       
  3773 	// in CS
       
  3774 	if (iFragmentationMutex)
       
  3775 		{
       
  3776 		LockFragmentation();
       
  3777 		Free();					// at last!
       
  3778 		UnlockFragmentation();
       
  3779 		Kern::SafeClose((DObject*&)iFragmentationMutex,NULL);
       
  3780 		}
       
  3781 	}
       
  3782 
       
  3783 #else
       
  3784 #if !defined(__WINS__)
       
  3785 EXPORT_C TInt TLocDrvRequest::WriteToPageHandler(const TAny* , TInt , TInt)
       
  3786 	{
       
  3787 	return KErrNone;		// stub for def file
       
  3788 	}
       
  3789 #endif // __WINS__
       
  3790 #endif //__DEMAND_PAGING__
       
  3791 /********************************************
       
  3792  * Media driver base class
       
  3793  ********************************************/
       
  3794  
       
  3795  
       
  3796  
       
  3797  
       
  3798 /**
       
  3799 Constructor.
       
  3800 
       
  3801 This is called, typically, by a derived class constructor in its ctor list.
       
  3802 
       
  3803 @param aMediaId The value of the unique media ID assigned when the media
       
  3804                 driver is registered.
       
  3805                 
       
  3806 @see LocDrv::RegisterMediaDevice()                
       
  3807 */
       
  3808 EXPORT_C DMediaDriver::DMediaDriver(TInt aMediaId)
       
  3809 	{
       
  3810 //	iPhysicalDevice=NULL;
       
  3811 //	iTotalSizeInBytes=0;
       
  3812 //	iCurrentConsumption=0;
       
  3813 //	iPrimaryMedia=NULL;
       
  3814 //	iCritical=EFalse;
       
  3815 	iPrimaryMedia=(DPrimaryMediaBase*)TheMedia[aMediaId];
       
  3816 	}
       
  3817 
       
  3818 
       
  3819 
       
  3820 
       
  3821 /**
       
  3822 Destructor.
       
  3823 
       
  3824 Sets the device's current consumption to zero, and calls Close() on
       
  3825 the PDD factory object.
       
  3826 
       
  3827 @see DObject::Close()
       
  3828 */
       
  3829 EXPORT_C DMediaDriver::~DMediaDriver()
       
  3830 	{
       
  3831 	SetCurrentConsumption(0);
       
  3832 	Kern::SafeClose((DObject*&)iPhysicalDevice,NULL);
       
  3833 	}
       
  3834 
       
  3835 
       
  3836 
       
  3837 
       
  3838 /**
       
  3839 Closes the media driver.
       
  3840 
       
  3841 This default implementation simply deletes this DMediaDriver object.
       
  3842 
       
  3843 Media drivers can provide their own implementation, which gives them
       
  3844 the opportunity to clean up resources before closure; for example,
       
  3845 cancelling a DFC.
       
  3846 Any replacement function must call this base class function as
       
  3847 the last instruction. 
       
  3848 */
       
  3849 EXPORT_C void DMediaDriver::Close()
       
  3850 	{
       
  3851 	delete this;
       
  3852 	}
       
  3853 
       
  3854 
       
  3855 
       
  3856 
       
  3857 /**
       
  3858 Sets the total size of the media device.
       
  3859 
       
  3860 The function must be called by the media driver's implementation of PartitionInfo().
       
  3861 
       
  3862 @param aTotalSizeInBytes The total size of the media, in bytes.
       
  3863 @param aLocDrv           This is not used by media drivers; the class
       
  3864                          definition provides a default value.
       
  3865 
       
  3866 @see DMediaDriver::PartitionInfo()
       
  3867 */
       
  3868 EXPORT_C void DMediaDriver::SetTotalSizeInBytes(Int64 aTotalSizeInBytes, TLocDrv* aLocDrv)
       
  3869 	{
       
  3870 	iTotalSizeInBytes=aTotalSizeInBytes;
       
  3871 	if (aLocDrv)
       
  3872 		aLocDrv->iPartitionLen=aTotalSizeInBytes;
       
  3873 	}
       
  3874 
       
  3875 
       
  3876 
       
  3877 
       
  3878 /**
       
  3879 Gets the total size of the media.
       
  3880 
       
  3881 @return The total size of the media, in bytes.
       
  3882 
       
  3883 @see DMediaDriver::SetTotalSizeInBytes()
       
  3884 */
       
  3885 EXPORT_C Int64 DMediaDriver::TotalSizeInBytes()
       
  3886 	{
       
  3887 	return iTotalSizeInBytes;
       
  3888 	}
       
  3889 
       
  3890 
       
  3891 
       
  3892 
       
  3893 /**
       
  3894 Flags the media driver as entering a critical part of its processing.
       
  3895 
       
  3896 In this context, critical means that the driver must be allowed to complete
       
  3897 its current activity.
       
  3898 For example, a request to power down the device must be deferred until
       
  3899 the driver exits the critical part.
       
  3900 
       
  3901 @return KErrNone, if the driver has been successfully flagged as being in
       
  3902         a critical part; otherwise, one of the other system-wide error codes.
       
  3903         
       
  3904 @see DMediaDriver::EndInCritical()
       
  3905 */
       
  3906 EXPORT_C TInt DMediaDriver::InCritical()
       
  3907 	{
       
  3908 	if (!iCritical)
       
  3909 		{
       
  3910 		TInt r=iPrimaryMedia->InCritical();
       
  3911 		if (r!=KErrNone)
       
  3912 			return r;
       
  3913 		iCritical=ETrue;
       
  3914 		}
       
  3915 	return KErrNone;
       
  3916 	}
       
  3917 
       
  3918 
       
  3919 
       
  3920 
       
  3921 /**
       
  3922 Flags the media driver as leaving a critical part of its processing.
       
  3923 
       
  3924 @see DMediaDriver::InCritical()
       
  3925 */
       
  3926 EXPORT_C void DMediaDriver::EndInCritical()
       
  3927 	{
       
  3928 	if (iCritical)
       
  3929 		{
       
  3930 		iCritical=EFalse;
       
  3931 		iPrimaryMedia->EndInCritical();
       
  3932 		}
       
  3933 	}
       
  3934 
       
  3935 
       
  3936 
       
  3937 
       
  3938 /**
       
  3939 @internalComponent
       
  3940 */
       
  3941 EXPORT_C void DMediaDriver::SetCurrentConsumption(TInt aValue)
       
  3942 	{
       
  3943 	TInt old = (TInt)__e32_atomic_swp_ord32(&iCurrentConsumption, aValue);
       
  3944 	TInt delta = aValue - old;
       
  3945 	iPrimaryMedia->DeltaCurrentConsumption(delta);
       
  3946 	}
       
  3947 
       
  3948 
       
  3949 
       
  3950 
       
  3951 /**
       
  3952 Informs the media driver subsystem that an asynchronous request is complete.
       
  3953 
       
  3954 @param m       The request that this call is completing.
       
  3955 @param aResult The return code for the asynchronous request. Typically, this
       
  3956                is KErrNone to report success, or one of the other system-wide
       
  3957                error codes to report failure or other problems.
       
  3958 */
       
  3959 EXPORT_C void DMediaDriver::Complete(TLocDrvRequest& m, TInt aResult)
       
  3960 	{
       
  3961 	CHECK_RET(aResult);
       
  3962 #ifdef __DEMAND_PAGING__
       
  3963 	if (DMediaPagingDevice::PagingRequest(m))
       
  3964 		{
       
  3965 		__ASSERT_ALWAYS(iPrimaryMedia && iPrimaryMedia->iPagingMedia && iPrimaryMedia->iBody->iPagingDevice,LOCM_FAULT());
       
  3966 		__ASSERT_ALWAYS( ((m.Flags() & TLocDrvRequest::ECodePaging) == 0) || (m.Drive()->iPagingDrv), LOCM_FAULT());
       
  3967 		DMediaPagingDevice* pagingdevice = iPrimaryMedia->iBody->iPagingDevice;
       
  3968 		pagingdevice->CompleteRequest(&m, aResult);
       
  3969 		}
       
  3970 	else
       
  3971 #endif
       
  3972 	iPrimaryMedia->CompleteRequest(m, aResult);
       
  3973 	
       
  3974 	if (&m == iPrimaryMedia->iCurrentReq)	// Complete() called on request serviced synchronously
       
  3975 		iPrimaryMedia->iCurrentReq = NULL;
       
  3976 
       
  3977 	iPrimaryMedia->RunDeferred();
       
  3978 	}
       
  3979 
       
  3980 
       
  3981 
       
  3982  
       
  3983 /**
       
  3984 Informs the media driver subsystem that the media driver is open
       
  3985 and has been initialised.
       
  3986 
       
  3987 This can be called from the PDD factory function Create(), if opening and
       
  3988 initialising the media driver is synchronous, otherwise it should be called by
       
  3989 the asynchronous media driver function that is responsible for opening and
       
  3990 initialising the driver.
       
  3991 
       
  3992 @param anError KErrNone if successful, otherwise one of the other system wide
       
  3993        error codes.
       
  3994 */
       
  3995 EXPORT_C void DMediaDriver::OpenMediaDriverComplete(TInt anError)
       
  3996 	{
       
  3997 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::OpenMediaDriverComplete(%d) this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
       
  3998 	DPrimaryMediaBase* pM=iPrimaryMedia;
       
  3999 	pM->iAsyncErrorCode=anError;
       
  4000 	pM->iAsyncDfc.Enque();
       
  4001 	}
       
  4002 
       
  4003 
       
  4004 
       
  4005 
       
  4006 /**
       
  4007 Informs the media driver subsystem that the media driver has completed
       
  4008 the provision of partition information.
       
  4009 
       
  4010 The media driver provides partition information in its implementation
       
  4011 of PartitionInfo().
       
  4012 
       
  4013 @param anError KErrNone if successful, otherwise one of the other system wide
       
  4014        error codes.
       
  4015 
       
  4016 @see DMediaDriver::PartitionInfo()
       
  4017 */
       
  4018 EXPORT_C void DMediaDriver::PartitionInfoComplete(TInt anError)
       
  4019 	{
       
  4020 	__KTRACE_OPT(KLOCDRV,Kern::Printf("DMediaDriver::PartitionInfoComplete(%d) anError %d this %x iPrimaryMedia %x", anError, this, iPrimaryMedia));
       
  4021 	DPrimaryMediaBase* pM=iPrimaryMedia;
       
  4022 	pM->iAsyncErrorCode=anError;
       
  4023 	pM->iAsyncDfc.Enque();
       
  4024 	}
       
  4025 
       
  4026 
       
  4027 
       
  4028 
       
  4029 /**
       
  4030 @internalComponent
       
  4031 */
       
  4032 // Default implementation
       
  4033 EXPORT_C void DMediaDriver::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
       
  4034 	{
       
  4035 	// don't need to worry about DLocalDrive going away
       
  4036 	aLocalDrive->Deque();
       
  4037 
       
  4038 	aMsg->Complete(KErrNone, EFalse);
       
  4039 	}
       
  4040 
       
  4041 
       
  4042 
       
  4043 
       
  4044 /**
       
  4045 Registers a media driver with the Local Media Subsystem, and provides
       
  4046 information about the number of supported drives, partitions,
       
  4047 names and drive numbers.
       
  4048 
       
  4049 @param aDevice       The unique Media ID for this device.
       
  4050                      This can take one of the enumerated values defined
       
  4051                      by the TMediaDevice enum.
       
  4052 @param aDriveCount   Specifies the number of local drive objects to be assigned
       
  4053                      to the media driver. Drives that support more than one
       
  4054                      partition must specify a number greater than 1.
       
  4055 @param aDriveList    A pointer to an array of TInt values, which define
       
  4056                      the drive numbers that are to be allocated to each partition.
       
  4057                      0 signifies Drive C, 1 signifies drive D, etc. For example,
       
  4058                      to allocate drive letters J and K, specify an array
       
  4059                      containing the values [7,8].
       
  4060                      Note that the size of this array must be the same as the value 
       
  4061                      specified by aDriveCount.
       
  4062 @param aPrimaryMedia A pointer to the primary DPrimaryMedia object to be
       
  4063                      associated with the media. This object is responsible for
       
  4064                      the overall state of the media, i.e. powering up, reading
       
  4065                      partition information etc. It also has overall control over
       
  4066                      all partitions as represented by the additional (aNumMedia-1)
       
  4067                      DMedia objects. 
       
  4068 @param aNumMedia     Specifies the total number of DMedia objects to be
       
  4069                      associated with the media driver. This number includes the
       
  4070                      primary DPrimaryMedia object referred to by aPrimaryMedia,
       
  4071                      plus all of the DMedia objects that are created for each
       
  4072                      additional drive, and which hold basic information about
       
  4073                      partitions.
       
  4074 @param aName         The name of the media driver, for example: PCCard
       
  4075        
       
  4076 @return              KErrNone, if successful;
       
  4077                      KErrInUse, if a drive is already in use;
       
  4078                      KErrNoMemory, if there is insufficient memory;
       
  4079                      or one of the other system-wide error codes.  
       
  4080 */
       
  4081 EXPORT_C TInt LocDrv::RegisterMediaDevice(TMediaDevice aDevice, TInt aDriveCount, const TInt* aDriveList, DPrimaryMediaBase* aPrimaryMedia, TInt aNumMedia, const TDesC& aName)
       
  4082 	{
       
  4083 	// Create TLocDrv / DMedia objects to handle a media device
       
  4084 	__KTRACE_OPT(KBOOT,Kern::Printf("RegisterMediaDevice %lS dev=%1d #drives=%d 1st=%d PM=%08x #media=%d",&aName,aDevice,aDriveCount,*aDriveList,aPrimaryMedia,aNumMedia));
       
  4085 	const TInt* p=aDriveList;
       
  4086 	TInt i;
       
  4087 	TInt r=0;
       
  4088 	if (UsedMedia+aNumMedia>KMaxLocalDrives)
       
  4089 		return KErrInUse;
       
  4090 	for (i=0; i<aDriveCount; ++i)
       
  4091 		{
       
  4092 		TInt drv = *p++;
       
  4093 		// -1 means not used; this is to enable Dual-slot MMC support 
       
  4094 		if (drv == -1)
       
  4095 			continue;
       
  4096 		__KTRACE_OPT(KBOOT,Kern::Printf("Registering drive %d", drv));
       
  4097 		if (TheDrives[drv])
       
  4098 			{
       
  4099 			__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d already in use", drv));
       
  4100 			return KErrInUse;
       
  4101 			}
       
  4102 		}
       
  4103 	HBuf* pN=HBuf::New(aName);
       
  4104 	if (!pN)
       
  4105 		return KErrNoMemory;
       
  4106 	TInt lastMedia=UsedMedia+aNumMedia-1;
       
  4107 	for (i=UsedMedia; i<=lastMedia; ++i)
       
  4108 		{
       
  4109 		if (i==UsedMedia)
       
  4110 			TheMedia[i]=aPrimaryMedia;
       
  4111 		else
       
  4112 			TheMedia[i]=new DMedia;
       
  4113 		if (!TheMedia[i])
       
  4114 			return KErrNoMemory;
       
  4115 		r=TheMedia[i]->Create(aDevice,i,lastMedia);
       
  4116 		__KTRACE_OPT(KBOOT,Kern::Printf("Media %d Create() returns %d",i,r));
       
  4117 		if (r!=KErrNone)
       
  4118 			return r;
       
  4119 		}
       
  4120 
       
  4121 	__KTRACE_OPT(KBOOT,Kern::Printf("FirstMedia %d LastMedia %d",UsedMedia,lastMedia));
       
  4122 	UsedMedia+=aNumMedia;
       
  4123 	p=aDriveList;
       
  4124 	for (i=0; i<aDriveCount; ++i)
       
  4125 		{
       
  4126 		TInt drv=*p++;
       
  4127 		if (drv == -1)
       
  4128 			continue;
       
  4129 		TLocDrv* pL=new TLocDrv(drv);
       
  4130 		if (!pL)
       
  4131 			return KErrNoMemory;
       
  4132 		TheDrives[drv]=pL;
       
  4133 		DriveNames[drv]=pN;
       
  4134 		pL->iPrimaryMedia=aPrimaryMedia;
       
  4135 		__KTRACE_OPT(KBOOT,Kern::Printf("Drive %d: TLocDrv @ %08x",drv,pL));
       
  4136 		}
       
  4137 	return KErrNone;
       
  4138 	}
       
  4139 
       
  4140 
       
  4141 
       
  4142 
       
  4143 /**
       
  4144 A utility function that is used internally to register the specified
       
  4145 password store.
       
  4146 
       
  4147 The password store is used to save passwords for local media.
       
  4148 
       
  4149 @param aStore A pointer to the password store to be registered.
       
  4150 
       
  4151 @return KErrNone, if successful;
       
  4152         KErrAlreadyExists, if a password store has already been registered.
       
  4153 */ 
       
  4154 EXPORT_C TInt LocDrv::RegisterPasswordStore(TPasswordStore* aStore)
       
  4155 	{
       
  4156 	// Create TLocDrv / DMedia objects to handle a media device
       
  4157 	__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPasswordStore"));
       
  4158 
       
  4159 	TInt r = KErrNone;
       
  4160 
       
  4161 	if(ThePasswordStore == NULL)
       
  4162 		ThePasswordStore = aStore;
       
  4163 	else
       
  4164 		r = KErrAlreadyExists;
       
  4165 
       
  4166 	return r;
       
  4167 	}
       
  4168 
       
  4169 /**
       
  4170 Returns a pointer to the registered password store.
       
  4171 
       
  4172 The password store is used to save passwords for local media.
       
  4173 
       
  4174 @return A pointer to the registered password store.
       
  4175 */ 
       
  4176 EXPORT_C TPasswordStore* LocDrv::PasswordStore()
       
  4177 	{
       
  4178 	return ThePasswordStore;
       
  4179 	}
       
  4180 
       
  4181 
       
  4182 #ifdef __DEMAND_PAGING__
       
  4183 /**
       
  4184 Registers a paging device with the Local Media Subsystem, and provides
       
  4185 information about drive numbers used in Code Paging.
       
  4186 
       
  4187 @param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated 
       
  4188 					 with the media.
       
  4189 @param aPagingDriveList    A pointer to an array of TInt values, which define
       
  4190                      the drive numbers used as Code backup in Code Paging, which
       
  4191 					 are the target of Page In requests. For NAND these will
       
  4192 					 will be usually associated with ROFS and/or User Data drives.
       
  4193 					 In ROM pagigng systems no drive is specified, it is assumed
       
  4194 					 a fixed media for which no non-primary media exists, will be 
       
  4195 					 used.
       
  4196 @param aDriveCount   Specifies the number of local drives associated with this
       
  4197 					 media device which can be used for code paging. 
       
  4198 @param aPagingType	 Identifies the type of Paging this media device is capable
       
  4199 					 of servicing.
       
  4200 @param aReadShift	 Log2 of the read unit size. A read unit is the number of bytes
       
  4201 					 which the device can optimally read from the underlying media.
       
  4202 					 E.g. for small block NAND, a read unit would be equal to the 
       
  4203 					 page size,	512 bytes, therefore iReadShift would be set to 9.
       
  4204 @param aNumPages     The number of pages to alloc for each drive associated with this
       
  4205 					 media driver. The pages are used in request fragmentation.
       
  4206 
       
  4207 @return              KErrNone, if successful;
       
  4208 					 KErrNotFound, if at least one of the drive numbers
       
  4209 					 specified has not yet been mapped.
       
  4210 					 KErrArgument, if the passed in an invalid argument.
       
  4211 					 KErrNotSupported, if at least one of the drive numbers 
       
  4212 					 specifed is not associated with this Primary Media.
       
  4213                      KErrNoMemory, if there is insufficient memory;
       
  4214                      or one of the other system-wide error codes.  
       
  4215 */
       
  4216 EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* aPrimaryMedia, const TInt* aPagingDriveList, TInt aDriveCount, TUint aPagingType, TInt aReadShift, TUint aNumPages)
       
  4217 	{
       
  4218 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf(">RegisterPagingDevice: paging type=%d PM=0x%x read shift=%d",aPagingType,aPrimaryMedia,aReadShift));
       
  4219 	TInt i;
       
  4220 
       
  4221 	if(!aPagingType || (aPagingType&~(DPagingDevice::ERom | DPagingDevice::ECode | DPagingDevice::EData)))
       
  4222 		{
       
  4223 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Unsupported paging type, exiting"));
       
  4224 		return KErrArgument;
       
  4225 		}
       
  4226 
       
  4227 
       
  4228 
       
  4229 	for(i=0; i<KMaxLocalDrives; i++)
       
  4230 		{
       
  4231 		if (ThePagingDevices[i] == NULL)
       
  4232 			continue;
       
  4233 		if ((ThePagingDevices[i]->iType&DPagingDevice::ERom) &&	(aPagingType & DPagingDevice::ERom))
       
  4234 			{
       
  4235 			aPagingType&=~DPagingDevice::ERom;		// already have a ROM paging device
       
  4236 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has ROM pager on locdrv no %d",i));
       
  4237 			}
       
  4238 		if ((ThePagingDevices[i]->iType&DPagingDevice::EData) && (aPagingType & DPagingDevice::EData))
       
  4239 			{
       
  4240 			aPagingType&=~DPagingDevice::EData;		// already have a Data paging device
       
  4241 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Already has Data pager on locdrv no %d",i));
       
  4242 			}
       
  4243 		}
       
  4244 
       
  4245 
       
  4246 	if (aPagingType == 0)
       
  4247 		{
       
  4248 		// there's already a ROM or Data paging device & this doesn't support code paging so quietly exit without further addo
       
  4249 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Nothing left to register on locdrv no %d, exiting",i));
       
  4250 		return KErrNone;
       
  4251 		}
       
  4252 
       
  4253 	const TInt* p=aPagingDriveList;
       
  4254 	if(aPagingType&DPagingDevice::ECode)	// supports code paging, do argument check
       
  4255 		{
       
  4256 		if(!aDriveCount || (aDriveCount>=KMaxLocalDrives))
       
  4257 			{
       
  4258 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count: %d", aDriveCount));
       
  4259 			return KErrArgument;
       
  4260 			}
       
  4261 
       
  4262 		TInt drvCount=0;
       
  4263 		for(i=0; i<KMaxLocalDrives; i++)
       
  4264 			if(TheDrives[i] && TheDrives[i]->iPrimaryMedia==aPrimaryMedia)
       
  4265 				drvCount++;
       
  4266 		if(aDriveCount>drvCount)	// can't exceed number of drives registered by this device
       
  4267 			{
       
  4268 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive count: %d total %d", aDriveCount, drvCount));
       
  4269 			return KErrArgument;
       
  4270 			}
       
  4271 
       
  4272 		for (i=0; i<aDriveCount; ++i)
       
  4273 			{
       
  4274 			__KTRACE_OPT(KBOOT,Kern::Printf("RegisterPagingDevice: registering drive=%d ",*p));
       
  4275 			TInt drv=*p++;
       
  4276 			if(drv>=KMaxLocalDrives)
       
  4277 				{
       
  4278 				__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("Invalid code paging drive number: %d", drv));
       
  4279 				return KErrArgument;
       
  4280 				}
       
  4281 			TLocDrv* pD=TheDrives[drv];
       
  4282 			if (!pD)
       
  4283 				return KErrNotFound;
       
  4284 			if (pD->iPrimaryMedia!=aPrimaryMedia)
       
  4285 				return KErrNotSupported;
       
  4286 			}
       
  4287 		}
       
  4288 
       
  4289 
       
  4290 	TInt firstLocalDriveNumber = KErrNotFound; 
       
  4291 	TInt romPagingDriveNumber = KErrNotFound;
       
  4292 
       
  4293 	TInt dataPagingDriveNumber = KErrNotFound;
       
  4294 	TInt swapSize = 0;
       
  4295 
       
  4296 	// find the local drive assocated with the primary media
       
  4297 	for (i=0; i<KMaxLocalDrives; ++i)
       
  4298 		{
       
  4299 		if(TheDrives[i] && TheDrives[i]->iPrimaryMedia == aPrimaryMedia)
       
  4300 			{
       
  4301 			firstLocalDriveNumber = i;
       
  4302 			break;
       
  4303 			}
       
  4304 		}
       
  4305 	__ASSERT_ALWAYS(i < KMaxLocalDrives, LOCM_FAULT());
       
  4306 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("DMediaPagingDevice(), firstLocalDriveNumber %d", firstLocalDriveNumber)); 
       
  4307 
       
  4308 
       
  4309 	// Send an ECaps message to wake up the media driver & ensure all partitions are 
       
  4310 	// reported, then search for paged-data or paged-ROM partitions
       
  4311 	if ((aPagingType & DPagingDevice::EData) ||
       
  4312 		(aPagingType & DPagingDevice::ERom && aPrimaryMedia->iDfcQ && aPrimaryMedia->iMsgQ.iReady))
       
  4313 		{
       
  4314 		// the message queue must have been started already (by the media driver calling iMsgQ.Receive())
       
  4315 		// otherwise we can't send the DLocalDrive::EQueryDevice request
       
  4316 		if (aPrimaryMedia->iDfcQ && !aPrimaryMedia->iMsgQ.iReady)
       
  4317 			{
       
  4318 			__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: Message queue not started"));
       
  4319 			return KErrNotReady;
       
  4320 			}
       
  4321 
       
  4322 
       
  4323 		TLocDrvRequest m;
       
  4324 		memclr(&m, sizeof(m));
       
  4325 		
       
  4326 
       
  4327 		// Get the Caps from the device. NB for MMC/SD we may need to retry as some PSLs start up
       
  4328 		// in "door open" or "media not present" state which can result in the cancellation of requests
       
  4329 		TInt i;
       
  4330 		const TInt KRetries = 5;
       
  4331 		TInt r = KErrNotReady;
       
  4332 		for (i=0; r == KErrNotReady && i < KRetries; i++)
       
  4333 			{
       
  4334 			TBuf8<KMaxLocalDriveCapsLength> capsBuf;
       
  4335 			capsBuf.SetMax();
       
  4336 			capsBuf.FillZ();
       
  4337 			m.Drive() = TheDrives[firstLocalDriveNumber];
       
  4338 			m.Id() = DLocalDrive::ECaps;
       
  4339 			m.RemoteDes() = (TAny*)capsBuf.Ptr();	// overload this
       
  4340 			m.Length() = KMaxLocalDriveCapsLength;	// for pinning
       
  4341 			r = aPrimaryMedia->Request(m);
       
  4342 
       
  4343 //Kern::Printf("EQueryPageDeviceInfo: i %d: r %d ", i, r);
       
  4344 			__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Paging device ECaps: i %d: r %d ", i, r));
       
  4345 			}
       
  4346 
       
  4347 		if (r != KErrNone)
       
  4348 			return r;
       
  4349 
       
  4350 		TLocDrv* drive;
       
  4351 		for (i=0; i<KMaxLocalDrives; ++i)
       
  4352 			{
       
  4353 			drive = TheDrives[i];
       
  4354 			if(drive && drive->iPrimaryMedia == aPrimaryMedia)
       
  4355 				{
       
  4356 				__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("RegisterPagingDevice: local drive %d, partition type %x size %x", i, drive->iPartitionType, I64LOW(drive->iPartitionLen)));
       
  4357 				// ROM partition ?
       
  4358 				if ((romPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypeROM))
       
  4359 					{
       
  4360 					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found ROM partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
       
  4361 					romPagingDriveNumber = i;
       
  4362 					}
       
  4363 			    // swap partition ?
       
  4364 				else if ((dataPagingDriveNumber == KErrNotFound) && (drive->iPartitionType == KPartitionTypePagedData))
       
  4365 					{
       
  4366 					__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Found swap partition on local drive %d, size %x", i, I64LOW(drive->iPartitionLen)));
       
  4367 					dataPagingDriveNumber = i;
       
  4368 					swapSize = drive->iPartitionLen >> aReadShift;
       
  4369 					}
       
  4370 				}
       
  4371 			}
       
  4372 
       
  4373 		if (swapSize == 0)
       
  4374 			{
       
  4375 			__KTRACE_OPT2(KBOOT,KLOCDPAGING, Kern::Printf("Disabling data paging"));
       
  4376 			aPagingType &= ~DPagingDevice::EData;
       
  4377 			}
       
  4378 
       
  4379 		}
       
  4380 
       
  4381 
       
  4382 	// create and set up a DPagingDevice to allow PageIn request servicing
       
  4383 	DMediaPagingDevice* pagingDevice = new DMediaPagingDevice(aPrimaryMedia);
       
  4384 	if(!pagingDevice)
       
  4385 		{
       
  4386 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create paging device"));
       
  4387 		return KErrNoMemory;
       
  4388 		}
       
  4389 
       
  4390 	pagingDevice->iType = aPagingType;
       
  4391 	pagingDevice->iReadUnitShift = aReadShift;
       
  4392 
       
  4393 	pagingDevice->iFirstLocalDriveNumber = firstLocalDriveNumber;
       
  4394 	pagingDevice->iRomPagingDriveNumber = romPagingDriveNumber;
       
  4395 
       
  4396 	pagingDevice->iDataPagingDriveNumber = dataPagingDriveNumber;
       
  4397 	pagingDevice->iSwapSize = swapSize;
       
  4398 
       
  4399 #ifdef __DEBUG_DEMAND_PAGING__
       
  4400 	Kern::Printf("PagingDevice :");
       
  4401 	Kern::Printf("iType 0x%x\n", pagingDevice->iType);
       
  4402 	Kern::Printf("iReadUnitShift 0x%x\n", pagingDevice->iReadUnitShift);
       
  4403 	Kern::Printf("iFirstLocalDriveNumber 0x%x\n", pagingDevice->iFirstLocalDriveNumber);
       
  4404 	Kern::Printf("iRomPagingDriveNumber 0x%x\n", pagingDevice->iRomPagingDriveNumber);
       
  4405 	Kern::Printf("iDataPagingDriveNumber 0x%x\n", pagingDevice->iDataPagingDriveNumber);
       
  4406 	Kern::Printf("iSwapSize 0x%x\n", pagingDevice->iSwapSize);
       
  4407 #endif
       
  4408 
       
  4409 
       
  4410 	// This table is indexed by DPagingDevice::TType
       
  4411 	const char* DeviceName[] = 
       
  4412 		{
       
  4413 		"Error",
       
  4414 		"RomPagingDevice",
       
  4415 		"CodePagingDevice",
       
  4416 		"RomAndCodePagingDevice",
       
  4417 		"DataPagingDevice",
       
  4418 		"RomAndDataPagingDevice",
       
  4419 		"CodeAndDataPagingDevice",
       
  4420 		"RomAndCodeAndDataPagingDevice"
       
  4421 		};
       
  4422 
       
  4423 
       
  4424 	if(aPagingType & DPagingDevice::ECode)
       
  4425 		{
       
  4426 		for (i=0; i<aDriveCount; ++i)
       
  4427 			pagingDevice->iDrivesSupported|=(0x1<<aPagingDriveList[i]);
       
  4428 		}
       
  4429 	pagingDevice->iName = DeviceName[aPagingType];
       
  4430 
       
  4431 	if (ThePinObjectAllocator == NULL)
       
  4432 		ThePinObjectAllocator = new DPinObjectAllocator();
       
  4433 	if(!ThePinObjectAllocator)
       
  4434 		{
       
  4435 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not create ThePinObjectAllocator"));
       
  4436 		return KErrNoMemory;
       
  4437 		}
       
  4438 	TInt r = ThePinObjectAllocator->Construct(KDynamicPagingLockCount, aNumPages);
       
  4439 	if (r != KErrNone)
       
  4440 		{
       
  4441 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not construct ThePinObjectAllocator"));
       
  4442 		return r;
       
  4443 		}
       
  4444 
       
  4445 
       
  4446 	// Register our DPagingDevice with the Kernel
       
  4447 	r=Kern::InstallPagingDevice(pagingDevice);
       
  4448 
       
  4449 #ifdef __DEBUG_DEMAND_PAGING__
       
  4450 	Kern::Printf("Kern::InstallPagingDevice() r %d", r);
       
  4451 #endif
       
  4452 
       
  4453 	if (r!=KErrNone)
       
  4454 		{
       
  4455 		__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("RegisterPagingDevice: could not install paging device"));
       
  4456 		delete pagingDevice;
       
  4457 		return r;
       
  4458 		}
       
  4459 
       
  4460 	// all hunky dory, save paging device and mark our media as pageable
       
  4461 	ThePagingDevices[aPrimaryMedia->iMediaId] = pagingDevice;	// association created between PrimaryMedia and PagingDevice via iMediaId
       
  4462 	aPrimaryMedia->iPagingMedia = 1;
       
  4463 
       
  4464 	// mark our drives as pageable
       
  4465 	p=aPagingDriveList;
       
  4466 	if (aPagingType&DPagingDevice::ECode)
       
  4467 		{
       
  4468 		for (i=0; i<aDriveCount; ++i)
       
  4469 			{
       
  4470 			TLocDrv* pD=TheDrives[*p++];
       
  4471 			pD->iPagingDrv=1;
       
  4472 			}
       
  4473 		}
       
  4474 
       
  4475 	// Flags to indicate that a paging device is registered and pinning of user requests may be required
       
  4476 	aPrimaryMedia->iPagingMedia = 1;
       
  4477 
       
  4478 	// point the primary media to the paging device
       
  4479 	aPrimaryMedia->iBody->iPagingDevice = pagingDevice;
       
  4480 
       
  4481 	if (aPagingType & DPagingDevice::ERom)
       
  4482 		{
       
  4483 		aPrimaryMedia->iRomPagingMedia = 1;
       
  4484 		TheRomPagingMedia = aPrimaryMedia;
       
  4485 		}
       
  4486 	
       
  4487 	// Is data paging enabled in this ROM ?
       
  4488 	TInt memModelAttributes = Kern::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
       
  4489 	TBool dataPagingSupported = memModelAttributes & EMemModelAttrDataPaging;
       
  4490 #ifdef __DEBUG_DEMAND_PAGING__
       
  4491 	Kern::Printf("memModelAttributes %08X", memModelAttributes);
       
  4492 	Kern::Printf("DataPagingSupported %d", dataPagingSupported);
       
  4493 #endif
       
  4494 	if (!dataPagingSupported)
       
  4495 		{
       
  4496 #ifdef __DEBUG_DEMAND_PAGING__
       
  4497 		if (aPagingType & DPagingDevice::EData)
       
  4498 			Kern::Printf("Disabling data paging, not supported in this ROM");
       
  4499 #endif
       
  4500 		aPagingType&= ~DPagingDevice::EData;
       
  4501 		}
       
  4502 
       
  4503 
       
  4504 	if (aPagingType & DPagingDevice::EData)
       
  4505 		{
       
  4506 		DataPagingDeviceRegistered = ETrue;
       
  4507 		aPrimaryMedia->iDataPagingMedia = 1;
       
  4508 		TheDataPagingMedia = aPrimaryMedia;
       
  4509 		}
       
  4510 
       
  4511 	__KTRACE_OPT2(KBOOT,KLOCDPAGING,Kern::Printf("<RegisterPagingDevice"));
       
  4512 	return KErrNone;
       
  4513 	}
       
  4514 
       
  4515 #else //__DEMAND_PAGING__
       
  4516 
       
  4517 #if !defined(__WINS__)
       
  4518 EXPORT_C TInt LocDrv::RegisterPagingDevice(DPrimaryMediaBase* , const TInt* , TInt , TUint , TInt , TUint )
       
  4519 	{
       
  4520 	return KErrNotSupported;
       
  4521 	}		// stub for def file
       
  4522 #endif // __WINS__
       
  4523 
       
  4524 #endif //__DEMAND_PAGING__
       
  4525 
       
  4526 
       
  4527 /**
       
  4528 Registers a media device with physical memory addressing capabilities with the
       
  4529 Local Media Subsystem.
       
  4530 
       
  4531 @param aPrimaryMedia A pointer to the primary DPrimaryMedia object associated 
       
  4532 					 with the media device.
       
  4533 @param aMediaBlockSize The Minimum transfer size (bytes) for the media device.
       
  4534 @param aDmaMaxAddressable The Maximum Addressing Range for the media device's DMA controller, 0 if None.				 
       
  4535 @param aDmaAlignment The required memory alignment for the media device's DMA controller.
       
  4536 
       
  4537 @return KErrNone, Always;
       
  4538 */
       
  4539 EXPORT_C TInt LocDrv::RegisterDmaDevice(DPrimaryMediaBase* aPrimaryMedia, 
       
  4540 										TInt aMediaBlockSize,				// Minimum transfer size (bytes) for the media
       
  4541 										TInt aDmaMaxAddressable,			// Max Addressing Range for DMA controller, 0 if None.
       
  4542 										TInt aDmaAlignment)					// DMA Alignment e.g. word alignment required = 2
       
  4543 	{
       
  4544 	__KTRACE_OPT(KBOOT ,Kern::Printf("RegisterPhysicalAddrDevice: PM=0x%x BS=%d MaxAddr=%d DMA=%d", 
       
  4545 									aPrimaryMedia, aMediaBlockSize, aDmaMaxAddressable, aDmaAlignment));
       
  4546 
       
  4547 	for (TInt i=0; i<KMaxLocalDrives; ++i)
       
  4548 		{
       
  4549 		TLocDrv* pL=TheDrives[i];
       
  4550 		if (pL && pL->iPrimaryMedia == aPrimaryMedia && pL->iDmaHelper == NULL)
       
  4551 			{
       
  4552 			pL->iDmaHelper = new DDmaHelper;
       
  4553 			__ASSERT_ALWAYS(pL != NULL, LOCM_FAULT());
       
  4554 			
       
  4555 			// if no limit stated on addressing range use 1MB
       
  4556 			TInt MaxAddress = aDmaMaxAddressable ? (1024*1024) : aDmaMaxAddressable;
       
  4557 			
       
  4558 			TInt r = pL->iDmaHelper->Construct(MaxAddress, aMediaBlockSize, aDmaAlignment);
       
  4559 			__ASSERT_ALWAYS(r == KErrNone, LOCM_FAULT());
       
  4560 			}
       
  4561 		}
       
  4562 
       
  4563 	return KErrNone;
       
  4564 	}
       
  4565 
       
  4566 void GetDriveInfo(TDriveInfoV1& info)
       
  4567 	{
       
  4568 	TInt i;
       
  4569 	TInt drives=0;
       
  4570 	TUint32 sock_mask=0;
       
  4571 	TInt sockets=0;
       
  4572 
       
  4573 	info.iRegisteredDriveBitmask = 0;
       
  4574 
       
  4575 	for (i=0; i<KMaxPBusSockets; ++i)
       
  4576 		info.iSocketName[i].Zero();
       
  4577 	for (i=0; i<KMaxLocalDrives; ++i)
       
  4578 		{
       
  4579 		TLocDrv* pL=TheDrives[i];
       
  4580 		if (pL)
       
  4581 			{
       
  4582 			++drives;
       
  4583 			TInt sockNum;
       
  4584 			DPrimaryMediaBase* pM=pL->iPrimaryMedia;
       
  4585 			if (pM->IsRemovableDevice(sockNum))
       
  4586 				{
       
  4587 				if (!(sock_mask & (1<<sockNum)))
       
  4588 					{
       
  4589 					info.iSocketName[sockNum]=*DriveNames[i];
       
  4590 					__KTRACE_OPT(KLOCDRV,Kern::Printf("Socket %d device %d name %lS", sockNum, pM->iDevice, DriveNames[i]));
       
  4591 					if ( (sockNum + 1) > sockets )
       
  4592 						sockets = sockNum + 1;
       
  4593 					}
       
  4594 				sock_mask |= (1<<sockNum);
       
  4595 				}
       
  4596 			info.iDriveName[i]=*DriveNames[i];
       
  4597 			__KTRACE_OPT(KLOCDRV,Kern::Printf("Drive %d device %d name %lS",i,pM->iDevice,DriveNames[i]));
       
  4598 			
       
  4599 			info.iRegisteredDriveBitmask |= (0x01 << i);
       
  4600 			}
       
  4601 		}
       
  4602 	info.iTotalSupportedDrives=drives;
       
  4603 	info.iTotalSockets=sockets;
       
  4604 	info.iRuggedFileSystem=ETrue;
       
  4605 	__KTRACE_OPT(KLOCDRV,Kern::Printf("Total drives=%d, sockets=%d",drives,sockets));
       
  4606 	}
       
  4607 
       
  4608 #if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
       
  4609 void ResetConcurrencyStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
       
  4610 	{
       
  4611 	NKern::FMWait(&aDevice->iInstrumentationLock);
       
  4612 	switch(aStats)
       
  4613 		{
       
  4614 		case EMediaPagingStatsRom:
       
  4615 			aDevice->iServicingROM=0;
       
  4616 			memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
       
  4617 			break;
       
  4618 		case EMediaPagingStatsCode:
       
  4619 			aDevice->iServicingCode=0;
       
  4620 			memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
       
  4621 			break;
       
  4622 		case EMediaPagingStatsDataIn:
       
  4623 			aDevice->iServicingDataIn=0;
       
  4624 			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
       
  4625 			break;
       
  4626 		case EMediaPagingStatsDataOut:
       
  4627 			aDevice->iServicingDataOut=0;
       
  4628 			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
       
  4629 			break;
       
  4630 		case EMediaPagingStatsAll:
       
  4631 			aDevice->iServicingROM=0;
       
  4632 			aDevice->iServicingCode=0;
       
  4633 			aDevice->iServicingDataIn=0;
       
  4634 			aDevice->iServicingDataOut=0;
       
  4635 			memclr(&aDevice->iROMStats,sizeof(SMediaROMPagingConcurrencyInfo));
       
  4636 			memclr(&aDevice->iCodeStats,sizeof(SMediaCodePagingConcurrencyInfo));
       
  4637 			memclr(&aDevice->iDataStats,sizeof(SMediaDataPagingConcurrencyInfo));
       
  4638 			break;
       
  4639 		}
       
  4640 	NKern::FMSignal(&aDevice->iInstrumentationLock);
       
  4641 	}
       
  4642 #endif
       
  4643 #if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
       
  4644 void ResetBenchmarkStats(DMediaPagingDevice* aDevice, TMediaPagingStats aStats)
       
  4645 	{
       
  4646 	NKern::FMWait(&aDevice->iInstrumentationLock);
       
  4647 	switch(aStats)
       
  4648 		{
       
  4649 		case EMediaPagingStatsRom:
       
  4650 			aDevice->iROMBenchmarkData.iCount = 0;
       
  4651 			aDevice->iROMBenchmarkData.iTotalTime = 0;
       
  4652 			aDevice->iROMBenchmarkData.iMaxTime = 0;
       
  4653 			aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
       
  4654 			break;
       
  4655 		case EMediaPagingStatsCode:
       
  4656 			aDevice->iCodeBenchmarkData.iCount = 0;
       
  4657 			aDevice->iCodeBenchmarkData.iTotalTime = 0;
       
  4658 			aDevice->iCodeBenchmarkData.iMaxTime = 0;
       
  4659 			aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
       
  4660 			break;
       
  4661 		case EMediaPagingStatsDataIn:
       
  4662 			aDevice->iDataInBenchmarkData.iCount = 0;
       
  4663 			aDevice->iDataInBenchmarkData.iTotalTime = 0;
       
  4664 			aDevice->iDataInBenchmarkData.iMaxTime = 0;
       
  4665 			aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
       
  4666 			break;
       
  4667 		case EMediaPagingStatsDataOut:
       
  4668 			aDevice->iDataOutBenchmarkData.iCount = 0;
       
  4669 			aDevice->iDataOutBenchmarkData.iTotalTime = 0;
       
  4670 			aDevice->iDataOutBenchmarkData.iMaxTime = 0;
       
  4671 			aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
       
  4672 			break;
       
  4673 		case EMediaPagingStatsAll:
       
  4674 			aDevice->iDataInBenchmarkData.iCount = 0;
       
  4675 			aDevice->iDataInBenchmarkData.iTotalTime = 0;
       
  4676 			aDevice->iDataInBenchmarkData.iMaxTime = 0;
       
  4677 			aDevice->iDataInBenchmarkData.iMinTime = KMaxTInt;
       
  4678 
       
  4679 			aDevice->iDataOutBenchmarkData.iCount = 0;
       
  4680 			aDevice->iDataOutBenchmarkData.iTotalTime = 0;
       
  4681 			aDevice->iDataOutBenchmarkData.iMaxTime = 0;
       
  4682 			aDevice->iDataOutBenchmarkData.iMinTime = KMaxTInt;
       
  4683 
       
  4684 			aDevice->iROMBenchmarkData.iCount = 0;
       
  4685 			aDevice->iROMBenchmarkData.iTotalTime = 0;
       
  4686 			aDevice->iROMBenchmarkData.iMaxTime = 0;
       
  4687 			aDevice->iROMBenchmarkData.iMinTime = KMaxTInt;
       
  4688 
       
  4689 			aDevice->iCodeBenchmarkData.iCount = 0;
       
  4690 			aDevice->iCodeBenchmarkData.iTotalTime = 0;
       
  4691 			aDevice->iCodeBenchmarkData.iMaxTime = 0;
       
  4692 			aDevice->iCodeBenchmarkData.iMinTime = KMaxTInt;
       
  4693 			break;
       
  4694 		}
       
  4695 	NKern::FMSignal(&aDevice->iInstrumentationLock);
       
  4696 	}
       
  4697 #endif
       
  4698 
       
  4699 TInt MediaHalFunction(TAny*, TInt aFunction, TAny* a1, TAny* a2)
       
  4700 	{
       
  4701 	TInt r=KErrNotSupported;
       
  4702 	switch (aFunction)
       
  4703 		{
       
  4704 		case EMediaHalDriveInfo:
       
  4705 			{
       
  4706 			(void) a2;
       
  4707 			TDriveInfoV1Buf infoBuf;
       
  4708 			TDriveInfoV1& info=infoBuf();
       
  4709 			GetDriveInfo(info);
       
  4710 			Kern::InfoCopy(*(TDes8*)a1,infoBuf);
       
  4711 			r=KErrNone;
       
  4712 			break;
       
  4713 			}
       
  4714 #if defined(__DEMAND_PAGING__) && defined(__CONCURRENT_PAGING_INSTRUMENTATION__)
       
  4715 		case EMediaHalGetROMConcurrencyInfo:
       
  4716 			{
       
  4717 			TInt drvNo=(TInt)a1;
       
  4718 			TLocDrv* drv=TheDrives[drvNo];
       
  4719 			if(!drv)
       
  4720 				break;
       
  4721 			DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4722 			if(!device)
       
  4723 				break;
       
  4724 			NKern::FMWait(&device->iInstrumentationLock);
       
  4725 			SMediaROMPagingConcurrencyInfo info=device->iROMStats;
       
  4726 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4727 			kumemput32(a2,&info,sizeof(info));
       
  4728 			r=KErrNone;
       
  4729 			break;
       
  4730 			}
       
  4731 		case EMediaHalGetCodeConcurrencyInfo:
       
  4732 			{
       
  4733 			TInt drvNo=(TInt)a1;
       
  4734 			TLocDrv* drv=TheDrives[drvNo];
       
  4735 			if(!drv)
       
  4736 				break;
       
  4737 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4738 			if(!device)
       
  4739 				break;
       
  4740 			NKern::FMWait(&device->iInstrumentationLock);
       
  4741 			SMediaCodePagingConcurrencyInfo info=device->iCodeStats;
       
  4742 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4743 			kumemput32(a2,&info,sizeof(info));
       
  4744 			r=KErrNone;
       
  4745 			break;
       
  4746 			}
       
  4747 		case EMediaHalGetDataConcurrencyInfo:
       
  4748 			{
       
  4749 			TInt drvNo=(TInt)a1;
       
  4750 			TLocDrv* drv=TheDrives[drvNo];
       
  4751 			if(!drv)
       
  4752 				break;
       
  4753 			DMediaPagingDevice* device = drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4754 			if(!device)
       
  4755 				break;
       
  4756 			NKern::FMWait(&device->iInstrumentationLock);
       
  4757 			SMediaDataPagingConcurrencyInfo info=device->iDataStats;
       
  4758 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4759 			kumemput32(a2,&info,sizeof(info));
       
  4760 			r=KErrNone;
       
  4761 			break;
       
  4762 			}
       
  4763 		case EMediaHalResetConcurrencyInfo:
       
  4764 			{
       
  4765 			TInt drvNo=(TInt)a1;
       
  4766 			TLocDrv* drv=TheDrives[drvNo];
       
  4767 			if(!drv)
       
  4768 				break;
       
  4769 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4770 			if(!device)
       
  4771 				break;
       
  4772 			TUint index=(TInt)a2;
       
  4773 			if(index>EMediaPagingStatsCode)
       
  4774 				break;
       
  4775 			ResetConcurrencyStats(device, (TMediaPagingStats)index);
       
  4776 			r=KErrNone;
       
  4777 			break;
       
  4778 			}
       
  4779 #endif
       
  4780 #if defined(__DEMAND_PAGING__) && defined(__DEMAND_PAGING_BENCHMARKS__)
       
  4781 		case EMediaHalGetROMPagingBenchmark:
       
  4782 			{
       
  4783 			TInt drvNo=(TInt)a1;
       
  4784 			TLocDrv* drv=TheDrives[drvNo];
       
  4785 			if(!drv)
       
  4786 				break;
       
  4787 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4788 			if(!device)
       
  4789 				break;
       
  4790 			NKern::FMWait(&device->iInstrumentationLock);
       
  4791 			SPagingBenchmarkInfo info = device->iROMBenchmarkData;
       
  4792 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4793 			kumemput32(a2,&info,sizeof(info));
       
  4794 			r=KErrNone;
       
  4795 			break;
       
  4796 			}		
       
  4797 		case EMediaHalGetCodePagingBenchmark:
       
  4798 			{
       
  4799 			TInt drvNo=(TInt)a1;
       
  4800 			TLocDrv* drv=TheDrives[drvNo];
       
  4801 			if(!drv)
       
  4802 				break;
       
  4803 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4804 			if(!device)
       
  4805 				break;
       
  4806 			NKern::FMWait(&device->iInstrumentationLock);
       
  4807 			SPagingBenchmarkInfo info = device->iCodeBenchmarkData;
       
  4808 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4809 			kumemput32(a2,&info,sizeof(info));
       
  4810 			r=KErrNone;
       
  4811 			break;
       
  4812 			}	
       
  4813 		case EMediaHalGetDataInPagingBenchmark:
       
  4814 			{
       
  4815 			TInt drvNo=(TInt)a1;
       
  4816 			TLocDrv* drv=TheDrives[drvNo];
       
  4817 			if(!drv)
       
  4818 				break;
       
  4819 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4820 			if(!device)
       
  4821 				break;
       
  4822 			NKern::FMWait(&device->iInstrumentationLock);
       
  4823 			SPagingBenchmarkInfo info = device->iDataInBenchmarkData;
       
  4824 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4825 			kumemput32(a2,&info,sizeof(info));
       
  4826 			r=KErrNone;
       
  4827 			break;
       
  4828 			}		
       
  4829 		case EMediaHalGetDataOutPagingBenchmark:
       
  4830 			{
       
  4831 			TInt drvNo=(TInt)a1;
       
  4832 			TLocDrv* drv=TheDrives[drvNo];
       
  4833 			if(!drv)
       
  4834 				break;
       
  4835 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4836 			if(!device)
       
  4837 				break;
       
  4838 			NKern::FMWait(&device->iInstrumentationLock);
       
  4839 			SPagingBenchmarkInfo info = device->iDataOutBenchmarkData;
       
  4840 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4841 			kumemput32(a2,&info,sizeof(info));
       
  4842 			r=KErrNone;
       
  4843 			break;
       
  4844 			}		
       
  4845 		case EMediaHalResetPagingBenchmark:
       
  4846 			{
       
  4847 			TInt drvNo=(TInt)a1;
       
  4848 			TLocDrv* drv=TheDrives[drvNo];
       
  4849 			if(!drv)
       
  4850 				break;
       
  4851 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4852 			if(!device)
       
  4853 				break;
       
  4854 			TUint index=(TInt)a2;
       
  4855 			if(index>EMediaPagingStatsCode)
       
  4856 				break;
       
  4857 			ResetBenchmarkStats(device, (TMediaPagingStats)index);
       
  4858 			r=KErrNone;
       
  4859 			break;
       
  4860 			}
       
  4861 		case EMediaHalGetPagingInfo:
       
  4862 			{
       
  4863 			TInt drvNo=(TInt)a1;
       
  4864 			TLocDrv* drv=TheDrives[drvNo];
       
  4865 			if(!drv)
       
  4866 				break;
       
  4867 			DMediaPagingDevice* device=drv->iPrimaryMedia->iBody->iPagingDevice;
       
  4868 			if(!device)
       
  4869 				break;
       
  4870 			NKern::FMWait(&device->iInstrumentationLock);
       
  4871 			SMediaPagingInfo info = device->iMediaPagingInfo;
       
  4872 			NKern::FMSignal(&device->iInstrumentationLock);
       
  4873 			kumemput32(a2,&info,sizeof(info));
       
  4874 			r=KErrNone;
       
  4875 			break;
       
  4876 			}		
       
  4877 #endif
       
  4878 		default:
       
  4879 			break;
       
  4880 		}
       
  4881 	return r;
       
  4882 	}
       
  4883 
       
  4884 
       
  4885 /******************************************************************************
       
  4886  Partition table scanner
       
  4887  ******************************************************************************/
       
  4888 
       
  4889 #ifdef _DEBUG
       
  4890 #define DMEMDUMP(base,size)	DbgMemDump((TLinAddr)base,size)
       
  4891 void DbgMemDump(TLinAddr aBase, TInt aSize)
       
  4892 	{
       
  4893 	TInt off;
       
  4894 	const TUint8* p=(const TUint8*)aBase;
       
  4895 	NKern::Lock();
       
  4896 	for (off=0; off<aSize; off+=16, p+=16)
       
  4897 		{
       
  4898 		Kern::Printf("%04x: %02x %02x %02x %02x  %02x %02x %02x %02x | %02x %02x %02x %02x  %02x %02x %02x %02x",
       
  4899 			off,	p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
       
  4900 					p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
       
  4901 		}
       
  4902 	NKern::Unlock();
       
  4903 	}
       
  4904 #else
       
  4905 #define DMEMDUMP(base,size)
       
  4906 #endif
       
  4907 
       
  4908 EXPORT_C void TPartitionTableScanner::Set(TUint8* aSectorBuffer, TPartitionEntry* aEntry, TInt aMaxPartitions, TInt64 aMediaSize)
       
  4909 	{
       
  4910 	__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner @ %08x : buf %08x entry %08x max %d sz %08x %08x",
       
  4911 								this, aSectorBuffer, aEntry, aMaxPartitions, I64HIGH(aMediaSize), I64LOW(aMediaSize)));
       
  4912 	__ASSERT_ALWAYS(aMaxPartitions>0, LOCM_FAULT());
       
  4913 	memclr(this, sizeof(TPartitionTableScanner));
       
  4914 	iLBA = -1;
       
  4915 	iSectorBuffer = aSectorBuffer;
       
  4916 	iFirstEntry = aEntry;
       
  4917 	iNextEntry = aEntry;
       
  4918 	iLimit = aEntry + aMaxPartitions;
       
  4919 	iMediaSize = aMediaSize;
       
  4920 	}
       
  4921 
       
  4922 EXPORT_C TInt TPartitionTableScanner::NumberOfPartitionsFound() const
       
  4923 	{
       
  4924 	TInt n = iNextEntry - iFirstEntry;
       
  4925 	__KTRACE_OPT(KLOCDRV, Kern::Printf("TPartitionTableScanner N=%d", n));
       
  4926 	return n;
       
  4927 	}
       
  4928 
       
  4929 TPartitionTableScanner::SPart::SPart(const TUint8* a)
       
  4930 	{
       
  4931 	iBootInd = a[0];
       
  4932 	iType = a[4];
       
  4933 	iRSS = a[8]|(a[9]<<8)|(a[10]<<16)|(a[11]<<24);
       
  4934 	iSectors = a[12]|(a[13]<<8)|(a[14]<<16)|(a[15]<<24);
       
  4935 	__KTRACE_OPT(KLOCDRV, Kern::Printf("SPart: BI=%02x TYPE=%02x RSS=%08x SIZE=%08x", iBootInd, iType, iRSS, iSectors));
       
  4936 	}
       
  4937 
       
  4938 TInt TPartitionTableScanner::MakeEntry(const SPart& a)
       
  4939 	{
       
  4940 	if (iNextEntry == iLimit)
       
  4941 		return KErrOverflow;
       
  4942 	if (a.iRSS<=0 || a.iSectors<=0 || a.iRSS>=iMediaSize)
       
  4943 		return KErrCorrupt;
       
  4944 	if (TUint64(a.iRSS) + TUint64(a.iSectors) > TUint64(iMediaSize))
       
  4945 		return KErrCorrupt;
       
  4946 	iNextEntry->iBootIndicator = a.iBootInd;
       
  4947 	iNextEntry->iPartitionType = a.iType;
       
  4948 	iNextEntry->iPartitionBaseAddr = TInt64(a.iRSS)<<ESectorShift;
       
  4949 	iNextEntry->iPartitionLen = TInt64(a.iSectors)<<ESectorShift;
       
  4950 	++iNextEntry;
       
  4951 	return KErrNone;
       
  4952 	}
       
  4953 
       
  4954 EXPORT_C TInt64 TPartitionTableScanner::NextLBA()
       
  4955 	{
       
  4956 	__KTRACE_OPT(KLOCDRV, Kern::Printf(">TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
       
  4957 	TInt r;
       
  4958 	TUint8* b = iSectorBuffer;
       
  4959 	TUint8* pS = b + 0x1be;
       
  4960 	TUint8* pE = pS + 64;
       
  4961 	TUint8* p = pS;
       
  4962 	TInt orig_sp = iStackPointer;
       
  4963 	TInt sp;
       
  4964 	if (iLBA < 0)
       
  4965 		{
       
  4966 		iLBA = 0;
       
  4967 		goto end;
       
  4968 		}
       
  4969 	__KTRACE_OPT(KLOCDRV,DMEMDUMP(b, ESectorSize));
       
  4970 	if (b[ESectorSize-2]!=0x55 || b[ESectorSize-1]!=0xaa)
       
  4971 		{
       
  4972 		__KTRACE_OPT(KLOCDRV, Kern::Printf("Bad signature"));
       
  4973 		iLBA = KErrCorrupt;
       
  4974 		goto end;
       
  4975 		}
       
  4976 	if (iLBA==0 && iNextEntry==iFirstEntry)
       
  4977 		{
       
  4978 		// Look for bootable partition first
       
  4979 		for (; p<pE; p+=16)
       
  4980 			{
       
  4981 			SPart pt(p);
       
  4982 			if (pt.iBootInd==0x80 && pt.iType && pt.iSectors>0)
       
  4983 				{
       
  4984 				p[4] = 0;
       
  4985 				r = MakeEntry(pt);
       
  4986 				if (r!=KErrNone)
       
  4987 					{
       
  4988 					iLBA = r;
       
  4989 					goto end;
       
  4990 					}
       
  4991 				}
       
  4992 			}
       
  4993 		}
       
  4994 	// Look for extended partitions
       
  4995 	for (p=pE-16; p>=pS; p-=16)
       
  4996 		{
       
  4997 		SPart pt(p);
       
  4998 		if ((pt.iType==0x05 || pt.iType==0x0f) && pt.iSectors>0)
       
  4999 			{
       
  5000 			// This one is an EBR
       
  5001 			p[4] = 0;
       
  5002 			if (iStackPointer == EMaxNest)
       
  5003 				{
       
  5004 				if (iStackPointer == orig_sp)
       
  5005 					continue;
       
  5006 				--iStackPointer;
       
  5007 				for(sp = orig_sp; sp<iStackPointer; ++sp)
       
  5008 					iStack[sp] = iStack[sp+1];
       
  5009 				}
       
  5010 			iStack[iStackPointer].iRSS = pt.iRSS;
       
  5011 			iStack[iStackPointer].iSectors = pt.iSectors;
       
  5012 			++iStackPointer;
       
  5013 #ifdef _DEBUG
       
  5014 			for (sp=0; sp<iStackPointer; ++sp)
       
  5015 				{
       
  5016 				const TInt64& rss = iStack[sp].iRSS;
       
  5017 				const TInt64& size = iStack[sp].iSectors;
       
  5018 				__KTRACE_OPT(KLOCDRV, Kern::Printf("Stack[%d] RSS %08x %08x SIZE %08x %08x", sp,
       
  5019 					I64HIGH(rss), I64LOW(rss), I64HIGH(size), I64LOW(size) ));
       
  5020 				}
       
  5021 #endif
       
  5022 			}
       
  5023 		}
       
  5024 	// Look for other data partitions
       
  5025 	for (p=pS; p<pE; p+=16)
       
  5026 		{
       
  5027 		SPart pt(p);
       
  5028 		if (pt.iType && pt.iSectors>0)
       
  5029 			{
       
  5030 			pt.iRSS += TUint32(iLBA);	// data partitions are specified relative to the EBR they appear in
       
  5031 			r = MakeEntry(pt);
       
  5032 			if (r!=KErrNone)
       
  5033 				{
       
  5034 				iLBA = r;
       
  5035 				goto end;
       
  5036 				}
       
  5037 			}
       
  5038 		}
       
  5039 	// If any EBRs on stack, pop off the first and process it
       
  5040 	if (iStackPointer)
       
  5041 		{
       
  5042 		--iStackPointer;
       
  5043 		iLBA = iFirstEBR + iStack[iStackPointer].iRSS;	// LBA of second and subsequent EBR is specified relative to first EBR
       
  5044 		if (!iFirstEBR)
       
  5045 			iFirstEBR = iLBA;
       
  5046 		}
       
  5047 	else
       
  5048 		iLBA = KErrEof;	// finished
       
  5049 
       
  5050 end:
       
  5051 	__KTRACE_OPT(KLOCDRV, Kern::Printf("<TPartitionTableScanner iLBA=%08x %08x", I64HIGH(iLBA), I64LOW(iLBA)));
       
  5052 	return iLBA;
       
  5053 	}
       
  5054 
       
  5055 /**
       
  5056  * Returns Address and Length of next contiguous Physical memory fragment
       
  5057  * 
       
  5058  * @param aAddr On success, populated with the Physical Address of the next fragment.
       
  5059  * @param aLen  On success, populated with the length in bytes of the next fragment.
       
  5060  * 
       
  5061  * @return KErrNone, if successful;
       
  5062  * 		   KErrNoMemory, if no more memory fragments left.
       
  5063  * 		   KErrNotSupported, if Physical Memory addressing is not supported by this Media.
       
  5064  */
       
  5065 EXPORT_C TInt TLocDrvRequest::GetNextPhysicalAddress(TPhysAddr& aAddr, TInt& aLen)
       
  5066 	{
       
  5067 	if (Flags() & EPhysAddr) 
       
  5068 		{
       
  5069 
       
  5070 #ifdef __DEMAND_PAGING__
       
  5071 		if (DMediaPagingDevice::PagingRequest(*this))
       
  5072 			{
       
  5073 			return DDmaHelper::GetPhysicalAddress(*this, aAddr, aLen);
       
  5074 			}
       
  5075 #endif
       
  5076 		return Drive()->iDmaHelper->GetPhysicalAddress(aAddr, aLen);
       
  5077 		}
       
  5078 	else
       
  5079 		{
       
  5080 		return KErrNotSupported;
       
  5081 		}
       
  5082 	}
       
  5083 
       
  5084 
       
  5085 /******************************************************************************
       
  5086  Entry point
       
  5087  ******************************************************************************/
       
  5088 DECLARE_STANDARD_EXTENSION()
       
  5089 	{
       
  5090 	__KTRACE_OPT(KBOOT,Kern::Printf("Starting LOCMEDIA extension"));
       
  5091 
       
  5092 	// install the HAL function
       
  5093 	TInt r=Kern::AddHalEntry(EHalGroupMedia,MediaHalFunction,NULL);
       
  5094 #ifdef __DEMAND_PAGING__
       
  5095 	if (r==KErrNone)
       
  5096 		{
       
  5097 		__KTRACE_OPT(KBOOT,Kern::Printf("Creating LocDrv device"));
       
  5098 		DLocalDriveFactory* device = new DLocalDriveFactory;
       
  5099 		if (device==NULL)
       
  5100 			r=KErrNoMemory;
       
  5101 		else
       
  5102 			r=Kern::InstallLogicalDevice(device);
       
  5103 		__KTRACE_OPT(KBOOT,Kern::Printf("Installing LocDrv device in kernel returned %d",r));
       
  5104 		}
       
  5105 #endif // __DEMAND_PAGING__
       
  5106 	return r;
       
  5107 	}
       
  5108 
       
  5109