os/kernelhwsrv/kernel/eka/drivers/medmmc/medmmc.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1999-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 // Media driver for MultiMediaCard Flash device
    15 // 
    16 //
    17 
    18 #include "mmc.h" 
    19 #include "pbusmedia.h"
    20 #include <drivers/emmcptn.h>
    21 
    22 #include "OstTraceDefinitions.h"
    23 #ifdef OST_TRACE_COMPILER_IN_USE
    24 #include "locmedia_ost.h"
    25 #ifdef __VC32__
    26 #pragma warning(disable: 4127) // disabling warning "conditional expression is constant"
    27 #endif
    28 #include "medmmcTraces.h"
    29 #endif
    30 
    31 #if defined(__DEMAND_PAGING__)
    32 	// If in debug mode, enable paging stats and their retrieval using DLocalDrive::EControlIO
    33 	#if defined( _DEBUG)
    34 		#define __TEST_PAGING_MEDIA_DRIVER__
    35 	#endif
    36 	#include "mmcdp.h"
    37 #endif
    38 
    39 #ifndef BTRACE_PAGING_MEDIA
    40 	#undef BTraceContext8
    41 	#define BTraceContext8(aCategory,aSubCategory,a1,a2) 
    42 #endif	// BTRACE_PAGING_MEDIA
    43 
    44 // Enable this macro to debug cache: 
    45 // NB The greater the number of blocks, the slower this is...
    46 //#define _DEBUG_CACHE
    47 #ifdef _DEBUG_CACHE
    48 #define __ASSERT_CACHE(c,p) (void)((c)||(p,0))
    49 #else
    50 #define __ASSERT_CACHE(c,p)
    51 #endif
    52 
    53 
    54 GLREF_C TInt GetMediaDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry, TUint16& aReservedSectors, const TMMCard* aCardP);
    55 GLREF_C TBool MBRMandatory(const TMMCard* aCardP);
    56 GLREF_C TBool CreateMBRAfterFormat(const TMMCard* aCardP);
    57 GLREF_C TInt BlockSize(const TMMCard* aCardP);
    58 GLREF_C TInt EraseBlockSize(const TMMCard* aCardP);
    59 GLREF_C TInt GetCardFormatInfo(const TMMCard* aCardP, TLDFormatInfo& aFormatInfo);
    60 
    61 const TInt KStackNumber = 0;
    62 
    63 const TInt KDiskSectorSize=512;
    64 const TInt KDiskSectorShift=9;
    65 
    66 const TInt KIdleCurrentInMilliAmps = 1;
    67 
    68 const TInt KMBRFirstPartitionEntry=0x1BE;
    69 
    70 template <class T>
    71 inline T UMin(T aLeft,T aRight)
    72 	{return(aLeft<aRight ? aLeft : aRight);}
    73 
    74 
    75 class DPhysicalDeviceMediaMmcFlash : public DPhysicalDevice
    76 	{
    77 public:
    78 	DPhysicalDeviceMediaMmcFlash();
    79 
    80 	virtual TInt Install();
    81 	virtual void GetCaps(TDes8& aDes) const;
    82 	virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* aInfo, const TVersion& aVer);
    83 	virtual TInt Validate(TInt aDeviceType, const TDesC8* aInfo, const TVersion& aVer);
    84 	virtual TInt Info(TInt aFunction, TAny* a1);
    85 	};
    86 
    87 
    88 // these should be static const members of DMmcMediaDriverFlash, but VC doesn't support this
    89 const TInt64 KInvalidBlock = -1;
    90 const TInt KNoCacheBlock = -1;
    91 
    92 class DMmcMediaDriverFlash : public DMediaDriver
    93 	{
    94 public:
    95 	DMmcMediaDriverFlash(TInt aMediaId);
    96 	~DMmcMediaDriverFlash();
    97 	// ...from DMediaDriver
    98 	virtual void Close();
    99 	// replacing pure virtual
   100 	virtual void Disconnect(DLocalDrive* aLocalDrive, TThreadMessage*);
   101 	virtual TInt Request(TLocDrvRequest& aRequest);
   102 	virtual TInt PartitionInfo(TPartitionInfo& anInfo);
   103 	virtual void NotifyPowerDown();
   104 	virtual void NotifyEmergencyPowerDown();
   105 	// For creation by DPhysicalDeviceMediaMmcFlash
   106 	TInt DoCreate(TInt aMediaId);
   107 
   108 private:
   109 	enum TPanic
   110 		{
   111 		EDRInUse		= 0x0000,	EDRStart, EDRNotPositive, EDREnd,
   112 		ELRRequest		= 0x0010,	ELRStart, ELRNotPositive, ELREnd, ELRCached,
   113 		EDWInUse		= 0x0020,	EDWStart, EDWNotPositive, EDWEnd,
   114 		EDFInUse		= 0x0030,	EDFStart, EDFNotPositive, EDFEnd, ENotMmcSocket,
   115 		ELWRequest		= 0x0040,	ELWStart, ELWFmtStAlign, ELWNotPositive, ELWEnd, ELWFmtEndAlign, 
   116 									ELWLength, ELFStart, ELFEnd, ELFNotPositive,
   117 		ERPIInUse		= 0x0050,
   118 		EPCInUse		= 0x0060,	EPCFunc,
   119 		ESECBQueued		= 0x0070,
   120 		EDSEDRequest	= 0x0080,	EDSEDNotErrComplete,
   121 		ECRReqIdle		= 0x0090,	ECRRequest,
   122 		ERRBStAlign		= 0x00a0,	ERRBStPos, ERRBNotPositive, ERRBEndAlign, ERRBEndPos,
   123 									ERRBOverflow, ERRBCchInv, ERRBExist,
   124 		ERWBStPos		= 0x00b0,	ERWBNotPositive, ERWBEndPos, ERWBOverflow, ERWBCchInv,
   125 		EMBStPos		= 0x00c0,	EMBStAlign, EMBNotPositive, EMBEndPos, EMBEndAlign,
   126 									EMBOverflow, EMBCchInvPre, EMBCchInvPost,
   127 		EBGAStPos		= 0x00d0,	EBGAStAlign, EBGANotPositive, EBGAEndPos, EBGAEndAlign,
   128 									EBGAOverflow, EBGACchInv,
   129 		EICMNegative	= 0x00e0,	EICMOverflow, ECMIOverflow,
   130 		EGCBAlign		= 0x00f0,	EGCBPos, EGCBCchInv,
   131 		
   132 		ECFSessPtrNull	= 0x0100,	// Code Fault - session pointer NULL
   133 
   134 		EDBNotEven		= 0x0110,	// Not and even number of blocks in the buffer cache
   135 		EDBCBQueued		= 0x0111,	// The data transfer callback is already queued
   136 		EDBLength		= 0x0112,	// The length of data to transfer in data transfer callback is not positive
   137 		EDBLengthTooBig	= 0x0113,	// The length of data to transfer in data transfer callback is too big
   138 		EDBOffsetTooBig = 0x0114,	// The Offset into the user data buffer is too big
   139 		EDBCacheInvalid	= 0x0115,	// The cache is invalid at the end of data transfer
   140 		EDBNotOptimal	= 0x0116,	// Due to Cache size DB functionality will never be utilised
   141 		ENoDBSupport	= 0x0120,	// DMA request arrived but PSL does not support double buffering
   142 		ENotDMAAligned  = 0x0121,
   143 		};
   144 	static void Panic(TPanic aPnc);
   145 
   146 	enum TMediaRequest
   147 		{
   148 		EMReqRead = 0,
   149 		EMReqWrite = 1,
   150 		EMReqFormat = 2,
   151 		EMReqPtnInfo,
   152 		EMReqPswdCtrl,
   153 		EMReqForceErase,
   154 		EMReqUpdatePtnInfo,
   155 		EMReqWritePasswordData,
   156 		EMReqIdle,
   157 		EMReqEMMCPtnInfo,
   158 		};
   159 	enum TMediaReqType {EMReqTypeNormalRd,EMReqTypeNormalWr,EMReqTypeUnlockPswd,EMReqTypeChangePswd};
   160 
   161 	enum {KWtRBMFst = 0x00000001, 	// iWtRBM - Read First Block only
   162 		  KWtRBMLst = 0x00000002,	// iWtRBM - Read Last Block only
   163 		  KWtMinFst = 0x00000004,	// iWtRBM - Write First Block only
   164 		  KWtMinLst = 0x00000008,	// iWtRBM - Write Last Block only
   165 		  KIPCSetup = 0x00000010,	// iRdROB - IPC Setup Next Iteration
   166 		  KIPCWrite = 0x00000020};	// iRdROB - IPC Write Next Iteration
   167 
   168 private:
   169 	// MMC device specific stuff
   170 	TInt DoRead();
   171 	TInt DoWrite();
   172 	TInt DoFormat();
   173 	TInt Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo);
   174 
   175 	inline DMMCStack& Stack() const;
   176 	inline TInt CardNum() const;
   177 	inline TMediaRequest CurrentRequest() const;
   178 
   179 	TInt LaunchRead(TInt64 aStart, TUint32 aLength);
   180 	TInt LaunchDBRead();
   181 	TInt LaunchPhysRead(TInt64 aStart, TUint32 aLength);
   182 	
   183 	TInt LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq);
   184 	TInt LaunchFormat(TInt64 aStart, TUint32 aLength);
   185 
   186 	TInt LaunchRPIUnlock(TLocalDrivePasswordData& aData);
   187 	TInt LaunchRPIRead();
   188 	TInt LaunchRPIErase();
   189 	TInt DecodePartitionInfo();
   190 	TInt WritePartitionInfo();
   191 	TInt GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry);
   192 	TInt CreateDefaultPartition();
   193 
   194 
   195 #if defined __TEST_PAGING_MEDIA_DRIVER__
   196 	TInt HandleControlIORequest();
   197 #endif
   198 
   199 	static void SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors);
   200 
   201 	TInt CheckDevice(TMediaReqType aReqType);
   202 
   203 	static void SessionEndCallBack(TAny* aMediaDriver);
   204 	static void SessionEndDfc(TAny* aMediaDriver);
   205 	void DoSessionEndDfc();
   206 
   207 	static void DataTransferCallBack(TAny* aMediaDriver);
   208 	static void DataTransferCallBackDfc(TAny* aMediaDriver);
   209 
   210 	void DoReadDataTransferCallBack();
   211 	void DoWriteDataTransferCallBack();
   212 	void DoPhysReadDataTransferCallBack();
   213 	void DoPhysWriteDataTransferCallBack();
   214 	
   215 	TInt AdjustPhysicalFragment(TPhysAddr &physAddr, TInt &physLength);
   216 	TInt PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength);
   217 	void PrepareNextPhysicalFragment();
   218 
   219 	TInt EngageAndSetReadRequest(TMediaRequest aRequest);
   220 	TInt EngageAndSetWriteRequest(TMediaRequest aRequest);
   221 	TInt EngageAndSetRequest(TMediaRequest aRequest, TInt aCurrent);
   222 	void CompleteRequest(TInt aReason);
   223 
   224 	TInt ReadDataUntilCacheExhausted(TBool* aAllDone);
   225 	TInt WriteDataToUser(TUint8* aBufPtr);
   226 	TInt ReadDataFromUser(TDes8& aDes, TInt aOffset);
   227 	TUint8* ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength);
   228 	TUint8* ReserveWriteBlocks(TInt64 aMedStart, TInt64 aMedEnd, TUint* aRBM);
   229 	void MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex);
   230 	void BuildGammaArray(TInt64 aStart, TInt64 aEnd);
   231 	void InvalidateCache();
   232 	void InvalidateCache(TInt64 aStart, TInt64 aEnd);
   233 	TUint8* IdxToCchMem(TInt aIdx) const;
   234 	TInt CchMemToIdx(TUint8* aMemP) const;
   235 
   236 	TInt DoPasswordOp();
   237 	void PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData);
   238 	void Reset();
   239 	TInt AllocateSession();  
   240 
   241 #ifdef _DEBUG_CACHE
   242 	TBool CacheInvariant();
   243 	TUint8* GetCachedBlock(TInt64 aAddr);
   244 #endif
   245 private:
   246 	DMMCStack* iStack;			 				// controller objects
   247 	TMMCard* iCard;
   248 	DMMCSession* iSession;
   249 	DMMCSocket* iSocket;
   250 
   251 	TInt iCardNumber;
   252 
   253 	TUint iBlkLenLog2;							// cached CSD data
   254 	TUint32 iBlkLen;
   255 	TInt64 iBlkMsk;
   256 	TBool iReadBlPartial;
   257 	TUint32 iPrWtGpLen;							// preferred write group size in bytes,
   258 	TInt64 iPrWtGpMsk;
   259 
   260 	TInt iReadCurrentInMilliAmps;				// power management
   261 	TInt iWriteCurrentInMilliAmps;
   262 
   263 	TUint8* iMinorBuf;							// MBR, CMD42, partial read
   264 	TUint8* iCacheBuf;							// cached buffer
   265 	TUint32 iMaxBufSize;
   266 	TInt iBlocksInBuffer;
   267 	TInt64* iCachedBlocks;
   268 	TInt* iGamma;								// B lookup, ReserveReadBlocks()
   269 	TUint8* iIntBuf;							// start of current buffer region
   270 	TInt iLstUsdCchEnt;							// index of last used cache entry
   271 
   272 	TLocDrvRequest* iCurrentReq;				// Current Request
   273 	TMediaRequest iMedReq;
   274 	
   275 	TInt64 iReqStart;							// user-requested start region
   276 	TInt64 iReqCur;								// Currently requested start region
   277 	TInt64 iReqEnd;							    // user-requested end region
   278 	TInt64 iPhysStart;							// physical region for one operation
   279 	TInt64 iPhysEnd;						    // physical end point for one operation
   280 	TInt64 iDbEnd;								// Double buffer end point for one operation
   281 
   282 	TUint64 iEraseUnitMsk;
   283 
   284 	TUint iWtRBM;								// Write - Read Before Modify Flags
   285 	TUint iRdROB;								// Read  - Read Odd Blocks Flags
   286 	
   287 	TInt iFragOfset;			
   288 	TUint32 iIPCLen;
   289 	TUint32 iNxtIPCLen;
   290 	TUint32 iBufOfset;
   291 	
   292 	TUint iHiddenSectors;						// bootup / password
   293 
   294 	TMMCCallBack iSessionEndCallBack;
   295 	TDfc iSessionEndDfc;
   296 
   297 	TPartitionInfo* iPartitionInfo;
   298 	TMMCMediaTypeEnum iMediaType;
   299 	TMMCEraseInfo iEraseInfo;
   300 	TBool iMbrMissing;
   301 	TInt iMediaId;
   302 
   303 	DMMCStack::TDemandPagingInfo iDemandPagingInfo;
   304 
   305 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
   306 	SMmcStats iMmcStats;
   307 #endif // __TEST_PAGING_MEDIA_DRIVER__
   308 
   309 	TMMCCallBack iDataTransferCallBack;	// Callback registered with the MMC stack to perform double-buffering
   310 	TDfc iDataTransferCallBackDfc;		// ...and the associated DFC queue.
   311 
   312 	TBool iSecondBuffer;				// Specified the currently active buffer
   313 	TBool iDoLastRMW;					// ETrue if the last double-buffer transfer requires RMW modification
   314 	TBool iDoDoubleBuffer;				// ETrue if double-buffering is currently active
   315 	TBool iDoPhysicalAddress;			// ETrue if Physical Addressing is currently active
   316 	TBool iCreateMbr;
   317 	TBool iReadToEndOfCard;				// {Read Only} ETrue if Reading to end of Card
   318 
   319 	TBool iInternalSlot;
   320 
   321 	DEMMCPartitionInfo* iMmcPartitionInfo;  // Responsible for decoding partitions for embedded devices
   322 	};
   323 	
   324 // ======== DPhysicalDeviceMediaMmcFlash ========
   325 
   326 
   327 DPhysicalDeviceMediaMmcFlash::DPhysicalDeviceMediaMmcFlash()
   328 	{
   329 	OstTraceFunctionEntry1( DPHYSICALDEVICEMEDIAMMCFLASH_DPHYSICALDEVICEMEDIAMMCFLASH_ENTRY, this );
   330 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ctr"));
   331 
   332 	iUnitsMask = 0x01;
   333 	iVersion = TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
   334 	OstTraceFunctionExit1( DPHYSICALDEVICEMEDIAMMCFLASH_DPHYSICALDEVICEMEDIAMMCFLASH_EXIT, this );
   335 	}
   336 
   337 
   338 TInt DPhysicalDeviceMediaMmcFlash::Install()
   339 	{
   340 	OstTraceFunctionEntry1( DPHYSICALDEVICEMEDIAMMCFLASH_INSTALL_ENTRY, this );
   341 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ins"));
   342 
   343 	_LIT(KDrvNm, "Media.MmcF");
   344 	TInt r = SetName(&KDrvNm);
   345 	OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INSTALL_EXIT, this, r );
   346 	return r;
   347 	}
   348 
   349 
   350 void DPhysicalDeviceMediaMmcFlash::GetCaps(TDes8& /* aDes */) const
   351 	{
   352 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cap"));
   353 	}
   354 								 
   355 									 
   356 TInt DPhysicalDeviceMediaMmcFlash::Info(TInt aFunction, TAny* /*a1*/)
   357 //
   358 // Return the priority of this media driver
   359 //
   360 	{
   361 	OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_INFO_ENTRY ,"DPhysicalDeviceMediaMmcFlash::Info;aFunction=%d;this=%x", aFunction, (TUint) this);
   362 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:info"));
   363 	if (aFunction==EPriority)
   364 	    {
   365 		OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT1, this, KMediaDriverPriorityNormal );
   366 		return KMediaDriverPriorityNormal;
   367 	    }
   368 	// Don't close media driver when peripheral bus powers down. This avoids the need for Caps() to power up the stack.
   369 	if (aFunction==EMediaDriverPersistent)
   370 	    {
   371 		OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT2, this, KErrNone );
   372 		return KErrNone;
   373 	    }
   374 	
   375 	OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_INFO_EXIT3, this, KErrNotSupported );
   376 	return KErrNotSupported;
   377 	}
   378 								 
   379 TInt DPhysicalDeviceMediaMmcFlash::Validate(TInt aDeviceType, const TDesC8* /*aInfo*/, const TVersion& aVer)
   380 	{
   381 	OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_ENTRY ,"DPhysicalDeviceMediaMmcFlash::Validate;aDeviceType=%d;this=%x", aDeviceType, (TUint) this);
   382 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:validate aDeviceType %d", aDeviceType));
   383 	if (!Kern::QueryVersionSupported(iVersion,aVer))
   384 	    {
   385 		OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT1, this, KErrNotSupported );
   386 		return KErrNotSupported;
   387 	    }
   388 	if (aDeviceType!=MEDIA_DEVICE_MMC)
   389 	    {
   390 		OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT2, this, KErrNotSupported );
   391 		return KErrNotSupported;
   392 	    }
   393 
   394 	OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_VALIDATE_EXIT3, this, KErrNone );
   395 	return KErrNone;
   396 	}
   397 								 
   398 TInt DPhysicalDeviceMediaMmcFlash::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*aInfo*/, const TVersion& aVer)
   399 //
   400 // Create an MMC Card media driver.
   401 //
   402 	{
   403 	OstTraceExt2(TRACE_FLOW, DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_ENTRY, "DPhysicalDeviceMediaMmcFlash::Create;aMediaId=%d;this=%x", aMediaId, (TUint) this);
   404 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:crt"));
   405 
   406 	if (!Kern::QueryVersionSupported(iVersion,aVer))
   407 	    {
   408 		OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_EXIT1, this, KErrNotSupported );
   409 		return KErrNotSupported;
   410 	    }
   411 
   412 	DMmcMediaDriverFlash* pD = new DMmcMediaDriverFlash(aMediaId);
   413 	aChannel=pD;
   414 
   415 	TInt r=KErrNoMemory;
   416 	if (pD)
   417 		r=pD->DoCreate(aMediaId);
   418 	if (r==KErrNone)
   419 		pD->OpenMediaDriverComplete(KErrNone);
   420 
   421 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:mdf"));
   422 
   423 	OstTraceFunctionExitExt( DPHYSICALDEVICEMEDIAMMCFLASH_CREATE_EXIT2, this, r );
   424 	return r;
   425 	}
   426 
   427 
   428 // ======== DMmcMediaDriverFlash ========
   429 
   430 
   431 void DMmcMediaDriverFlash::Panic(TPanic aPanic)
   432 	{
   433 	_LIT(KPncNm, "MEDMMC");
   434 	Kern::PanicCurrentThread(KPncNm, aPanic);
   435 	}
   436 
   437 
   438 // ---- accessor functions -----
   439 
   440 inline DMMCStack& DMmcMediaDriverFlash::Stack() const
   441 	{ return *static_cast<DMMCStack*>(iStack); }
   442 
   443 
   444 inline TInt DMmcMediaDriverFlash::CardNum() const
   445 	{ return iCardNumber; }
   446 
   447 
   448 inline DMmcMediaDriverFlash::TMediaRequest DMmcMediaDriverFlash::CurrentRequest() const
   449 	{ return iMedReq; }
   450 
   451 
   452 // Helper
   453 template <class T>
   454 inline T* KernAlloc(const TUint32 n)
   455 	{ return static_cast<T*>(Kern::Alloc(n * sizeof(T))); }
   456 
   457 // ---- ctor, open, close, dtor ----
   458 
   459 #pragma warning( disable : 4355 )	// this used in initializer list
   460 DMmcMediaDriverFlash::DMmcMediaDriverFlash(TInt aMediaId)
   461    :DMediaDriver(aMediaId),
   462 	iMedReq(EMReqIdle),
   463     iSessionEndCallBack(DMmcMediaDriverFlash::SessionEndCallBack, this),
   464 	iSessionEndDfc(DMmcMediaDriverFlash::SessionEndDfc, this, 1),
   465 	iMediaId(iPrimaryMedia->iNextMediaId),
   466     iDataTransferCallBack(DMmcMediaDriverFlash::DataTransferCallBack, this),
   467 	iDataTransferCallBackDfc(DMmcMediaDriverFlash::DataTransferCallBackDfc, this, 1)
   468 	{
   469 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mmd"));
   470 	// NB aMedia Id = the media ID of the primary media, iMediaId = the media ID of this media
   471 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash(), iMediaId %d, aMediaId %d\n", iMediaId, aMediaId));
   472 	OstTraceExt2( TRACE_FLOW, DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH, "> DMmcMediaDriverFlash::DMmcMediaDriverFlash;aMediaId=%d;iMediaId=%d", (TInt) aMediaId, (TInt) iMediaId );
   473 	
   474 	}
   475 
   476 #pragma warning( default : 4355 )
   477 TInt DMmcMediaDriverFlash::DoCreate(TInt /*aMediaId*/)
   478 	{
   479 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOCREATE_ENTRY, this );
   480 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:opn"));
   481 
   482 	iSocket = ((DMMCSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket);
   483 	if(iSocket == NULL)
   484 	    {
   485 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT1, this, KErrNoMemory );
   486 		return KErrNoMemory;
   487 	    }
   488 
   489 	iCardNumber = ((DPBusPrimaryMedia*)iPrimaryMedia)->iSlotNumber;
   490 
   491 	iStack = iSocket->Stack(KStackNumber);
   492 	iCard = iStack->CardP(CardNum());
   493 
   494 	TMMCMachineInfo machineInfo;
   495 	Stack().MachineInfo(machineInfo);
   496 	TInt slotFlag = iCardNumber == 0 ? TMMCMachineInfo::ESlot1Internal : TMMCMachineInfo::ESlot2Internal;
   497 	iInternalSlot = machineInfo.iFlags & slotFlag;
   498 
   499 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("DMmcMediaDriverFlash::DoCreate() slotNumber %d iInternalSlot %d", iCardNumber, iInternalSlot));
   500 	OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_SLOT, "slotNumber=%d; iInternalSlot=%d", iCardNumber, iInternalSlot);
   501 
   502 	iSessionEndDfc.SetDfcQ(&iSocket->iDfcQ);
   503 	iDataTransferCallBackDfc.SetDfcQ(&iSocket->iDfcQ);
   504 
   505 	// check right type of card
   506 	if ((iMediaType=iCard->MediaType())==EMultiMediaNotSupported)	
   507 	    {
   508 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT2, this, KErrNotReady );
   509 		return KErrNotReady;
   510 	    }
   511 
   512 	// get card characteristics
   513 	const TCSD& csd = iCard->CSD();
   514 	iBlkLenLog2 = iCard->MaxReadBlLen();
   515 	iBlkLen = 1 << iBlkLenLog2;
   516 	iBlkMsk = (TInt64)(iBlkLen - 1);
   517 
   518 	SetTotalSizeInBytes(iCard->DeviceSize64());
   519 	
   520 	//
   521 	// High capcity cards (block addressable, MMCV4.2, SD2.0) do not support partial reads
   522 	// ...some cards incorrectly report that they do, so ensure that we don't
   523 	//
   524 	iReadBlPartial = iCard->IsHighCapacity() ? EFalse : csd.ReadBlPartial();
   525 
   526 	// allocate and initialize session object
   527 	TInt r = AllocateSession();
   528 	if (r!= KErrNone)
   529 	    {
   530 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT3, this, r );
   531 		return r;
   532 	    }
   533 
   534 	// get buffer memory from EPBUS
   535 	TUint8* buf;
   536 	TInt bufLen;
   537 	TInt minorBufLen;
   538 	Stack().BufferInfo(buf, bufLen, minorBufLen);
   539 
   540 	iMinorBuf = buf;
   541 	
   542 	// cache buffer can use rest of blocks in buffer.  Does not have to be power of 2.
   543 	iCacheBuf = iMinorBuf + minorBufLen;
   544 
   545 	// We need to devide up the buffer space between the media drivers.
   546 	// The number of buffer sub-areas = number of physical card slots * number of media
   547 	bufLen-= minorBufLen;
   548 	DPBusPrimaryMedia* primaryMedia = (DPBusPrimaryMedia*) iPrimaryMedia;
   549 	TInt physicalCardSlots = iStack->iMaxCardsInStack;
   550 	TInt numMedia = primaryMedia->iLastMediaId - primaryMedia->iMediaId + 1;
   551 	TInt totalNumMedia = numMedia * physicalCardSlots;
   552 
   553 	TInt mediaIndex = iMediaId - primaryMedia->iMediaId;
   554 	TInt bufIndex = (iCardNumber * numMedia)  + mediaIndex;
   555 	
   556 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("physicalCardSlots %d, iCardNumber %d\n",  physicalCardSlots, iCardNumber));
   557 	OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS1, "physicalCardSlots=%d; iCardNumber=%d", physicalCardSlots, iCardNumber);
   558 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("iMediaId %d numMedia %d, mediaIndex %d, totalNumMedia %d, bufIndex %d\n", 
   559 			  iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex));
   560 	OstTraceExt5(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_VARS2, "iMediaId=%d; numMedia=%d; mediaIndex=%d; totalNumMedia=%d; bufIndex=%d", iMediaId, numMedia, mediaIndex, totalNumMedia, bufIndex);
   561 
   562 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen1 %08X iCacheBuf1 %08X", bufLen, iCacheBuf));
   563 	OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF1, "bufLen1=0x%08x; iCacheBuf1=0x%08x", (TUint) bufLen, (TUint) iCacheBuf);
   564 	bufLen/= totalNumMedia;
   565 	iCacheBuf+= bufIndex * bufLen;
   566 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("bufLen2 %08X iCacheBuf2 %08X", bufLen, iCacheBuf));
   567 	OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_CACHEBUF2, "bufLen2=0x%08x; iCacheBuf2=0x%08x", (TUint) bufLen, (TUint) iCacheBuf);
   568 
   569 	iBlocksInBuffer = bufLen >> iBlkLenLog2;	// may lose partial block
   570 	if(iSocket->SupportsDoubleBuffering())
   571 		{
   572 		// Ensure that there's always an even number of buffered blocks when double-buffering
   573 		iBlocksInBuffer &= ~1;
   574 		__ASSERT_DEBUG(iBlocksInBuffer >= 2, Panic(EDBNotEven));
   575 #if defined(_DEBUG)		
   576 		/** 
   577 		 * If Double-Buffering is enabled then the cache should not be greater than the maximum addressable range of the DMA controller,
   578 		 * otherwise Double buffering will never be utilised because all transfers will fit into the cache.
   579 		 */
   580 		const TUint32 maxDbBlocks = iSocket->MaxDataTransferLength() >> iBlkLenLog2;
   581         if (maxDbBlocks)
   582             {
   583             __ASSERT_DEBUG(iBlocksInBuffer <= (TInt)maxDbBlocks, Panic(EDBNotOptimal));
   584             }
   585 #endif		
   586 		}
   587 
   588 	iMaxBufSize = iBlocksInBuffer << iBlkLenLog2;
   589 
   590 	iPrWtGpLen = iCard->PreferredWriteGroupLength();
   591 
   592 	// check the preferred write group length is a power of two
   593 	if(iPrWtGpLen == 0 || (iPrWtGpLen & (~iPrWtGpLen + 1)) != iPrWtGpLen)
   594 	    {
   595 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT4, this, KErrNotReady );
   596 		return KErrNotReady;
   597 	    }
   598 
   599 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("iMaxBufSize %d iPrWtGpLen %d\n", iMaxBufSize, iPrWtGpLen));
   600 	OstTraceExt2(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN1, "iMaxBufSize=%d; iPrWtGpLen1=%d", iMaxBufSize, iPrWtGpLen);
   601 	// ensure the preferred write group length is as large as possible
   602 	// so we can write to more than one write group at once
   603 	while (iPrWtGpLen < (TUint32) iMaxBufSize)
   604 		iPrWtGpLen <<= 1;
   605 
   606 	// ensure preferred write group length is no greater than internal cache buffer
   607 	while (iPrWtGpLen > (TUint32) iMaxBufSize)
   608 		iPrWtGpLen >>= 1;
   609 	iPrWtGpMsk = TInt64(iPrWtGpLen - 1);
   610 
   611 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("iPrWtGpLen #2 %d\n", iPrWtGpLen));
   612 	OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOCREATE_IPRWTGPLEN2, "iPrWtGpLen2=%d", iPrWtGpLen);
   613 
   614 	// allocate index for cached blocks
   615 	iCachedBlocks =	KernAlloc<TInt64>(iBlocksInBuffer);
   616 	if (iCachedBlocks == 0)
   617 	    {
   618 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT5, this, KErrNoMemory );
   619 		return KErrNoMemory;
   620 	    }
   621 
   622 	InvalidateCache();
   623 	iLstUsdCchEnt = iBlocksInBuffer - 1;		// use entry 0 first
   624 
   625 	// allocate read lookup index
   626 	iGamma = KernAlloc<TInt>(iBlocksInBuffer);
   627 	if (iGamma == 0)
   628 	    {
   629 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT6, this, KErrNoMemory );
   630 		return KErrNoMemory;
   631 	    }
   632 
   633 	// get current requirements
   634 	iReadCurrentInMilliAmps = csd.MaxReadCurrentInMilliamps();
   635 	iWriteCurrentInMilliAmps = csd.MaxWriteCurrentInMilliamps();
   636 
   637 	// get preferred erase information for format operations
   638 	const TInt err = iCard->GetEraseInfo(iEraseInfo);
   639 	if(err != KErrNone)
   640 	    {
   641 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT7, this, err );
   642 		return err;
   643 	    }
   644 
   645 	iEraseUnitMsk = TInt64(iEraseInfo.iPreferredEraseUnitSize) - 1;
   646 
   647 	// Retrieve the demand paging info from the PSL of the stack
   648 	Stack().DemandPagingInfo(iDemandPagingInfo);
   649 
   650 	// if a password has been supplied then it is sent when the partition info is read
   651 
   652 	//
   653 	// If this is an internal slot, then use the eMMC partition function
   654 	//
   655 	if(iInternalSlot)
   656 		{
   657 		iMmcPartitionInfo = CreateEmmcPartitionInfo();
   658 		if(iMmcPartitionInfo == NULL)
   659 		    {
   660 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT8, this, KErrNoMemory );
   661 			return KErrNoMemory;
   662 		    }
   663 		TInt err = iMmcPartitionInfo->Initialise(this);
   664 		if(err != KErrNone)
   665 		    {
   666 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT9, this, err );
   667 			return err;
   668 		    }
   669 		}
   670 
   671 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:opn"));
   672 
   673 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOCREATE_EXIT10, this, KErrNone );
   674 	return KErrNone;
   675 	}
   676 
   677 void DMmcMediaDriverFlash::Close()
   678 //
   679 // Close the media driver - also called on media change
   680 //
   681 	{
   682 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_CLOSE_ENTRY );
   683 	__KTRACE_OPT(KPBUSDRV,Kern::Printf("=mmd:cls"));
   684 	
   685 	EndInCritical();
   686 	iSessionEndDfc.Cancel();
   687 	iDataTransferCallBackDfc.Cancel();
   688 	CompleteRequest(KErrNotReady);
   689 	DMediaDriver::Close();
   690 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_CLOSE_EXIT );
   691 	}
   692 
   693 
   694 DMmcMediaDriverFlash::~DMmcMediaDriverFlash()
   695 	{
   696 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH_ENTRY );
   697 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dtr"));
   698 
   699 	iSessionEndDfc.Cancel();
   700 	iDataTransferCallBackDfc.Cancel();
   701 
   702 	delete iSession;
   703 	Kern::Free(iCachedBlocks);
   704 	Kern::Free(iGamma);
   705 
   706 	delete iMmcPartitionInfo;
   707 
   708 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dtr"));
   709 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DMMCMEDIADRIVERFLASH_EXIT );
   710 	}
   711 
   712 
   713 TInt DMmcMediaDriverFlash::AllocateSession()
   714 	{
   715 OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_ENTRY, this );
   716 
   717 	
   718 	// already allocated ?
   719 	if (iSession != NULL)
   720 	    {
   721 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT1, this, KErrNone );
   722 		return KErrNone;
   723 	    }
   724 
   725 	iSession = iStack->AllocSession(iSessionEndCallBack);
   726 	if (iSession == NULL)
   727 	    {
   728 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT2, this, KErrNoMemory );
   729 		return KErrNoMemory;
   730 	    }
   731 
   732 	iSession->SetStack(iStack);
   733 	iSession->SetCard(iCard);
   734 	iSession->SetDataTransferCallback(iDataTransferCallBack);
   735 
   736 
   737 
   738 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ALLOCATESESSION_EXIT3, this, KErrNone );
   739 	return KErrNone;
   740 	}
   741 
   742 // ---- media access ----
   743 
   744 TInt DMmcMediaDriverFlash::DoRead()
   745 //
   746 // set up iReqStart, iReqEnd and iReqCur and launch first read.  Subsequent reads
   747 // will be launched from the callback DFC.
   748 //
   749 	{
   750 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREAD_ENTRY, this );
   751 	TInt r = CheckDevice(EMReqTypeNormalRd); 
   752 	if (r != KErrNone)
   753 	    {
   754 	    OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT1, this, r );
   755 	    return r;
   756 	    }
   757 	
   758 	const TInt64 pos(iCurrentReq->Pos());
   759 	TUint32 length(I64LOW(iCurrentReq->Length()));
   760 
   761 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dr:0x%lx,0x%x", pos, length));
   762 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DO_READ, "Position=0x%lx; Length=0x%x", (TUint) pos, (TUint) length);
   763 	__ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDRInUse));
   764 	__ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDRStart));
   765 	__ASSERT_DEBUG(iCurrentReq->Length() >= 0, Panic(EDRNotPositive));
   766 	__ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDREnd));
   767 
   768 	if(length > 0)
   769 		{
   770 		iReqCur = iReqStart = pos;
   771 		iReqEnd = iReqStart + length;
   772 
   773 		TBool allDone(EFalse);
   774 		if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone)
   775 			{
   776 			iMedReq = EMReqRead;
   777 			iPhysStart = iReqCur & ~iBlkMsk;
   778 			__ASSERT_DEBUG(I64HIGH(iPhysStart >> KMMCardHighCapBlockSizeLog2) == 0, Panic(ELRStart));
   779 			
   780 			iReadToEndOfCard = ( iReqEnd >= TotalSizeInBytes() );
   781 			// Re-calculate length as some data may have been recovered from cache
   782 			length = I64LOW(iReqEnd - iReqCur);
   783 			
   784 			if (iCurrentReq->IsPhysicalAddress() && !iReadToEndOfCard && (length >= iBlkLen) )
   785 				r = LaunchPhysRead(iReqCur, length);
   786 			else if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard)
   787 				r = LaunchDBRead();
   788 			else
   789 				r = LaunchRead(iReqCur, length);
   790 
   791 			if (r == KErrNone)
   792 			    {
   793 			    OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT2, this, r );
   794 			    return r;
   795 			    }
   796 			}
   797 		}
   798 	else
   799 		{
   800 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
   801 		if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
   802 			{
   803 			r = iCurrentReq->WriteToPageHandler(NULL, 0, 0);
   804 			}
   805 		else
   806 #endif	// __DEMAND_PAGING__
   807 			{
   808 			TPtrC8 zeroDes(NULL, 0);
   809 			r = iCurrentReq->WriteRemote(&zeroDes,0);
   810 			}
   811 		}
   812 
   813 	// error occurred or read all from cache so complete immediately
   814 	if(r == KErrNone)
   815 		r = KErrCompletion;
   816 
   817 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dr:%d", r));
   818 	
   819 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOREAD_EXIT3, this, r );
   820 	return r;
   821 	}
   822 
   823 
   824 TInt DMmcMediaDriverFlash::LaunchRead(TInt64 aStart, TUint32 aLength)
   825 //
   826 // starts reads from DoRead() and the session end DFC.  This function does not maintain the
   827 // iReq* instance variables.  It sets iPhysStart and iPhysEnd to the region that was actually
   828 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer.  It is
   829 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used.
   830 //
   831 	{
   832 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHREAD_ENTRY, this );
   833 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHREAD, "position=0x%lx; length=0x%x", (TUint) iCurrentReq->Pos(), (TUint) I64LOW(iCurrentReq->Length()));
   834 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lr:0x%lx,0x%x", aStart, aLength));
   835 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart));
   836 	__ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive));
   837 	__ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd));
   838 	__ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached));
   839 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
   840 
   841 	iDoPhysicalAddress = EFalse;
   842 	iDoDoubleBuffer = EFalse;
   843 	iSecondBuffer = EFalse;
   844 	
   845 	// 
   846 	// if this read goes up to the end of the card then use only 
   847 	// single sector reads to avoid CMD12 timing problems
   848 	//
   849 	const TUint32 bufSize(iReadToEndOfCard ? iBlkLen : iMaxBufSize);
   850 	
   851 	iPhysEnd = (UMin(iReqEnd, iPhysStart + bufSize) + iBlkMsk) & ~iBlkMsk;
   852 	
   853 	TUint32 physLen(I64LOW(iPhysEnd - iPhysStart));
   854 	
   855 	__ASSERT_DEBUG(I64HIGH(iPhysEnd - iPhysStart) == 0, Panic(ELREnd));
   856 
   857 	// partial reads must be within a single physical block
   858 	if (iReadBlPartial && physLen == iBlkLen && aLength <= (iBlkLen >> 1))
   859 		{
   860 		// 
   861 		// Note : Partial reads are not supported for large block devices 
   862 		//        (MMCV4.2 and SD2.0 high capacity cards)
   863 		//
   864 		__ASSERT_DEBUG(I64HIGH(aStart) == 0, Panic(ELRStart));
   865 		__ASSERT_DEBUG(I64HIGH(aStart + aLength) == 0, Panic(ELREnd));
   866 
   867 		iIntBuf = iMinorBuf;
   868 		Stack().AdjustPartialRead(iCard, I64LOW(aStart), I64LOW(aStart + aLength), (TUint32*)&iPhysStart, (TUint32*)&iPhysEnd);
   869 		iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2);
   870 		}
   871 	else
   872 		{	
   873 		iIntBuf = ReserveReadBlocks(iPhysStart, iPhysEnd, &physLen);
   874 			
   875 		// EPBUSM automatically uses CMD17 instead of CMD18 for single block reads
   876 		iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, physLen >> KMMCardHighCapBlockSizeLog2);
   877 		
   878 		// Update Physical end point as less may have been required due to additional blocks found in cache during ReserveReadBlocks
   879 		iPhysEnd = iPhysStart + physLen;
   880 		}
   881 	
   882 	TInt r = EngageAndSetReadRequest(EMReqRead);
   883 	
   884 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lr:%d", r));
   885 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHREAD_EXIT, this, r );
   886 	return r;
   887 	}
   888 
   889 TInt DMmcMediaDriverFlash::LaunchDBRead()
   890 //
   891 // starts reads from DoRead() and the session end DFC.  This function does not maintain the
   892 // iReq* instance variables.  It sets iPhysStart and iPhysEnd to the region that was actually
   893 // read into iIntBuf. iIntBuf can be set to a cached entry or to the minor buffer.  It is
   894 // assumed that before this function is called that ReadDataUntilCacheExhausted() has been used.
   895 //
   896 	{
   897 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHDBREAD_ENTRY, this );
   898 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:ldbr:0x%lx,0x%x", iReqCur, I64LOW(iReqEnd - iReqCur)));
   899 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHDBREAD, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
   900 	__ASSERT_DEBUG(TotalSizeInBytes() > iReqCur, Panic(ELRStart));
   901 	__ASSERT_DEBUG(I64LOW(iReqEnd - iReqCur) > 0, Panic(ELRNotPositive));
   902 	__ASSERT_DEBUG(TotalSizeInBytes() >= iReqEnd, Panic(ELREnd));
   903 	__ASSERT_CACHE(GetCachedBlock(iReqCur & ~iBlkMsk) == 0, Panic(ELRCached));
   904 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
   905 
   906 	iDoDoubleBuffer = ETrue;
   907 	iDoPhysicalAddress = EFalse;
   908 	
   909 	iDbEnd = iReqEnd;
   910 	const TUint32 maxDbLength = iSocket->MaxDataTransferLength();
   911 
   912 	if(maxDbLength)
   913 		{
   914 		//
   915 		// If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request...
   916 		//
   917 		iDbEnd = UMin(iDbEnd, iPhysStart + maxDbLength);
   918 		}
   919 
   920 	iDbEnd = (iDbEnd + iBlkMsk) & ~iBlkMsk;
   921 
   922 	const TUint32 doubleBufferSize = iMaxBufSize >> 1;
   923 	iPhysEnd = (iReqCur + doubleBufferSize) & ~iBlkMsk;	// The end of the first double-buffered transfer
   924 	
   925 	//
   926 	// If we're double-buffering, then the entire cache will be re-used
   927 	// continuously.  Rather than continually reserve blocks during each 
   928 	// transfer we calculate the blocks that will be present after all
   929 	// transfers have completed. 
   930 	// @see DoSessionEndDfc()
   931 	//
   932 	InvalidateCache();
   933 	iIntBuf = iCacheBuf;
   934 	
   935 	iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW(iDbEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2);
   936 
   937 	iSession->EnableDoubleBuffering(doubleBufferSize >> KDiskSectorShift);
   938 
   939 	// ...and switch to the 'second' buffer, which will be populated in the
   940 	// data transfer callback in parallel with hardware transfer of the first.
   941 	iSecondBuffer = ETrue;
   942 
   943 	TInt r = EngageAndSetReadRequest(EMReqRead);
   944 
   945 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:ldbr:%d", r));
   946 
   947 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHDBREAD_EXIT, this, r );
   948 	return r;
   949 	}
   950 
   951 
   952 TInt DMmcMediaDriverFlash::LaunchPhysRead(TInt64 aStart, TUint32 aLength)
   953 //
   954 // This function does not maintain the iReq* instance variables.  
   955 // It is assumed that before this function is called that 
   956 // ReadDataUntilCacheExhausted() has been used.
   957 //
   958 	{
   959 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD_ENTRY, this );
   960 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
   961 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:0x%lx,0x%x", aStart, aLength));
   962 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELRStart));
   963 	__ASSERT_DEBUG(aLength > 0, Panic(ELRNotPositive));
   964 	__ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELREnd));
   965 	__ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ELRCached));
   966 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
   967 
   968 	TInt r(KErrNone);
   969 	
   970 	iDoPhysicalAddress = ETrue;  
   971 	iDoDoubleBuffer = EFalse;
   972 	
   973 	// Local Media Subsystem ensures DMA Addressable range not exceeded.
   974 	// @see LocDrv::RegisterDmaDevice()
   975 	iPhysEnd = (iReqEnd + iBlkMsk) & ~iBlkMsk;
   976 	
   977 	iRdROB = 0;
   978 	iFragOfset = iIPCLen = iNxtIPCLen = iBufOfset = 0; 
   979 	
   980 	// Determine if start/end are block aligned
   981 	// physical memory can only read the exact amount, not more!
   982 	const TBool firstPartial( (aStart & iBlkMsk) != 0);
   983 	
   984 	TPhysAddr physAddr(0);						
   985 	TInt physLength(0);
   986 	TUint32 physLen(I64LOW(iPhysEnd - iPhysStart));
   987 	
   988 	if (firstPartial)
   989 		{
   990 		__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:physr:FirstPartial"));
   991 		OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCH_PHYSREAD_FP, "FirstPartial");
   992 		// first index does not start on block boundary
   993 		// iIntBuf linear address is used for IPC within DoReadDataTransferCallBack()
   994 		iRdROB |= KIPCWrite;
   995 		
   996 		iIntBuf = ReserveReadBlocks(iPhysStart, iPhysStart+iBlkLen,(TUint32*)&physLength);
   997 #if !defined(__WINS__)
   998 		physAddr = Epoc::LinearToPhysical((TLinAddr)iIntBuf);
   999 #else
  1000 		physAddr = (TPhysAddr)iIntBuf;
  1001 #endif
  1002 		// Set SecondBuffer flag to indicate IPC cannot be done on next callback
  1003 		iSecondBuffer = ETrue;
  1004 		iBufOfset = I64LOW(iReqStart - iPhysStart);
  1005 		//iReqCur already set in DoRead;
  1006 		iFragOfset = iNxtIPCLen = physLength - iBufOfset;
  1007 		}				
  1008 	else
  1009 		{
  1010 		// Determine offset from start due to data possibly recovered from local cache
  1011 		iFragOfset = I64LOW(aStart - iReqStart);	
  1012 		r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength);
  1013 		
  1014 		// No use for secondBuffer yet...
  1015 		iSecondBuffer = EFalse;
  1016 		}
  1017 	
  1018 	if(r == KErrNone)
  1019    		{         
  1020    		iDbEnd = iPhysEnd;
  1021    		iPhysEnd = iPhysStart + physLength;
  1022    		
  1023         if ((TUint32)physLength > physLen) physLength = physLen; // more memory in chunk than required
  1024         
  1025     	iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*)physAddr, physLen >> KMMCardHighCapBlockSizeLog2);				
  1026     	
  1027 		iSession->Command().iFlags|= KMMCCmdFlagPhysAddr;
  1028 		iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift);
  1029 		
  1030 		r = EngageAndSetReadRequest(EMReqRead);
  1031    		} 
  1032 		
  1033 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lphysr:%d", r));
  1034 
  1035 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHPHYSREAD_EXIT, this, r );
  1036 	return r;
  1037 	}
  1038 
  1039 
  1040 TInt DMmcMediaDriverFlash::DoWrite()
  1041 //
  1042 // set up iReqStart, iReqEnd, and iReqCur, and launch first write.  Any subsequent
  1043 // writes are launched from the session end DFC.  LaunchWrite() handles pre-reading
  1044 // any sectors that are only partially modified.
  1045 //
  1046 	{
  1047 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOWRITE_ENTRY, this );
  1048 	const TInt64 pos = iCurrentReq->Pos();
  1049 	const TUint32 length = I64LOW(iCurrentReq->Length());
  1050 
  1051 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dw:0x%lx,0x%x", pos, length));
  1052 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOWRITE, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length);
  1053 	__ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDWInUse));
  1054 	__ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDWStart));
  1055 	__ASSERT_DEBUG(length > 0, Panic(EDWNotPositive));
  1056 	__ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDWEnd));
  1057 
  1058 	iReqCur = iReqStart = pos;
  1059 	iReqEnd = iReqStart + length;
  1060 
  1061 	// iWtRBM is zero on construction because CBase-derived, and cleared at end
  1062 	// of successful writes.  If a write does not complete successfully, it may
  1063 	// be left in non-zero state.
  1064 	iWtRBM = 0;
  1065 	
  1066 	iSecondBuffer  = EFalse;
  1067 	iDoLastRMW     = EFalse;
  1068 	iDoDoubleBuffer= EFalse;
  1069 	iDoPhysicalAddress = EFalse;
  1070 	
  1071 	const TInt r = LaunchWrite(iReqStart, length, EMReqWrite);
  1072 
  1073 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:dw:%d", r));
  1074 
  1075 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOWRITE_EXIT, this, r );
  1076 	return r;
  1077 	}
  1078 
  1079 
  1080 TInt DMmcMediaDriverFlash::DoFormat()
  1081 	{
  1082 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOFORMAT_ENTRY, this );
  1083 	const TInt64 pos = iCurrentReq->Pos();
  1084 	const TUint32 length = I64LOW(iCurrentReq->Length());
  1085 
  1086 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:df:0x%lx,0x%x", pos, length));
  1087 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOFORMAT, "position=0x%lx; length=0x%x", (TUint) pos, (TUint) length);
  1088 	__ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EDFInUse));
  1089 	__ASSERT_DEBUG(pos < TotalSizeInBytes(), Panic(EDFStart));
  1090 	__ASSERT_DEBUG(length > 0, Panic(EDFNotPositive));
  1091 	__ASSERT_DEBUG(TotalSizeInBytes() >= pos + length, Panic(EDFEnd));
  1092 
  1093 	iReqCur = iReqStart = pos & ~iBlkMsk;
  1094 	iReqEnd = (iReqStart + length + iBlkMsk) & ~iBlkMsk;
  1095 
  1096 	// the cache isn't maintained during a format operation to avoid redundantly
  1097 	// writing 0xff to memory (the blocks won't be re-used.)
  1098 	InvalidateCache();
  1099 
  1100 	// create an MBR after the first format step (or second if misaligned) 
  1101  
  1102 	if (iInternalSlot)
  1103 		{
  1104 		iCreateMbr = EFalse;
  1105 		}
  1106 	else
  1107 		{
  1108 		if (iReqStart == (TInt64(iHiddenSectors) << KDiskSectorShift) && CreateMBRAfterFormat(iCard))
  1109 			iCreateMbr = ETrue;
  1110 		}
  1111 
  1112 	const TInt r = LaunchFormat(iReqStart, I64LOW(iReqEnd - iReqStart));
  1113 
  1114 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:df:%d", r));
  1115 
  1116 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOFORMAT_EXIT, this, r );
  1117 	return r;
  1118 	}
  1119 
  1120 
  1121 TInt DMmcMediaDriverFlash::LaunchFormat(TInt64 aStart, TUint32 aLength)
  1122 //
  1123 // starts writes from DoWrite(), DoFormat() and the session end DFC.  This function does not
  1124 // maintain the iReq* instance variables.  It sets iIntBuf, iPhysStart and iPhysEnd.
  1125 //
  1126 	{
  1127 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_ENTRY, this );
  1128 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHFORMAT, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
  1129 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lf:0x%lx,0x%x", aStart, aLength));
  1130 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELFStart));
  1131 	__ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign));
  1132 	__ASSERT_DEBUG(aLength > 0, Panic(ELFNotPositive));
  1133 	__ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELFEnd));
  1134 	__ASSERT_DEBUG((aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign));
  1135 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1136 
  1137 	TInt r;
  1138 
  1139 	if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
  1140 		{
  1141 		iPhysStart = aStart & ~iBlkMsk;
  1142 
  1143 		// formats are always block-aligned, and the buffer is initialized to 0xff
  1144 		//  Check whether erase commands are supported by this card
  1145 		if (iCard->CSD().CCC() & KMMCCmdClassErase)
  1146 			{
  1147 			// Determine the erase end point for the next command. We don't erase past the preferred erase unit
  1148 			// size. Therefore, check which is lower, the preferred erase unit size or the end of the requested range.
  1149 			TInt64 prefEraseUnitEnd = (iPhysStart + iEraseInfo.iPreferredEraseUnitSize) & ~iEraseUnitMsk;
  1150 			iPhysEnd = UMin(prefEraseUnitEnd, aStart + aLength);
  1151 
  1152 			const TUint32 minEraseSectorSize=iEraseInfo.iMinEraseSectorSize;
  1153 			const TInt64  minEraseSecMsk = TInt64(minEraseSectorSize-1);
  1154 			
  1155 			// If erase start point doesn't lie on a min. erase unit boundary, then truncate the erase endpoint to
  1156 			// the next min. erase unit boundary (assuming requested range allows this)
  1157 			if ((iPhysStart & minEraseSecMsk)!=0)
  1158 				{
  1159 				prefEraseUnitEnd=(iPhysStart+minEraseSectorSize) & ~minEraseSecMsk;
  1160 				iPhysEnd=UMin(prefEraseUnitEnd,iPhysEnd);
  1161 				}
  1162 				
  1163 			// Otherwise, if calculated erase end point doesn't lie on a min. erase unit boundary, but is at least one
  1164 			// min. erase unit beyond the erase start point then move erase endpoint back to last min. erase unit boundary
  1165 			else if ((iPhysEnd & minEraseSecMsk)!=0 && (iPhysEnd & ~minEraseSecMsk)>iPhysStart)
  1166 				{
  1167 				iPhysEnd&=(~minEraseSecMsk);
  1168 				}
  1169 
  1170 			// Now, if the erase start/end points are aligned to a min. erase unit boundary, we can use an erase cmd.
  1171 			if ((iPhysStart & minEraseSecMsk) == 0 && (iPhysEnd & minEraseSecMsk) == 0)
  1172 				{
  1173 				// Aligned erase
  1174 				//  Check that erase commands are supported prior to issuing an erase command
  1175 				if(iEraseInfo.EraseGroupCmdsSupported())
  1176 					{
  1177 					iSession->SetupCIMEraseMGroup(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2),
  1178 												  I64LOW((iPhysEnd-iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD35/36/38 (Erase Group)
  1179 					}
  1180 				else
  1181 					{
  1182 					iSession->SetupCIMEraseMSector(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2),
  1183 												   I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2)); // Use ACMD32/33/38 (Erase Sector)
  1184 					}
  1185 				}
  1186 			else
  1187 				{
  1188 				// Misaligned erase - use multi-block write. However, first - check write length doesn't exceed buffer size.
  1189 				if ((iPhysEnd-iPhysStart)>(TUint32)iMaxBufSize)
  1190 					{
  1191 					iPhysEnd=(iPhysStart+iMaxBufSize);
  1192 					}
  1193 					
  1194 				__ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength));
  1195 				const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart);
  1196 				memset (iCacheBuf, 0x00, writeLen);
  1197 				iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2);
  1198 				}
  1199 			}
  1200 		else
  1201 			{
  1202 			// Write to end of current write group, or end of request range, whichever is lower
  1203 			const TInt64 prefEraseUnitEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk;
  1204 			iPhysEnd = Min(prefEraseUnitEnd, aStart + aLength);				
  1205 			
  1206 			__ASSERT_DEBUG((iPhysEnd - iPhysStart) > 0, Panic(ELWLength));
  1207 			const TUint32 writeLen = I64LOW(iPhysEnd - iPhysStart);
  1208 			memset (iCacheBuf, 0x00, writeLen);
  1209 			iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iCacheBuf, writeLen >> KMMCardHighCapBlockSizeLog2);
  1210 			}
  1211 		
  1212 		r = EngageAndSetWriteRequest(EMReqFormat);
  1213 		}
  1214 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHFORMAT_EXIT, this, r );
  1215 		return r;
  1216 	}
  1217 
  1218 
  1219 
  1220 TInt DMmcMediaDriverFlash::LaunchWrite(TInt64 aStart, TUint32 aLength, TMediaRequest aMedReq)
  1221 //
  1222 // starts writes from DoWrite(), DoFormat() and the session end DFC.  This function does not
  1223 // maintain the iReq* instance variables.  It sets iIntBuf, iPhysStart and iPhysEnd.
  1224 //
  1225 	{
  1226 	OstTraceExt4(TRACE_FLOW, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_ENTRY, "DMmcMediaDriverFlash::LaunchWrite;aStart=%Ld;aLength=%x;aMedReq=%d;this=%x", aStart, (TUint) aLength, (TInt) aMedReq, (TUint) this);
  1227 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE, "position=0x%lx; length=0x%x", (TInt) iReqCur, (TInt) I64LOW(iReqEnd - iReqCur));
  1228 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("\n>mmd:lw:0x%lx,%d,%d", aStart, aLength, aMedReq));
  1229 	__ASSERT_DEBUG(aMedReq == EMReqWrite || aMedReq == EMReqFormat, Panic(ELWRequest));
  1230 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ELWStart));
  1231 	__ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aStart & iBlkMsk) == 0, Panic(ELWFmtStAlign));
  1232 	__ASSERT_DEBUG(aLength > 0, Panic(ELWNotPositive));
  1233 	__ASSERT_DEBUG(TotalSizeInBytes() >= aStart + aLength, Panic(ELWEnd));
  1234 	__ASSERT_DEBUG(!(aMedReq == EMReqFormat) || (aLength & iBlkMsk) == 0, Panic(ELWFmtEndAlign));
  1235 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1236 
  1237 	TInt r;
  1238 
  1239 	if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
  1240 		{
  1241 		iPhysStart = aStart & ~iBlkMsk;
  1242 
  1243 		// PSL MUST support double-buffering for DMA requests
  1244 		// first write, or have just completed previous write
  1245 		if (iWtRBM == 0)
  1246 			{
  1247 			if(iDoDoubleBuffer == EFalse)
  1248 				{
  1249 				//
  1250 				// Can we use double-buffering for this request?
  1251 				//
  1252 				//  - Only if PSL supports double buffering and the request length 
  1253 				//	  is greater than the maximum PSL buffer size.
  1254 				//
  1255 				iDoPhysicalAddress = iCurrentReq->IsPhysicalAddress();
  1256 								
  1257 				TInt64 medEnd = aStart + aLength;
  1258 		
  1259 				TInt64 maxPslEnd = medEnd;
  1260 				const TUint32 maxDbLength = iSocket->MaxDataTransferLength();
  1261 				
  1262 				if(maxDbLength)
  1263 					{
  1264 					//
  1265 					// If the PSL specifies a limit on the maximum size of a data transfer, then truncate the request...
  1266 					//
  1267 					maxPslEnd = UMin(medEnd, iPhysStart + maxDbLength);
  1268 					}
  1269 
  1270 				iPhysEnd = (maxPslEnd + iBlkMsk) & ~iBlkMsk;
  1271 				
  1272 				if (iDoPhysicalAddress)
  1273 					{
  1274 					iDoDoubleBuffer = EFalse;
  1275 					iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM);
  1276 					iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
  1277 					}
  1278 
  1279 				if (!iDoPhysicalAddress)
  1280 					{
  1281 					iDoDoubleBuffer = iSocket->SupportsDoubleBuffering() && ((iPhysEnd - iPhysStart) > iMaxBufSize);
  1282 					if(iDoDoubleBuffer)
  1283 						{
  1284 						//
  1285 						// Conditions for double-buffering are met.  Set up the size of the first
  1286 						// transfer to half the size of the block cache.  
  1287 						//
  1288 						// Note that we don't bother to align to write groups here, as the entire
  1289 						// request will be processed under one multi-block command so there's no 
  1290 						// danger of forcing the card into RMW cycles as would be the case when
  1291 						// issuing multiple misaligned commands.
  1292 						//
  1293 						iDbEnd = maxPslEnd;												// The end of the complete double-buffered transfer
  1294 						iPhysEnd = (iPhysStart + (iMaxBufSize >> 1) + iBlkMsk) &~ iBlkMsk;	// The end of the first double-buffered transfer
  1295 						__ASSERT_DEBUG(iPhysEnd - iPhysStart <= (iMaxBufSize >> 1), Panic(ELWLength));
  1296 	
  1297 						//
  1298 						// Now reserve write blocks from the buffer cache. When double-buffering,
  1299 						// write blocks are only really reserved during the last transfer to avoid
  1300 						// continuously updating the cache indexes. Since the block cache is
  1301 						// continuously recycled, the following call shall invalidate the cache
  1302 						// and inform us as to whether we need to perform an RMW operation for
  1303 						// the first and last blocks prior to initiating data transfer.
  1304 						//
  1305 						iIntBuf = ReserveWriteBlocks(aStart, iDbEnd, &iWtRBM);
  1306 						}
  1307 					else
  1308 						{				
  1309 						if ( (iPhysEnd - iPhysStart) > iMaxBufSize)
  1310 						    {
  1311 		                    //
  1312                             // reserve buffers to end of first write group, or end of request range,
  1313                             // whichever is lower.  Note that if the range already exists in the buffer,
  1314                             // e.g. because of a previous RBM, the same range will be returned.  This
  1315                             // means that iWtRBM can be set to zero in the callback DFC, and this code
  1316                             // will retrieve the reserved range.
  1317                             //  
  1318 						    const TInt64 wtGpEnd = (iPhysStart + iPrWtGpLen) & ~iPrWtGpMsk;
  1319 						    medEnd = UMin(wtGpEnd, aStart + aLength);
  1320 						    iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
  1321 						    }
  1322 						
  1323 						iIntBuf = ReserveWriteBlocks(aStart, medEnd, &iWtRBM);
  1324 						}
  1325 					} //if (!iDoPhysicalAddress)
  1326 				} //if(iDoDoubleBuffer == EFalse)
  1327 			} //if (iWtRBM == 0)
  1328 
  1329 		if (iWtRBM & KWtRBMFst)
  1330 			{			
  1331 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on first block"));
  1332 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBMF, "Read-before-modify required on first block");
  1333 			if (iDoPhysicalAddress)
  1334 				iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
  1335 			else
  1336 				iSession->SetupCIMReadBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
  1337 			r = EngageAndSetReadRequest(aMedReq);
  1338 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT1, this, r );
  1339 			return r;
  1340 			}
  1341 
  1342 		else if (iWtRBM & KWtRBMLst)
  1343 			{
  1344 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw: read-before-modify required on last block"));			
  1345 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_RBML, "Read-before-modify required on last block");
  1346 			if(iDoDoubleBuffer || iDoPhysicalAddress)
  1347 				{
  1348 				//
  1349 				// When double-buffering, the result of the RMW-read operation shall be stored
  1350 				// in the minor buffer, otherwise the data would be overwritten before the last
  1351 				// data transfer takes place.
  1352 				//
  1353 				const TInt64 lastBlock = (aStart + aLength) & ~iBlkMsk;  // start posn in media to read from (we know aStart + aLength isn't block aligned due to KWtRBMLst flag)
  1354 				if (iDoDoubleBuffer)
  1355 					iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iMinorBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
  1356 				else
  1357 					iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iCacheBuf, iBlkLen >> KMMCardHighCapBlockSizeLog2);
  1358 				}
  1359 			else
  1360 				{
  1361 				//
  1362 				// If not double-buffering, we can read the RMW data of the last block directly
  1363 				// into the block cache as we know that the data transfer will fit entirely
  1364 				// within the cache..
  1365 				//
  1366 				const TInt64 lastBlock = iPhysEnd - iBlkLen;		// start posn in media to read from
  1367 				iSession->SetupCIMReadBlock(I64LOW(lastBlock >> KMMCardHighCapBlockSizeLog2), iIntBuf + (lastBlock - iPhysStart), iBlkLen >> KMMCardHighCapBlockSizeLog2);
  1368 				}
  1369 
  1370 			// Kick off the RMW-read operation for the last block...
  1371 			r = EngageAndSetReadRequest(aMedReq);
  1372 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT2, this, r );
  1373 			return r;
  1374 			}
  1375 		
  1376 		if (iWtRBM & KWtMinFst)
  1377 			{
  1378 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-first-block-only"));			
  1379 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_FBO, "Write first block only");
  1380 			//Overwrite first block with the new data			
  1381 			TInt32 tlen = I64LOW(aStart & iBlkMsk);
  1382 			TInt32 wlen = UMin(I64LOW((iBlkMsk+1) - tlen), aLength);			
  1383 			
  1384 			const TInt64 usrOfst = (aStart - iReqStart);
  1385 			TPtr8 tgt(&iMinorBuf[tlen], I64LOW(wlen));
  1386 
  1387 			if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst))) != KErrNone)
  1388 			    {
  1389 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT3, this, r );
  1390 				return r;			
  1391 			    }
  1392 			}
  1393 		
  1394 		if (iWtRBM & KWtMinLst)
  1395 			{
  1396 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:Phys write-last-block-only"));
  1397 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_LBO, "Write last block only");
  1398 			iWtRBM &= ~KWtMinLst;
  1399 			//Overwrite last block with the new data
  1400 			const TInt64 medEnds = aStart + aLength;
  1401 			TInt64 tlen = medEnds & iBlkMsk;
  1402 			
  1403 			const TInt64 usrOfst = (aStart - iReqStart);					
  1404 			TPtr8 tgt(iCacheBuf, I64LOW(tlen));			
  1405 						
  1406 			if ( (r = iCurrentReq->ReadRemote(&tgt,I64LOW(usrOfst+aLength-tlen))) !=KErrNone)
  1407 			    {
  1408 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT4, this, r );
  1409 				return r;			
  1410 			    }
  1411 			}
  1412 		
  1413 		// no reads required - read data from user buffer and launch write
  1414 		const TInt64 usrOfst = (aStart - iReqStart);
  1415 		const TInt64 bufOfst = aStart - iPhysStart;		// offset into first sector, not whole buffer
  1416 		const TInt64 len = UMin(aStart + aLength, iPhysEnd) - iReqCur;
  1417 		__ASSERT_DEBUG(len > 0, Panic(ELWLength));
  1418 		__ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(ELWLength));
  1419 
  1420 		if (iDoPhysicalAddress)
  1421 			{
  1422 			TPhysAddr physAddr = 0;
  1423 			TInt physLength = 0;
  1424 			TUint32 physLen = I64LOW(iPhysEnd - iPhysStart);
  1425 			
  1426 			if (iWtRBM & KWtMinFst)
  1427 				{
  1428 #if !defined(__WINS__)
  1429 				physAddr = Epoc::LinearToPhysical((TLinAddr)iMinorBuf);
  1430 #else
  1431 				physAddr = (TPhysAddr)iMinorBuf;
  1432 #endif
  1433 				physLength = iBlkLen;
  1434 				iBufOfset = I64LOW(iReqStart - iPhysStart);
  1435 				//iReqCur already set in DoWrite
  1436 				iFragOfset = iIPCLen = iBlkLen - iBufOfset;
  1437 				iWtRBM &= ~KWtMinFst;
  1438 				}
  1439 			else
  1440 				{
  1441 				iFragOfset = I64LOW(usrOfst);
  1442 			
  1443 				r = PrepareFirstPhysicalFragment(physAddr, physLength, aLength);
  1444 				}
  1445 					           						
  1446 			if (r == KErrNone)
  1447 				{
  1448 				iDbEnd = iPhysEnd;
  1449            		iPhysEnd = iPhysStart+physLength;
  1450            		
  1451            		if ((TUint32)physLength > physLen) physLength = physLen; // more memory in fragment than required!	
  1452            		OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_PHYSICAL, "Physical write request" );
  1453 				iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), (TUint8*) physAddr, physLen >> KMMCardHighCapBlockSizeLog2);
  1454 				iSession->Command().iFlags|= KMMCCmdFlagPhysAddr;
  1455 				iSession->EnableDoubleBuffering(physLength >> KDiskSectorShift);
  1456 				}
  1457 			else 
  1458 				{
  1459 				__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:Phys:%d", r));
  1460 				
  1461 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT5, this, r );
  1462 				return r;					
  1463 				}
  1464 			} // if (iDoPhysicalAddress)
  1465 		else
  1466 			{
  1467 			TPtr8 tgt(&iIntBuf[bufOfst], I64LOW(len));
  1468 	
  1469 			r = ReadDataFromUser(tgt, I64LOW(usrOfst));
  1470 			if (r == KErrNone)
  1471 				{
  1472 				if(!iDoDoubleBuffer)
  1473 					{
  1474 					// EPBUSM automatically uses CMD24 instead of CMD25 for single block writes
  1475 					OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_STANDARD, "Standard write request" );
  1476 					iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((iPhysEnd - iPhysStart) >> KMMCardHighCapBlockSizeLog2));
  1477 					}
  1478 				else
  1479 					{
  1480 					// 
  1481 					// When double-buffering, set up the data transfer command to the entire
  1482 					// request range. and flag the session to enable double-buffering (as well
  1483 					// as specifying the length of each double-buffered transfer as calculated
  1484 					// in 'len' above).  This is performed only once - the double-buffering 
  1485 					// is subsequently handled within the DoDataTransferCallback function.
  1486 					//
  1487 					OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHWRITE_DB, "Double-buffered write request" );
  1488 					iSession->SetupCIMWriteBlock(I64LOW(iPhysStart >> KMMCardHighCapBlockSizeLog2), iIntBuf, I64LOW((((iDbEnd + iBlkMsk) & ~iBlkMsk) - iPhysStart) >> KMMCardHighCapBlockSizeLog2));
  1489 					iSession->EnableDoubleBuffering(I64LOW((len + iBlkMsk) & ~iBlkMsk) >> KDiskSectorShift);
  1490 	
  1491 					// ...and switch to the 'second' buffer, which will be populated in the
  1492 					// data transfer callback in parallel with hardware transfer of the first.
  1493 					iSecondBuffer = ETrue;
  1494 					}
  1495 				}
  1496 			}
  1497 	
  1498 			//Reliable Write only supported by v4.3+ MMC media
  1499 			if (iCard->ExtendedCSD().ExtendedCSDRev() >= 3)
  1500 				{
  1501 				// One request, i.e. not end of previous DB request 
  1502 				// 512 Bytes long when sector aligned
  1503 				if ( ( I64LOW(iPhysEnd - iPhysStart) == iBlkLen) && ((iReqStart & ~iBlkMsk) == iPhysStart) )
  1504 					{
  1505 					__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lw:AtomicWrite"));
  1506 					iSession->Command().iFlags|= KMMCCmdFlagReliableWrite;
  1507 					}
  1508 				}
  1509 		
  1510 			// Engage the data transfer session...
  1511 			r = EngageAndSetWriteRequest(aMedReq);
  1512 		}	// if ((r = CheckDevice(EMReqTypeNormalWr)) == KErrNone)
  1513 
  1514 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lw:%d", r));
  1515 
  1516 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHWRITE_EXIT6, this, r );
  1517 	return r;
  1518 	}
  1519 
  1520 TInt DMmcMediaDriverFlash::PartitionInfo(TPartitionInfo& anInfo)
  1521 //
  1522 // Read the partition information for the media.  If the user supplied a password,
  1523 // then unlock the card before trying to read the first sector.
  1524 //
  1525 	{
  1526 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_PARTITIONINFO_ENTRY, this );
  1527 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rpi"));
  1528 	__ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(ERPIInUse));
  1529 
  1530 	iPartitionInfo = &anInfo;
  1531 
  1532 	if(iMmcPartitionInfo)
  1533 		{
  1534 		// If this is an embedded device, use the custom formatting function:
  1535 		TInt r = iMmcPartitionInfo->PartitionInfo(*iPartitionInfo, iSessionEndCallBack);
  1536 		
  1537 		iHiddenSectors = 0; // Not used for internal media
  1538 		
  1539 		if (KErrNone == r)
  1540 			iMedReq = EMReqEMMCPtnInfo;
  1541 		
  1542 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT1, this, r );
  1543 		return r;
  1544 		}
  1545 	
  1546 	// Assume MBR will be present or is not required
  1547 	iMbrMissing = EFalse;
  1548 
  1549 	// If media driver is persistent (see EMediaDriverPersistent), 
  1550 	// the card may have changed since last power down, so reset CID
  1551 	iSession->SetCard(iCard);
  1552 
  1553 	TInt r = LaunchRPIRead();
  1554 
  1555 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r));
  1556 
  1557 	if(r == KErrLocked)
  1558 		{
  1559 		// If the media is locked, we present a default partition entry to the local
  1560 		// media subsystem, which will be updated when the media is finally unlocked.
  1561 		r = CreateDefaultPartition();
  1562 		if (r != KErrNone)
  1563 		    {
  1564 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT2, this, r );
  1565 			return r;
  1566 		    }
  1567 		
  1568 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT3, this, KErrLocked );
  1569 		return KErrLocked;
  1570 		}
  1571 
  1572 	// KErrNone indicates asynchronous completion
  1573 	
  1574 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PARTITIONINFO_EXIT4, this, r );
  1575 	return r;
  1576 	}
  1577 
  1578 TInt DMmcMediaDriverFlash::LaunchRPIUnlock(TLocalDrivePasswordData& aPasswordData)
  1579 	{
  1580 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_ENTRY, this );
  1581 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lru:%d,%d", iCard->IsReady(), iCard->IsLocked()));
  1582 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_ICARD, "iCard->IsReady=%d; iCard->IsLocked=%d", iCard->IsReady(), iCard->IsLocked());
  1583 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1584 
  1585 	TInt r = KErrNone;
  1586 
  1587 	// CMD42 is an adtc, so check state in same way as for write
  1588 	if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone)
  1589 		{
  1590 		r = Stack().MMCSocket()->PrepareStore(CardNum(), DLocalDrive::EPasswordUnlock, aPasswordData);
  1591 
  1592 		if (r == KErrNone)
  1593 			{
  1594 			TMediaPassword curPwd;
  1595 
  1596 			curPwd = *aPasswordData.iOldPasswd;
  1597 
  1598 			TInt curPwdLen = curPwd.Length();
  1599 			TInt blockLen = 2 + curPwdLen;
  1600 
  1601 			TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
  1602 			pbuf[0] = 0;				// LOCK_UNLOCK = 0; SET_PWD = 0
  1603 			pbuf[1] = static_cast<TUint8>(curPwdLen);
  1604 			pbuf.Append(curPwd);
  1605 			iSession->SetupCIMLockUnlock(blockLen, iMinorBuf);
  1606 
  1607 			r = EngageAndSetWriteRequest(EMReqUpdatePtnInfo);
  1608 			}
  1609 		}
  1610 
  1611 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r));
  1612 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIUNLOCK_EXIT, this, r );
  1613 	return r;
  1614 	}
  1615 
  1616 
  1617 TInt DMmcMediaDriverFlash::LaunchRPIRead()
  1618 //
  1619 // launch read request on first KDiskSectorSize (512) bytes
  1620 //
  1621 	{
  1622 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIREAD_ENTRY, this );
  1623 	__KTRACE_OPT(KPBUSDRV, Kern::Printf((">mmd:lrr")));
  1624 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1625 
  1626 	// the partition information is read before any other area is read from /
  1627 	// written to, and so does not need to maintain cache coherence.  Therefore
  1628 	// it can safely use the minor buffer.
  1629 
  1630 	TInt r;
  1631 	if ((r = CheckDevice(EMReqTypeNormalRd)) == KErrNone)
  1632 		{
  1633 		iIntBuf = iMinorBuf;
  1634 		iSession->SetupCIMReadBlock(0, iIntBuf);	// aBlocks = 1
  1635 		r = EngageAndSetReadRequest(EMReqPtnInfo);
  1636 		}
  1637 
  1638 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lrr:%d", r));
  1639 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIREAD_EXIT, this, r );
  1640 	return r;
  1641 	}
  1642 
  1643 
  1644 TInt DMmcMediaDriverFlash::LaunchRPIErase()
  1645 	{
  1646 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_ENTRY, this );
  1647 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:lre:%d,%d", iCard->IsReady(), iCard->IsLocked()));
  1648 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1649 
  1650 	TInt r = KErrNone;
  1651 
  1652 	// CMD42 is an adtc, so check state in same way as for write
  1653 	if ((r = CheckDevice(EMReqTypeUnlockPswd)) == KErrNone)
  1654 		{
  1655 		if(iCard->IsWriteProtected())
  1656 			{
  1657 			r = KErrAccessDenied;
  1658 			}
  1659 		else
  1660 			{
  1661 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:df:EMReqForceErase"));
  1662 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_FORCE_ERASE, "Force erase");
  1663 			iMinorBuf[0] = KMMCLockUnlockErase;
  1664 			iSession->SetupCIMLockUnlock(1, iMinorBuf);
  1665 			r = EngageAndSetWriteRequest(EMReqForceErase);
  1666 			}
  1667 		}
  1668 
  1669 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:lru:%d", r));
  1670 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_LAUNCHRPIERASE_EXIT, this, r );
  1671 	return r;
  1672 	}
  1673 
  1674 
  1675 TInt DMmcMediaDriverFlash::DecodePartitionInfo()
  1676 //
  1677 // decode partition info that was read into internal buffer 
  1678 //
  1679 	{
  1680 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_ENTRY, this );
  1681 	TInt partitionCount=iPartitionInfo->iPartitionCount=0;
  1682 	TInt defaultPartitionNumber=-1;
  1683 	TMBRPartitionEntry* pe;
  1684 	const TUint KMBRFirstPartitionOffsetAligned = KMBRFirstPartitionOffset & ~3;
  1685 	TInt i;
  1686 
  1687 	// Read of the first sector successful so check for a Master Boot Record
  1688 	if (*(TUint16*)(&iIntBuf[KMBRSignatureOffset])!=0xAA55)
  1689 		goto mbr_done;
  1690 
  1691 	__ASSERT_COMPILE(KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry) <= KMBRSignatureOffset);
  1692 
  1693 	memmove(&iIntBuf[0], &iIntBuf[2],
  1694 		KMBRFirstPartitionOffsetAligned + KMBRMaxPrimaryPartitions * sizeof(TMBRPartitionEntry)); 
  1695 
  1696 
  1697 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
  1698 		pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
  1699 		{
  1700 		if (pe->IsDefaultBootPartition())
  1701 			{
  1702 			SetPartitionEntry(&iPartitionInfo->iEntry[0],pe->iFirstSector,pe->iNumSectors);
  1703 			defaultPartitionNumber=i;
  1704 			partitionCount++;
  1705 			break;
  1706 			}
  1707 		}
  1708 
  1709 	// Now add any other partitions
  1710 	for (i=0, pe = (TMBRPartitionEntry*)(&iIntBuf[KMBRFirstPartitionOffsetAligned]);
  1711 		pe->iPartitionType != 0 && i < KMBRMaxPrimaryPartitions;i++,pe++)
  1712 		{
  1713 		TBool validPartition = ETrue;	// assume partition valid
  1714 
  1715 		if (defaultPartitionNumber==i)
  1716 			{
  1717 			// Already sorted
  1718 			}
  1719 
  1720 		// FAT partition ?
  1721 		else if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition() || pe->IsValidExFATPartition())
  1722 			{
  1723 			SetPartitionEntry(&iPartitionInfo->iEntry[partitionCount],pe->iFirstSector,pe->iNumSectors);
  1724 			__KTRACE_OPT(KLOCDPAGING, Kern::Printf("Mmc: FAT partition found at sector #%u", pe->iFirstSector));
  1725 			OstTrace1(TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_FS,"FAT partition found at sector #%u", pe->iFirstSector);
  1726 			partitionCount++;
  1727 			}
  1728 		else
  1729 			{
  1730 			validPartition = EFalse;
  1731 			}
  1732 		
  1733 		if (validPartition && partitionCount == 1)
  1734 			iHiddenSectors = pe->iFirstSector;
  1735 
  1736 		}
  1737 
  1738 	// Check the validity of the partition address boundaries
  1739 	// If there is any
  1740 	if(partitionCount > 0)
  1741 		{
  1742 		const TInt64 deviceSize = iCard->DeviceSize64();
  1743 		TPartitionEntry& part = iPartitionInfo->iEntry[partitionCount - 1];
  1744 		// Check that the card address space boundary is not exceeded by the last partition
  1745 		// In case of only 1 partition in the media check also it
  1746 		if(part.iPartitionBaseAddr + part.iPartitionLen > deviceSize)
  1747 			{
  1748 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: MBR partition exceeds card memory space"));
  1749 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT1, "MBR partition exceeds card memory space" );
  1750 			// Adjust the partition length to card address boundary
  1751 			part.iPartitionLen = (deviceSize - part.iPartitionBaseAddr);
  1752 
  1753 			// Check that the base address contained valid information
  1754 			if(part.iPartitionLen <= 0)
  1755 				{
  1756 				__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address"));
  1757 				OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT2, "Invalid base address" );
  1758 				// Invalid MBR - assume the boot sector is in the first sector
  1759 				defaultPartitionNumber =-1; 
  1760 				partitionCount=0;
  1761 				}
  1762 			}
  1763 		// More than one partition. Go through all of them
  1764 		if (partitionCount > 0)
  1765 			{
  1766 			for(i=partitionCount-1; i>0; i--)
  1767 				{
  1768 				const TPartitionEntry& curr = iPartitionInfo->iEntry[i];
  1769 				TPartitionEntry& prev = iPartitionInfo->iEntry[i-1];
  1770 				// Check if partitions overlap
  1771 				if(curr.iPartitionBaseAddr < (prev.iPartitionBaseAddr + prev.iPartitionLen))
  1772 					{
  1773 					__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Overlapping partitions"));
  1774 					OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT3, "Overlapping partitions" );
  1775 					// Adjust the partition length to not overlap the next partition
  1776 					prev.iPartitionLen = (curr.iPartitionBaseAddr - prev.iPartitionBaseAddr);
  1777 
  1778 					// Check that the base address contained valid information
  1779 					if(prev.iPartitionLen <= 0)
  1780 						{
  1781 						__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc: Invalid base address"));
  1782 						OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTCOUNT4, "Invalid base address" );
  1783 						// Invalid MBR - assume the boot sector is in the first sector
  1784 						defaultPartitionNumber=(-1); 
  1785 						partitionCount=0;
  1786 						}
  1787 					}
  1788 				}
  1789 			}
  1790 		}
  1791 
  1792 mbr_done:
  1793 	if (defaultPartitionNumber==(-1) && partitionCount==0)
  1794 		{
  1795 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("Mmc:PartitionInfo no MBR"));
  1796 		OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE1, "No MBR" );
  1797 		if (MBRMandatory(iCard))
  1798 			{
  1799 			// If the MBR is missing AND is required, we present a default partition entry to the local
  1800 			// media subsystem, which will be updated when the media is finally formatted
  1801 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("MBR mandatory, defining space for MBR + default partition"));
  1802 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_MBRDONE2, "MBR mandatory, defining space for MBR + default partition" );
  1803 			iMbrMissing = ETrue;
  1804 			TInt r = CreateDefaultPartition();
  1805 			if (r != KErrNone)
  1806 			    {
  1807 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT1, this, r );
  1808 				return r;
  1809 			    }
  1810 			}
  1811 		else
  1812 			{
  1813 			// Assume it has no MBR, and the Boot Sector is in the 1st sector
  1814 			SetPartitionEntry(&iPartitionInfo->iEntry[0],0,I64LOW(iCard->DeviceSize64()>>KDiskSectorShift));
  1815 			iHiddenSectors=0;
  1816 			}
  1817 		partitionCount=1;
  1818 		}
  1819 
  1820 	iPartitionInfo->iPartitionCount=partitionCount;
  1821 	iPartitionInfo->iMediaSizeInBytes=TotalSizeInBytes();
  1822 
  1823 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<Mmc:PartitionInfo (C:%d)",iPartitionInfo->iPartitionCount));
  1824 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition1 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen)));
  1825 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition2 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen)));
  1826 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition3 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen)));
  1827 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("     Partition4 (B:%xH L:%xH)",I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen)));
  1828 	OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTINFO1, "Partition1 (B:0x%x L:0x%x); Partition2 (B:0x%x L:0x%x)", I64LOW(iPartitionInfo->iEntry[0].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[0].iPartitionLen),I64LOW(iPartitionInfo->iEntry[1].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[1].iPartitionLen));
  1829 	OstTraceDefExt4(OST_TRACE_CATEGORY_RND, TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_PARTINFO2, "Partition3 (B:0x%x L:0x%x); Partition4 (B:0x%x L:0x%x)", I64LOW(iPartitionInfo->iEntry[2].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[2].iPartitionLen),I64LOW(iPartitionInfo->iEntry[3].iPartitionBaseAddr),I64LOW(iPartitionInfo->iEntry[3].iPartitionLen));
  1830 
  1831 #ifdef _DEBUG
  1832 	TMBRPartitionEntry cPe;
  1833 	if(GetDefaultPartitionInfo(cPe) == KErrNone)
  1834 		{
  1835 		pe = (TMBRPartitionEntry*)(&iIntBuf[0]);
  1836 
  1837 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
  1838 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("-- Partition Entry Validation/Comparison --"));
  1839 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
  1840 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("-- iX86BootIndicator [%02x:%02x] %c       -", pe->iX86BootIndicator, cPe.iX86BootIndicator, pe->iX86BootIndicator == cPe.iX86BootIndicator ? ' ' : 'X'));
  1841 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--        iStartHead [%02x:%02x] %c       -", pe->iStartHead,        cPe.iStartHead,        pe->iStartHead        == cPe.iStartHead        ? ' ' : 'X'));
  1842 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--      iStartSector [%02x:%02x] %c       -", pe->iStartSector,      cPe.iStartSector,      pe->iStartSector      == cPe.iStartSector      ? ' ' : 'X'));
  1843 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--    iStartCylinder [%02x:%02x] %c       -", pe->iStartCylinder,    cPe.iStartCylinder,    pe->iStartCylinder    == cPe.iStartCylinder    ? ' ' : 'X'));
  1844 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--    iPartitionType [%02x:%02x] %c       -", pe->iPartitionType,    cPe.iPartitionType,    pe->iPartitionType    == cPe.iPartitionType    ? ' ' : 'X'));
  1845 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--          iEndHead [%02x:%02x] %c       -", pe->iEndHead,          cPe.iEndHead,          pe->iEndHead          == cPe.iEndHead          ? ' ' : 'X'));
  1846 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--        iEndSector [%02x:%02x] %c       -", pe->iEndSector,        cPe.iEndSector,        pe->iEndSector        == cPe.iEndSector        ? ' ' : 'X'));
  1847 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--      iEndCylinder [%02x:%02x] %c       -", pe->iEndCylinder,      cPe.iEndCylinder,      pe->iEndCylinder      == cPe.iEndCylinder      ? ' ' : 'X'));
  1848 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--      iFirstSector [%08x:%08x] %c       -", pe->iFirstSector,      cPe.iFirstSector,      pe->iFirstSector      == cPe.iFirstSector      ? ' ' : 'X'));
  1849 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("--       iNumSectors [%08x:%08x] %c       -", pe->iNumSectors,       cPe.iNumSectors,       pe->iNumSectors       == cPe.iNumSectors       ? ' ' : 'X'));
  1850 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("-------------------------------------------"));
  1851 		}
  1852 #endif
  1853 
  1854 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DECODEPARTITIONINFO_EXIT2, this, KErrNone );
  1855 	return KErrNone;
  1856 	}
  1857 
  1858 
  1859 TInt DMmcMediaDriverFlash::WritePartitionInfo()
  1860 /**
  1861 	Write the default partition table to freshly formatted media
  1862 	@return Standard Symbian OS Error Code
  1863  */
  1864 	{
  1865 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_ENTRY, this );
  1866 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:wpi"));
  1867 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  1868 
  1869 	TMBRPartitionEntry partitionEntry;
  1870 	TInt err = GetDefaultPartitionInfo(partitionEntry);
  1871 	if(err == KErrNone)
  1872 		{
  1873 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:MBR/Partition Table"));
  1874 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Boot ID          : %02xh", partitionEntry.iX86BootIndicator));
  1875 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Start Head       : %02xh", partitionEntry.iStartHead));
  1876 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Start Sector     : %02xh", partitionEntry.iStartSector));
  1877 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Start Cyclinder  : %02xh", partitionEntry.iStartCylinder));
  1878 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    System ID        : %02xh", partitionEntry.iPartitionType));
  1879 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    End Head         : %02xh", partitionEntry.iEndHead));
  1880 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    End Sector       : %02xh", partitionEntry.iEndSector));
  1881 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    End Cyclinder    : %02xh", partitionEntry.iEndCylinder));
  1882 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Relative Sector  : %08xh", partitionEntry.iFirstSector));
  1883 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("    Number of Sectors: %08xh", partitionEntry.iNumSectors));
  1884 		OstTraceExt5(TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_PARTINFO1, "Boot ID=0x%02x; Start Head=0x%02x; Start Sector=0x%02x; Start Cyclinder=0x%02x; System ID=0x%02x", (TUint) partitionEntry.iX86BootIndicator, (TUint) partitionEntry.iStartHead, (TUint) partitionEntry.iStartSector, (TUint) partitionEntry.iStartCylinder, (TUint) partitionEntry.iPartitionType);
  1885 		OstTraceExt5(TRACE_MMCDEBUG, DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_PARTINFO2, "End Head=0x%02x; End Sector=0x%02x; End Cyclinder=0x%02x; Relative Sector=0x%08x; Number of Sectors=0x%08x", (TUint) partitionEntry.iEndHead, (TUint) partitionEntry.iEndSector, (TUint) partitionEntry.iEndCylinder, (TUint) partitionEntry.iFirstSector, (TUint) partitionEntry.iNumSectors);
  1886 		//
  1887 		// Clear all other partition entries and align the partition info into the minor buffer for writing...
  1888 		//
  1889 		memclr(iMinorBuf, KDiskSectorSize);
  1890 		memcpy(&iMinorBuf[KMBRFirstPartitionEntry], &partitionEntry, sizeof(TMBRPartitionEntry));
  1891 
  1892 		*(TUint16*)(&iMinorBuf[KMBRSignatureOffset]) = 0xAA55;
  1893 
  1894 		iSession->SetupCIMWriteBlock(0, iMinorBuf);
  1895 		
  1896 		//
  1897 		// Write the partition table and engage the read to validate and complete the mount process
  1898 		//
  1899 		iMbrMissing = EFalse;
  1900 		iCreateMbr = EFalse;
  1901 		err = EngageAndSetWriteRequest(EMReqUpdatePtnInfo);
  1902 		}
  1903 
  1904 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:wpi:%d", err));
  1905 
  1906 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_WRITEPARTITIONINFO_EXIT, this, err );
  1907 	return err;
  1908 	}
  1909 
  1910 
  1911 TInt DMmcMediaDriverFlash::CreateDefaultPartition()
  1912 	{
  1913 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CREATEDEFAULTPARTITION_ENTRY, this );
  1914 	TMBRPartitionEntry defPartition;
  1915 	TInt r = GetDefaultPartitionInfo(defPartition);
  1916 	if (r == KErrNone)
  1917 		{
  1918 		SetPartitionEntry(&iPartitionInfo->iEntry[0], defPartition.iFirstSector, defPartition.iNumSectors);
  1919 		iHiddenSectors = defPartition.iFirstSector;
  1920 		iPartitionInfo->iPartitionCount   = 1;
  1921 		iPartitionInfo->iMediaSizeInBytes = TotalSizeInBytes();
  1922 		}
  1923 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CREATEDEFAULTPARTITION_EXIT, this, r );
  1924 	return r;
  1925 	}
  1926 
  1927 TInt DMmcMediaDriverFlash::GetDefaultPartitionInfo(TMBRPartitionEntry& aPartitionEntry)
  1928 /**
  1929 	Calculates the default patition information for an specific card.
  1930 	@param aPartitionEntry The TMBRPartitionEntry to be filled in with the format parameters
  1931 	@return Standard Symbian OS Error Code
  1932  */
  1933 	{
  1934 	memclr(&aPartitionEntry, sizeof(TMBRPartitionEntry));
  1935 	TUint16 reservedSectors; // Not used
  1936 	TInt r = GetMediaDefaultPartitionInfo(aPartitionEntry, reservedSectors, iCard);
  1937 	return r;
  1938 	}
  1939 
  1940 
  1941 void DMmcMediaDriverFlash::SetPartitionEntry(TPartitionEntry* aEntry, TUint aFirstSector, TUint aNumSectors)
  1942 //
  1943 // auxiliary static function to record partition information in TPartitionEntry object
  1944 //
  1945 	{
  1946 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_ENTRY );
  1947 	aEntry->iPartitionBaseAddr=aFirstSector;
  1948 	aEntry->iPartitionBaseAddr<<=KDiskSectorShift;
  1949 	aEntry->iPartitionLen=aNumSectors;
  1950 	aEntry->iPartitionLen<<=KDiskSectorShift;
  1951 	aEntry->iPartitionType=KPartitionTypeFAT12;	
  1952 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SETPARTITIONENTRY_EXIT );
  1953 	}
  1954 
  1955 TInt DMmcMediaDriverFlash::DoPasswordOp()
  1956 	{
  1957 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPASSWORDOP_ENTRY, this );
  1958 	// Reconstruct password data structure in our address space
  1959 	TLocalDrivePasswordData clientData;
  1960 	TInt r = iCurrentReq->ReadRemoteRaw(&clientData, sizeof(TLocalDrivePasswordData));
  1961 
  1962 	TMediaPassword oldPassword;
  1963 	if (r == KErrNone)
  1964 		r = iCurrentReq->ReadRemote(clientData.iOldPasswd, &oldPassword);
  1965 
  1966 	TMediaPassword newPassword;
  1967 	if (r == KErrNone)
  1968 		r = iCurrentReq->ReadRemote(clientData.iNewPasswd, &newPassword);
  1969 
  1970 	TLocalDrivePasswordData passData(oldPassword, newPassword, clientData.iStorePasswd);
  1971 
  1972 	if (r == KErrNone)
  1973 		{
  1974 		TInt id=iCurrentReq->Id();
  1975 		switch (id)
  1976 			{
  1977 			case DLocalDrive::EPasswordUnlock:
  1978 				r = LaunchRPIUnlock(passData);
  1979 				__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rpi:%d", r));
  1980 				break;
  1981 			case DLocalDrive::EPasswordLock:
  1982 			case DLocalDrive::EPasswordClear:
  1983 				PasswordControl(id, passData);	
  1984 				break;
  1985 			}
  1986 		}
  1987 		
  1988 	// This will complete the request in the event of an error
  1989 	if(r != KErrNone)
  1990 		PartitionInfoComplete(r);
  1991 
  1992 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_DOPASSWORDOP_EXIT, this, KErrNone );
  1993 	return KErrNone; // ensures to indicate asynchronoous completion
  1994 	}
  1995 
  1996 void DMmcMediaDriverFlash::PasswordControl(TInt aFunc, TLocalDrivePasswordData& aData)
  1997 //
  1998 // Change a card's password, or clear the pasword from a locked card.  The card
  1999 // must be unlocked for this function.  A locked card is unlocked when it is mounted,
  2000 // to read the partition information.  This is done from ReadPartitionInfo() and
  2001 // LaunchRPIUnlock().
  2002 //
  2003 	{
  2004 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_PASSWORDCONTROL_ENTRY ,"DMmcMediaDriverFlash::PasswordControl;aFunc=%d;this=%x", aFunc, (TUint) this);
  2005 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:pc:%d", (TInt) aFunc));
  2006 	__ASSERT_DEBUG(CurrentRequest() == EMReqIdle, Panic(EPCInUse));
  2007 	__ASSERT_DEBUG(aFunc == DLocalDrive::EPasswordLock || aFunc == DLocalDrive::EPasswordClear, Panic(EPCFunc));
  2008 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  2009 
  2010 	TInt r;
  2011 
  2012 	if ((r = CheckDevice(EMReqTypeChangePswd)) == KErrNone)
  2013 		{
  2014 		// check if the current password is correct here.  (This makes the
  2015 		// clear operation redundant only if the password is stored and it
  2016 		// is wrong.)  Complete with same value as DoSessionEndDfc() would.
  2017 
  2018 		TMediaPassword curPwd;
  2019 		
  2020 		curPwd = *aData.iOldPasswd;
  2021 		TInt curPwdLen = curPwd.Length();
  2022 		TInt blockLen;
  2023 
  2024 		if (!(iCard->iFlags & KMMCardIsLockable))
  2025 			r = KErrNotSupported;
  2026 		else if (Stack().PasswordStore()->IsMappingIncorrect(iCard->CID(), curPwd))
  2027 			r = KErrAccessDenied;
  2028 		else
  2029 			{
  2030 			if ((r = Stack().MMCSocket()->PrepareStore(CardNum(), aFunc, aData/*, aThread*/)) == KErrNone)
  2031 				{
  2032 				switch (aFunc)
  2033 					{
  2034 				case DLocalDrive::EPasswordLock:
  2035 					{
  2036 					TMediaPassword newPwd;
  2037 					newPwd = *aData.iNewPasswd;
  2038 					TInt newPwdLen = newPwd.Length();
  2039 					blockLen = 1 + 1 + curPwdLen + newPwdLen;
  2040 					
  2041 					#ifndef __EPOC32__
  2042 					TUint16 env_Var[]=L"_EPOC_PWD_LEN";
  2043 					TUint16 env_Val[2];
  2044 					env_Val[0]=(TUint16)(curPwdLen+1);
  2045 					env_Val[1]=0;//make a null terminated string
  2046 					r=SetEnvironmentVariable(env_Var,&env_Val[0]);
  2047 					__ASSERT_DEBUG(r!=0, Panic(EPCFunc));
  2048 					
  2049 					#endif
  2050 					
  2051 					TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
  2052 					pbuf[0] = KMMCLockUnlockSetPwd; 	// LOCK_UNLOCK = 0, SET_PWD = 1
  2053 					pbuf[1] = static_cast<TUint8>(curPwdLen + newPwdLen);
  2054 					pbuf.Append(curPwd);
  2055 					pbuf.Append(newPwd);
  2056 					}
  2057 					break;
  2058 
  2059 				case DLocalDrive::EPasswordClear:
  2060 					{
  2061 					blockLen = 1 + 1 + curPwdLen;
  2062 
  2063 					TPtr8 pbuf(&iMinorBuf[0], 2, blockLen);
  2064 					pbuf[0] = KMMCLockUnlockClrPwd; 	// LOCK_UNLOCK = dc, CLR_PWD = 1
  2065 					pbuf[1] = static_cast<TUint8>(curPwdLen);
  2066 					pbuf.Append(curPwd);
  2067 					}
  2068 					break;
  2069 
  2070 				default:
  2071 					// DLocalDrive::EPasswordUnlock is not handled.  This avoids warnings for unused
  2072 					// case, and uninitialized variable.
  2073 					blockLen = 0;
  2074 					break;
  2075 					}	// switch (aFunc)
  2076 
  2077 				iSession->SetupCIMLockUnlock(blockLen, iMinorBuf);
  2078 				r = EngageAndSetWriteRequest(EMReqPswdCtrl);
  2079 				}	// if ((r = Stack().PrepareStore(CardNum(), aFunc, aData, aThread)) == KErrNone)
  2080 			}	// else (Stack().IsMappingIncorrect(iCard->CID(), curPwd))
  2081 		}	// (r = CheckDevice(EMReqTypeChangePswd)) == KErrNone
  2082 
  2083 	// complete immediately if error occured
  2084 	if (r != KErrNone)
  2085 		CompleteRequest(r);
  2086 
  2087 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:pc:%d", r));
  2088 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_PASSWORDCONTROL_EXIT, this );
  2089 	}
  2090 
  2091 
  2092 // ---- device status, callback DFC ----
  2093 
  2094 TInt DMmcMediaDriverFlash::CheckDevice(TMediaReqType aReqType)
  2095 //
  2096 // Check the device before initiating a command
  2097 //
  2098 	{
  2099 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_CHECKDEVICE_ENTRY, "DMmcMediaDriverFlash::CheckDevice;aReqType=%d;this=%x", (TInt) aReqType, (TUint) this);
  2100 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:cd:%d",aReqType));
  2101 
  2102 	TInt r=KErrNone;
  2103 
  2104 	if (!iCard->IsReady())
  2105 		r=KErrNotReady;
  2106 
  2107 	// The card must be locked if attempting to unlock during RPI, and
  2108 	// unlocked at all other times.
  2109 	else if (aReqType!=EMReqTypeUnlockPswd && iCard->IsLocked())
  2110 		r=KErrLocked;
  2111 	// Don't perform Password setting for WriteProtected cards, 
  2112 	// unable to recover (ForcedErase) if password lost.
  2113 	else if (aReqType==EMReqTypeChangePswd)
  2114 		{
  2115 		if (iCard->MediaType()==EMultiMediaROM)
  2116 			{
  2117 			r=KErrAccessDenied;
  2118 			}
  2119 		}
  2120 	else if (iMbrMissing && aReqType==EMReqTypeNormalRd)
  2121 		r=KErrCorrupt;
  2122 
  2123 #if !defined(__WINS__)
  2124 	// Don't perform write/password operations when the battery is low
  2125 //	else if (aReqType!=EMReqTypeNormalRd && Hal::MainBatteryStatus()<ELow && !Hal::ExternalPowerPresent())
  2126 //		r=KErrBadPower;
  2127 #endif
  2128 	// Don't perform write operations when the mechanical write protect switch is set
  2129 	else if (aReqType==EMReqTypeNormalWr && iCard->IsWriteProtected())
  2130 		r=KErrAccessDenied;
  2131 	// Don't perform write/format operations on MMC ROM cards
  2132 	else if (iMediaType==EMultiMediaROM && aReqType == EMReqTypeNormalWr)
  2133 		r=KErrAccessDenied;
  2134 
  2135 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:cd:%d", r));
  2136 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CHECKDEVICE_EXIT, this, r );
  2137 	return r;
  2138 	}
  2139 
  2140 void DMmcMediaDriverFlash::SessionEndCallBack(TAny* aMediaDriver)
  2141 //
  2142 // called by EPBUS when a single session has finished.  Queues DFC to launch
  2143 // next session or to complete client request.
  2144 //
  2145 	{
  2146 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_SESSIONENDCALLBACK_ENTRY );
  2147 	DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
  2148 	__ASSERT_DEBUG(! md.iSessionEndDfc.Queued(), Panic(ESECBQueued));
  2149 	md.iSessionEndDfc.Enque();
  2150 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_SESSIONENDCALLBACK_EXIT );
  2151 	}
  2152 
  2153 
  2154 void DMmcMediaDriverFlash::SessionEndDfc(TAny* aMediaDriver)
  2155 	{
  2156 	static_cast<DMmcMediaDriverFlash*>(aMediaDriver)->DoSessionEndDfc();
  2157 	}
  2158 
  2159 
  2160 void DMmcMediaDriverFlash::DoSessionEndDfc()
  2161 //
  2162 // launch next session or complete client request
  2163 //
  2164 	{
  2165 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_ENTRY, this );
  2166 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:dsed:%d", CurrentRequest()));
  2167 	OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_REQUEST, "Current Request=%d", CurrentRequest());
  2168 
  2169 	TInt r=KErrNone;
  2170 
  2171 	EndInCritical();
  2172 
  2173 	// Abort if writing or formatting and power has gone down
  2174 	if (!Kern::PowerGood() && CurrentRequest()!=EMReqRead)
  2175 		r=KErrAbort;
  2176 	// Return KErrNotReady if we have has a deferred media change
  2177 	if (!iCard->IsReady())
  2178 		r=KErrNotReady;
  2179 	// if stack has powered down session pointer will be NULL 
  2180 	if (iSession == NULL)
  2181 		r = KErrNotReady;
  2182 
  2183 	TBool complete = ETrue;
  2184 
  2185 	if (r==KErrNone)
  2186 		{
  2187 		r = iSession->EpocErrorCode();
  2188 
  2189 		switch (CurrentRequest())
  2190 			{
  2191 			case EMReqRead:
  2192 				{
  2193 				if (r != KErrNone)						// abort if MMC error
  2194 					break;
  2195 				
  2196 				if(iDoDoubleBuffer)
  2197 					{
  2198 					//
  2199 					// This is the end of a double-buffered transfer.
  2200 					//  - Now we have two buffers to copy back to the user...
  2201 					//
  2202 					TUint8* bufPtr = iIntBuf + (iSecondBuffer ? (iMaxBufSize >> 1) : 0);
  2203 					if((r = WriteDataToUser(bufPtr)) == KErrNone)
  2204 						{
  2205 						MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr));
  2206 
  2207 						iReqCur  = iPhysEnd;
  2208 						iPhysEnd = iDbEnd;
  2209 
  2210 						bufPtr = iIntBuf + (iSecondBuffer ? 0 : (iMaxBufSize >> 1));
  2211 						if((r = WriteDataToUser(bufPtr)) == KErrNone)
  2212 							{
  2213 							MarkBlocks(iReqCur, (iPhysEnd + iBlkMsk) & ~iBlkMsk, CchMemToIdx(bufPtr));
  2214 							}
  2215 						}
  2216 					iDoDoubleBuffer = EFalse;
  2217 					}
  2218 				else if (iDoPhysicalAddress)
  2219 					{
  2220 					if (iRdROB & KIPCWrite)
  2221 						{
  2222 						// partial end point
  2223 						TInt len = I64LOW(iReqEnd & iBlkMsk);
  2224 						const TInt ofset = I64LOW(iPhysEnd - iBlkLen - iReqStart);								
  2225 				
  2226 						TPtrC8 extrView(iIntBuf, len);
  2227 						r = iCurrentReq->WriteRemote(&extrView,ofset);
  2228 						}
  2229 					// Reset attributes
  2230 					iRdROB = 0;
  2231 					iFragOfset = iIPCLen = iBufOfset = 0;
  2232 					iReqCur = iPhysEnd = iReqEnd;					
  2233 					iDoPhysicalAddress = EFalse;
  2234 					}
  2235 				else
  2236 					{
  2237 					r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)]);
  2238 					}
  2239 
  2240 				if (r != KErrNone)
  2241 					break;
  2242 
  2243 				// if there is more information to read for the user then engage another session
  2244 				if ((iReqCur = iPhysEnd) < iReqEnd)
  2245 					{
  2246 					TBool allDone = EFalse;
  2247 					if ( ((r = ReadDataUntilCacheExhausted(&allDone)) == KErrNone) && !allDone)
  2248 						{
  2249 						iPhysStart = iReqCur & ~iBlkMsk;
  2250 						TUint32 length = I64LOW(iReqEnd - iReqCur);
  2251 		
  2252 						if ( (iReqEnd - iPhysStart) > iMaxBufSize && iSocket->SupportsDoubleBuffering() && !iReadToEndOfCard)
  2253 							r = LaunchDBRead();				
  2254 						else
  2255 							r = LaunchRead(iReqCur, length);
  2256 						
  2257 						if ( r == KErrNone)
  2258 							complete = EFalse;
  2259 						}
  2260 					}
  2261 				}
  2262 				break;
  2263 
  2264 			case EMReqWrite:
  2265 				{				
  2266 				if (r != KErrNone)						// abort if MMC error
  2267 					{
  2268 					break;
  2269 					}
  2270 
  2271 				if (iWtRBM == 0)
  2272 					{
  2273 					iReqCur = iPhysEnd;
  2274 					iDoDoubleBuffer = EFalse;
  2275 					iDoPhysicalAddress = EFalse;
  2276 					iRdROB = 0;
  2277 					iFragOfset = iIPCLen = iBufOfset = 0;
  2278 					}
  2279 				// clear current RBM flag
  2280 				else
  2281 					{
  2282 					if (iWtRBM & KWtRBMFst)
  2283 						{
  2284 						iWtRBM &= ~KWtRBMFst;
  2285 						}
  2286 					else if (iWtRBM & KWtRBMLst)
  2287 						{
  2288 						iWtRBM &= ~KWtRBMLst;
  2289 						}
  2290 					}
  2291 
  2292 				// advance media position if just finished write, as opposed to read-before-modify
  2293 				if (iReqCur < iReqEnd)
  2294 					{
  2295 					if ((r = LaunchWrite(iReqCur, I64LOW(iReqEnd - iReqCur), EMReqWrite)) == KErrNone)
  2296 						{
  2297 						complete = EFalse;
  2298 						}
  2299 
  2300 					complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
  2301 					}
  2302 				}
  2303 				break;
  2304 
  2305 			case EMReqFormat:
  2306 				{
  2307 				if (r != KErrNone)						// abort if MMC error
  2308 					break;
  2309 
  2310 				if ((iEraseUnitMsk == KMaxTUint64) ||	// no erase unit defined (Erase Class Commands not supported) ?
  2311 					(iPhysEnd == iReqEnd) ||			// finshed already ?
  2312 					((iPhysStart & iEraseUnitMsk) == 0 && (iPhysEnd & iEraseUnitMsk) == 0))
  2313 					{
  2314 					iReqCur = iPhysEnd;
  2315 					}
  2316 				else
  2317 					{
  2318 					// Formating to a mis-aligned boundary, so we can't make best use of
  2319 					// multiple erase blocks.  We shall simply erase up to the next block
  2320 					// boundary, and return the adjustment info to the file system
  2321 					r = I64LOW(iPhysEnd - iPhysStart);
  2322 					iReqCur = iReqEnd;
  2323 					}
  2324 
  2325 				if(r == KErrNone)
  2326 					{
  2327 					// advance media position if just finished write, as opposed to read-before-modify
  2328 					if (iReqCur < iReqEnd)
  2329 						{
  2330 						if ((r = LaunchFormat(iReqCur, I64LOW(iReqEnd - iReqCur))) == KErrNone)
  2331 							{
  2332 							complete = EFalse;
  2333 							}
  2334 						}
  2335 					// if format finished, write an MBR if required
  2336 					// Always write an MBR if it's an SD card
  2337 					else if (iCreateMbr)
  2338 						{
  2339 						// Finished Format, so write the MBR/default partition table if required
  2340 						r = WritePartitionInfo();
  2341 						complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
  2342 						}
  2343 					}
  2344 				}
  2345 				break;
  2346 
  2347 			case EMReqPtnInfo:
  2348 				if (r == KErrNone)
  2349 					r = DecodePartitionInfo();		// set up iPartitionInfo
  2350 
  2351 				PartitionInfoComplete(r == KErrNone?KErrNone:KErrNotReady);
  2352 				break;
  2353 				
  2354 			case EMReqEMMCPtnInfo:
  2355 				iMedReq = EMReqIdle;
  2356 				// For now do nothing..
  2357 				break;				
  2358 				
  2359 			case EMReqUpdatePtnInfo:
  2360 				break;
  2361 
  2362 			case EMReqPswdCtrl:
  2363 				if (r == KErrLocked)
  2364 					r = KErrAccessDenied;
  2365 				break;
  2366 
  2367 			case EMReqForceErase:
  2368 				
  2369 				if (r == KErrNone)
  2370 					{
  2371 					// Finished Forced Erase , so write the default partition table...
  2372 					r = WritePartitionInfo();
  2373 					}
  2374 
  2375 				complete = (r != KErrNone) ? (TBool)ETrue : (TBool)EFalse;
  2376 				break;
  2377 
  2378 			case EMReqWritePasswordData:
  2379 				// 
  2380 				// WritePasswordData also kicks off an auto-unlock session to ensure that
  2381 				// any locked cards that have passwords in the password store are immediately
  2382 				// available.  We can safely ignore any errors returned at this stage, as the
  2383 				// password store will have been successfully updated (in locmedia.cpp), even
  2384 				// if the card is unable to accept the password.
  2385 				//
  2386 				r = KErrNone;
  2387 				break;
  2388 				
  2389 			case EMReqIdle:
  2390 				// request has been completed already (e.g. due to a power down)
  2391 				break;
  2392 
  2393 
  2394 			default:
  2395 				__ASSERT_DEBUG(EFalse, Panic(EDSEDRequest));
  2396 				break;
  2397 			}
  2398 		}
  2399 
  2400 	// r != KErrNone => complete
  2401 	__ASSERT_DEBUG(!(r != KErrNone) || complete, Panic(EDSEDNotErrComplete));
  2402 
  2403 	if (complete)
  2404 		{
  2405 		if (r != KErrNone)
  2406 			InvalidateCache();
  2407 
  2408 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:cmp:%d", r));
  2409 		OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_COMPLETE, "Complete request; retval=%d", r);
  2410 		CompleteRequest(r);
  2411 		}
  2412 	else
  2413 		{
  2414 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mdf:dsed:ncmp"));
  2415 		OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_NOT_COMPLETE, "Request not complete");
  2416 		}
  2417 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOSESSIONENDDFC_EXIT, this );
  2418 	}
  2419 
  2420 void DMmcMediaDriverFlash::DataTransferCallBack(TAny* aMediaDriver)
  2421 	{
  2422 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACK_ENTRY );
  2423 	DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
  2424 	__ASSERT_DEBUG(! md.iDataTransferCallBackDfc.Queued(), Panic(EDBCBQueued));
  2425 	md.iDataTransferCallBackDfc.Enque();
  2426 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACK_EXIT );
  2427 	}
  2428 
  2429 void DMmcMediaDriverFlash::DataTransferCallBackDfc(TAny* aMediaDriver)
  2430 	{
  2431 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_ENTRY );
  2432 	DMmcMediaDriverFlash& md = *static_cast<DMmcMediaDriverFlash*>(aMediaDriver);
  2433 
  2434 	if (md.iDoPhysicalAddress)
  2435 		{
  2436 		if(md.CurrentRequest() == EMReqWrite)
  2437 			{
  2438 			md.DoPhysWriteDataTransferCallBack();
  2439 			}
  2440 		else
  2441 			{
  2442 			md.DoPhysReadDataTransferCallBack();
  2443 			}
  2444 		}
  2445 	else
  2446 		{
  2447 		if(md.CurrentRequest() == EMReqWrite)
  2448 			{
  2449 			md.DoWriteDataTransferCallBack();
  2450 			}
  2451 		else
  2452 			{
  2453 			md.DoReadDataTransferCallBack();
  2454 			}
  2455 		}
  2456 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_DATATRANSFERCALLBACKDFC_EXIT );
  2457 	}
  2458 
  2459 void DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()
  2460 	{
  2461 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_ENTRY, this );
  2462 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()"));
  2463 
  2464 	TInt err = KErrNone;
  2465 		
  2466 	if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) )
  2467 		{
  2468 		//IPC to be setup, or partial end block read
  2469 		iRdROB &= ~KIPCSetup;
  2470 
  2471 		if ((iReqEnd - iPhysEnd) < iBlkLen)
  2472 			{
  2473 			iIntBuf = iCacheBuf;
  2474 			}
  2475 		else
  2476 			{	
  2477 			TPtr8 tgt(iMinorBuf, iBlkLen);				
  2478 			err = ReadDataFromUser(tgt, I64LOW(iPhysEnd-iReqStart));
  2479 			iIntBuf = iMinorBuf;
  2480 			}			
  2481 
  2482 		iReqCur = iPhysEnd;
  2483 		iPhysEnd += iBlkLen;
  2484 		iBufOfset = 0;
  2485 		iIPCLen = iBlkLen;
  2486 
  2487 #if !defined(__WINS__)
  2488 		iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err);			
  2489 #else
  2490 		iSession->MoreDataAvailable( (TInt)(iBlkLen >> KDiskSectorShift), iIntBuf, err);
  2491 #endif
  2492 		__KTRACE_OPT(KPBUSDRV, 	Kern::Printf("--iDoPhysicalAddress(KIPCSetup)"));
  2493 		OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT1, this );
  2494 		return;
  2495 		}
  2496 	
  2497 	PrepareNextPhysicalFragment();
  2498 
  2499 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoPhysWriteDataTransferCallBack()"));
  2500 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSWRITEDATATRANSFERCALLBACK_EXIT2, this );
  2501 	}
  2502 
  2503 
  2504 void DMmcMediaDriverFlash::DoPhysReadDataTransferCallBack()
  2505 	{
  2506 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_ENTRY, this );
  2507 	__KTRACE_OPT(KPBUSDRV, 	Kern::Printf("++DMmcMediaDriverFlash::DoPhysReadTransferCallBack()"));
  2508 
  2509 	TInt err = KErrNone;
  2510 	
  2511 	if ((iRdROB & KIPCWrite) && !iSecondBuffer)
  2512 		{
  2513 		// an IPC transfer completed
  2514 		iRdROB &= ~KIPCWrite;
  2515 		if(iNxtIPCLen)
  2516 			{
  2517 			// First transfer is an IPC, 
  2518 			// Corner-case - transfer is most likely IPC-DMA-IPC, 
  2519 			// because write cannot occur until after the first 2 iterations it is possible to arrive here with both IPCSetup & IPCWrite Set. 
  2520 			// need to use iIPCNxtLen instead
  2521 			TPtrC8 extrView(&iIntBuf[iBufOfset], iNxtIPCLen);
  2522 			err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart));
  2523 			iNxtIPCLen = iBufOfset = 0;  
  2524 			}
  2525 		else
  2526 			{
  2527 			TPtrC8 extrView(&iIntBuf[iBufOfset], iIPCLen);
  2528 			err = iCurrentReq->WriteRemote(&extrView,I64LOW(iReqCur - iReqStart));
  2529 			iIPCLen = iBufOfset = 0;     
  2530 			}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
  2531 		}
  2532 	
  2533 	if ( (iRdROB & KIPCSetup) || ((iReqEnd - iPhysEnd) < iBlkLen) )
  2534 		{
  2535 		// IPC to be setup, or partial end block read.
  2536 		iRdROB &= ~KIPCSetup;
  2537 		iRdROB |= KIPCWrite;
  2538 		
  2539 		iIntBuf = ReserveReadBlocks(iPhysEnd,(iPhysEnd+iBlkLen), &iIPCLen);
  2540 
  2541 		iReqCur = iPhysEnd;
  2542 		iPhysEnd += iIPCLen;
  2543 		iBufOfset = 0;
  2544 #if !defined(__WINS__)
  2545 		iSession->MoreDataAvailable( (TInt)(iIPCLen  >> KDiskSectorShift), (TUint8*)Epoc::LinearToPhysical((TLinAddr) iIntBuf), err);			
  2546 #else
  2547 		iSession->MoreDataAvailable( (TInt)(iIPCLen  >> KDiskSectorShift), iIntBuf, err);			
  2548 #endif
  2549 		iSecondBuffer = ETrue;
  2550 		__KTRACE_OPT(KPBUSDRV, 	Kern::Printf("--iDoPhysicalAddress(KIPCWrite)"));
  2551 		OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT1, this );
  2552 		return;
  2553 		}
  2554 
  2555 	PrepareNextPhysicalFragment();
  2556 
  2557 	__KTRACE_OPT(KPBUSDRV, 	Kern::Printf("--DMmcMediaDriverFlash::DoPhysReadTransferCallBack()"));
  2558 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOPHYSREADDATATRANSFERCALLBACK_EXIT2, this );
  2559 	}
  2560 
  2561 void DMmcMediaDriverFlash::DoWriteDataTransferCallBack()
  2562 	{
  2563 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_ENTRY, this );
  2564 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("++DMmcMediaDriverFlash::DoWriteDataTransferCallBack()"));
  2565 
  2566 	TInt err = KErrNone;
  2567 	
  2568 	// Advance current request progress...
  2569 	iReqCur = iPhysEnd;
  2570 
  2571 	const TUint32 doubleBufferSize = iMaxBufSize >> 1;
  2572 
  2573 	TInt64 length = iDbEnd - iReqCur;
  2574 	TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iReqCur + length);
  2575 
  2576 	iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
  2577 	TInt64 len = UMin(iDbEnd, iPhysEnd) - iReqCur;
  2578 	
  2579 	if(len > doubleBufferSize)
  2580 		{
  2581 		// Adjust for maximum size of double-buffering
  2582 		len = doubleBufferSize;
  2583 		}
  2584 
  2585 	__ASSERT_DEBUG(len > 0, Panic(EDBLength));
  2586 	__ASSERT_DEBUG(I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0, Panic(EDBLengthTooBig));
  2587 
  2588 	TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift);
  2589 
  2590 	const TInt64 usrOfst = (iReqCur - iReqStart);
  2591 	
  2592 	__ASSERT_DEBUG(I64HIGH(usrOfst) == 0, Panic(EDBOffsetTooBig));
  2593 
  2594 	// Setup the next buffer pointer and switch buffers...
  2595 	TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0);
  2596 	TPtr8 tgt(bufPtr, I64LOW(len));
  2597 	iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue;
  2598 
  2599 	if(iDoLastRMW && length < doubleBufferSize)
  2600 		{
  2601 		//
  2602 		// This is the last transfer, and RMW is required.  The result of the read exists
  2603 		// in iMinorBuf, so copy the non-modified section of the block to the active buffer.
  2604 		//
  2605 		memcpy(&bufPtr[(numBlocks-1) << KDiskSectorShift], iMinorBuf, KDiskSectorSize);
  2606 		}
  2607 
  2608 	if(I64LOW(iDbEnd - iReqCur) <= iMaxBufSize)
  2609 		{
  2610 		//
  2611 		// This is the last transfer (with or without RMW)
  2612 		//  - Mark the last blocks as active in the buffer cache.
  2613 		//
  2614 		MarkBlocks(iReqCur, iPhysEnd, CchMemToIdx(bufPtr));
  2615 		}
  2616 
  2617 	//
  2618 	// Read the requested data from the remote thread...
  2619 	//
  2620 	err = ReadDataFromUser(tgt, I64LOW(usrOfst));
  2621 
  2622 	//
  2623 	// ...and signal that data is available to the PSL.
  2624 	//
  2625 	iSession->MoreDataAvailable(numBlocks, bufPtr, err);
  2626 
  2627 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoWriteDataTransferCallBack()"));
  2628 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOWRITEDATATRANSFERCALLBACK_EXIT, this );
  2629 	}
  2630 
  2631 
  2632 void DMmcMediaDriverFlash::DoReadDataTransferCallBack()
  2633 	{
  2634 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_ENTRY, this );
  2635 	__KTRACE_OPT(KPBUSDRV, 	Kern::Printf("++DMmcMediaDriverFlash::DoReadTransferCallBack()"));
  2636 
  2637 	TInt err = KErrNone;
  2638 	
  2639 	const TUint32 doubleBufferSize = iMaxBufSize >> 1;
  2640 
  2641 	TUint32 bufOfst = 0;
  2642 
  2643 	if((iReqCur & ~iBlkMsk) == iPhysStart)
  2644 		{
  2645 		if(iSecondBuffer)
  2646 			{
  2647 			//
  2648 			// If this is the first callback, don't copy data as it's not available yet
  2649 			//  - just drop through to set up the next buffer.
  2650 			//
  2651 			TUint32 numBlocks = I64LOW((doubleBufferSize + (KDiskSectorSize-1)) >> KDiskSectorShift);
  2652 			TUint8* bufPtr = iIntBuf + doubleBufferSize;
  2653 
  2654 			iSecondBuffer = EFalse;
  2655 
  2656 			iSession->MoreDataAvailable(numBlocks, bufPtr, KErrNone);
  2657 			OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT1, this );
  2658 			return;
  2659 			}
  2660 		else
  2661 			{
  2662 			//
  2663 			// If this is the second callback we're ready to copy
  2664 			// back to the client - data may be mis-aligned in the first
  2665 			// instance, but all subsequent data will be aligned...
  2666 			//
  2667 			bufOfst = I64LOW(iReqCur - iPhysStart);
  2668 			}
  2669 		}
  2670 
  2671 	// ...otherwise, write the previous buffer contents to the user
  2672 	TUint8* bufPtr = iIntBuf + (iSecondBuffer ? doubleBufferSize : 0);
  2673 
  2674 	err = WriteDataToUser(bufPtr + bufOfst);
  2675 
  2676 	// Advance current request progress...
  2677 	iReqCur = iPhysEnd;
  2678 
  2679 	TInt64 medEnd = UMin(iReqCur + doubleBufferSize, iDbEnd);
  2680 
  2681 	iPhysEnd = (medEnd + iBlkMsk) & ~iBlkMsk;
  2682 
  2683 	// Current buffer is one step ahead of the current request progress...
  2684 	TInt64 len = UMin((iDbEnd - iPhysEnd + iBlkMsk) & ~iBlkMsk, TInt64(doubleBufferSize));
  2685 
  2686 	__ASSERT_DEBUG(len == 0 || (I64HIGH((len + (KDiskSectorSize-1)) >> KDiskSectorShift) == 0), Panic(EDBLengthTooBig));
  2687 
  2688 	TUint32 numBlocks = I64LOW((len + (KDiskSectorSize-1)) >> KDiskSectorShift);
  2689 
  2690 	//
  2691 	// ...switch buffers and signal that data is available to the PSL.
  2692 	//
  2693 	iSecondBuffer = iSecondBuffer ? (TBool)EFalse : (TBool)ETrue;
  2694 
  2695 	iSession->MoreDataAvailable(numBlocks, bufPtr, err);
  2696 
  2697 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("--DMmcMediaDriverFlash::DoDataTransferCallBack()"));
  2698 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DOREADDATATRANSFERCALLBACK_EXIT2, this );
  2699 	}
  2700 
  2701 
  2702 // ---- request management ----
  2703 
  2704 
  2705 TInt DMmcMediaDriverFlash::EngageAndSetReadRequest(DMmcMediaDriverFlash::TMediaRequest aRequest)
  2706 	{
  2707 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this);
  2708 	TInt r = EngageAndSetRequest(aRequest, iReadCurrentInMilliAmps);
  2709 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREADREQUEST_EXIT, this, r );
  2710 	return r;
  2711 	}
  2712 
  2713 
  2714 TInt DMmcMediaDriverFlash::EngageAndSetWriteRequest(DMmcMediaDriverFlash::TMediaRequest aRequest)
  2715 	{
  2716 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetReadRequest;aRequest=%d;this=%x", (TInt) aRequest, (TUint) this);
  2717 	TInt r = EngageAndSetRequest(aRequest, iWriteCurrentInMilliAmps);
  2718 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETWRITEREQUEST_EXIT, this, r );
  2719 	return r;
  2720 	}
  2721 
  2722 
  2723 TInt DMmcMediaDriverFlash::EngageAndSetRequest(DMmcMediaDriverFlash::TMediaRequest aRequest, TInt aCurrent)
  2724 //
  2725 // In WINS, all of the processing, including the callbacks, is done when Engage() is called,
  2726 // so the request value must be set up in advanced.  Both the request and the current are
  2727 // cleared in the corresponding call to CompleteRequest().
  2728 //
  2729 	{
  2730 	OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_ENTRY, "DMmcMediaDriverFlash::EngageAndSetRequest;aRequest=%d;aCurrent=%d;this=%x", (TInt) aRequest, aCurrent, (TUint) this);
  2731 	__ASSERT_DEBUG(iSession != NULL, Panic(ECFSessPtrNull));
  2732 
  2733 	iMedReq = aRequest;
  2734 	SetCurrentConsumption(aCurrent);
  2735 
  2736 	TInt r = InCritical();
  2737 	if (r == KErrNone)
  2738 		{
  2739 		r = iSession->Engage();
  2740 		}
  2741 
  2742 	if(r != KErrNone)
  2743 		{
  2744 		if (!Kern::PowerGood())
  2745 			r=KErrAbort; // If emergency power down - return abort rather than anything else.
  2746 		if (!iCard->IsReady())
  2747 			r=KErrNotReady; // If media change - return not ready rather than anything else.
  2748 		EndInCritical();
  2749 		}
  2750 
  2751 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ENGAGEANDSETREQUEST_EXIT, this, r );
  2752 	return r;
  2753 	}
  2754 
  2755 
  2756 void DMmcMediaDriverFlash::CompleteRequest(TInt aReason)
  2757 //
  2758 // completes the specified request
  2759 //
  2760 	{
  2761 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_ENTRY, this );
  2762 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:cr0x%08x,%d", iCurrentReq, aReason));
  2763 	
  2764 	iMedReq = EMReqIdle;
  2765 	SetCurrentConsumption(KIdleCurrentInMilliAmps);
  2766 
  2767 	TLocDrvRequest* pR=iCurrentReq;
  2768 	if (pR)
  2769 		{
  2770 #ifdef __DEMAND_PAGING__
  2771 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
  2772 		__KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Complete req Id(%d) with(%d)", pR->Id(), aReason));
  2773 #endif		// __TEST_PAGING_MEDIA_DRIVER__
  2774 #endif		// __DEMAND_PAGING__
  2775 		iCurrentReq=NULL;
  2776 		DMediaDriver::Complete(*pR,aReason);
  2777 		}
  2778 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_COMPLETEREQUEST_EXIT, this );
  2779 	}
  2780 
  2781 TInt DMmcMediaDriverFlash::Caps(TLocDrv& aDrive, TLocalDriveCapsV6& aInfo)
  2782 	{
  2783 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CAPS_ENTRY, this );
  2784 	// Fill buffer with current media caps.
  2785 	aInfo.iType = EMediaHardDisk;
  2786 	aInfo.iConnectionBusType = EConnectionBusInternal;
  2787 	aInfo.iDriveAtt = KDriveAttLocal;
  2788 	aInfo.iMediaAtt	= KMediaAttFormattable;
  2789 
  2790 	if(iCard->iFlags & KMMCardIsLockable)
  2791 		aInfo.iMediaAtt |= KMediaAttLockable;
  2792 
  2793 	if (iCard->HasPassword())
  2794 		aInfo.iMediaAtt |= KMediaAttHasPassword;
  2795 	if (iCard->IsWriteProtected())
  2796 		aInfo.iMediaAtt |= KMediaAttWriteProtected;
  2797 	if (iCard->IsLocked())
  2798 		aInfo.iMediaAtt |= KMediaAttLocked;
  2799 
  2800 	aInfo.iFileSystemId = KDriveFileSysFAT;
  2801 
  2802 	// Format is performed in multiples of the erase sector (or multiple block) size
  2803 	aInfo.iMaxBytesPerFormat = iEraseInfo.iPreferredEraseUnitSize;
  2804 
  2805 	if ((!iInternalSlot) && (GetCardFormatInfo(iCard,aInfo.iFormatInfo) == KErrNone))
  2806 		{
  2807 		TUint16 reservedSectors;
  2808 		TMBRPartitionEntry dummy;	// Not used here
  2809 		const TInt r = GetMediaDefaultPartitionInfo(dummy, reservedSectors, iCard);
  2810 		if(r != KErrNone)
  2811 		    {
  2812 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT1, this, r );
  2813 			return r;
  2814 		    }
  2815 
  2816 		aInfo.iFormatInfo.iReservedSectors = reservedSectors;
  2817 		aInfo.iExtraInfo = ETrue;
  2818 		}
  2819 
  2820     // Set serial number to CID
  2821     __ASSERT_DEBUG(KMMCCIDLength<=KMaxSerialNumLength, Kern::PanicCurrentThread(_L("Mmc"), KErrOverflow));
  2822     aInfo.iSerialNumLength = KMMCCIDLength;
  2823     for (TUint i=0; i<KMMCCIDLength; i++)
  2824         aInfo.iSerialNum[i] = iCard->CID().At(i);
  2825     
  2826 	// Get block size & erase block size to allow the file system to align first usable cluster correctly
  2827 	aInfo.iBlockSize = BlockSize(iCard);
  2828 	aInfo.iEraseBlockSize = EraseBlockSize(iCard);
  2829 
  2830 #if defined(__DEMAND_PAGING__)
  2831 	// If the stack has flagged this as a demand-paging device, then it is assumed that it is internal
  2832 	// and (optionally) write protected.
  2833 	if(aDrive.iPrimaryMedia->iPagingMedia)
  2834 		{
  2835 		aInfo.iMediaAtt|= KMediaAttPageable;
  2836 		if (iDemandPagingInfo.iWriteProtected)
  2837 			{
  2838 			aInfo.iMediaAtt|= KMediaAttWriteProtected;
  2839 			aInfo.iMediaAtt&= ~KMediaAttFormattable;
  2840 			}		
  2841 		}
  2842 
  2843 	// code paging enabled on this drive ?
  2844 	if(aDrive.iPagingDrv)
  2845 		{
  2846 		aInfo.iDriveAtt|= KDriveAttPageable;
  2847 		}
  2848 
  2849 #endif
  2850 
  2851 	if (iInternalSlot)
  2852 		{
  2853 		aInfo.iDriveAtt|= KDriveAttInternal;
  2854 		}
  2855 	else
  2856 		{
  2857 		aInfo.iDriveAtt|= KDriveAttRemovable;
  2858 		}
  2859 
  2860 
  2861 	if (iMmcPartitionInfo)
  2862 		{
  2863 		TLocalDriveCapsV6Buf CapsInfo = aInfo;
  2864 		iMmcPartitionInfo->PartitionCaps(aDrive,CapsInfo);
  2865 		aInfo = CapsInfo();
  2866 		}
  2867 	
  2868 	
  2869 	if (iMediaType==EMultiMediaROM)
  2870 		{
  2871 		aInfo.iMediaAtt|= KMediaAttWriteProtected;
  2872 		aInfo.iMediaAtt&= ~KMediaAttFormattable;
  2873 		}
  2874 	
  2875 	// Must return KErrCompletion to indicate that this 
  2876 	// is a synchronous version of the function
  2877 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_CAPS_EXIT2, this, KErrCompletion );
  2878 	return KErrCompletion;
  2879 	}
  2880 
  2881 
  2882 // ---- cache ----
  2883 
  2884 TInt DMmcMediaDriverFlash::ReadDataUntilCacheExhausted(TBool* aAllDone)
  2885 //
  2886 // scans the cache for blocks corresponding to the range iReqCur to iReqEnd and
  2887 // writes them to user memory.  Starts at iReqCur & ~iBlkMsk and looks for blocks
  2888 // at sequential media positions.  Completes when a block is not available, even
  2889 // if a following block is available in the cache.  *aAllDone is undefined if the
  2890 // return value is not KErrNone.
  2891 //
  2892 // This function is linear in the number of blocks in the cache.
  2893 //
  2894 	{
  2895 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_ENTRY, this );
  2896 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rdc:%x,%x", iReqCur, iReqEnd));
  2897 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED, "iReqCur=0x%x; iReqEnd=0x%x", (TUint) iReqCur, (TUint) iReqEnd );
  2898 	
  2899 	if ( iCurrentReq->IsPhysicalAddress()
  2900 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
  2901 	     || DMediaPagingDevice::PageInRequest(*iCurrentReq)
  2902 #endif //DEMAND_PAGING 
  2903         )
  2904 		{
  2905 		*aAllDone = EFalse;
  2906 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_EXIT1, this, KErrNone );
  2907 		return KErrNone;
  2908 		}
  2909 	
  2910 	TInt64 physStart = iReqCur & ~iBlkMsk;
  2911 	TInt64 physEnd = Min(physStart + iMaxBufSize, (iReqEnd + iBlkMsk) & ~iBlkMsk);
  2912 	BuildGammaArray(physStart, physEnd);
  2913 
  2914 	TInt r = KErrNone;
  2915 	TInt curBlk = 0;
  2916 	TInt cchBlk;
  2917 	while (
  2918 			r == KErrNone
  2919 		&&	physStart + (curBlk << iBlkLenLog2) < physEnd
  2920 		&&	(cchBlk = iGamma[curBlk]) != KNoCacheBlock )
  2921 		{
  2922 		// set up instance variables for WriteDataToUser()
  2923 		iPhysStart = physStart + (curBlk << iBlkLenLog2);
  2924 		iPhysEnd = iPhysStart + iBlkLen;
  2925 		iIntBuf = IdxToCchMem(cchBlk);
  2926 
  2927 		if ((r = WriteDataToUser(&iIntBuf[I64LOW(iReqCur - iPhysStart)])) == KErrNone)
  2928 			{
  2929 			iReqCur = iPhysEnd;
  2930 			iLstUsdCchEnt = iGamma[curBlk];
  2931 			++curBlk;
  2932 			}
  2933 		}
  2934 
  2935 	*aAllDone = (iReqCur >= iReqEnd);
  2936 
  2937 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rdc:%d,%d", *aAllDone, r));
  2938 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAUNTILCACHEEXHAUSTED_EXIT2, this, r );
  2939 	return r;
  2940 	}
  2941 
  2942 
  2943 TInt DMmcMediaDriverFlash::WriteDataToUser(TUint8* aBufPtr)
  2944 //
  2945 // write the data from the most recent read operation to the user descriptor
  2946 //
  2947 	{
  2948 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_ENTRY, this );
  2949 	TInt r = KErrNotSupported;
  2950 
  2951 	// get range of data to read out of internal buffer
  2952 
  2953 	TInt len = I64LOW(UMin(iPhysEnd, iReqEnd) - iReqCur);
  2954 	TPtrC8 extrView(aBufPtr, len);
  2955 
  2956 	// write data from internal buffer
  2957 	TUint usrOfst = I64LOW(iReqCur - iReqStart);
  2958 
  2959 	OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY1, "Begin writing user data" );
  2960 #if defined(__DEMAND_PAGING__) && !defined(__WINS__)
  2961 	if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
  2962 		r=iCurrentReq->WriteToPageHandler((TUint8 *)(&extrView[0]), len, usrOfst);
  2963 	else
  2964 #endif	// __DEMAND_PAGING__
  2965 		r = iCurrentReq->WriteRemote(&extrView,usrOfst);
  2966 	
  2967 	OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_LATENCY2, "End writing user data" );
  2968 
  2969 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_WRITEDATATOUSER_EXIT, this, r );
  2970 	return r;
  2971 	}
  2972 
  2973 TInt DMmcMediaDriverFlash::ReadDataFromUser(TDes8& aDes, TInt aOffset)
  2974 	{
  2975 	OstTraceExt2(TRACE_FLOW, DMMCMEDIADRIVERFLASH_READDATAFROMUSER_ENTRY ,"DMmcMediaDriverFlash::ReadDataFromUser;aOffset=%d;this=%x", aOffset, (TUint) this);
  2976 	TInt r = KErrNotSupported;
  2977 #ifndef __WINS__
  2978 	if (DMediaPagingDevice::PageOutRequest(*iCurrentReq))
  2979 	    {
  2980 		r = iCurrentReq->ReadFromPageHandler((TAny*) aDes.Ptr(), aDes.MaxLength(), aOffset);
  2981 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT1, this, r );
  2982 		return r;
  2983 	    }
  2984 	else
  2985 #endif // #ifndef __WINS__
  2986 		r = iCurrentReq->ReadRemote(&aDes, aOffset);
  2987 	
  2988 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_READDATAFROMUSER_EXIT2, this, r );
  2989 	return r;
  2990 	}
  2991 
  2992 TInt DMmcMediaDriverFlash::AdjustPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength)
  2993 //
  2994 // Retrieve next Physical memory fragment and adjust the start pointer and length with
  2995 // respect to the set offset {iFragOfset}.
  2996 // Note the offset may encompass multiple memory fragments.
  2997 //
  2998 	{
  2999 	OstTraceExt3(TRACE_FLOW, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_ENTRY, "DMmcMediaDriverFlash::AdjustPhysicalFragment;aPhysAddr=%x;aPhysLength=%d;this=%x", (TUint) aPhysAddr, aPhysLength, (TUint) this);
  3000 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:APF"));
  3001 	
  3002 	TInt err = KErrNone;
  3003 	TInt offset = iFragOfset;
  3004 
  3005 	do 
  3006 		{				
  3007 		err = iCurrentReq->GetNextPhysicalAddress(aPhysAddr, aPhysLength);
  3008 
  3009 		if (err != KErrNone)
  3010 		    {
  3011 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT1, this, err );
  3012 			return err;
  3013 		    }
  3014 		
  3015 		if (offset >= aPhysLength) // more offset than in this physical chunk
  3016 			{
  3017 			offset -= aPhysLength;
  3018 			}
  3019 		else
  3020 			{
  3021 			// offset < physLength
  3022 			// offset lies within the memory chunk
  3023 			// Adjust length and address for first transfer
  3024 			aPhysLength -= offset;
  3025 			aPhysAddr += offset;
  3026 			offset = -1;
  3027 			}
  3028 			
  3029 		} while (offset >= 0);
  3030 	
  3031 	iFragOfset = 0; // reset offset now complete
  3032 	
  3033 	if (aPhysAddr == 0)
  3034 		{
  3035 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT2, this, KErrNoMemory );
  3036 		return KErrNoMemory;
  3037 		}
  3038 
  3039 #ifdef _DEBUG
  3040 	// DMAHelper ensures memory is dma aligned
  3041 	if ( (aPhysAddr & (iSocket->DmaAlignment()-1) ) )
  3042 		{
  3043 		__KTRACE_OPT(KPBUSDRV, Kern::Printf("mmd:lr:Memory Fragment Not Word Aligned!"));
  3044 		OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_DMA, "Memory fragment not word aligned");
  3045 		Panic(ENotDMAAligned);
  3046 		}
  3047 #endif	//_DEBUG
  3048 	
  3049 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:APF physAddr(0x%x), physLength(%d)",aPhysAddr, aPhysLength));
  3050 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_ADJUSTPHYSICALFRAGMENT_EXIT3, this, err );
  3051 	return err;
  3052 	}
  3053 
  3054 TInt DMmcMediaDriverFlash::PrepareFirstPhysicalFragment(TPhysAddr &aPhysAddr, TInt &aPhysLength, TUint32 aLength)
  3055 //
  3056 // Retrieves the first Physical memory fragment and determines the type of the next transfer
  3057 // Next transfer may either be the last block (end not block aligned) or a block may straddle
  3058 // memory fragments.
  3059 //
  3060 	{
  3061 	OstTraceExt4(TRACE_FLOW, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_ENTRY, "DMmcMediaDriverFlash::PrepareFirstPhysicalFragment;aPhysAddr=%x;aPhysLength=%d;aLength=%x;this=%x", (TUint) aPhysAddr, aPhysLength, (TUint) aLength, (TUint) this);
  3062 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF"));
  3063 	TInt r = KErrNone;
  3064 	
  3065 	r = AdjustPhysicalFragment(aPhysAddr, aPhysLength);
  3066 	
  3067 	if (r == KErrNone)
  3068 		{
  3069 		TUint len = I64LOW(iReqEnd & iBlkMsk);
  3070 		if ( ((TUint32)aPhysLength >= aLength) && len )
  3071 			{
  3072 			__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-end block"));
  3073 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_EB, "End block");
  3074 			//next iteration will be an IPC for the end block
  3075 			//There is enough space in physical memory to fit
  3076 			//the extended read, but exceeds boundary for this request.
  3077 			iIPCLen = len;
  3078 			iRdROB |= KIPCSetup; // IPC setup for next iteration
  3079 			aPhysLength -= len;
  3080 			}
  3081 		
  3082 		if (aPhysLength & iBlkMsk)
  3083 			{
  3084 			__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PFPF-straddles boundary"));
  3085 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_SB, "Straddles boundary");
  3086 			// block must be straddling a fragment boundary
  3087 			// Next iteration must be an IPC 
  3088 			iRdROB |= KIPCSetup;
  3089 			
  3090 			// Calculate the offset into the next memory block
  3091 			iFragOfset = I64LOW(iBlkLen - (aPhysLength & iBlkMsk));
  3092 			aPhysLength &= ~iBlkMsk;
  3093 			}
  3094 		}
  3095 	
  3096 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PFPF err(%d), physAddr(0x%x), physLength(%d)",r, aPhysAddr, aPhysLength));	
  3097 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_PREPAREFIRSTPHYSICALFRAGMENT_EXIT, this, r );
  3098 	return r;
  3099 	}
  3100 	
  3101 
  3102 void DMmcMediaDriverFlash::PrepareNextPhysicalFragment()
  3103 //
  3104 // Retrieves next Physical memory fragment and determines the type of the next transfer
  3105 // Next transfer may either be the last block (end not block aligned) or a block may straddle
  3106 // memory fragments.
  3107 //
  3108 	{
  3109 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_ENTRY );
  3110 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF"));
  3111 	TInt err = KErrNone;
  3112 	TPhysAddr physAddr = 0;
  3113 	TInt physLength = 0;
  3114 	
  3115 	err = AdjustPhysicalFragment(physAddr, physLength);
  3116 	
  3117 	if (err == KErrNone)
  3118 		{
  3119 		if (iPhysEnd+physLength >= iReqEnd)
  3120 			{
  3121 			//Last physical transfer ...
  3122 			TUint len = I64LOW(iReqEnd & iBlkMsk);
  3123 			if (len)
  3124 				{
  3125 				__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-end block"));
  3126 				OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_EB, "End block" );
  3127 				
  3128 				// end point not block aligned!
  3129 				// next iteration must be an IPC call
  3130 				iRdROB |= KIPCSetup;
  3131 				iIPCLen = len;
  3132 				physLength -= len;
  3133 				}
  3134 			else{
  3135 				physLength = I64LOW(iDbEnd  - iPhysEnd);
  3136 				}
  3137 			}
  3138 			
  3139 		if (physLength & iBlkMsk)
  3140 			{
  3141 			__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:PNPF-straddles boundary"));
  3142 			OstTrace0( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_SB, "Straddles boundary" );
  3143 			
  3144 			// block must be straddling a fragment boundary
  3145 			// Next iteration must be an IPC 
  3146 			iRdROB |= KIPCSetup;
  3147 			
  3148 			// Calculate the offset into the next memory block
  3149 			iFragOfset = I64LOW(iBlkLen - (physLength & iBlkMsk));
  3150 			physLength &= ~iBlkMsk;
  3151 			}			
  3152 		
  3153 		iPhysEnd += physLength;
  3154 		}
  3155 		
  3156 	iSession->MoreDataAvailable( (physLength  >> KDiskSectorShift), (TUint8*) physAddr, err);		
  3157 	iSecondBuffer = EFalse;
  3158 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:PNPF"));
  3159 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_PREPARENEXTPHYSICALFRAGMENT_EXIT );
  3160 	}
  3161 
  3162 TUint8* DMmcMediaDriverFlash::ReserveReadBlocks(TInt64 aStart, TInt64 aEnd, TUint32* aLength)
  3163 //
  3164 // Assume the cache has been drained before this function is called and so
  3165 // the first block is not in the cache.  The length of the allocated range is
  3166 // either aEnd - aStart, or enough blocks such that the next block to read
  3167 // is already available in the cache, and so will be read when
  3168 // ReadDataUntilCacheExhausted() is called from the callback DFC.
  3169 //
  3170 	{
  3171 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_ENTRY, this );
  3172 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rrb:%lx,%lx", aStart, aEnd));
  3173 
  3174 	__ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(ERRBStAlign));
  3175 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(ERRBStPos));
  3176 	__ASSERT_DEBUG(aEnd > aStart, Panic(ERRBNotPositive));
  3177 	__ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(ERRBEndAlign));
  3178 	__ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(ERRBEndPos));
  3179 	__ASSERT_DEBUG(!iDoDoubleBuffer, Panic(ENoDBSupport));
  3180 	__ASSERT_CACHE(CacheInvariant(), Panic(ERRBCchInv));
  3181 	__ASSERT_CACHE(GetCachedBlock(aStart & ~iBlkMsk) == 0, Panic(ERRBExist));
  3182 
  3183 	TUint8* raby;
  3184 
  3185 	BuildGammaArray(aStart, aEnd);
  3186 
  3187 	// reposition start index at 0 if the full range would run off the end of the
  3188 	// buffer.  This is heuristic - enabling a longer multi-block may cost some
  3189 	// cached reads.  However, assume long reads do not generally re-read the same
  3190 	// data, and are used for streaming large amounts of data into memory.
  3191 
  3192 	const TInt blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2);
  3193 	TInt startIndex = (iLstUsdCchEnt + 1) % iBlocksInBuffer;
  3194 	if (startIndex + blocksInRange > iBlocksInBuffer)
  3195 		startIndex = 0;
  3196 
  3197 	// starting at startIndex, increase the range until it covers aEnd - aStart,
  3198 	// or until the next block to read is available in the cache.
  3199 
  3200 	TInt blkCnt = 0;
  3201 	TBool finished;
  3202 	do
  3203 		{
  3204 		finished = (
  3205 			// range allocated for entire read
  3206 				blkCnt == blocksInRange
  3207 			// next block already exists in buffer and has not been overwritten
  3208 			// by existing multi-block read
  3209 			|| (	iGamma[blkCnt] != KNoCacheBlock
  3210 				&&	(	iGamma[blkCnt] < startIndex
  3211 					||	iGamma[blkCnt] >= startIndex + blkCnt ) ) );
  3212 
  3213 		if (! finished)
  3214 			++blkCnt;
  3215 		} while (! finished);
  3216 
  3217 	iLstUsdCchEnt = startIndex + blkCnt - 1;
  3218 
  3219 	if (blkCnt < 1) blkCnt = 1; //RBW required < 1 block to be read
  3220 	
  3221 	OstTraceExt2( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_RANGE, "blocksInRange=%d; blkCnt=%d", blocksInRange, blkCnt );
  3222 	
  3223 	TUint32 lengthInBytes = blkCnt << iBlkLenLog2;
  3224 	*aLength = lengthInBytes;
  3225 	MarkBlocks(aStart, aStart + lengthInBytes, startIndex);
  3226 
  3227 	raby = IdxToCchMem(startIndex);
  3228 
  3229 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rrb:%x", (TUint32) raby));
  3230 
  3231 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEREADBLOCKS_EXIT, this, ( TUint )( raby ) );
  3232 	return raby;
  3233 	}
  3234 
  3235 
  3236 TUint8* DMmcMediaDriverFlash::ReserveWriteBlocks(TInt64 aStart, TInt64 aEnd, TUint* aRBM)
  3237 //
  3238 // reserve a range of blocks in the buffer.  If the block containing aStart or aEnd
  3239 // are already in the buffer, attempts to position on them.  This can save one or two
  3240 // RBMs for writes.
  3241 //
  3242 // This function is linear in the number of blocks - it runs through the array
  3243 // exactly twice.
  3244 //
  3245 // aStart and aEnd are not necessarily block aligned - the function uses alignment
  3246 // information to minimize RBMs.
  3247 //
  3248 	{
  3249 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_ENTRY, this );
  3250 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:rwb:%lx,%lx", aStart, aEnd));
  3251 
  3252 	TInt64 physStart = aStart & ~iBlkMsk;
  3253 	TInt64 physEnd = (aEnd + iBlkMsk) & ~iBlkMsk;
  3254 
  3255 	__ASSERT_DEBUG(TotalSizeInBytes() > physStart, Panic(ERWBStPos));
  3256 	__ASSERT_DEBUG(aEnd > aStart, Panic(ERWBNotPositive));
  3257 	__ASSERT_DEBUG(TotalSizeInBytes() >= physEnd, Panic(ERWBEndPos));
  3258 	__ASSERT_DEBUG(iDoPhysicalAddress || iDoDoubleBuffer || (!iDoDoubleBuffer && !iDoPhysicalAddress && physEnd - physStart <= (TInt64)iMaxBufSize), Panic(ERWBOverflow));
  3259 	__ASSERT_CACHE(CacheInvariant(), Panic(ERWBCchInv));
  3260 	
  3261 	const TBool firstPartial = (aStart & iBlkMsk) != 0;
  3262 	const TBool lastPartial  = (aEnd & iBlkMsk)   != 0;
  3263 	
  3264 	const TInt blkCnt = I64LOW((physEnd - physStart) >> iBlkLenLog2);
  3265 	OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_RANGE, "blkCnt=%d", blkCnt );
  3266 	
  3267 	TBool startUsed = EFalse;
  3268 	TBool endUsed   = EFalse;
  3269 	
  3270 	TUint8* raby = NULL;
  3271 
  3272 	if(iDoDoubleBuffer)
  3273 		{
  3274 		//
  3275 		// If we're double-buffering, then the entire cache will be re-used
  3276 		// continuously.  Rather than continually reserve blocks during each 
  3277 		// transfer we calculate the blocks that will be present after all
  3278 		// transfers have completed.
  3279 		//
  3280 		InvalidateCache();
  3281 		raby = iCacheBuf;
  3282 		}
  3283 	else
  3284 		{
  3285 		TInt idx;
  3286 
  3287 		// check if the first or last blocks are already in the buffer.
  3288 		TInt fst = -1, lst = -1;
  3289 		const TInt64 lstBlk = physEnd - iBlkLen;
  3290 		TInt i;
  3291 		for (i = 0; i < iBlocksInBuffer; ++i)
  3292 			{
  3293 			if (iCachedBlocks[i] == physStart)
  3294 				fst = i;
  3295 
  3296 			if (iCachedBlocks[i] == lstBlk)
  3297 				lst = i;
  3298 			}
  3299 
  3300 		const TBool firstUsable = (fst != -1) && (iBlocksInBuffer - fst) >= blkCnt;
  3301 		const TBool lastUsable = (lst != -1) && lst >= (blkCnt - 1);
  3302 
  3303 		if (iDoPhysicalAddress)
  3304 			{				
  3305 			if ( (firstPartial || lastPartial) && blkCnt <= 2)
  3306 				{
  3307 				//Physical addressing not to be used.
  3308 				//more efficent to use local Cache copying
  3309 				iDoPhysicalAddress = EFalse;
  3310 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT1, this, ( TUint )( raby ) );
  3311 				return raby;
  3312 				}
  3313 			else
  3314 				{						
  3315 				raby = iMinorBuf;
  3316 				
  3317 				const TBool firstPres = (fst != -1);
  3318 				const TBool lastPres = (lst != -1);
  3319 				
  3320 				if (firstPartial && firstPres)
  3321 					{
  3322 					// move to minor buffer
  3323 					memcpy(iMinorBuf, IdxToCchMem(fst), iBlkLen);
  3324 					}
  3325 				if (lastPartial && lastPres)
  3326 					{
  3327 					// move to beginning of cache
  3328 					memcpy(iCacheBuf, IdxToCchMem(lst), iBlkLen);
  3329 					}					
  3330 								
  3331 				InvalidateCache(physStart,physEnd);
  3332 				
  3333 				if (lastPartial)
  3334 					{
  3335 					//re-mark beginning of cache
  3336 					MarkBlocks((physEnd-iBlkLen), physEnd, 0);
  3337 					}
  3338 				
  3339 				if (aRBM)
  3340 					{
  3341 					*aRBM = 0;
  3342 										
  3343 					if (firstPartial) 
  3344 						*aRBM |= KWtMinFst; 
  3345 					
  3346 					if (firstPartial && !firstPres) 
  3347 						*aRBM |= KWtRBMFst;
  3348 					
  3349 					if (lastPartial) 
  3350 						*aRBM |= KWtMinLst;					
  3351 					
  3352 					if (lastPartial && !lastPres) 
  3353 						*aRBM |= KWtRBMLst;
  3354 					}
  3355 				
  3356 				OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT2, this, ( TUint )( raby ) );
  3357 				return raby;
  3358 				}
  3359 			} // if (iDoPhysicalAddress)			
  3360 		
  3361 		if (!firstUsable && !lastUsable)
  3362 			{
  3363 			if(iDoDoubleBuffer)
  3364 				{
  3365 				idx = iSecondBuffer ? iBlocksInBuffer >> 1 : 0;
  3366 				}
  3367 			else
  3368 				{
  3369 				idx = (iLstUsdCchEnt + 1) % iBlocksInBuffer;
  3370 				if (idx + blkCnt > iBlocksInBuffer)
  3371 					idx = 0;
  3372 				}
  3373 			}
  3374 		else if (firstUsable && ! lastUsable)
  3375 			{
  3376 			idx = fst;
  3377 			}
  3378 		else if (! firstUsable && lastUsable)
  3379 			{
  3380 			idx = lst - (blkCnt - 1);
  3381 			}
  3382 		else	// (lastUsable && firstUsable)
  3383 			{
  3384 			if (firstPartial || ! lastPartial)
  3385 				idx = fst;
  3386 			else
  3387 				idx = lst - (blkCnt - 1);
  3388 			}
  3389 
  3390 		MarkBlocks(physStart, physEnd, idx);
  3391 
  3392 		// if the range started or ended on a partial block, but could not
  3393 		// be allocated on that existing block, and the existing block is
  3394 		// somewhere in the cache, then memcpy() that block to the end of the
  3395 		// range.  used is not the same as usable - both the start and end
  3396 		// blocks may be usable, through not in the same range, or any range.
  3397 
  3398 		const TInt startExtent = I64LOW(aStart & iBlkMsk);
  3399 		TBool firstInTemp = EFalse;
  3400 		startUsed = (idx == fst);
  3401 		if (! startUsed && firstPartial && fst != -1)
  3402 			{
  3403 			// if the range has started at index occupied by the last block then
  3404 			// temporarily copy to minor buffer.  This is unnecessary when the
  3405 			// last block is not partial because the last block does not need to
  3406 			// be preserved.
  3407 
  3408 			if (idx == lst && lastPartial)
  3409 				{
  3410 				firstInTemp = ETrue;
  3411 				memcpy(iMinorBuf, IdxToCchMem(fst), startExtent);
  3412 				}
  3413 			else
  3414 				{
  3415 				memcpy(IdxToCchMem(idx), IdxToCchMem(fst), startExtent);
  3416 				}
  3417 
  3418 			startUsed = ETrue;
  3419 			}
  3420 
  3421 		endUsed = (idx + blkCnt - 1 == lst);
  3422 		if (! endUsed && lastPartial && lst != -1)
  3423 			{
  3424 			const TInt endOffset = I64LOW(aEnd & iBlkMsk);
  3425 			const TInt endExtent = iBlkLen - endOffset;
  3426 			memcpy(IdxToCchMem(idx + blkCnt - 1) + endOffset, IdxToCchMem(lst) + endOffset, endExtent);
  3427 			endUsed = ETrue;
  3428 			}
  3429 
  3430 		if (firstInTemp)
  3431 			memcpy(IdxToCchMem(idx), iMinorBuf, startExtent);
  3432 
  3433 		// start reclaiming at block following this range
  3434 		iLstUsdCchEnt = idx + blkCnt - 1;
  3435 		raby = IdxToCchMem(idx);
  3436 		}
  3437 
  3438 	// work out if read-before-write required
  3439 	if (aRBM)
  3440 		{
  3441 		*aRBM = 0;
  3442 		// first index was not already in range, and does not start on block boundary
  3443 		if (firstPartial && ! startUsed)
  3444 			*aRBM |= KWtRBMFst;
  3445 
  3446 		// last index was not already in range, and does not end on block boundary
  3447 		if (lastPartial && ! endUsed)
  3448 			*aRBM |= KWtRBMLst;
  3449 
  3450 		// only use one pre-read if contained in single block
  3451 		if (blkCnt == 1 && *aRBM == (KWtRBMFst | KWtRBMLst))
  3452 			*aRBM = KWtRBMFst;
  3453 
  3454 		//
  3455 		// When double-buffering, RMW for the last block is stored in the
  3456 		// minor buffer and writen during the last transfer, so flag this
  3457 		// seperately (as aRBM is used for the initial RMW Read then subsequently cleared).
  3458 		//
  3459 		if(iDoDoubleBuffer && (*aRBM & KWtRBMLst))
  3460 			iDoLastRMW = ETrue;
  3461 		}
  3462 
  3463 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:rwb:%x", (TUint32) raby));
  3464 
  3465 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_RESERVEWRITEBLOCKS_EXIT3, this, ( TUint )( raby ) );
  3466 	return raby;
  3467 	}
  3468 
  3469 void DMmcMediaDriverFlash::MarkBlocks(TInt64 aStart, TInt64 aEnd, TInt aStartIndex)
  3470 //
  3471 // mark range of blocks for media range.  If existing cache entries for any part of
  3472 // the cache are already in the buffer they are invalidated.
  3473 //
  3474 	{
  3475 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_MARKBLOCKS_ENTRY, this );
  3476 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:mb:%lx,%lx,%d", aStart, aEnd, aStartIndex));
  3477 
  3478 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EMBStPos));
  3479 	__ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EMBStAlign));
  3480 	__ASSERT_DEBUG(aEnd > aStart, Panic(EMBNotPositive));
  3481 	__ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EMBEndPos));
  3482 	__ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EMBEndAlign));
  3483 	__ASSERT_DEBUG(aStartIndex + (TInt)((aEnd - aStart) >> iBlkLenLog2) <= iBlocksInBuffer, Panic(EMBOverflow));
  3484 	__ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPre));
  3485 
  3486 	TInt i;
  3487 
  3488 	for (i = 0; i < aStartIndex; ++i)
  3489 		{
  3490 		if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd)
  3491 			iCachedBlocks[i] = KInvalidBlock;
  3492 		}
  3493 
  3494 	TInt blkCnt = I64LOW((aEnd - aStart) >> iBlkLenLog2);
  3495 	OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_MARKBLOCKS_RANGE, "blkCnt=%d", blkCnt );
  3496 	for (i = aStartIndex; i < aStartIndex + blkCnt; ++i)
  3497 		iCachedBlocks[i] = aStart + (static_cast<TUint32>(i - aStartIndex) << iBlkLenLog2);
  3498 
  3499 	for (i = aStartIndex + blkCnt; i < iBlocksInBuffer; ++i)
  3500 		{
  3501 		if (iCachedBlocks[i] >= aStart && iCachedBlocks[i] < aEnd)
  3502 			iCachedBlocks[i] = KInvalidBlock;
  3503 		}
  3504 
  3505 	__ASSERT_CACHE(CacheInvariant(), Panic(EMBCchInvPost));
  3506 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_MARKBLOCKS_EXIT, this );
  3507 	}
  3508 
  3509 
  3510 void DMmcMediaDriverFlash::BuildGammaArray(TInt64 aStart, TInt64 aEnd)
  3511 //
  3512 // iGamma is an array of indexes that correspond to cached blocks starting
  3513 // from aStart.  iGamma[0] is the index of aStart, iGamma[1] is the index of
  3514 // aStart + iBlkLen, and so on.  Building an array here means that all of
  3515 // the available cached entries can be found in linear time instead of
  3516 // quadratically searching through the array for each block.
  3517 //
  3518 	{
  3519 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_ENTRY, this );
  3520 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:bga:%lx,%lx", aStart, aEnd));
  3521 
  3522 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos));
  3523 	__ASSERT_DEBUG((aStart & iBlkMsk) == 0, Panic(EBGAStAlign));
  3524 	__ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive));
  3525 	__ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos));
  3526 	__ASSERT_DEBUG((aEnd & iBlkMsk) == 0, Panic(EBGAEndAlign));
  3527 	__ASSERT_DEBUG(aEnd - aStart <= (TInt64) iMaxBufSize, Panic(EBGAOverflow));
  3528 	__ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv));
  3529 
  3530 	// KNoCacheBlock = (0xff) x 4
  3531 	TUint blocksInRange = I64LOW((aEnd - aStart) >> iBlkLenLog2);
  3532 	OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_RANGE, "blocksInRange=%d", blocksInRange );
  3533 	memset(iGamma, 0xff, sizeof(*iGamma) * blocksInRange);
  3534 
  3535 	TInt64 blkAddr = 0;
  3536 	for (TInt i = 0; ( (blocksInRange > 0 ) && (i < iBlocksInBuffer) ); ++i)
  3537 		{
  3538 		blkAddr = iCachedBlocks[i];
  3539 		if (blkAddr >= aStart && blkAddr < aEnd)
  3540 			{
  3541 			iGamma[I64LOW((blkAddr - aStart) >> iBlkLenLog2)] = i;
  3542 			blocksInRange--;
  3543 			}
  3544 		}
  3545 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_BUILDGAMMAARRAY_EXIT, this );
  3546 	}
  3547 
  3548 void DMmcMediaDriverFlash::InvalidateCache()
  3549 	{
  3550 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_ENTRY );
  3551 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich"));
  3552 
  3553 	// KInvalidBlock = (0xff) x 4
  3554 	memset(iCachedBlocks, 0xff, sizeof(*iCachedBlocks) * iBlocksInBuffer);
  3555 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_INVALIDATECACHE1_EXIT );
  3556 	}
  3557 
  3558 // Invalidate any cache entries from aStart to aEnd
  3559 // This is for DMA writes and is to prevent the cache becoming inconsistent with the media.
  3560 void DMmcMediaDriverFlash::InvalidateCache(TInt64 aStart, TInt64 aEnd)
  3561 	{
  3562 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_ENTRY, this );
  3563 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:ich:%lx,%lx", aStart, aEnd));
  3564 
  3565 	__ASSERT_DEBUG(TotalSizeInBytes() > aStart, Panic(EBGAStPos));
  3566 	__ASSERT_DEBUG(aEnd > aStart, Panic(EBGANotPositive));
  3567 	__ASSERT_DEBUG(TotalSizeInBytes() >= aEnd, Panic(EBGAEndPos));
  3568 
  3569 	const TInt blkCnt = I64LOW((aStart - aEnd) >> iBlkLenLog2);
  3570 	OstTrace1( TRACE_INTERNALS, DMMCMEDIADRIVERFLASH_INVALIDATECACHE_RANGE, "blocksInRange=%d", blkCnt );
  3571 
  3572 	__ASSERT_CACHE(CacheInvariant(), Panic(EBGACchInv));
  3573 	
  3574 	TInt64 endBlk = (blkCnt == 0) ? (aStart+iBlkLen) : aEnd;			
  3575 	
  3576 	for (TInt i = 0; i < iBlocksInBuffer; ++i)
  3577 		{
  3578 		const TInt64 blkAddr = iCachedBlocks[i];
  3579 		if (blkAddr >= aStart && blkAddr < endBlk)
  3580 			iCachedBlocks[i] = KInvalidBlock;
  3581 		}
  3582 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_INVALIDATECACHE2_EXIT, this );
  3583 	}
  3584 
  3585 TUint8* DMmcMediaDriverFlash::IdxToCchMem(TInt aIdx) const
  3586 	{
  3587 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_ENTRY, this );
  3588 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("=mmd:icm:%d", aIdx));
  3589 
  3590 	__ASSERT_DEBUG(aIdx >= 0, Panic(EICMNegative));
  3591 	__ASSERT_DEBUG(aIdx < iBlocksInBuffer, Panic(EICMOverflow));
  3592 	
  3593 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_IDXTOCCHMEM_EXIT, this );
  3594 	return &iCacheBuf[aIdx << iBlkLenLog2];
  3595 	}
  3596 
  3597 TInt DMmcMediaDriverFlash::CchMemToIdx(TUint8* aMemP) const
  3598 	{
  3599 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CCHMEMTOIDX_ENTRY, this );
  3600 	__ASSERT_DEBUG((aMemP >= iCacheBuf) && (aMemP < iCacheBuf + (iBlocksInBuffer << iBlkLenLog2)), Panic(ECMIOverflow));
  3601 
  3602 	return((aMemP - iCacheBuf) >> iBlkLenLog2);
  3603 	}
  3604 
  3605 #ifdef _DEBUG_CACHE
  3606 TBool DMmcMediaDriverFlash::CacheInvariant()
  3607 //
  3608 // check each cache entry refers to a valid block and that no two
  3609 // entries cover the same block.  This algorithm is quadratic in
  3610 // the cache length.
  3611 //
  3612 	{
  3613 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_ENTRY, this );
  3614 	for (TInt i = 0; i < iBlocksInBuffer; ++i)
  3615 		{
  3616 		if (iCachedBlocks[i] == KInvalidBlock)
  3617 			continue;
  3618 
  3619 		if ((iCachedBlocks[i] & iBlkMsk) != 0)
  3620 			return EFalse;
  3621 
  3622 		if (iCachedBlocks[i] >= TotalSizeInBytes())
  3623 			return EFalse;
  3624 
  3625 		for (TInt j = i + 1; j < iBlocksInBuffer; ++j)
  3626 			{
  3627 			if (iCachedBlocks[i] == iCachedBlocks[j])
  3628 				return EFalse;
  3629 			}
  3630 		}
  3631 
  3632 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_CACHEINVARIANT_EXIT, this );
  3633 	return ETrue;
  3634 	}
  3635 #endif
  3636 
  3637 void DMmcMediaDriverFlash::NotifyPowerDown()
  3638 	{
  3639 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_ENTRY );
  3640 	__KTRACE_OPT(KPBUSDRV,Kern::Printf(">Mmc:NotifyPowerDown"));
  3641 
  3642 	iSessionEndDfc.Cancel();
  3643 	iDataTransferCallBackDfc.Cancel();
  3644 
  3645 	EndInCritical();
  3646 
  3647 	// need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once.
  3648 	if (iSession)
  3649 		iStack->CancelSession(iSession);
  3650 
  3651 	CompleteRequest(KErrNotReady);
  3652 	iMedReq = EMReqIdle;
  3653 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYPOWERDOWN_EXIT );
  3654 	}
  3655 
  3656 void DMmcMediaDriverFlash::NotifyEmergencyPowerDown()
  3657 	{
  3658 	OstTraceFunctionEntry0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_ENTRY );
  3659 	__KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown"));
  3660 
  3661 	iSessionEndDfc.Cancel();
  3662 	iDataTransferCallBackDfc.Cancel();
  3663 
  3664 	TInt r=KErrNotReady;
  3665 	if (iCritical)
  3666 		r=KErrAbort;
  3667 	EndInCritical();
  3668 
  3669 	// need to cancel the session as the stack doesn't take too kindly to having the same session engaged more than once.
  3670 	if (iSession)
  3671 		iStack->CancelSession(iSession);
  3672 
  3673 	CompleteRequest(r);
  3674 	iMedReq = EMReqIdle;
  3675 	OstTraceFunctionExit0( DMMCMEDIADRIVERFLASH_NOTIFYEMERGENCYPOWERDOWN_EXIT );
  3676 	}
  3677 
  3678 TInt DMmcMediaDriverFlash::Request(TLocDrvRequest& aRequest)
  3679 	{
  3680 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_REQUEST_ENTRY, this );
  3681 	__KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x id %d",&aRequest,aRequest.Id()));
  3682 	TInt r=KErrNotSupported;
  3683 	TInt id=aRequest.Id();
  3684 	OstTraceDefExt2( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ID, "Request=0x%08x; Request ID=%d", (TUint) &aRequest, id);
  3685 
  3686 #if defined (__TEST_PAGING_MEDIA_DRIVER__)
  3687 	DThread* client=aRequest.Client();
  3688 	__KTRACE_OPT(KLOCDPAGING,Kern::Printf("Client:0x%08x",client));
  3689 	OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CLIENT, "Request client=0x%08x", (TUint) client);
  3690 #endif // __TEST_PAGING_MEDIA_DRIVER__
  3691 
  3692 	// First handle requests that can be handled without deferring
  3693 	if(id==DLocalDrive::ECaps)
  3694 		{
  3695 		TLocalDriveCapsV6& c = *(TLocalDriveCapsV6*)aRequest.RemoteDes();
  3696 		TLocDrv& drive = *aRequest.Drive();
  3697 		r = Caps(drive, c);
  3698 		c.iSize = drive.iPartitionLen;
  3699 		c.iPartitionType = drive.iPartitionType;	
  3700 		c.iHiddenSectors = (TUint) (drive.iPartitionBaseAddr >> KDiskSectorShift);
  3701 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT1, this, r );
  3702 		return r;
  3703 		}
  3704 
  3705 	// All other requests must be deferred if a request is currently in progress
  3706 	if (iCurrentReq)
  3707 		{
  3708 
  3709 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
  3710 		if (DMediaPagingDevice::PageInRequest(*iCurrentReq))
  3711 			iMmcStats.iReqPage++;
  3712 		else
  3713 			iMmcStats.iReqNormal++;
  3714 #endif // __TEST_PAGING_MEDIA_DRIVER__
  3715 
  3716 		// a request is already in progress, so hold on to this one
  3717 		__KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x ret 1",&aRequest));
  3718 		OstTraceDef1( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_IN_PROGRESS, "Request in progress=0x%08x", (TUint) &aRequest);
  3719 		OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT2, this, KMediaDriverDeferRequest );
  3720 		return KMediaDriverDeferRequest;
  3721 		}
  3722 	else
  3723 		{
  3724 		iCurrentReq=&aRequest;
  3725 		TUint partitionType = iCurrentReq->Drive()->iPartitionType;
  3726 		TBool readOnly = (partitionType == KPartitionTypeRofs || partitionType == KPartitionTypeROM);
  3727 
  3728 		switch (id)
  3729 			{
  3730 
  3731 
  3732 #if defined(__DEMAND_PAGING__)
  3733 			case DMediaPagingDevice::ERomPageInRequest:
  3734 				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ERomPageInRequest)"));
  3735 				BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq);
  3736 				OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_ROM_PAGE_IN, "ROM page-in request");
  3737 				r=DoRead();
  3738 				break;
  3739 			case DMediaPagingDevice::ECodePageInRequest:
  3740 				__KTRACE_OPT(KLOCDPAGING,Kern::Printf("DMediaDriverFlash::Request(ECodePageInRequest)"));
  3741 				BTraceContext8(BTrace::EPagingMedia,BTrace::EPagingMediaPagingMedDrvBegin,MEDIA_DEVICE_MMC,iCurrentReq);
  3742 				OstTraceDef0( OST_TRACE_CATEGORY_RND, TRACE_REQUEST, DMMCMEDIADRIVERFLASH_REQUEST_CODE_PAGE_IN, "Code page-in request");
  3743 				r=DoRead();
  3744 				break;
  3745 #endif	// __DEMAND_PAGING__
  3746 
  3747 			case DLocalDrive::EQueryDevice:
  3748 				r = KErrNotSupported;
  3749 				break;
  3750 
  3751 			case DLocalDrive::ERead:
  3752 				r=DoRead();
  3753 				break;
  3754 			case DLocalDrive::EWrite:
  3755 				if (readOnly)
  3756 				    {
  3757 					OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT3, this, KErrNotSupported );
  3758 					return KErrNotSupported;
  3759 				    }
  3760 				r=DoWrite();
  3761 				break;
  3762 			case DLocalDrive::EFormat:
  3763 				if (readOnly)
  3764 				    {
  3765 					OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT4, this, KErrNotSupported );
  3766 					return KErrNotSupported;
  3767 				    }
  3768 				r=DoFormat();
  3769 				break;
  3770 
  3771 #if defined __TEST_PAGING_MEDIA_DRIVER__
  3772 			case DLocalDrive::EControlIO:
  3773 				{
  3774 				r = HandleControlIORequest();
  3775 				break;
  3776 				}
  3777 #endif
  3778 
  3779 			case DLocalDrive::EPasswordUnlock:
  3780 			case DLocalDrive::EPasswordLock:
  3781 			case DLocalDrive::EPasswordClear:
  3782 				// Don't allow passords on internal MMC; one reason is that this may be used for paging and 
  3783 				// we can't really stop paging just because the password hasn't been supplied
  3784 				if (iInternalSlot)
  3785 					r = KErrNotSupported;
  3786 				else
  3787 					r = DoPasswordOp();
  3788 				break;
  3789 			case DLocalDrive::EPasswordErase:
  3790 				{
  3791 				r = LaunchRPIErase();
  3792 				// This will complete the request in the event of an error
  3793 				if(r != KErrNone)
  3794 					PartitionInfoComplete(r);
  3795 
  3796 				r = KErrNone; // ensures to indicate asynchronoous completion
  3797 				break;
  3798 				}
  3799 			case DLocalDrive::EWritePasswordStore:
  3800 				{
  3801 				//
  3802 				// If the card is ready and locked, request the stack to perform the 
  3803 				// auto-unlock sequence.  This is required, as the stack only performs
  3804 				// automatic unlocking during power-up, and the stack may already be powered.
  3805 				//
  3806 				r = KErrNone; // asynchronous completion
  3807 
  3808 				if(iCard->IsReady() && iCard->IsLocked())
  3809 					{
  3810 					iSession->SetupCIMAutoUnlock();
  3811 					if(EngageAndSetRequest(EMReqWritePasswordData, 0) != KErrNone)
  3812 						{
  3813 						// If error, complete with KErrNone anyway
  3814 						//  - The password store has been set, any errors
  3815 						//    will be reported on the next access.
  3816 						CompleteRequest(KErrNone);
  3817 						}
  3818 					}
  3819 				else
  3820 					{
  3821 					CompleteRequest(KErrNone);
  3822 					}
  3823 				break;
  3824 				}
  3825 			case DLocalDrive::EEnlarge:
  3826 			case DLocalDrive::EReduce:
  3827 			default:
  3828 				r=KErrNotSupported;
  3829 				break;
  3830 			}
  3831 		}
  3832 
  3833 	__KTRACE_OPT(KLOCDRV,Kern::Printf("MmcMd:Req %08x cmp %d",&aRequest,r));
  3834 
  3835 	if (r != KErrNone)
  3836 		{
  3837 		iMedReq = EMReqIdle;
  3838 		iCurrentReq=NULL;
  3839 		SetCurrentConsumption(KIdleCurrentInMilliAmps);
  3840 		}
  3841 	
  3842 	OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_REQUEST_EXIT5, this, r );
  3843 	return r;
  3844 	}
  3845 
  3846 void DMmcMediaDriverFlash::Disconnect(DLocalDrive* aLocalDrive, TThreadMessage* aMsg)
  3847 	{
  3848 	OstTraceFunctionEntry1( DMMCMEDIADRIVERFLASH_DISCONNECT_ENTRY, this );
  3849 	// Complete using the default implementation
  3850 	DMediaDriver::Disconnect(aLocalDrive, aMsg);
  3851 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_DISCONNECT_EXIT, this );
  3852 	}
  3853 
  3854 #ifdef _DEBUG_CACHE
  3855 TUint8* DMmcMediaDriverFlash::GetCachedBlock(TInt64 aMdAddr)
  3856 // 
  3857 // return cache block for media at aMdAddr, 0 if not found.
  3858 // This is a debug function to determine whether or not a block is in
  3859 // the cache.  It should not be used for general block retrieval.
  3860 // If there are m blocks in the cache, and n in the requested range,
  3861 // this function is o(mn), whereas BuildGammaArray() is theta(m).
  3862 //
  3863 	{
  3864 	OstTraceFunctionEntryExt( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_ENTRY, this );
  3865 	__KTRACE_OPT(KPBUSDRV, Kern::Printf(">mmd:gcb:%lx", aMdAddr));
  3866 
  3867 	__ASSERT_DEBUG((aMdAddr & iBlkMsk) == 0, Panic(EGCBAlign));
  3868 	__ASSERT_DEBUG(TotalSizeInBytes() > aMdAddr, Panic(EGCBPos));
  3869 	__ASSERT_CACHE(CacheInvariant(), Panic(EGCBCchInv));
  3870 
  3871 	for (TInt i = 0; i < iBlocksInBuffer; ++i)
  3872 		{
  3873 		if (iCachedBlocks[i] == aMdAddr)
  3874 			{
  3875 			TUint8* raby = IdxToCchMem(i);
  3876 			__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:%x", (TUint32) raby));
  3877 			OstTraceFunctionExitExt( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_EXIT1, this, ( TUint )( raby ) );
  3878 			return raby;
  3879 			}
  3880 		}
  3881 
  3882 	__KTRACE_OPT(KPBUSDRV, Kern::Printf("<mmd:gcb:0"));
  3883 	OstTraceFunctionExit1( DMMCMEDIADRIVERFLASH_GETCACHEDBLOCK_EXIT2, this );
  3884 	return 0;
  3885 	}
  3886 #endif // _DEBUG_CACHE
  3887 
  3888 
  3889 #if defined(__TEST_PAGING_MEDIA_DRIVER__)
  3890 /**
  3891 Handles a ControlIO request to the MMC media driver.
  3892 made by one of the MMC paging tests
  3893 
  3894 @internalTechnology
  3895 
  3896 @return Corresponding Symbian OS error code
  3897 */
  3898 TInt DMmcMediaDriverFlash::HandleControlIORequest()
  3899 	{
  3900 	const TInt command = iCurrentReq->Int0();
  3901 	TAny* aParam1 = iCurrentReq->Ptr1();
  3902 //	TAny* aParam2 = iCurrentReq->Ptr2();
  3903 
  3904 	TInt r = KErrCompletion;
  3905 
  3906 	__KTRACE_OPT(KLOCDPAGING,Kern::Printf("[MD :   ] HandleControlIORequest aCommand: 0x%x", command));
  3907 
  3908 
  3909 	switch (command)
  3910 		{
  3911 		case KMmcGetStats:
  3912 			{	
  3913 			DThread* pC = iCurrentReq->Client();
  3914 			DThread* pT = iCurrentReq->RemoteThread();
  3915 			if (!pT)
  3916 				pT = pC;
  3917 			Kern::ThreadRawWrite(pT, aParam1, &iMmcStats, sizeof(iMmcStats), pC);
  3918 		
  3919 			iMmcStats.iReqNormal=0;
  3920 			iMmcStats.iNormalFragmenting=0;
  3921 			iMmcStats.iClashFragmenting=0;
  3922 				
  3923 			break; 
  3924 			}
  3925 		default:
  3926 			r=KErrNotSupported;
  3927 			break;
  3928 		}
  3929 
  3930 	return r;
  3931 	}
  3932 #endif	// __TEST_PAGING_MEDIA_DRIVER__
  3933 
  3934 
  3935 
  3936 
  3937 DECLARE_EXTENSION_PDD()
  3938 	{
  3939 	// NB if the media driver has been defined as a kernel extension in the .OBY/.IBY file 
  3940 	// i.e the "extension" keyword has been used rather than "device", then an instance of 
  3941 	// DPhysicalDeviceMediaMmcFlash will already have been created by InitExtension(). In this 
  3942 	// case the kernel will see that an object of the same name already exists and delete the 
  3943 	// new one.
  3944 	return new DPhysicalDeviceMediaMmcFlash;
  3945 	}
  3946 DECLARE_STANDARD_EXTENSION()
  3947 	{	
  3948 	__KTRACE_OPT(KBOOT,Kern::Printf("Creating MMCDrv PDD"));
  3949 
  3950 	DPhysicalDeviceMediaMmcFlash* device = new DPhysicalDeviceMediaMmcFlash;
  3951 
  3952 	TInt r;
  3953 	if (device==NULL)
  3954 		r=KErrNoMemory;
  3955 	else
  3956 		r=Kern::InstallPhysicalDevice(device);
  3957 	__KTRACE_OPT(KBOOT,Kern::Printf("Installing MMCDrv PDD in kernel returned %d",r));
  3958 
  3959 	__KTRACE_OPT(KBOOT,Kern::Printf("Mmc extension entry point drive returns %d",r));
  3960 	return r;
  3961 	}
  3962 	
  3963