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